summaryrefslogtreecommitdiffstats
path: root/src/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins')
-rw-r--r--src/plugins/CMakeLists.txt15
-rw-r--r--src/plugins/bearer/.prev_CMakeLists.txt12
-rw-r--r--src/plugins/bearer/CMakeLists.txt14
-rw-r--r--src/plugins/bearer/android/CMakeLists.txt4
-rw-r--r--src/plugins/bearer/android/android.pro4
-rw-r--r--src/plugins/bearer/android/jar/.prev_CMakeLists.txt16
-rw-r--r--src/plugins/bearer/android/jar/CMakeLists.txt22
-rw-r--r--src/plugins/bearer/android/jar/jar.pro15
-rw-r--r--src/plugins/bearer/android/jar/src/org/qtproject/qt5/android/bearer/QtNetworkReceiver.java92
-rw-r--r--src/plugins/bearer/android/src/CMakeLists.txt19
-rw-r--r--src/plugins/bearer/android/src/android.json3
-rw-r--r--src/plugins/bearer/android/src/main.cpp63
-rw-r--r--src/plugins/bearer/android/src/qandroidbearerengine.cpp391
-rw-r--r--src/plugins/bearer/android/src/qandroidbearerengine.h95
-rw-r--r--src/plugins/bearer/android/src/src.pro14
-rw-r--r--src/plugins/bearer/android/src/wrappers/androidconnectivitymanager.cpp387
-rw-r--r--src/plugins/bearer/android/src/wrappers/androidconnectivitymanager.h168
-rw-r--r--src/plugins/bearer/android/src/wrappers/wrappers.pri6
-rw-r--r--src/plugins/bearer/bearer.pro11
-rw-r--r--src/plugins/bearer/connman/.prev_CMakeLists.txt26
-rw-r--r--src/plugins/bearer/connman/CMakeLists.txt22
-rw-r--r--src/plugins/bearer/connman/connman.json3
-rw-r--r--src/plugins/bearer/connman/connman.pro16
-rw-r--r--src/plugins/bearer/connman/main.cpp85
-rw-r--r--src/plugins/bearer/connman/qconnmanengine.cpp570
-rw-r--r--src/plugins/bearer/connman/qconnmanengine.h145
-rw-r--r--src/plugins/bearer/connman/qconnmanservice_linux.cpp516
-rw-r--r--src/plugins/bearer/connman/qconnmanservice_linux_p.h230
-rw-r--r--src/plugins/bearer/corewlan/CMakeLists.txt30
-rw-r--r--src/plugins/bearer/corewlan/corewlan.json3
-rw-r--r--src/plugins/bearer/corewlan/corewlan.pro20
-rw-r--r--src/plugins/bearer/corewlan/main.cpp82
-rw-r--r--src/plugins/bearer/corewlan/qcorewlanengine.h147
-rw-r--r--src/plugins/bearer/corewlan/qcorewlanengine.mm862
-rw-r--r--src/plugins/bearer/generic/CMakeLists.txt28
-rw-r--r--src/plugins/bearer/generic/generic.json3
-rw-r--r--src/plugins/bearer/generic/generic.pro16
-rw-r--r--src/plugins/bearer/generic/main.cpp78
-rw-r--r--src/plugins/bearer/generic/qgenericengine.cpp446
-rw-r--r--src/plugins/bearer/generic/qgenericengine.h90
-rw-r--r--src/plugins/bearer/nativewifi/main.cpp127
-rw-r--r--src/plugins/bearer/nativewifi/nativewifi.json3
-rw-r--r--src/plugins/bearer/nativewifi/nativewifi.pro15
-rw-r--r--src/plugins/bearer/nativewifi/platformdefs.h327
-rw-r--r--src/plugins/bearer/nativewifi/qnativewifiengine.cpp622
-rw-r--r--src/plugins/bearer/nativewifi/qnativewifiengine.h106
-rw-r--r--src/plugins/bearer/networkmanager/.prev_CMakeLists.txt26
-rw-r--r--src/plugins/bearer/networkmanager/CMakeLists.txt22
-rw-r--r--src/plugins/bearer/networkmanager/main.cpp84
-rw-r--r--src/plugins/bearer/networkmanager/networkmanager.json3
-rw-r--r--src/plugins/bearer/networkmanager/networkmanager.pro16
-rw-r--r--src/plugins/bearer/networkmanager/qnetworkmanagerengine.cpp935
-rw-r--r--src/plugins/bearer/networkmanager/qnetworkmanagerengine.h153
-rw-r--r--src/plugins/bearer/networkmanager/qnetworkmanagerservice.cpp1019
-rw-r--r--src/plugins/bearer/networkmanager/qnetworkmanagerservice.h500
-rw-r--r--src/plugins/bearer/nla/main.cpp78
-rw-r--r--src/plugins/bearer/nla/nla.json3
-rw-r--r--src/plugins/bearer/nla/nla.pro17
-rw-r--r--src/plugins/bearer/nla/qnlaengine.cpp639
-rw-r--r--src/plugins/bearer/nla/qnlaengine.h110
-rw-r--r--src/plugins/bearer/platformdefs_win.h142
-rw-r--r--src/plugins/doc/snippets/code/src_plugins_platforms_qnx_qqnxwindow.cpp40
-rw-r--r--src/plugins/generic/.prev_CMakeLists.txt23
-rw-r--r--src/plugins/generic/CMakeLists.txt7
-rw-r--r--src/plugins/generic/bsdkeyboard/bsdkeyboard.pro16
-rw-r--r--src/plugins/generic/bsdkeyboard/main.cpp40
-rw-r--r--src/plugins/generic/bsdkeyboard/qbsdkeyboard.cpp40
-rw-r--r--src/plugins/generic/bsdkeyboard/qbsdkeyboard.h44
-rw-r--r--src/plugins/generic/bsdkeyboard/qbsdkeyboard_defaultmap.h42
-rw-r--r--src/plugins/generic/bsdmouse/bsdmouse.pro16
-rw-r--r--src/plugins/generic/bsdmouse/main.cpp40
-rw-r--r--src/plugins/generic/bsdmouse/qbsdmouse.cpp41
-rw-r--r--src/plugins/generic/bsdmouse/qbsdmouse.h40
-rw-r--r--src/plugins/generic/evdevkeyboard/CMakeLists.txt14
-rw-r--r--src/plugins/generic/evdevkeyboard/evdevkeyboard.pro13
-rw-r--r--src/plugins/generic/evdevkeyboard/main.cpp43
-rw-r--r--src/plugins/generic/evdevmouse/CMakeLists.txt14
-rw-r--r--src/plugins/generic/evdevmouse/evdevmouse.pro13
-rw-r--r--src/plugins/generic/evdevmouse/main.cpp43
-rw-r--r--src/plugins/generic/evdevtablet/CMakeLists.txt14
-rw-r--r--src/plugins/generic/evdevtablet/evdevtablet.pro13
-rw-r--r--src/plugins/generic/evdevtablet/main.cpp42
-rw-r--r--src/plugins/generic/evdevtouch/CMakeLists.txt14
-rw-r--r--src/plugins/generic/evdevtouch/evdevtouch.pro13
-rw-r--r--src/plugins/generic/evdevtouch/main.cpp42
-rw-r--r--src/plugins/generic/generic.pro24
-rw-r--r--src/plugins/generic/libinput/CMakeLists.txt14
-rw-r--r--src/plugins/generic/libinput/libinput.pro12
-rw-r--r--src/plugins/generic/libinput/main.cpp44
-rw-r--r--src/plugins/generic/tslib/.prev_CMakeLists.txt23
-rw-r--r--src/plugins/generic/tslib/CMakeLists.txt16
-rw-r--r--src/plugins/generic/tslib/main.cpp44
-rw-r--r--src/plugins/generic/tslib/tslib.pro14
-rw-r--r--src/plugins/generic/tuiotouch/CMakeLists.txt14
-rw-r--r--src/plugins/generic/tuiotouch/main.cpp46
-rw-r--r--src/plugins/generic/tuiotouch/qoscbundle.cpp48
-rw-r--r--src/plugins/generic/tuiotouch/qoscbundle_p.h58
-rw-r--r--src/plugins/generic/tuiotouch/qoscmessage.cpp48
-rw-r--r--src/plugins/generic/tuiotouch/qoscmessage_p.h53
-rw-r--r--src/plugins/generic/tuiotouch/qtuio_p.h42
-rw-r--r--src/plugins/generic/tuiotouch/qtuiocursor_p.h60
-rw-r--r--src/plugins/generic/tuiotouch/qtuiohandler.cpp121
-rw-r--r--src/plugins/generic/tuiotouch/qtuiohandler_p.h53
-rw-r--r--src/plugins/generic/tuiotouch/qtuiotoken_p.h62
-rw-r--r--src/plugins/generic/tuiotouch/tuiotouch.pro28
-rw-r--r--src/plugins/imageformats/CMakeLists.txt3
-rw-r--r--src/plugins/imageformats/gif/.prev_CMakeLists.txt19
-rw-r--r--src/plugins/imageformats/gif/CMakeLists.txt19
-rw-r--r--src/plugins/imageformats/gif/gif.pro10
-rw-r--r--src/plugins/imageformats/gif/main.cpp55
-rw-r--r--src/plugins/imageformats/gif/main.h62
-rw-r--r--src/plugins/imageformats/gif/qgifhandler.cpp118
-rw-r--r--src/plugins/imageformats/gif/qgifhandler_p.h51
-rw-r--r--src/plugins/imageformats/ico/.prev_CMakeLists.txt21
-rw-r--r--src/plugins/imageformats/ico/CMakeLists.txt15
-rw-r--r--src/plugins/imageformats/ico/ico.pro10
-rw-r--r--src/plugins/imageformats/ico/main.cpp59
-rw-r--r--src/plugins/imageformats/ico/main.h59
-rw-r--r--src/plugins/imageformats/ico/qicohandler.cpp106
-rw-r--r--src/plugins/imageformats/ico/qicohandler.h46
-rw-r--r--src/plugins/imageformats/imageformats.pro6
-rw-r--r--src/plugins/imageformats/jpeg/.prev_CMakeLists.txt22
-rw-r--r--src/plugins/imageformats/jpeg/CMakeLists.txt23
-rw-r--r--src/plugins/imageformats/jpeg/jpeg.pro18
-rw-r--r--src/plugins/imageformats/jpeg/main.cpp54
-rw-r--r--src/plugins/imageformats/jpeg/main.h58
-rw-r--r--src/plugins/imageformats/jpeg/qjpeghandler.cpp228
-rw-r--r--src/plugins/imageformats/jpeg/qjpeghandler_p.h44
-rw-r--r--src/plugins/networkinformation/CMakeLists.txt22
-rw-r--r--src/plugins/networkinformation/android/CMakeLists.txt46
-rw-r--r--src/plugins/networkinformation/android/jar/.gitignore6
-rw-r--r--src/plugins/networkinformation/android/jar/build.gradle51
-rw-r--r--src/plugins/networkinformation/android/jar/settings.gradle1
-rw-r--r--src/plugins/networkinformation/android/jar/src/org/qtproject/qt/android/networkinformation/QtAndroidNetworkInformation.java160
-rw-r--r--src/plugins/networkinformation/android/qandroidnetworkinformationbackend.cpp147
-rw-r--r--src/plugins/networkinformation/android/wrapper/androidconnectivitymanager.cpp97
-rw-r--r--src/plugins/networkinformation/android/wrapper/androidconnectivitymanager.h54
-rw-r--r--src/plugins/networkinformation/glib/CMakeLists.txt17
-rw-r--r--src/plugins/networkinformation/glib/qglibnetworkinformationbackend.cpp137
-rw-r--r--src/plugins/networkinformation/networklistmanager/CMakeLists.txt25
-rw-r--r--src/plugins/networkinformation/networklistmanager/qnetworklistmanagerevents.cpp268
-rw-r--r--src/plugins/networkinformation/networklistmanager/qnetworklistmanagerevents.h79
-rw-r--r--src/plugins/networkinformation/networklistmanager/qnetworklistmanagernetworkinformationbackend.cpp199
-rw-r--r--src/plugins/networkinformation/networkmanager/CMakeLists.txt17
-rw-r--r--src/plugins/networkinformation/networkmanager/qnetworkmanagernetworkinformationbackend.cpp181
-rw-r--r--src/plugins/networkinformation/networkmanager/qnetworkmanagernetworkinformationbackend.h60
-rw-r--r--src/plugins/networkinformation/networkmanager/qnetworkmanagerservice.cpp220
-rw-r--r--src/plugins/networkinformation/networkmanager/qnetworkmanagerservice.h173
-rw-r--r--src/plugins/networkinformation/scnetworkreachability/CMakeLists.txt14
-rw-r--r--src/plugins/networkinformation/scnetworkreachability/qscnetworkreachabilitynetworkinformationbackend.mm158
-rw-r--r--src/plugins/platforminputcontexts/CMakeLists.txt5
-rw-r--r--src/plugins/platforminputcontexts/compose/.prev_CMakeLists.txt24
-rw-r--r--src/plugins/platforminputcontexts/compose/CMakeLists.txt20
-rw-r--r--src/plugins/platforminputcontexts/compose/compose.pro19
-rw-r--r--src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.cpp60
-rw-r--r--src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.h42
-rw-r--r--src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontextmain.cpp46
-rw-r--r--src/plugins/platforminputcontexts/ibus/CMakeLists.txt16
-rw-r--r--src/plugins/platforminputcontexts/ibus/ibus.pro22
-rw-r--r--src/plugins/platforminputcontexts/ibus/interfaces/org.freedesktop.IBus.InputContext.xml18
-rw-r--r--src/plugins/platforminputcontexts/ibus/main.cpp49
-rw-r--r--src/plugins/platforminputcontexts/ibus/qibusinputcontextproxy.cpp2
-rw-r--r--src/plugins/platforminputcontexts/ibus/qibusinputcontextproxy.h57
-rw-r--r--src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp291
-rw-r--r--src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.h43
-rw-r--r--src/plugins/platforminputcontexts/ibus/qibusproxy.cpp3
-rw-r--r--src/plugins/platforminputcontexts/ibus/qibusproxy.h19
-rw-r--r--src/plugins/platforminputcontexts/ibus/qibusproxyportal.cpp2
-rw-r--r--src/plugins/platforminputcontexts/ibus/qibusproxyportal.h2
-rw-r--r--src/plugins/platforminputcontexts/ibus/qibustypes.cpp84
-rw-r--r--src/plugins/platforminputcontexts/ibus/qibustypes.h92
-rw-r--r--src/plugins/platforminputcontexts/platforminputcontexts.pro11
-rw-r--r--src/plugins/platforms/.prev_CMakeLists.txt57
-rw-r--r--src/plugins/platforms/CMakeLists.txt35
-rw-r--r--src/plugins/platforms/android/.prev_CMakeLists.txt85
-rw-r--r--src/plugins/platforms/android/CMakeLists.txt74
-rw-r--r--src/plugins/platforms/android/android.pro94
-rw-r--r--src/plugins/platforms/android/androidcontentfileengine.cpp860
-rw-r--r--src/plugins/platforms/android/androidcontentfileengine.h131
-rw-r--r--src/plugins/platforms/android/androiddeadlockprotector.cpp43
-rw-r--r--src/plugins/platforms/android/androiddeadlockprotector.h54
-rw-r--r--src/plugins/platforms/android/androidjniaccessibility.cpp495
-rw-r--r--src/plugins/platforms/android/androidjniaccessibility.h52
-rw-r--r--src/plugins/platforms/android/androidjniclipboard.cpp128
-rw-r--r--src/plugins/platforms/android/androidjniclipboard.h62
-rw-r--r--src/plugins/platforms/android/androidjniinput.cpp475
-rw-r--r--src/plugins/platforms/android/androidjniinput.h73
-rw-r--r--src/plugins/platforms/android/androidjnimain.cpp698
-rw-r--r--src/plugins/platforms/android/androidjnimain.h89
-rw-r--r--src/plugins/platforms/android/androidjnimenu.cpp127
-rw-r--r--src/plugins/platforms/android/androidjnimenu.h45
-rw-r--r--src/plugins/platforms/android/androidsurfaceclient.h60
-rw-r--r--src/plugins/platforms/android/androidwindowembedding.cpp75
-rw-r--r--src/plugins/platforms/android/androidwindowembedding.h41
-rw-r--r--src/plugins/platforms/android/extract-dummy.cpp48
-rw-r--r--src/plugins/platforms/android/extract.cpp64
-rw-r--r--src/plugins/platforms/android/main.cpp44
-rw-r--r--src/plugins/platforms/android/qandroidassetsfileenginehandler.cpp262
-rw-r--r--src/plugins/platforms/android/qandroidassetsfileenginehandler.h42
-rw-r--r--src/plugins/platforms/android/qandroideventdispatcher.cpp48
-rw-r--r--src/plugins/platforms/android/qandroideventdispatcher.h46
-rw-r--r--src/plugins/platforms/android/qandroidinputcontext.cpp485
-rw-r--r--src/plugins/platforms/android/qandroidinputcontext.h50
-rw-r--r--src/plugins/platforms/android/qandroidplatformaccessibility.cpp69
-rw-r--r--src/plugins/platforms/android/qandroidplatformaccessibility.h41
-rw-r--r--src/plugins/platforms/android/qandroidplatformbackingstore.cpp88
-rw-r--r--src/plugins/platforms/android/qandroidplatformbackingstore.h65
-rw-r--r--src/plugins/platforms/android/qandroidplatformclipboard.cpp134
-rw-r--r--src/plugins/platforms/android/qandroidplatformclipboard.h62
-rw-r--r--src/plugins/platforms/android/qandroidplatformdialoghelpers.cpp135
-rw-r--r--src/plugins/platforms/android/qandroidplatformdialoghelpers.h61
-rw-r--r--src/plugins/platforms/android/qandroidplatformfiledialoghelper.cpp273
-rw-r--r--src/plugins/platforms/android/qandroidplatformfiledialoghelper.h78
-rw-r--r--src/plugins/platforms/android/qandroidplatformfontdatabase.cpp94
-rw-r--r--src/plugins/platforms/android/qandroidplatformfontdatabase.h43
-rw-r--r--src/plugins/platforms/android/qandroidplatformforeignwindow.cpp129
-rw-r--r--src/plugins/platforms/android/qandroidplatformforeignwindow.h57
-rw-r--r--src/plugins/platforms/android/qandroidplatformiconengine.cpp616
-rw-r--r--src/plugins/platforms/android/qandroidplatformiconengine.h44
-rw-r--r--src/plugins/platforms/android/qandroidplatformintegration.cpp431
-rw-r--r--src/plugins/platforms/android/qandroidplatformintegration.h119
-rw-r--r--src/plugins/platforms/android/qandroidplatformmenu.cpp51
-rw-r--r--src/plugins/platforms/android/qandroidplatformmenu.h45
-rw-r--r--src/plugins/platforms/android/qandroidplatformmenubar.cpp40
-rw-r--r--src/plugins/platforms/android/qandroidplatformmenubar.h46
-rw-r--r--src/plugins/platforms/android/qandroidplatformmenuitem.cpp46
-rw-r--r--src/plugins/platforms/android/qandroidplatformmenuitem.h40
-rw-r--r--src/plugins/platforms/android/qandroidplatformoffscreensurface.cpp71
-rw-r--r--src/plugins/platforms/android/qandroidplatformoffscreensurface.h53
-rw-r--r--src/plugins/platforms/android/qandroidplatformopenglcontext.cpp54
-rw-r--r--src/plugins/platforms/android/qandroidplatformopenglcontext.h48
-rw-r--r--src/plugins/platforms/android/qandroidplatformopenglwindow.cpp138
-rw-r--r--src/plugins/platforms/android/qandroidplatformopenglwindow.h59
-rw-r--r--src/plugins/platforms/android/qandroidplatformscreen.cpp402
-rw-r--r--src/plugins/platforms/android/qandroidplatformscreen.h97
-rw-r--r--src/plugins/platforms/android/qandroidplatformservices.cpp144
-rw-r--r--src/plugins/platforms/android/qandroidplatformservices.h54
-rw-r--r--src/plugins/platforms/android/qandroidplatformtheme.cpp242
-rw-r--r--src/plugins/platforms/android/qandroidplatformtheme.h56
-rw-r--r--src/plugins/platforms/android/qandroidplatformvulkaninstance.cpp40
-rw-r--r--src/plugins/platforms/android/qandroidplatformvulkaninstance.h42
-rw-r--r--src/plugins/platforms/android/qandroidplatformvulkanwindow.cpp106
-rw-r--r--src/plugins/platforms/android/qandroidplatformvulkanwindow.h59
-rw-r--r--src/plugins/platforms/android/qandroidplatformwindow.cpp320
-rw-r--r--src/plugins/platforms/android/qandroidplatformwindow.h114
-rw-r--r--src/plugins/platforms/android/qandroidsystemlocale.cpp124
-rw-r--r--src/plugins/platforms/android/qandroidsystemlocale.h45
-rw-r--r--src/plugins/platforms/bsdfb/bsdfb.pro19
-rw-r--r--src/plugins/platforms/bsdfb/main.cpp46
-rw-r--r--src/plugins/platforms/bsdfb/qbsdfbintegration.cpp54
-rw-r--r--src/plugins/platforms/bsdfb/qbsdfbintegration.h40
-rw-r--r--src/plugins/platforms/bsdfb/qbsdfbscreen.cpp55
-rw-r--r--src/plugins/platforms/bsdfb/qbsdfbscreen.h42
-rw-r--r--src/plugins/platforms/cocoa/.prev_CMakeLists.txt150
-rw-r--r--src/plugins/platforms/cocoa/CMakeLists.txt90
-rw-r--r--src/plugins/platforms/cocoa/cocoa.pro149
-rw-r--r--src/plugins/platforms/cocoa/main.mm46
-rw-r--r--src/plugins/platforms/cocoa/messages.cpp115
-rw-r--r--src/plugins/platforms/cocoa/messages.h69
-rw-r--r--src/plugins/platforms/cocoa/qcocoaaccessibility.h52
-rw-r--r--src/plugins/platforms/cocoa/qcocoaaccessibility.mm68
-rw-r--r--src/plugins/platforms/cocoa/qcocoaaccessibilityelement.h67
-rw-r--r--src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm701
-rw-r--r--src/plugins/platforms/cocoa/qcocoaapplication.h54
-rw-r--r--src/plugins/platforms/cocoa/qcocoaapplication.mm42
-rw-r--r--src/plugins/platforms/cocoa/qcocoaapplicationdelegate.h54
-rw-r--r--src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm144
-rw-r--r--src/plugins/platforms/cocoa/qcocoabackingstore.h96
-rw-r--r--src/plugins/platforms/cocoa/qcocoabackingstore.mm747
-rw-r--r--src/plugins/platforms/cocoa/qcocoaclipboard.h40
-rw-r--r--src/plugins/platforms/cocoa/qcocoaclipboard.mm50
-rw-r--r--src/plugins/platforms/cocoa/qcocoacolordialoghelper.h44
-rw-r--r--src/plugins/platforms/cocoa/qcocoacolordialoghelper.mm121
-rw-r--r--src/plugins/platforms/cocoa/qcocoacursor.h48
-rw-r--r--src/plugins/platforms/cocoa/qcocoacursor.mm119
-rw-r--r--src/plugins/platforms/cocoa/qcocoadrag.h53
-rw-r--r--src/plugins/platforms/cocoa/qcocoadrag.mm207
-rw-r--r--src/plugins/platforms/cocoa/qcocoaeventdispatcher.h67
-rw-r--r--src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm231
-rw-r--r--src/plugins/platforms/cocoa/qcocoafiledialoghelper.h68
-rw-r--r--src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm923
-rw-r--r--src/plugins/platforms/cocoa/qcocoafontdialoghelper.h43
-rw-r--r--src/plugins/platforms/cocoa/qcocoafontdialoghelper.mm71
-rw-r--r--src/plugins/platforms/cocoa/qcocoaglcontext.h53
-rw-r--r--src/plugins/platforms/cocoa/qcocoaglcontext.mm192
-rw-r--r--src/plugins/platforms/cocoa/qcocoahelpers.h165
-rw-r--r--src/plugins/platforms/cocoa/qcocoahelpers.mm203
-rw-r--r--src/plugins/platforms/cocoa/qcocoainputcontext.h52
-rw-r--r--src/plugins/platforms/cocoa/qcocoainputcontext.mm154
-rw-r--r--src/plugins/platforms/cocoa/qcocoaintegration.h82
-rw-r--r--src/plugins/platforms/cocoa/qcocoaintegration.mm254
-rw-r--r--src/plugins/platforms/cocoa/qcocoaintrospection.h47
-rw-r--r--src/plugins/platforms/cocoa/qcocoaintrospection.mm40
-rw-r--r--src/plugins/platforms/cocoa/qcocoakeymapper.h104
-rw-r--r--src/plugins/platforms/cocoa/qcocoakeymapper.mm471
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenu.h50
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenu.mm129
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenubar.h49
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenubar.mm213
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenuitem.h59
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenuitem.mm218
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenuloader.h47
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenuloader.mm57
-rw-r--r--src/plugins/platforms/cocoa/qcocoamessagedialog.h38
-rw-r--r--src/plugins/platforms/cocoa/qcocoamessagedialog.mm425
-rw-r--r--src/plugins/platforms/cocoa/qcocoamimetypes.h40
-rw-r--r--src/plugins/platforms/cocoa/qcocoamimetypes.mm102
-rw-r--r--src/plugins/platforms/cocoa/qcocoanativeinterface.h105
-rw-r--r--src/plugins/platforms/cocoa/qcocoanativeinterface.mm249
-rw-r--r--src/plugins/platforms/cocoa/qcocoansmenu.h61
-rw-r--r--src/plugins/platforms/cocoa/qcocoansmenu.mm64
-rw-r--r--src/plugins/platforms/cocoa/qcocoaprintdevice.h124
-rw-r--r--src/plugins/platforms/cocoa/qcocoaprintdevice.mm494
-rw-r--r--src/plugins/platforms/cocoa/qcocoaprintersupport.h67
-rw-r--r--src/plugins/platforms/cocoa/qcocoaprintersupport.mm107
-rw-r--r--src/plugins/platforms/cocoa/qcocoaresources.qrc7
-rw-r--r--src/plugins/platforms/cocoa/qcocoascreen.h70
-rw-r--r--src/plugins/platforms/cocoa/qcocoascreen.mm441
-rw-r--r--src/plugins/platforms/cocoa/qcocoaservices.h44
-rw-r--r--src/plugins/platforms/cocoa/qcocoaservices.mm79
-rw-r--r--src/plugins/platforms/cocoa/qcocoasessionmanager.cpp42
-rw-r--r--src/plugins/platforms/cocoa/qcocoasessionmanager.h40
-rw-r--r--src/plugins/platforms/cocoa/qcocoasystemtrayicon.h68
-rw-r--r--src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm354
-rw-r--r--src/plugins/platforms/cocoa/qcocoatheme.h50
-rw-r--r--src/plugins/platforms/cocoa/qcocoatheme.mm282
-rw-r--r--src/plugins/platforms/cocoa/qcocoavulkaninstance.h50
-rw-r--r--src/plugins/platforms/cocoa/qcocoavulkaninstance.mm51
-rw-r--r--src/plugins/platforms/cocoa/qcocoawindow.h138
-rw-r--r--src/plugins/platforms/cocoa/qcocoawindow.mm907
-rw-r--r--src/plugins/platforms/cocoa/qcocoawindowmanager.h49
-rw-r--r--src/plugins/platforms/cocoa/qcocoawindowmanager.mm71
-rw-r--r--src/plugins/platforms/cocoa/qiosurfacegraphicsbuffer.h43
-rw-r--r--src/plugins/platforms/cocoa/qiosurfacegraphicsbuffer.mm40
-rw-r--r--src/plugins/platforms/cocoa/qmacclipboard.h80
-rw-r--r--src/plugins/platforms/cocoa/qmacclipboard.mm368
-rw-r--r--src/plugins/platforms/cocoa/qmacdefines_mac.h129
-rw-r--r--src/plugins/platforms/cocoa/qmultitouch_mac.mm94
-rw-r--r--src/plugins/platforms/cocoa/qmultitouch_mac_p.h55
-rw-r--r--src/plugins/platforms/cocoa/qnsview.h65
-rw-r--r--src/plugins/platforms/cocoa/qnsview.mm163
-rw-r--r--src/plugins/platforms/cocoa/qnsview_accessibility.mm56
-rw-r--r--src/plugins/platforms/cocoa/qnsview_complextext.mm757
-rw-r--r--src/plugins/platforms/cocoa/qnsview_dragging.mm91
-rw-r--r--src/plugins/platforms/cocoa/qnsview_drawing.mm143
-rw-r--r--src/plugins/platforms/cocoa/qnsview_gestures.mm70
-rw-r--r--src/plugins/platforms/cocoa/qnsview_keys.mm402
-rw-r--r--src/plugins/platforms/cocoa/qnsview_menus.mm163
-rw-r--r--src/plugins/platforms/cocoa/qnsview_mouse.mm454
-rw-r--r--src/plugins/platforms/cocoa/qnsview_tablet.mm244
-rw-r--r--src/plugins/platforms/cocoa/qnsview_touch.mm60
-rw-r--r--src/plugins/platforms/cocoa/qnswindow.h58
-rw-r--r--src/plugins/platforms/cocoa/qnswindow.mm221
-rw-r--r--src/plugins/platforms/cocoa/qnswindowdelegate.h46
-rw-r--r--src/plugins/platforms/cocoa/qnswindowdelegate.mm66
-rw-r--r--src/plugins/platforms/cocoa/qpaintengine_mac.mm1422
-rw-r--r--src/plugins/platforms/cocoa/qpaintengine_mac_p.h205
-rw-r--r--src/plugins/platforms/cocoa/qprintengine_mac.mm793
-rw-r--r--src/plugins/platforms/cocoa/qprintengine_mac_p.h157
-rw-r--r--src/plugins/platforms/cocoa/qt_attribution.json2
-rw-r--r--src/plugins/platforms/cocoa/qt_mac_p.h127
-rw-r--r--src/plugins/platforms/direct2d/CMakeLists.txt228
-rw-r--r--src/plugins/platforms/direct2d/direct2d.pro47
-rw-r--r--src/plugins/platforms/direct2d/qwindowsdirect2dbackingstore.cpp41
-rw-r--r--src/plugins/platforms/direct2d/qwindowsdirect2dbackingstore.h40
-rw-r--r--src/plugins/platforms/direct2d/qwindowsdirect2dbitmap.cpp43
-rw-r--r--src/plugins/platforms/direct2d/qwindowsdirect2dbitmap.h40
-rw-r--r--src/plugins/platforms/direct2d/qwindowsdirect2dcontext.cpp41
-rw-r--r--src/plugins/platforms/direct2d/qwindowsdirect2dcontext.h40
-rw-r--r--src/plugins/platforms/direct2d/qwindowsdirect2ddevicecontext.cpp40
-rw-r--r--src/plugins/platforms/direct2d/qwindowsdirect2ddevicecontext.h40
-rw-r--r--src/plugins/platforms/direct2d/qwindowsdirect2dhelpers.h40
-rw-r--r--src/plugins/platforms/direct2d/qwindowsdirect2dintegration.cpp41
-rw-r--r--src/plugins/platforms/direct2d/qwindowsdirect2dintegration.h40
-rw-r--r--src/plugins/platforms/direct2d/qwindowsdirect2dnativeinterface.cpp40
-rw-r--r--src/plugins/platforms/direct2d/qwindowsdirect2dnativeinterface.h40
-rw-r--r--src/plugins/platforms/direct2d/qwindowsdirect2dpaintdevice.cpp43
-rw-r--r--src/plugins/platforms/direct2d/qwindowsdirect2dpaintdevice.h40
-rw-r--r--src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp69
-rw-r--r--src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.h40
-rw-r--r--src/plugins/platforms/direct2d/qwindowsdirect2dplatformpixmap.cpp42
-rw-r--r--src/plugins/platforms/direct2d/qwindowsdirect2dplatformpixmap.h40
-rw-r--r--src/plugins/platforms/direct2d/qwindowsdirect2dplatformplugin.cpp46
-rw-r--r--src/plugins/platforms/direct2d/qwindowsdirect2dwindow.cpp40
-rw-r--r--src/plugins/platforms/direct2d/qwindowsdirect2dwindow.h40
-rw-r--r--src/plugins/platforms/directfb/.prev_CMakeLists.txt61
-rw-r--r--src/plugins/platforms/directfb/CMakeLists.txt33
-rw-r--r--src/plugins/platforms/directfb/directfb.pro53
-rw-r--r--src/plugins/platforms/directfb/main.cpp48
-rw-r--r--src/plugins/platforms/directfb/qdirectfb_egl.cpp48
-rw-r--r--src/plugins/platforms/directfb/qdirectfb_egl.h40
-rw-r--r--src/plugins/platforms/directfb/qdirectfbbackingstore.cpp40
-rw-r--r--src/plugins/platforms/directfb/qdirectfbbackingstore.h48
-rw-r--r--src/plugins/platforms/directfb/qdirectfbblitter.cpp46
-rw-r--r--src/plugins/platforms/directfb/qdirectfbblitter.h71
-rw-r--r--src/plugins/platforms/directfb/qdirectfbconvenience.cpp48
-rw-r--r--src/plugins/platforms/directfb/qdirectfbconvenience.h44
-rw-r--r--src/plugins/platforms/directfb/qdirectfbcursor.cpp40
-rw-r--r--src/plugins/platforms/directfb/qdirectfbcursor.h42
-rw-r--r--src/plugins/platforms/directfb/qdirectfbeglhooks.h40
-rw-r--r--src/plugins/platforms/directfb/qdirectfbeglhooks_stub.cpp40
-rw-r--r--src/plugins/platforms/directfb/qdirectfbglcontext.cpp40
-rw-r--r--src/plugins/platforms/directfb/qdirectfbglcontext.h40
-rw-r--r--src/plugins/platforms/directfb/qdirectfbinput.cpp53
-rw-r--r--src/plugins/platforms/directfb/qdirectfbinput.h42
-rw-r--r--src/plugins/platforms/directfb/qdirectfbintegration.cpp46
-rw-r--r--src/plugins/platforms/directfb/qdirectfbintegration.h58
-rw-r--r--src/plugins/platforms/directfb/qdirectfbscreen.cpp40
-rw-r--r--src/plugins/platforms/directfb/qdirectfbscreen.h50
-rw-r--r--src/plugins/platforms/directfb/qdirectfbwindow.cpp40
-rw-r--r--src/plugins/platforms/directfb/qdirectfbwindow.h60
-rw-r--r--src/plugins/platforms/eglfs/.prev_CMakeLists.txt113
-rw-r--r--src/plugins/platforms/eglfs/CMakeLists.txt90
-rw-r--r--src/plugins/platforms/eglfs/api/api.pri35
-rw-r--r--src/plugins/platforms/eglfs/api/qeglfscontext.cpp66
-rw-r--r--src/plugins/platforms/eglfs/api/qeglfscontext_p.h48
-rw-r--r--src/plugins/platforms/eglfs/api/qeglfscursor.cpp128
-rw-r--r--src/plugins/platforms/eglfs/api/qeglfscursor_p.h48
-rw-r--r--src/plugins/platforms/eglfs/api/qeglfsdeviceintegration.cpp115
-rw-r--r--src/plugins/platforms/eglfs/api/qeglfsdeviceintegration_p.h50
-rw-r--r--src/plugins/platforms/eglfs/api/qeglfsglobal_p.h42
-rw-r--r--src/plugins/platforms/eglfs/api/qeglfshooks.cpp40
-rw-r--r--src/plugins/platforms/eglfs/api/qeglfshooks_p.h40
-rw-r--r--src/plugins/platforms/eglfs/api/qeglfsintegration.cpp143
-rw-r--r--src/plugins/platforms/eglfs/api/qeglfsintegration_p.h73
-rw-r--r--src/plugins/platforms/eglfs/api/qeglfsoffscreenwindow.cpp42
-rw-r--r--src/plugins/platforms/eglfs/api/qeglfsoffscreenwindow_p.h40
-rw-r--r--src/plugins/platforms/eglfs/api/qeglfsscreen.cpp92
-rw-r--r--src/plugins/platforms/eglfs/api/qeglfsscreen_p.h45
-rw-r--r--src/plugins/platforms/eglfs/api/qeglfswindow.cpp106
-rw-r--r--src/plugins/platforms/eglfs/api/qeglfswindow_p.h52
-rw-r--r--src/plugins/platforms/eglfs/api/vulkan/qeglfsvulkaninstance_p.h88
-rw-r--r--src/plugins/platforms/eglfs/api/vulkan/qeglfsvulkanwindow.cpp75
-rw-r--r--src/plugins/platforms/eglfs/api/vulkan/qeglfsvulkanwindow_p.h74
-rw-r--r--src/plugins/platforms/eglfs/cursor.qrc7
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/.prev_CMakeLists.txt38
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/CMakeLists.txt17
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/deviceintegration.pro17
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_brcm/eglfs_brcm.pro22
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_brcm/qeglfsbrcmintegration.cpp42
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_brcm/qeglfsbrcmintegration.h40
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_brcm/qeglfsbrcmmain.cpp40
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/CMakeLists.txt13
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/eglfs_emu.pro27
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/qeglfsemulatorintegration.cpp46
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/qeglfsemulatorintegration.h40
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/qeglfsemulatorscreen.cpp88
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/qeglfsemulatorscreen.h43
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/qeglfsemumain.cpp40
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/CMakeLists.txt49
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/eglfs_kms.pro30
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmcursor.cpp75
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmcursor.h122
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmcursor_p.h97
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice.cpp84
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice.h88
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice_p.h68
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmintegration.cpp56
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmintegration.h74
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmintegration_p.h49
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmmain.cpp44
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp298
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.h106
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen_p.h92
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmwindow.cpp64
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmwindow.h70
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmwindow_p.h45
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/CMakeLists.txt16
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/eglfs_kms_egldevice.pro26
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevice.cpp49
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevice.h42
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.cpp55
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.h46
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicemain.cpp40
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicescreen.cpp104
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicescreen.h45
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/CMakeLists.txt23
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/eglfs_kms_support.pro24
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice.cpp46
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice.h68
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice_p.h37
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmseventreader.cpp55
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmseventreader.h99
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmseventreader_p.h74
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmshelpers.h60
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmshelpers_p.h35
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsintegration.cpp67
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsintegration.h87
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsintegration_p.h63
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen.cpp81
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen.h125
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen_p.h102
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/eglfs_kms_vsp2.pro30
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qeglfskmsvsp2device.cpp46
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qeglfskmsvsp2device.h48
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qeglfskmsvsp2integration.cpp101
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qeglfskmsvsp2integration.h56
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qeglfskmsvsp2main.cpp40
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qeglfskmsvsp2screen.cpp46
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qeglfskmsvsp2screen.h63
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qlinuxmediadevice.cpp44
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qlinuxmediadevice.h40
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qvsp2blendingdevice.cpp46
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qvsp2blendingdevice.h44
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_mali/CMakeLists.txt24
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_mali/eglfs_mali.pro20
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_mali/qeglfsmaliintegration.cpp40
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_mali/qeglfsmaliintegration.h40
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_mali/qeglfsmalimain.cpp40
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_openwfd/CMakeLists.txt22
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_openwfd/eglfs_openwfd.pro17
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_openwfd/qeglfsopenwfdintegration.cpp64
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_openwfd/qeglfsopenwfdintegration.h42
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_openwfd/qeglfsopenwfdmain.cpp40
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_rcar/eglfs_rcar.pro18
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_rcar/qeglfsrcarintegration.cpp42
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_rcar/qeglfsrcarintegration.h40
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_rcar/qeglfsrcarmain.cpp40
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/CMakeLists.txt25
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/eglfs_viv.pro18
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/qeglfsvivintegration.cpp65
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/qeglfsvivintegration.h46
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/qeglfsvivmain.cpp40
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_viv_wl/CMakeLists.txt26
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_viv_wl/eglfs_viv_wl.pro20
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_viv_wl/qeglfsvivwlintegration.cpp44
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_viv_wl/qeglfsvivwlintegration.h40
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_viv_wl/qeglfsvivwlmain.cpp40
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/CMakeLists.txt14
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/eglfs_x11.pro22
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/qeglfsx11integration.cpp44
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/qeglfsx11integration.h40
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/qeglfsx11main.cpp40
-rw-r--r--src/plugins/platforms/eglfs/eglfs-plugin.pro19
-rw-r--r--src/plugins/platforms/eglfs/eglfs.pro6
-rw-r--r--src/plugins/platforms/eglfs/eglfsdeviceintegration.pro52
-rw-r--r--src/plugins/platforms/eglfs/qeglfsmain.cpp46
-rw-r--r--src/plugins/platforms/haiku/haiku.pro41
-rw-r--r--src/plugins/platforms/haiku/main.cpp44
-rw-r--r--src/plugins/platforms/haiku/main.h40
-rw-r--r--src/plugins/platforms/haiku/qhaikuapplication.cpp40
-rw-r--r--src/plugins/platforms/haiku/qhaikuapplication.h40
-rw-r--r--src/plugins/platforms/haiku/qhaikubuffer.cpp40
-rw-r--r--src/plugins/platforms/haiku/qhaikubuffer.h40
-rw-r--r--src/plugins/platforms/haiku/qhaikuclipboard.cpp48
-rw-r--r--src/plugins/platforms/haiku/qhaikuclipboard.h40
-rw-r--r--src/plugins/platforms/haiku/qhaikucursor.cpp40
-rw-r--r--src/plugins/platforms/haiku/qhaikucursor.h40
-rw-r--r--src/plugins/platforms/haiku/qhaikuintegration.cpp46
-rw-r--r--src/plugins/platforms/haiku/qhaikuintegration.h40
-rw-r--r--src/plugins/platforms/haiku/qhaikukeymapper.cpp40
-rw-r--r--src/plugins/platforms/haiku/qhaikukeymapper.h40
-rw-r--r--src/plugins/platforms/haiku/qhaikurasterbackingstore.cpp40
-rw-r--r--src/plugins/platforms/haiku/qhaikurasterbackingstore.h40
-rw-r--r--src/plugins/platforms/haiku/qhaikurasterwindow.cpp40
-rw-r--r--src/plugins/platforms/haiku/qhaikurasterwindow.h40
-rw-r--r--src/plugins/platforms/haiku/qhaikuscreen.cpp40
-rw-r--r--src/plugins/platforms/haiku/qhaikuscreen.h40
-rw-r--r--src/plugins/platforms/haiku/qhaikuservices.cpp40
-rw-r--r--src/plugins/platforms/haiku/qhaikuservices.h40
-rw-r--r--src/plugins/platforms/haiku/qhaikuutils.cpp40
-rw-r--r--src/plugins/platforms/haiku/qhaikuutils.h40
-rw-r--r--src/plugins/platforms/haiku/qhaikuwindow.cpp42
-rw-r--r--src/plugins/platforms/haiku/qhaikuwindow.h40
-rw-r--r--src/plugins/platforms/integrity/integrity.pro29
-rw-r--r--src/plugins/platforms/integrity/main.cpp44
-rw-r--r--src/plugins/platforms/integrity/qintegrityfbintegration.cpp46
-rw-r--r--src/plugins/platforms/integrity/qintegrityfbintegration.h40
-rw-r--r--src/plugins/platforms/integrity/qintegrityfbscreen.cpp48
-rw-r--r--src/plugins/platforms/integrity/qintegrityfbscreen.h40
-rw-r--r--src/plugins/platforms/integrity/qintegrityhidmanager.cpp40
-rw-r--r--src/plugins/platforms/integrity/qintegrityhidmanager.h42
-rw-r--r--src/plugins/platforms/ios/.prev_CMakeLists.txt65
-rw-r--r--src/plugins/platforms/ios/CMakeLists.txt63
-rw-r--r--src/plugins/platforms/ios/ios.pro2
-rw-r--r--src/plugins/platforms/ios/kernel.pro78
-rw-r--r--src/plugins/platforms/ios/optional/CMakeLists.txt5
-rw-r--r--src/plugins/platforms/ios/optional/nsphotolibrarysupport/CMakeLists.txt22
-rw-r--r--src/plugins/platforms/ios/optional/nsphotolibrarysupport/nsphotolibrarysupport.pro26
-rw-r--r--src/plugins/platforms/ios/optional/nsphotolibrarysupport/plugin.mm42
-rw-r--r--src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosfileengineassetslibrary.h47
-rw-r--r--src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosfileengineassetslibrary.mm111
-rw-r--r--src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosfileenginefactory.h48
-rw-r--r--src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosimagepickercontroller.h40
-rw-r--r--src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosimagepickercontroller.mm42
-rw-r--r--src/plugins/platforms/ios/optional/optional.pro2
-rw-r--r--src/plugins/platforms/ios/plugin.mm46
-rw-r--r--src/plugins/platforms/ios/qiosapplicationdelegate.h40
-rw-r--r--src/plugins/platforms/ios/qiosapplicationdelegate.mm60
-rw-r--r--src/plugins/platforms/ios/qiosapplicationstate.h40
-rw-r--r--src/plugins/platforms/ios/qiosapplicationstate.mm48
-rw-r--r--src/plugins/platforms/ios/qiosbackingstore.h62
-rw-r--r--src/plugins/platforms/ios/qiosbackingstore.mm91
-rw-r--r--src/plugins/platforms/ios/qiosclipboard.h41
-rw-r--r--src/plugins/platforms/ios/qiosclipboard.mm117
-rw-r--r--src/plugins/platforms/ios/qioscolordialog.h38
-rw-r--r--src/plugins/platforms/ios/qioscolordialog.mm159
-rw-r--r--src/plugins/platforms/ios/qioscontext.h40
-rw-r--r--src/plugins/platforms/ios/qioscontext.mm48
-rw-r--r--src/plugins/platforms/ios/qiosdocumentpickercontroller.h13
-rw-r--r--src/plugins/platforms/ios/qiosdocumentpickercontroller.mm115
-rw-r--r--src/plugins/platforms/ios/qioseventdispatcher.h46
-rw-r--r--src/plugins/platforms/ios/qioseventdispatcher.mm43
-rw-r--r--src/plugins/platforms/ios/qiosfiledialog.h44
-rw-r--r--src/plugins/platforms/ios/qiosfiledialog.mm124
-rw-r--r--src/plugins/platforms/ios/qiosfontdialog.h41
-rw-r--r--src/plugins/platforms/ios/qiosfontdialog.mm190
-rw-r--r--src/plugins/platforms/ios/qiosglobal.h46
-rw-r--r--src/plugins/platforms/ios/qiosglobal.mm68
-rw-r--r--src/plugins/platforms/ios/qiosinputcontext.h56
-rw-r--r--src/plugins/platforms/ios/qiosinputcontext.mm129
-rw-r--r--src/plugins/platforms/ios/qiosintegration.h63
-rw-r--r--src/plugins/platforms/ios/qiosintegration.mm135
-rw-r--r--src/plugins/platforms/ios/qiosmenu.h42
-rw-r--r--src/plugins/platforms/ios/qiosmenu.mm58
-rw-r--r--src/plugins/platforms/ios/qiosmessagedialog.h40
-rw-r--r--src/plugins/platforms/ios/qiosmessagedialog.mm63
-rw-r--r--src/plugins/platforms/ios/qiosoptionalplugininterface.h44
-rw-r--r--src/plugins/platforms/ios/qiosplatformaccessibility.h42
-rw-r--r--src/plugins/platforms/ios/qiosplatformaccessibility.mm72
-rw-r--r--src/plugins/platforms/ios/qiosscreen.h65
-rw-r--r--src/plugins/platforms/ios/qiosscreen.mm197
-rw-r--r--src/plugins/platforms/ios/qiosservices.h40
-rw-r--r--src/plugins/platforms/ios/qiosservices.mm50
-rw-r--r--src/plugins/platforms/ios/qiostextinputoverlay.h40
-rw-r--r--src/plugins/platforms/ios/qiostextinputoverlay.mm243
-rw-r--r--src/plugins/platforms/ios/qiostextresponder.h55
-rw-r--r--src/plugins/platforms/ios/qiostextresponder.mm444
-rw-r--r--src/plugins/platforms/ios/qiostheme.h53
-rw-r--r--src/plugins/platforms/ios/qiostheme.mm157
-rw-r--r--src/plugins/platforms/ios/qiosviewcontroller.h42
-rw-r--r--src/plugins/platforms/ios/qiosviewcontroller.mm112
-rw-r--r--src/plugins/platforms/ios/qioswindow.h53
-rw-r--r--src/plugins/platforms/ios/qioswindow.mm270
-rw-r--r--src/plugins/platforms/ios/quiaccessibilityelement.h44
-rw-r--r--src/plugins/platforms/ios/quiaccessibilityelement.mm88
-rw-r--r--src/plugins/platforms/ios/quiview.h44
-rw-r--r--src/plugins/platforms/ios/quiview.mm369
-rw-r--r--src/plugins/platforms/ios/quiview_accessibility.mm52
-rw-r--r--src/plugins/platforms/ios/quiwindow.h13
-rw-r--r--src/plugins/platforms/ios/quiwindow.mm56
-rw-r--r--src/plugins/platforms/ios/uistrings.cpp15
-rw-r--r--src/plugins/platforms/ios/uistrings_p.h30
-rw-r--r--src/plugins/platforms/linuxfb/.prev_CMakeLists.txt46
-rw-r--r--src/plugins/platforms/linuxfb/CMakeLists.txt28
-rw-r--r--src/plugins/platforms/linuxfb/linuxfb.pro31
-rw-r--r--src/plugins/platforms/linuxfb/main.cpp46
-rw-r--r--src/plugins/platforms/linuxfb/qlinuxfbdrmscreen.cpp54
-rw-r--r--src/plugins/platforms/linuxfb/qlinuxfbdrmscreen.h40
-rw-r--r--src/plugins/platforms/linuxfb/qlinuxfbintegration.cpp97
-rw-r--r--src/plugins/platforms/linuxfb/qlinuxfbintegration.h51
-rw-r--r--src/plugins/platforms/linuxfb/qlinuxfbscreen.cpp70
-rw-r--r--src/plugins/platforms/linuxfb/qlinuxfbscreen.h40
-rw-r--r--src/plugins/platforms/minimal/.prev_CMakeLists.txt37
-rw-r--r--src/plugins/platforms/minimal/CMakeLists.txt23
-rw-r--r--src/plugins/platforms/minimal/main.cpp46
-rw-r--r--src/plugins/platforms/minimal/minimal.pro22
-rw-r--r--src/plugins/platforms/minimal/qminimalbackingstore.cpp44
-rw-r--r--src/plugins/platforms/minimal/qminimalbackingstore.h40
-rw-r--r--src/plugins/platforms/minimal/qminimalintegration.cpp100
-rw-r--r--src/plugins/platforms/minimal/qminimalintegration.h46
-rw-r--r--src/plugins/platforms/minimalegl/.prev_CMakeLists.txt41
-rw-r--r--src/plugins/platforms/minimalegl/CMakeLists.txt27
-rw-r--r--src/plugins/platforms/minimalegl/main.cpp46
-rw-r--r--src/plugins/platforms/minimalegl/minimalegl.pro37
-rw-r--r--src/plugins/platforms/minimalegl/qminimaleglbackingstore.cpp42
-rw-r--r--src/plugins/platforms/minimalegl/qminimaleglbackingstore.h40
-rw-r--r--src/plugins/platforms/minimalegl/qminimaleglintegration.cpp74
-rw-r--r--src/plugins/platforms/minimalegl/qminimaleglintegration.h40
-rw-r--r--src/plugins/platforms/minimalegl/qminimaleglscreen.cpp52
-rw-r--r--src/plugins/platforms/minimalegl/qminimaleglscreen.h42
-rw-r--r--src/plugins/platforms/minimalegl/qminimaleglwindow.cpp40
-rw-r--r--src/plugins/platforms/minimalegl/qminimaleglwindow.h40
-rw-r--r--src/plugins/platforms/offscreen/.prev_CMakeLists.txt40
-rw-r--r--src/plugins/platforms/offscreen/CMakeLists.txt25
-rw-r--r--src/plugins/platforms/offscreen/main.cpp47
-rw-r--r--src/plugins/platforms/offscreen/offscreen.pro29
-rw-r--r--src/plugins/platforms/offscreen/qoffscreencommon.cpp125
-rw-r--r--src/plugins/platforms/offscreen/qoffscreencommon.h70
-rw-r--r--src/plugins/platforms/offscreen/qoffscreenintegration.cpp348
-rw-r--r--src/plugins/platforms/offscreen/qoffscreenintegration.h60
-rw-r--r--src/plugins/platforms/offscreen/qoffscreenintegration_x11.cpp106
-rw-r--r--src/plugins/platforms/offscreen/qoffscreenintegration_x11.h82
-rw-r--r--src/plugins/platforms/offscreen/qoffscreenwindow.cpp80
-rw-r--r--src/plugins/platforms/offscreen/qoffscreenwindow.h45
-rw-r--r--src/plugins/platforms/openwfd/main.cpp61
-rw-r--r--src/plugins/platforms/openwfd/openwf.pro40
-rw-r--r--src/plugins/platforms/openwfd/qopenwfdbackingstore.cpp64
-rw-r--r--src/plugins/platforms/openwfd/qopenwfdbackingstore.h63
-rw-r--r--src/plugins/platforms/openwfd/qopenwfddevice.cpp315
-rw-r--r--src/plugins/platforms/openwfd/qopenwfddevice.h111
-rw-r--r--src/plugins/platforms/openwfd/qopenwfdevent.cpp44
-rw-r--r--src/plugins/platforms/openwfd/qopenwfdevent.h49
-rw-r--r--src/plugins/platforms/openwfd/qopenwfdglcontext.cpp101
-rw-r--r--src/plugins/platforms/openwfd/qopenwfdglcontext.h66
-rw-r--r--src/plugins/platforms/openwfd/qopenwfdintegration.cpp138
-rw-r--r--src/plugins/platforms/openwfd/qopenwfdintegration.h82
-rw-r--r--src/plugins/platforms/openwfd/qopenwfdnativeinterface.cpp139
-rw-r--r--src/plugins/platforms/openwfd/qopenwfdnativeinterface.h74
-rw-r--r--src/plugins/platforms/openwfd/qopenwfdoutputbuffer.cpp88
-rw-r--r--src/plugins/platforms/openwfd/qopenwfdoutputbuffer.h67
-rw-r--r--src/plugins/platforms/openwfd/qopenwfdport.cpp209
-rw-r--r--src/plugins/platforms/openwfd/qopenwfdport.h87
-rw-r--r--src/plugins/platforms/openwfd/qopenwfdportmode.cpp61
-rw-r--r--src/plugins/platforms/openwfd/qopenwfdportmode.h72
-rw-r--r--src/plugins/platforms/openwfd/qopenwfdscreen.cpp190
-rw-r--r--src/plugins/platforms/openwfd/qopenwfdscreen.h88
-rw-r--r--src/plugins/platforms/openwfd/qopenwfdwindow.cpp59
-rw-r--r--src/plugins/platforms/openwfd/qopenwfdwindow.h59
-rw-r--r--src/plugins/platforms/platforms.pro51
-rw-r--r--src/plugins/platforms/qnx/CMakeLists.txt93
-rw-r--r--src/plugins/platforms/qnx/main.cpp44
-rw-r--r--src/plugins/platforms/qnx/main.h40
-rw-r--r--src/plugins/platforms/qnx/qnx.pro125
-rw-r--r--src/plugins/platforms/qnx/qqnxabstractcover.h40
-rw-r--r--src/plugins/platforms/qnx/qqnxabstractnavigator.cpp40
-rw-r--r--src/plugins/platforms/qnx/qqnxabstractnavigator.h42
-rw-r--r--src/plugins/platforms/qnx/qqnxabstractvirtualkeyboard.cpp42
-rw-r--r--src/plugins/platforms/qnx/qqnxabstractvirtualkeyboard.h42
-rw-r--r--src/plugins/platforms/qnx/qqnxbuffer.cpp42
-rw-r--r--src/plugins/platforms/qnx/qqnxbuffer.h44
-rw-r--r--src/plugins/platforms/qnx/qqnxbuttoneventnotifier.cpp48
-rw-r--r--src/plugins/platforms/qnx/qqnxbuttoneventnotifier.h45
-rw-r--r--src/plugins/platforms/qnx/qqnxclipboard.cpp46
-rw-r--r--src/plugins/platforms/qnx/qqnxclipboard.h40
-rw-r--r--src/plugins/platforms/qnx/qqnxcursor.cpp40
-rw-r--r--src/plugins/platforms/qnx/qqnxcursor.h40
-rw-r--r--src/plugins/platforms/qnx/qqnxeglwindow.cpp42
-rw-r--r--src/plugins/platforms/qnx/qqnxeglwindow.h40
-rw-r--r--src/plugins/platforms/qnx/qqnxforeignwindow.cpp40
-rw-r--r--src/plugins/platforms/qnx/qqnxforeignwindow.h40
-rw-r--r--src/plugins/platforms/qnx/qqnxglcontext.cpp44
-rw-r--r--src/plugins/platforms/qnx/qqnxglcontext.h42
-rw-r--r--src/plugins/platforms/qnx/qqnxglobal.cpp40
-rw-r--r--src/plugins/platforms/qnx/qqnxglobal.h40
-rw-r--r--src/plugins/platforms/qnx/qqnxinputcontext_imf.cpp62
-rw-r--r--src/plugins/platforms/qnx/qqnxinputcontext_imf.h40
-rw-r--r--src/plugins/platforms/qnx/qqnxinputcontext_noimf.cpp40
-rw-r--r--src/plugins/platforms/qnx/qqnxinputcontext_noimf.h40
-rw-r--r--src/plugins/platforms/qnx/qqnxintegration.cpp62
-rw-r--r--src/plugins/platforms/qnx/qqnxintegration.h44
-rw-r--r--src/plugins/platforms/qnx/qqnxkeytranslator.h40
-rw-r--r--src/plugins/platforms/qnx/qqnxlgmon.cpp40
-rw-r--r--src/plugins/platforms/qnx/qqnxlgmon.h40
-rw-r--r--src/plugins/platforms/qnx/qqnxnativeinterface.cpp48
-rw-r--r--src/plugins/platforms/qnx/qqnxnativeinterface.h40
-rw-r--r--src/plugins/platforms/qnx/qqnxnavigatoreventhandler.cpp40
-rw-r--r--src/plugins/platforms/qnx/qqnxnavigatoreventhandler.h42
-rw-r--r--src/plugins/platforms/qnx/qqnxnavigatoreventnotifier.cpp48
-rw-r--r--src/plugins/platforms/qnx/qqnxnavigatoreventnotifier.h45
-rw-r--r--src/plugins/platforms/qnx/qqnxnavigatorpps.cpp48
-rw-r--r--src/plugins/platforms/qnx/qqnxnavigatorpps.h45
-rw-r--r--src/plugins/platforms/qnx/qqnxrasterbackingstore.cpp58
-rw-r--r--src/plugins/platforms/qnx/qqnxrasterbackingstore.h40
-rw-r--r--src/plugins/platforms/qnx/qqnxrasterwindow.cpp52
-rw-r--r--src/plugins/platforms/qnx/qqnxrasterwindow.h40
-rw-r--r--src/plugins/platforms/qnx/qqnxscreen.cpp146
-rw-r--r--src/plugins/platforms/qnx/qqnxscreen.h41
-rw-r--r--src/plugins/platforms/qnx/qqnxscreeneventfilter.h40
-rw-r--r--src/plugins/platforms/qnx/qqnxscreeneventhandler.cpp146
-rw-r--r--src/plugins/platforms/qnx/qqnxscreeneventhandler.h43
-rw-r--r--src/plugins/platforms/qnx/qqnxscreeneventthread.cpp42
-rw-r--r--src/plugins/platforms/qnx/qqnxscreeneventthread.h42
-rw-r--r--src/plugins/platforms/qnx/qqnxscreentraits.h40
-rw-r--r--src/plugins/platforms/qnx/qqnxservices.cpp40
-rw-r--r--src/plugins/platforms/qnx/qqnxservices.h40
-rw-r--r--src/plugins/platforms/qnx/qqnxvirtualkeyboardpps.cpp52
-rw-r--r--src/plugins/platforms/qnx/qqnxvirtualkeyboardpps.h40
-rw-r--r--src/plugins/platforms/qnx/qqnxwindow.cpp92
-rw-r--r--src/plugins/platforms/qnx/qqnxwindow.h50
-rw-r--r--src/plugins/platforms/vkkhrdisplay/CMakeLists.txt32
-rw-r--r--src/plugins/platforms/vkkhrdisplay/main.cpp29
-rw-r--r--src/plugins/platforms/vkkhrdisplay/qvkkhrdisplayintegration.cpp315
-rw-r--r--src/plugins/platforms/vkkhrdisplay/qvkkhrdisplayintegration.h52
-rw-r--r--src/plugins/platforms/vkkhrdisplay/qvkkhrdisplayvulkaninstance.cpp (renamed from src/plugins/platforms/eglfs/api/vulkan/qeglfsvulkaninstance.cpp)203
-rw-r--r--src/plugins/platforms/vkkhrdisplay/qvkkhrdisplayvulkaninstance.h70
-rw-r--r--src/plugins/platforms/vkkhrdisplay/vkkhrdisplay.json3
-rw-r--r--src/plugins/platforms/vnc/.prev_CMakeLists.txt43
-rw-r--r--src/plugins/platforms/vnc/CMakeLists.txt25
-rw-r--r--src/plugins/platforms/vnc/main.cpp44
-rw-r--r--src/plugins/platforms/vnc/qvnc.cpp139
-rw-r--r--src/plugins/platforms/vnc/qvnc_p.h44
-rw-r--r--src/plugins/platforms/vnc/qvncclient.cpp50
-rw-r--r--src/plugins/platforms/vnc/qvncclient.h42
-rw-r--r--src/plugins/platforms/vnc/qvncintegration.cpp51
-rw-r--r--src/plugins/platforms/vnc/qvncintegration.h40
-rw-r--r--src/plugins/platforms/vnc/qvncscreen.cpp69
-rw-r--r--src/plugins/platforms/vnc/qvncscreen.h40
-rw-r--r--src/plugins/platforms/vnc/vnc.pro31
-rw-r--r--src/plugins/platforms/wasm/CMakeLists.txt108
-rw-r--r--src/plugins/platforms/wasm/main.cpp34
-rw-r--r--src/plugins/platforms/wasm/qtloader.js806
-rw-r--r--src/plugins/platforms/wasm/qtlogo.svg40
-rw-r--r--src/plugins/platforms/wasm/qwasmaccessibility.cpp789
-rw-r--r--src/plugins/platforms/wasm/qwasmaccessibility.h92
-rw-r--r--src/plugins/platforms/wasm/qwasmbackingstore.cpp124
-rw-r--r--src/plugins/platforms/wasm/qwasmbackingstore.h41
-rw-r--r--src/plugins/platforms/wasm/qwasmbase64iconstore.cpp40
-rw-r--r--src/plugins/platforms/wasm/qwasmbase64iconstore.h37
-rw-r--r--src/plugins/platforms/wasm/qwasmclipboard.cpp356
-rw-r--r--src/plugins/platforms/wasm/qwasmclipboard.h60
-rw-r--r--src/plugins/platforms/wasm/qwasmcompositor.cpp774
-rw-r--r--src/plugins/platforms/wasm/qwasmcompositor.h162
-rw-r--r--src/plugins/platforms/wasm/qwasmcssstyle.cpp248
-rw-r--r--src/plugins/platforms/wasm/qwasmcssstyle.h18
-rw-r--r--src/plugins/platforms/wasm/qwasmcursor.cpp162
-rw-r--r--src/plugins/platforms/wasm/qwasmcursor.h36
-rw-r--r--src/plugins/platforms/wasm/qwasmdom.cpp303
-rw-r--r--src/plugins/platforms/wasm/qwasmdom.h63
-rw-r--r--src/plugins/platforms/wasm/qwasmdrag.cpp291
-rw-r--r--src/plugins/platforms/wasm/qwasmdrag.h47
-rw-r--r--src/plugins/platforms/wasm/qwasmevent.cpp338
-rw-r--r--src/plugins/platforms/wasm/qwasmevent.h271
-rw-r--r--src/plugins/platforms/wasm/qwasmeventdispatcher.cpp215
-rw-r--r--src/plugins/platforms/wasm/qwasmeventdispatcher.h58
-rw-r--r--src/plugins/platforms/wasm/qwasmeventtranslator.cpp967
-rw-r--r--src/plugins/platforms/wasm/qwasmeventtranslator.h99
-rw-r--r--src/plugins/platforms/wasm/qwasmfontdatabase.cpp401
-rw-r--r--src/plugins/platforms/wasm/qwasmfontdatabase.h59
-rw-r--r--src/plugins/platforms/wasm/qwasminputcontext.cpp161
-rw-r--r--src/plugins/platforms/wasm/qwasminputcontext.h48
-rw-r--r--src/plugins/platforms/wasm/qwasmintegration.cpp372
-rw-r--r--src/plugins/platforms/wasm/qwasmintegration.h75
-rw-r--r--src/plugins/platforms/wasm/qwasmkeytranslator.cpp295
-rw-r--r--src/plugins/platforms/wasm/qwasmkeytranslator.h34
-rw-r--r--src/plugins/platforms/wasm/qwasmoffscreensurface.cpp56
-rw-r--r--src/plugins/platforms/wasm/qwasmoffscreensurface.h47
-rw-r--r--src/plugins/platforms/wasm/qwasmopenglcontext.cpp204
-rw-r--r--src/plugins/platforms/wasm/qwasmopenglcontext.h61
-rw-r--r--src/plugins/platforms/wasm/qwasmplatform.cpp32
-rw-r--r--src/plugins/platforms/wasm/qwasmplatform.h29
-rw-r--r--src/plugins/platforms/wasm/qwasmscreen.cpp311
-rw-r--r--src/plugins/platforms/wasm/qwasmscreen.h77
-rw-r--r--src/plugins/platforms/wasm/qwasmservices.cpp35
-rw-r--r--src/plugins/platforms/wasm/qwasmservices.h30
-rw-r--r--src/plugins/platforms/wasm/qwasmstring.cpp62
-rw-r--r--src/plugins/platforms/wasm/qwasmstring.h45
-rw-r--r--src/plugins/platforms/wasm/qwasmstylepixmaps_p.h183
-rw-r--r--src/plugins/platforms/wasm/qwasmtheme.cpp42
-rw-r--r--src/plugins/platforms/wasm/qwasmtheme.h30
-rw-r--r--src/plugins/platforms/wasm/qwasmwindow.cpp765
-rw-r--r--src/plugins/platforms/wasm/qwasmwindow.h203
-rw-r--r--src/plugins/platforms/wasm/qwasmwindowclientarea.cpp195
-rw-r--r--src/plugins/platforms/wasm/qwasmwindowclientarea.h52
-rw-r--r--src/plugins/platforms/wasm/qwasmwindownonclientarea.cpp460
-rw-r--r--src/plugins/platforms/wasm/qwasmwindownonclientarea.h227
-rw-r--r--src/plugins/platforms/wasm/qwasmwindowstack.cpp203
-rw-r--r--src/plugins/platforms/wasm/qwasmwindowstack.h75
-rw-r--r--src/plugins/platforms/wasm/qwasmwindowtreenode.cpp108
-rw-r--r--src/plugins/platforms/wasm/qwasmwindowtreenode.h53
-rw-r--r--src/plugins/platforms/wasm/resources/maximize.svg1
-rw-r--r--src/plugins/platforms/wasm/resources/qtlogo.svg1
-rw-r--r--src/plugins/platforms/wasm/resources/restore.svg1
-rw-r--r--src/plugins/platforms/wasm/resources/x.svg1
-rw-r--r--src/plugins/platforms/wasm/wasm.pro79
-rw-r--r--src/plugins/platforms/wasm/wasm_shell.html91
-rw-r--r--src/plugins/platforms/windows/.prev_CMakeLists.txt245
-rw-r--r--src/plugins/platforms/windows/CMakeLists.txt179
-rw-r--r--src/plugins/platforms/windows/cursors.qrc25
-rw-r--r--src/plugins/platforms/windows/main.cpp54
-rw-r--r--src/plugins/platforms/windows/openglblacklists.qrc5
-rw-r--r--src/plugins/platforms/windows/openglblacklists/default.json2
-rw-r--r--src/plugins/platforms/windows/qtwindowsglobal.h117
-rw-r--r--src/plugins/platforms/windows/qwin10helpers.cpp83
-rw-r--r--src/plugins/platforms/windows/qwin10helpers.h40
-rw-r--r--src/plugins/platforms/windows/qwindowsapplication.cpp151
-rw-r--r--src/plugins/platforms/windows/qwindowsapplication.h56
-rw-r--r--src/plugins/platforms/windows/qwindowsbackingstore.cpp54
-rw-r--r--src/plugins/platforms/windows/qwindowsbackingstore.h40
-rw-r--r--src/plugins/platforms/windows/qwindowsclipboard.cpp59
-rw-r--r--src/plugins/platforms/windows/qwindowsclipboard.h40
-rw-r--r--src/plugins/platforms/windows/qwindowscombase.h73
-rw-r--r--src/plugins/platforms/windows/qwindowscontext.cpp682
-rw-r--r--src/plugins/platforms/windows/qwindowscontext.h152
-rw-r--r--src/plugins/platforms/windows/qwindowscursor.cpp95
-rw-r--r--src/plugins/platforms/windows/qwindowscursor.h44
-rw-r--r--src/plugins/platforms/windows/qwindowsdialoghelpers.cpp319
-rw-r--r--src/plugins/platforms/windows/qwindowsdialoghelpers.h44
-rw-r--r--src/plugins/platforms/windows/qwindowsdrag.cpp171
-rw-r--r--src/plugins/platforms/windows/qwindowsdrag.h56
-rw-r--r--src/plugins/platforms/windows/qwindowsdropdataobject.cpp51
-rw-r--r--src/plugins/platforms/windows/qwindowsdropdataobject.h44
-rw-r--r--src/plugins/platforms/windows/qwindowseglcontext.cpp920
-rw-r--r--src/plugins/platforms/windows/qwindowseglcontext.h176
-rw-r--r--src/plugins/platforms/windows/qwindowsgdiintegration.cpp50
-rw-r--r--src/plugins/platforms/windows/qwindowsgdiintegration.h40
-rw-r--r--src/plugins/platforms/windows/qwindowsgdinativeinterface.cpp40
-rw-r--r--src/plugins/platforms/windows/qwindowsgdinativeinterface.h40
-rw-r--r--src/plugins/platforms/windows/qwindowsglcontext.cpp189
-rw-r--r--src/plugins/platforms/windows/qwindowsglcontext.h66
-rw-r--r--src/plugins/platforms/windows/qwindowsiconengine.cpp394
-rw-r--r--src/plugins/platforms/windows/qwindowsiconengine.h47
-rw-r--r--src/plugins/platforms/windows/qwindowsinputcontext.cpp64
-rw-r--r--src/plugins/platforms/windows/qwindowsinputcontext.h40
-rw-r--r--src/plugins/platforms/windows/qwindowsintegration.cpp432
-rw-r--r--src/plugins/platforms/windows/qwindowsintegration.h71
-rw-r--r--src/plugins/platforms/windows/qwindowsinternalmimedata.cpp66
-rw-r--r--src/plugins/platforms/windows/qwindowsinternalmimedata.h42
-rw-r--r--src/plugins/platforms/windows/qwindowskeymapper.cpp212
-rw-r--r--src/plugins/platforms/windows/qwindowskeymapper.h48
-rw-r--r--src/plugins/platforms/windows/qwindowsmenu.cpp71
-rw-r--r--src/plugins/platforms/windows/qwindowsmenu.h47
-rw-r--r--src/plugins/platforms/windows/qwindowsmime.h108
-rw-r--r--src/plugins/platforms/windows/qwindowsmimeregistry.cpp (renamed from src/plugins/platforms/windows/qwindowsmime.cpp)566
-rw-r--r--src/plugins/platforms/windows/qwindowsmimeregistry.h58
-rw-r--r--src/plugins/platforms/windows/qwindowsmousehandler.cpp159
-rw-r--r--src/plugins/platforms/windows/qwindowsmousehandler.h53
-rw-r--r--src/plugins/platforms/windows/qwindowsnativeinterface.cpp202
-rw-r--r--src/plugins/platforms/windows/qwindowsnativeinterface.h86
-rw-r--r--src/plugins/platforms/windows/qwindowsole.cpp58
-rw-r--r--src/plugins/platforms/windows/qwindowsole.h84
-rw-r--r--src/plugins/platforms/windows/qwindowsopenglcontext.h44
-rw-r--r--src/plugins/platforms/windows/qwindowsopengltester.cpp148
-rw-r--r--src/plugins/platforms/windows/qwindowsopengltester.h51
-rw-r--r--src/plugins/platforms/windows/qwindowspointerhandler.cpp359
-rw-r--r--src/plugins/platforms/windows/qwindowspointerhandler.h66
-rw-r--r--src/plugins/platforms/windows/qwindowsscreen.cpp537
-rw-r--r--src/plugins/platforms/windows/qwindowsscreen.h71
-rw-r--r--src/plugins/platforms/windows/qwindowsservices.cpp159
-rw-r--r--src/plugins/platforms/windows/qwindowsservices.h40
-rw-r--r--src/plugins/platforms/windows/qwindowssessionmanager.cpp42
-rw-r--r--src/plugins/platforms/windows/qwindowssessionmanager.h42
-rw-r--r--src/plugins/platforms/windows/qwindowssystemtrayicon.cpp140
-rw-r--r--src/plugins/platforms/windows/qwindowssystemtrayicon.h42
-rw-r--r--src/plugins/platforms/windows/qwindowstabletsupport.cpp361
-rw-r--r--src/plugins/platforms/windows/qwindowstabletsupport.h99
-rw-r--r--src/plugins/platforms/windows/qwindowstheme.cpp679
-rw-r--r--src/plugins/platforms/windows/qwindowstheme.h48
-rw-r--r--src/plugins/platforms/windows/qwindowsthreadpoolrunner.h41
-rw-r--r--src/plugins/platforms/windows/qwindowsvulkaninstance.cpp40
-rw-r--r--src/plugins/platforms/windows/qwindowsvulkaninstance.h42
-rw-r--r--src/plugins/platforms/windows/qwindowswindow.cpp1214
-rw-r--r--src/plugins/platforms/windows/qwindowswindow.h110
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiaaccessibility.cpp67
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiaaccessibility.h43
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiabaseprovider.cpp40
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiabaseprovider.h44
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiaexpandcollapseprovider.cpp90
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiaexpandcollapseprovider.h33
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiagriditemprovider.cpp40
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiagriditemprovider.h42
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiagridprovider.cpp40
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiagridprovider.h43
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiainvokeprovider.cpp40
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiainvokeprovider.h43
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp243
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.h52
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiaprovidercache.cpp42
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiaprovidercache.h40
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiarangevalueprovider.cpp40
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiarangevalueprovider.h42
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionitemprovider.cpp97
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionitemprovider.h42
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionprovider.cpp218
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionprovider.h61
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiatableitemprovider.cpp40
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiatableitemprovider.h42
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiatableprovider.cpp40
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiatableprovider.h43
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiatextprovider.cpp61
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiatextprovider.h59
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiatextrangeprovider.cpp101
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiatextrangeprovider.h44
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiatoggleprovider.cpp40
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiatoggleprovider.h43
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiautils.cpp62
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiautils.h42
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiautomation.cpp74
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiautomation.h70
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiavalueprovider.cpp42
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiavalueprovider.h43
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiawindowprovider.cpp40
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiawindowprovider.h43
-rw-r--r--src/plugins/platforms/windows/uiautomation/uiautomation.pri44
-rw-r--r--src/plugins/platforms/windows/windows.pri130
-rw-r--r--src/plugins/platforms/windows/windows.pro36
-rw-r--r--src/plugins/platforms/winrt/main.cpp66
-rw-r--r--src/plugins/platforms/winrt/qwinrtbackingstore.cpp194
-rw-r--r--src/plugins/platforms/winrt/qwinrtbackingstore.h74
-rw-r--r--src/plugins/platforms/winrt/qwinrtcanvas.cpp142
-rw-r--r--src/plugins/platforms/winrt/qwinrtcanvas.h75
-rw-r--r--src/plugins/platforms/winrt/qwinrtclipboard.cpp188
-rw-r--r--src/plugins/platforms/winrt/qwinrtclipboard.h77
-rw-r--r--src/plugins/platforms/winrt/qwinrtcursor.cpp230
-rw-r--r--src/plugins/platforms/winrt/qwinrtcursor.h66
-rw-r--r--src/plugins/platforms/winrt/qwinrtdrag.cpp889
-rw-r--r--src/plugins/platforms/winrt/qwinrtdrag.h116
-rw-r--r--src/plugins/platforms/winrt/qwinrteglcontext.cpp371
-rw-r--r--src/plugins/platforms/winrt/qwinrteglcontext.h73
-rw-r--r--src/plugins/platforms/winrt/qwinrteventdispatcher.cpp66
-rw-r--r--src/plugins/platforms/winrt/qwinrteventdispatcher.h60
-rw-r--r--src/plugins/platforms/winrt/qwinrtfiledialoghelper.cpp588
-rw-r--r--src/plugins/platforms/winrt/qwinrtfiledialoghelper.h107
-rw-r--r--src/plugins/platforms/winrt/qwinrtfileengine.cpp554
-rw-r--r--src/plugins/platforms/winrt/qwinrtfileengine.h104
-rw-r--r--src/plugins/platforms/winrt/qwinrtinputcontext.cpp222
-rw-r--r--src/plugins/platforms/winrt/qwinrtinputcontext.h99
-rw-r--r--src/plugins/platforms/winrt/qwinrtintegration.cpp317
-rw-r--r--src/plugins/platforms/winrt/qwinrtintegration.h113
-rw-r--r--src/plugins/platforms/winrt/qwinrtmessagedialoghelper.cpp247
-rw-r--r--src/plugins/platforms/winrt/qwinrtmessagedialoghelper.h88
-rw-r--r--src/plugins/platforms/winrt/qwinrtscreen.cpp1543
-rw-r--r--src/plugins/platforms/winrt/qwinrtscreen.h168
-rw-r--r--src/plugins/platforms/winrt/qwinrtservices.cpp145
-rw-r--r--src/plugins/platforms/winrt/qwinrtservices.h65
-rw-r--r--src/plugins/platforms/winrt/qwinrttheme.cpp342
-rw-r--r--src/plugins/platforms/winrt/qwinrttheme.h72
-rw-r--r--src/plugins/platforms/winrt/qwinrtwindow.cpp438
-rw-r--r--src/plugins/platforms/winrt/qwinrtwindow.h86
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiaaccessibility.cpp113
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiaaccessibility.h64
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiabaseprovider.cpp76
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiabaseprovider.h72
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiacontrolmetadata.cpp182
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiacontrolmetadata.h117
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiaemptypropertyvalue.h108
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiagriditemprovider.cpp160
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiagriditemprovider.h78
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiagridprovider.cpp135
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiagridprovider.h76
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiainvokeprovider.cpp88
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiainvokeprovider.h74
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiamainprovider.cpp787
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiamainprovider.h125
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiametadatacache.cpp112
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiametadatacache.h76
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiapeervector.cpp149
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiapeervector.h80
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiaprovidercache.cpp99
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiaprovidercache.h77
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiarangevalueprovider.cpp167
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiarangevalueprovider.h80
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiaselectionitemprovider.cpp214
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiaselectionitemprovider.h78
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiaselectionprovider.cpp156
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiaselectionprovider.h76
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiatableitemprovider.cpp139
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiatableitemprovider.h75
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiatableprovider.cpp165
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiatableprovider.h76
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiatextprovider.cpp234
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiatextprovider.h83
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiatextrangeprovider.cpp498
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiatextrangeprovider.h95
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiatoggleprovider.cpp104
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiatoggleprovider.h75
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiautils.cpp182
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiautils.h83
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiavalueprovider.cpp133
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiavalueprovider.h77
-rw-r--r--src/plugins/platforms/winrt/uiautomation/uiautomation.pri45
-rw-r--r--src/plugins/platforms/winrt/winrt.json3
-rw-r--r--src/plugins/platforms/winrt/winrt.pro68
-rw-r--r--src/plugins/platforms/xcb/.prev_CMakeLists.txt166
-rw-r--r--src/plugins/platforms/xcb/CMakeLists.txt133
-rw-r--r--src/plugins/platforms/xcb/README6
-rw-r--r--src/plugins/platforms/xcb/gl_integrations/CMakeLists.txt3
-rw-r--r--src/plugins/platforms/xcb/gl_integrations/gl_integrations.pri13
-rw-r--r--src/plugins/platforms/xcb/gl_integrations/gl_integrations.pro10
-rw-r--r--src/plugins/platforms/xcb/gl_integrations/gl_integrations_plugin_base.pri7
-rw-r--r--src/plugins/platforms/xcb/gl_integrations/qxcbglintegration.cpp40
-rw-r--r--src/plugins/platforms/xcb/gl_integrations/qxcbglintegration.h42
-rw-r--r--src/plugins/platforms/xcb/gl_integrations/qxcbglintegrationfactory.cpp61
-rw-r--r--src/plugins/platforms/xcb/gl_integrations/qxcbglintegrationfactory.h42
-rw-r--r--src/plugins/platforms/xcb/gl_integrations/qxcbglintegrationplugin.h40
-rw-r--r--src/plugins/platforms/xcb/gl_integrations/qxcbnativeinterfacehandler.cpp40
-rw-r--r--src/plugins/platforms/xcb/gl_integrations/qxcbnativeinterfacehandler.h40
-rw-r--r--src/plugins/platforms/xcb/gl_integrations/xcb_egl/CMakeLists.txt14
-rw-r--r--src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglcontext.h63
-rw-r--r--src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglinclude.h43
-rw-r--r--src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglintegration.cpp218
-rw-r--r--src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglintegration.h49
-rw-r--r--src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglmain.cpp42
-rw-r--r--src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglnativeinterfacehandler.cpp42
-rw-r--r--src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglnativeinterfacehandler.h40
-rw-r--r--src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglwindow.cpp78
-rw-r--r--src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglwindow.h43
-rw-r--r--src/plugins/platforms/xcb/gl_integrations/xcb_egl/xcb_egl.pro24
-rw-r--r--src/plugins/platforms/xcb/gl_integrations/xcb_glx/CMakeLists.txt20
-rw-r--r--src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp183
-rw-r--r--src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.h70
-rw-r--r--src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxintegration.cpp73
-rw-r--r--src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxintegration.h44
-rw-r--r--src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxmain.cpp42
-rw-r--r--src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxnativeinterfacehandler.cpp40
-rw-r--r--src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxnativeinterfacehandler.h40
-rw-r--r--src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxwindow.cpp51
-rw-r--r--src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxwindow.h40
-rw-r--r--src/plugins/platforms/xcb/gl_integrations/xcb_glx/xcb_glx.pro27
-rw-r--r--src/plugins/platforms/xcb/nativepainting/nativepainting.pri22
-rw-r--r--src/plugins/platforms/xcb/nativepainting/qbackingstore_x11.cpp55
-rw-r--r--src/plugins/platforms/xcb/nativepainting/qbackingstore_x11_p.h40
-rw-r--r--src/plugins/platforms/xcb/nativepainting/qcolormap_x11.cpp52
-rw-r--r--src/plugins/platforms/xcb/nativepainting/qcolormap_x11_p.h44
-rw-r--r--src/plugins/platforms/xcb/nativepainting/qpaintengine_x11.cpp98
-rw-r--r--src/plugins/platforms/xcb/nativepainting/qpaintengine_x11_p.h40
-rw-r--r--src/plugins/platforms/xcb/nativepainting/qpixmap_x11.cpp80
-rw-r--r--src/plugins/platforms/xcb/nativepainting/qpixmap_x11_p.h40
-rw-r--r--src/plugins/platforms/xcb/nativepainting/qpolygonclipper_p.h280
-rw-r--r--src/plugins/platforms/xcb/nativepainting/qt_x11_p.h42
-rw-r--r--src/plugins/platforms/xcb/nativepainting/qtessellator.cpp45
-rw-r--r--src/plugins/platforms/xcb/nativepainting/qtessellator_p.h40
-rw-r--r--src/plugins/platforms/xcb/nativepainting/qxcbnativepainting.cpp48
-rw-r--r--src/plugins/platforms/xcb/nativepainting/qxcbnativepainting.h42
-rw-r--r--src/plugins/platforms/xcb/qt_xlib_wrapper.c7
-rw-r--r--src/plugins/platforms/xcb/qt_xlib_wrapper.h17
-rw-r--r--src/plugins/platforms/xcb/qxcbatom.cpp76
-rw-r--r--src/plugins/platforms/xcb/qxcbatom.h379
-rw-r--r--src/plugins/platforms/xcb/qxcbbackingstore.cpp122
-rw-r--r--src/plugins/platforms/xcb/qxcbbackingstore.h47
-rw-r--r--src/plugins/platforms/xcb/qxcbclipboard.cpp187
-rw-r--r--src/plugins/platforms/xcb/qxcbclipboard.h47
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.cpp293
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.h129
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection_basic.cpp81
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection_basic.h49
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection_screens.cpp488
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection_xi2.cpp1284
-rw-r--r--src/plugins/platforms/xcb/qxcbcursor.cpp210
-rw-r--r--src/plugins/platforms/xcb/qxcbcursor.h54
-rw-r--r--src/plugins/platforms/xcb/qxcbcursorfont.h88
-rw-r--r--src/plugins/platforms/xcb/qxcbdrag.cpp350
-rw-r--r--src/plugins/platforms/xcb/qxcbdrag.h78
-rw-r--r--src/plugins/platforms/xcb/qxcbeventdispatcher.cpp61
-rw-r--r--src/plugins/platforms/xcb/qxcbeventdispatcher.h46
-rw-r--r--src/plugins/platforms/xcb/qxcbeventqueue.cpp62
-rw-r--r--src/plugins/platforms/xcb/qxcbeventqueue.h77
-rw-r--r--src/plugins/platforms/xcb/qxcbexport.h40
-rw-r--r--src/plugins/platforms/xcb/qxcbimage.cpp42
-rw-r--r--src/plugins/platforms/xcb/qxcbimage.h41
-rw-r--r--src/plugins/platforms/xcb/qxcbintegration.cpp244
-rw-r--r--src/plugins/platforms/xcb/qxcbintegration.h70
-rw-r--r--src/plugins/platforms/xcb/qxcbkeyboard.cpp62
-rw-r--r--src/plugins/platforms/xcb/qxcbkeyboard.h50
-rw-r--r--src/plugins/platforms/xcb/qxcbmain.cpp46
-rw-r--r--src/plugins/platforms/xcb/qxcbmime.cpp163
-rw-r--r--src/plugins/platforms/xcb/qxcbmime.h48
-rw-r--r--src/plugins/platforms/xcb/qxcbnativeinterface.cpp126
-rw-r--r--src/plugins/platforms/xcb/qxcbnativeinterface.h53
-rw-r--r--src/plugins/platforms/xcb/qxcbobject.h40
-rw-r--r--src/plugins/platforms/xcb/qxcbscreen.cpp369
-rw-r--r--src/plugins/platforms/xcb/qxcbscreen.h87
-rw-r--r--src/plugins/platforms/xcb/qxcbscrollingdevice.cpp16
-rw-r--r--src/plugins/platforms/xcb/qxcbscrollingdevice_p.h56
-rw-r--r--src/plugins/platforms/xcb/qxcbsessionmanager.cpp68
-rw-r--r--src/plugins/platforms/xcb/qxcbsessionmanager.h42
-rw-r--r--src/plugins/platforms/xcb/qxcbsystemtraytracker.cpp58
-rw-r--r--src/plugins/platforms/xcb/qxcbsystemtraytracker.h42
-rw-r--r--src/plugins/platforms/xcb/qxcbvulkaninstance.cpp42
-rw-r--r--src/plugins/platforms/xcb/qxcbvulkaninstance.h42
-rw-r--r--src/plugins/platforms/xcb/qxcbvulkanwindow.cpp40
-rw-r--r--src/plugins/platforms/xcb/qxcbvulkanwindow.h40
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.cpp886
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.h96
-rw-r--r--src/plugins/platforms/xcb/qxcbwmsupport.cpp46
-rw-r--r--src/plugins/platforms/xcb/qxcbwmsupport.h48
-rw-r--r--src/plugins/platforms/xcb/qxcbxsettings.cpp53
-rw-r--r--src/plugins/platforms/xcb/qxcbxsettings.h40
-rw-r--r--src/plugins/platforms/xcb/xcb-plugin.pro17
-rw-r--r--src/plugins/platforms/xcb/xcb.pro7
-rw-r--r--src/plugins/platforms/xcb/xcb_qpa_lib.pro118
-rw-r--r--src/plugins/platformthemes/CMakeLists.txt6
-rw-r--r--src/plugins/platformthemes/gtk3/.prev_CMakeLists.txt27
-rw-r--r--src/plugins/platformthemes/gtk3/CMakeLists.txt31
-rw-r--r--src/plugins/platformthemes/gtk3/gtk3.pro23
-rw-r--r--src/plugins/platformthemes/gtk3/main.cpp42
-rw-r--r--src/plugins/platformthemes/gtk3/qgtk3dialoghelpers.cpp205
-rw-r--r--src/plugins/platformthemes/gtk3/qgtk3dialoghelpers.h52
-rw-r--r--src/plugins/platformthemes/gtk3/qgtk3interface.cpp702
-rw-r--r--src/plugins/platformthemes/gtk3/qgtk3interface_p.h211
-rw-r--r--src/plugins/platformthemes/gtk3/qgtk3json.cpp404
-rw-r--r--src/plugins/platformthemes/gtk3/qgtk3json_p.h102
-rw-r--r--src/plugins/platformthemes/gtk3/qgtk3menu.cpp67
-rw-r--r--src/plugins/platformthemes/gtk3/qgtk3menu.h42
-rw-r--r--src/plugins/platformthemes/gtk3/qgtk3storage.cpp673
-rw-r--r--src/plugins/platformthemes/gtk3/qgtk3storage_p.h235
-rw-r--r--src/plugins/platformthemes/gtk3/qgtk3theme.cpp121
-rw-r--r--src/plugins/platformthemes/gtk3/qgtk3theme.h51
-rw-r--r--src/plugins/platformthemes/platformthemes.pro6
-rw-r--r--src/plugins/platformthemes/xdgdesktopportal/CMakeLists.txt14
-rw-r--r--src/plugins/platformthemes/xdgdesktopportal/main.cpp48
-rw-r--r--src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportalfiledialog.cpp266
-rw-r--r--src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportalfiledialog_p.h58
-rw-r--r--src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportaltheme.cpp133
-rw-r--r--src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportaltheme.h42
-rw-r--r--src/plugins/platformthemes/xdgdesktopportal/xdgdesktopportal.pro17
-rw-r--r--src/plugins/plugins.pro14
-rw-r--r--src/plugins/printsupport/.prev_CMakeLists.txt11
-rw-r--r--src/plugins/printsupport/CMakeLists.txt9
-rw-r--r--src/plugins/printsupport/cocoa/CMakeLists.txt22
-rw-r--r--src/plugins/printsupport/cocoa/cocoa.json3
-rw-r--r--src/plugins/printsupport/cocoa/cocoa.pro13
-rw-r--r--src/plugins/printsupport/cocoa/main.cpp76
-rw-r--r--src/plugins/printsupport/cups/.prev_CMakeLists.txt30
-rw-r--r--src/plugins/printsupport/cups/CMakeLists.txt14
-rw-r--r--src/plugins/printsupport/cups/cups.pro23
-rw-r--r--src/plugins/printsupport/cups/main.cpp44
-rw-r--r--src/plugins/printsupport/cups/qcupsprintengine.cpp79
-rw-r--r--src/plugins/printsupport/cups/qcupsprintengine_p.h41
-rw-r--r--src/plugins/printsupport/cups/qcupsprintersupport.cpp62
-rw-r--r--src/plugins/printsupport/cups/qcupsprintersupport_p.h42
-rw-r--r--src/plugins/printsupport/cups/qppdprintdevice.cpp56
-rw-r--r--src/plugins/printsupport/cups/qppdprintdevice.h40
-rw-r--r--src/plugins/printsupport/printsupport.pro6
-rw-r--r--src/plugins/printsupport/windows/main.cpp66
-rw-r--r--src/plugins/printsupport/windows/qwindowsprintdevice.cpp571
-rw-r--r--src/plugins/printsupport/windows/qwindowsprintdevice.h153
-rw-r--r--src/plugins/printsupport/windows/qwindowsprinterinfo.cpp120
-rw-r--r--src/plugins/printsupport/windows/qwindowsprintersupport.cpp84
-rw-r--r--src/plugins/printsupport/windows/qwindowsprintersupport.h64
-rw-r--r--src/plugins/printsupport/windows/windows.json3
-rw-r--r--src/plugins/printsupport/windows/windows.pro26
-rw-r--r--src/plugins/sqldrivers/.cmake.conf1
-rw-r--r--src/plugins/sqldrivers/.prev_CMakeLists.txt15
-rw-r--r--src/plugins/sqldrivers/CMakeLists.txt50
-rw-r--r--src/plugins/sqldrivers/configure.cmake54
-rw-r--r--src/plugins/sqldrivers/configure.json201
-rw-r--r--src/plugins/sqldrivers/configure.pri85
-rw-r--r--src/plugins/sqldrivers/db2/CMakeLists.txt16
-rw-r--r--src/plugins/sqldrivers/db2/db2.pro13
-rw-r--r--src/plugins/sqldrivers/db2/main.cpp44
-rw-r--r--src/plugins/sqldrivers/db2/qsql_db2.cpp344
-rw-r--r--src/plugins/sqldrivers/db2/qsql_db2_p.h44
-rw-r--r--src/plugins/sqldrivers/ibase/CMakeLists.txt20
-rw-r--r--src/plugins/sqldrivers/ibase/ibase.pro12
-rw-r--r--src/plugins/sqldrivers/ibase/main.cpp46
-rw-r--r--src/plugins/sqldrivers/ibase/qsql_ibase.cpp760
-rw-r--r--src/plugins/sqldrivers/ibase/qsql_ibase_p.h48
-rw-r--r--src/plugins/sqldrivers/mimer/CMakeLists.txt24
-rw-r--r--src/plugins/sqldrivers/mimer/README6
-rw-r--r--src/plugins/sqldrivers/mimer/main.cpp33
-rw-r--r--src/plugins/sqldrivers/mimer/mimer.json5
-rw-r--r--src/plugins/sqldrivers/mimer/qsql_mimer.cpp1610
-rw-r--r--src/plugins/sqldrivers/mimer/qsql_mimer.h50
-rw-r--r--src/plugins/sqldrivers/mysql/CMakeLists.txt13
-rw-r--r--src/plugins/sqldrivers/mysql/main.cpp45
-rw-r--r--src/plugins/sqldrivers/mysql/mysql.pro11
-rw-r--r--src/plugins/sqldrivers/mysql/qsql_mysql.cpp1029
-rw-r--r--src/plugins/sqldrivers/mysql/qsql_mysql_p.h40
-rw-r--r--src/plugins/sqldrivers/oci/CMakeLists.txt16
-rw-r--r--src/plugins/sqldrivers/oci/main.cpp46
-rw-r--r--src/plugins/sqldrivers/oci/oci.pro13
-rw-r--r--src/plugins/sqldrivers/oci/qsql_oci.cpp877
-rw-r--r--src/plugins/sqldrivers/oci/qsql_oci_p.h47
-rw-r--r--src/plugins/sqldrivers/odbc/.prev_CMakeLists.txt32
-rw-r--r--src/plugins/sqldrivers/odbc/CMakeLists.txt18
-rw-r--r--src/plugins/sqldrivers/odbc/main.cpp46
-rw-r--r--src/plugins/sqldrivers/odbc/odbc.pro12
-rw-r--r--src/plugins/sqldrivers/odbc/qsql_odbc.cpp1676
-rw-r--r--src/plugins/sqldrivers/odbc/qsql_odbc_p.h40
-rw-r--r--src/plugins/sqldrivers/psql/.prev_CMakeLists.txt24
-rw-r--r--src/plugins/sqldrivers/psql/CMakeLists.txt27
-rw-r--r--src/plugins/sqldrivers/psql/main.cpp44
-rw-r--r--src/plugins/sqldrivers/psql/psql.pro11
-rw-r--r--src/plugins/sqldrivers/psql/qsql_psql.cpp446
-rw-r--r--src/plugins/sqldrivers/psql/qsql_psql_p.h42
-rw-r--r--src/plugins/sqldrivers/qsqldriverbase.pri9
-rw-r--r--src/plugins/sqldrivers/qt_cmdline.cmake22
-rw-r--r--src/plugins/sqldrivers/sqldrivers.pro14
-rw-r--r--src/plugins/sqldrivers/sqlite/.prev_CMakeLists.txt93
-rw-r--r--src/plugins/sqldrivers/sqlite/CMakeLists.txt101
-rw-r--r--src/plugins/sqldrivers/sqlite/qsql_sqlite.cpp509
-rw-r--r--src/plugins/sqldrivers/sqlite/qsql_sqlite_p.h47
-rw-r--r--src/plugins/sqldrivers/sqlite/qsql_sqlite_vfs.cpp258
-rw-r--r--src/plugins/sqldrivers/sqlite/qsql_sqlite_vfs_p.h21
-rw-r--r--src/plugins/sqldrivers/sqlite/smain.cpp49
-rw-r--r--src/plugins/sqldrivers/sqlite/sqlite.pro18
-rw-r--r--src/plugins/styles/.prev_CMakeLists.txt11
-rw-r--r--src/plugins/styles/CMakeLists.txt7
-rw-r--r--src/plugins/styles/android/CMakeLists.txt18
-rw-r--r--src/plugins/styles/android/android.pro16
-rw-r--r--src/plugins/styles/android/main.cpp40
-rw-r--r--src/plugins/styles/android/qandroidstyle.cpp81
-rw-r--r--src/plugins/styles/android/qandroidstyle_p.h84
-rw-r--r--src/plugins/styles/mac/CMakeLists.txt14
-rw-r--r--src/plugins/styles/mac/mac.pro19
-rw-r--r--src/plugins/styles/mac/macstyle.json2
-rw-r--r--src/plugins/styles/mac/main.mm44
-rw-r--r--src/plugins/styles/mac/qmacstyle_mac.mm927
-rw-r--r--src/plugins/styles/mac/qmacstyle_mac_p.h70
-rw-r--r--src/plugins/styles/mac/qmacstyle_mac_p_p.h48
-rw-r--r--src/plugins/styles/modernwindows/CMakeLists.txt (renamed from src/plugins/styles/windowsvista/CMakeLists.txt)20
-rw-r--r--src/plugins/styles/modernwindows/main.cpp36
-rw-r--r--src/plugins/styles/modernwindows/modernwindowsstyles.json3
-rw-r--r--src/plugins/styles/modernwindows/qwindows11style.cpp2116
-rw-r--r--src/plugins/styles/modernwindows/qwindows11style_p.h69
-rw-r--r--src/plugins/styles/modernwindows/qwindowsthemedata.cpp59
-rw-r--r--src/plugins/styles/modernwindows/qwindowsthemedata_p.h183
-rw-r--r--src/plugins/styles/modernwindows/qwindowsvistaanimation.cpp15
-rw-r--r--src/plugins/styles/modernwindows/qwindowsvistaanimation_p.h49
-rw-r--r--src/plugins/styles/modernwindows/qwindowsvistastyle.cpp5012
-rw-r--r--src/plugins/styles/modernwindows/qwindowsvistastyle_p.h (renamed from src/plugins/styles/windowsvista/qwindowsvistastyle_p.h)49
-rw-r--r--src/plugins/styles/modernwindows/qwindowsvistastyle_p_p.h176
-rw-r--r--src/plugins/styles/styles.pro8
-rw-r--r--src/plugins/styles/windowsvista/main.cpp64
-rw-r--r--src/plugins/styles/windowsvista/qwindowsvistastyle.cpp2509
-rw-r--r--src/plugins/styles/windowsvista/qwindowsvistastyle_p_p.h204
-rw-r--r--src/plugins/styles/windowsvista/qwindowsxpstyle.cpp4202
-rw-r--r--src/plugins/styles/windowsvista/qwindowsxpstyle_p.h106
-rw-r--r--src/plugins/styles/windowsvista/qwindowsxpstyle_p_p.h345
-rw-r--r--src/plugins/styles/windowsvista/windowsvista.pro20
-rw-r--r--src/plugins/styles/windowsvista/windowsvistastyle.json3
-rw-r--r--src/plugins/tls/CMakeLists.txt16
-rw-r--r--src/plugins/tls/certonly/CMakeLists.txt20
-rw-r--r--src/plugins/tls/certonly/qtlsbackend_cert.cpp56
-rw-r--r--src/plugins/tls/certonly/qtlsbackend_cert_p.h45
-rw-r--r--src/plugins/tls/openssl/CMakeLists.txt63
-rw-r--r--src/plugins/tls/openssl/qdtls_openssl.cpp1417
-rw-r--r--src/plugins/tls/openssl/qdtls_openssl_p.h214
-rw-r--r--src/plugins/tls/openssl/qopenssl_p.h82
-rw-r--r--src/plugins/tls/openssl/qsslcontext_openssl.cpp815
-rw-r--r--src/plugins/tls/openssl/qsslcontext_openssl_p.h96
-rw-r--r--src/plugins/tls/openssl/qssldiffiehellmanparameters_openssl.cpp159
-rw-r--r--src/plugins/tls/openssl/qsslsocket_openssl_android.cpp58
-rw-r--r--src/plugins/tls/openssl/qsslsocket_openssl_symbols.cpp1266
-rw-r--r--src/plugins/tls/openssl/qsslsocket_openssl_symbols_p.h765
-rw-r--r--src/plugins/tls/openssl/qtls_openssl.cpp1860
-rw-r--r--src/plugins/tls/openssl/qtls_openssl_p.h140
-rw-r--r--src/plugins/tls/openssl/qtlsbackend_openssl.cpp611
-rw-r--r--src/plugins/tls/openssl/qtlsbackend_openssl_p.h104
-rw-r--r--src/plugins/tls/openssl/qtlskey_openssl.cpp541
-rw-r--r--src/plugins/tls/openssl/qtlskey_openssl_p.h100
-rw-r--r--src/plugins/tls/openssl/qwindowscarootfetcher.cpp249
-rw-r--r--src/plugins/tls/openssl/qwindowscarootfetcher_p.h59
-rw-r--r--src/plugins/tls/openssl/qx509_openssl.cpp947
-rw-r--r--src/plugins/tls/openssl/qx509_openssl_p.h88
-rw-r--r--src/plugins/tls/schannel/CMakeLists.txt34
-rw-r--r--src/plugins/tls/schannel/qtls_schannel.cpp2640
-rw-r--r--src/plugins/tls/schannel/qtls_schannel_p.h123
-rw-r--r--src/plugins/tls/schannel/qtlsbackend_schannel_p.h71
-rw-r--r--src/plugins/tls/schannel/qtlskey_schannel.cpp157
-rw-r--r--src/plugins/tls/schannel/qtlskey_schannel_p.h46
-rw-r--r--src/plugins/tls/schannel/qx509_schannel.cpp214
-rw-r--r--src/plugins/tls/schannel/qx509_schannel_p.h53
-rw-r--r--src/plugins/tls/securetransport/CMakeLists.txt35
-rw-r--r--src/plugins/tls/securetransport/qtls_st.cpp1321
-rw-r--r--src/plugins/tls/securetransport/qtls_st_p.h110
-rw-r--r--src/plugins/tls/securetransport/qtlsbackend_st.cpp361
-rw-r--r--src/plugins/tls/securetransport/qtlsbackend_st_p.h64
-rw-r--r--src/plugins/tls/securetransport/qtlskey_st.cpp75
-rw-r--r--src/plugins/tls/securetransport/qtlskey_st_p.h47
-rw-r--r--src/plugins/tls/securetransport/qx509_st.cpp25
-rw-r--r--src/plugins/tls/securetransport/qx509_st_p.h38
-rw-r--r--src/plugins/tls/shared/qasn1element.cpp353
-rw-r--r--src/plugins/tls/shared/qasn1element_p.h152
-rw-r--r--src/plugins/tls/shared/qdtls_base.cpp79
-rw-r--r--src/plugins/tls/shared/qdtls_base_p.h80
-rw-r--r--src/plugins/tls/shared/qsslsocket_mac_shared.cpp168
-rw-r--r--src/plugins/tls/shared/qsslsocket_qt.cpp271
-rw-r--r--src/plugins/tls/shared/qtlskey_base.cpp97
-rw-r--r--src/plugins/tls/shared/qtlskey_base_p.h72
-rw-r--r--src/plugins/tls/shared/qtlskey_generic.cpp849
-rw-r--r--src/plugins/tls/shared/qtlskey_generic_p.h83
-rw-r--r--src/plugins/tls/shared/qwincrypt_p.h55
-rw-r--r--src/plugins/tls/shared/qx509_base.cpp142
-rw-r--r--src/plugins/tls/shared/qx509_base_p.h89
-rw-r--r--src/plugins/tls/shared/qx509_generic.cpp432
-rw-r--r--src/plugins/tls/shared/qx509_generic_p.h65
-rw-r--r--src/plugins/tracing/CMakeLists.txt32
-rw-r--r--src/plugins/tracing/metadata_template.txt77
-rw-r--r--src/plugins/tracing/qctflib.cpp447
-rw-r--r--src/plugins/tracing/qctflib_p.h125
-rw-r--r--src/plugins/tracing/qctfplugin.cpp63
-rw-r--r--src/plugins/tracing/qctfplugin_p.h28
-rw-r--r--src/plugins/tracing/qctfserver.cpp404
-rw-r--r--src/plugins/tracing/qctfserver_p.h194
-rw-r--r--src/plugins/tracing/trace.json3
1367 files changed, 74119 insertions, 96127 deletions
diff --git a/src/plugins/CMakeLists.txt b/src/plugins/CMakeLists.txt
index 6718d64ca0..d26d2aae44 100644
--- a/src/plugins/CMakeLists.txt
+++ b/src/plugins/CMakeLists.txt
@@ -1,11 +1,9 @@
-# Generated from plugins.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
if(TARGET Qt::Sql)
add_subdirectory(sqldrivers)
endif()
-if(QT_FEATURE_bearermanagement AND TARGET Qt::Network)
- add_subdirectory(bearer)
-endif()
if(TARGET Qt::Gui)
add_subdirectory(platforms)
add_subdirectory(platforminputcontexts)
@@ -20,6 +18,13 @@ endif()
if(TARGET Qt::Widgets)
add_subdirectory(styles)
endif()
-if(TARGET Qt::PrintSupport AND NOT WINRT)
+if(TARGET Qt::PrintSupport)
add_subdirectory(printsupport)
endif()
+if (TARGET Qt::Network)
+ add_subdirectory(networkinformation)
+ add_subdirectory(tls)
+endif()
+if (QT_FEATURE_ctf AND TARGET Qt::Network)
+ add_subdirectory(tracing)
+endif()
diff --git a/src/plugins/bearer/.prev_CMakeLists.txt b/src/plugins/bearer/.prev_CMakeLists.txt
deleted file mode 100644
index a7a36f60c6..0000000000
--- a/src/plugins/bearer/.prev_CMakeLists.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-# Generated from bearer.pro.
-
-if(SUBDIRS_ISEMPTY OR (TARGET Qt::DBus AND linux_x_ AND NOT ANDROID))
- add_subdirectory(generic)
-endif()
-if(TARGET Qt::DBus AND linux_x_ AND NOT ANDROID)
- add_subdirectory(connman)
- add_subdirectory(networkmanager)
-endif()
-if(ANDROID AND NOT ANDROID_EMBEDDED)
- add_subdirectory(android)
-endif()
diff --git a/src/plugins/bearer/CMakeLists.txt b/src/plugins/bearer/CMakeLists.txt
deleted file mode 100644
index 528061d264..0000000000
--- a/src/plugins/bearer/CMakeLists.txt
+++ /dev/null
@@ -1,14 +0,0 @@
-# Generated from bearer.pro.
-
-# special case begin
-# The whole block is manual.
-if(NOT ANDROID AND LINUX AND TARGET Qt::DBus)
- add_subdirectory(generic)
- add_subdirectory(connman)
- add_subdirectory(networkmanager)
-elseif(ANDROID AND NOT ANDROID_EMBEDDED)
- add_subdirectory(android)
-else()
- add_subdirectory(generic)
-endif()
-# special case end
diff --git a/src/plugins/bearer/android/CMakeLists.txt b/src/plugins/bearer/android/CMakeLists.txt
deleted file mode 100644
index 193cbf1fe3..0000000000
--- a/src/plugins/bearer/android/CMakeLists.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-# Generated from android.pro.
-
-add_subdirectory(src)
-add_subdirectory(jar)
diff --git a/src/plugins/bearer/android/android.pro b/src/plugins/bearer/android/android.pro
deleted file mode 100644
index 6a51abf5d7..0000000000
--- a/src/plugins/bearer/android/android.pro
+++ /dev/null
@@ -1,4 +0,0 @@
-TEMPLATE = subdirs
-
-SUBDIRS += src \
- jar
diff --git a/src/plugins/bearer/android/jar/.prev_CMakeLists.txt b/src/plugins/bearer/android/jar/.prev_CMakeLists.txt
deleted file mode 100644
index f5f25c4f8b..0000000000
--- a/src/plugins/bearer/android/jar/.prev_CMakeLists.txt
+++ /dev/null
@@ -1,16 +0,0 @@
-# Generated from jar.pro.
-
-set(java_sources
- src/org/qtproject/qt5/android/bearer/QtNetworkReceiver.java
-)
-
-add_jar(QtAndroidBearer
- INCLUDE_JARS ${QT_ANDROID_JAR}
- SOURCES ${java_sources}
-)
-
-install_jar(QtAndroidBearer
- DESTINATION jar
- COMPONENT Devel
-)
-
diff --git a/src/plugins/bearer/android/jar/CMakeLists.txt b/src/plugins/bearer/android/jar/CMakeLists.txt
deleted file mode 100644
index 16641d42b7..0000000000
--- a/src/plugins/bearer/android/jar/CMakeLists.txt
+++ /dev/null
@@ -1,22 +0,0 @@
-#####################################################################
-## QtAndroidBearer Binary:
-#####################################################################
-
-set(java_sources
- src/org/qtproject/qt5/android/bearer/QtNetworkReceiver.java
-)
-
-add_jar(QtAndroidBearer
- INCLUDE_JARS ${QT_ANDROID_JAR}
- SOURCES ${java_sources}
- )
-
-install_jar(QtAndroidBearer
- DESTINATION jar
- COMPONENT Devel)
-
-#### Keys ignored in scope 1:.:.:jar.pro:<TRUE>:
-# JAVACLASSPATH = "$$PWD/src"
-# JAVASOURCES = "$$PWD/src/org/qtproject/qt5/android/bearer/QtNetworkReceiver.java"
-# _LOADED = "qt_build_paths"
-
diff --git a/src/plugins/bearer/android/jar/jar.pro b/src/plugins/bearer/android/jar/jar.pro
deleted file mode 100644
index 8277a8abc1..0000000000
--- a/src/plugins/bearer/android/jar/jar.pro
+++ /dev/null
@@ -1,15 +0,0 @@
-CONFIG += single_arch
-
-TARGET = QtAndroidBearer
-
-load(qt_build_paths)
-CONFIG += java
-DESTDIR = $$MODULE_BASE_OUTDIR/jar
-
-JAVACLASSPATH += $$PWD/src
-
-JAVASOURCES += $$PWD/src/org/qtproject/qt5/android/bearer/QtNetworkReceiver.java
-
-# install
-target.path = $$[QT_INSTALL_PREFIX]/jar
-INSTALLS += target
diff --git a/src/plugins/bearer/android/jar/src/org/qtproject/qt5/android/bearer/QtNetworkReceiver.java b/src/plugins/bearer/android/jar/src/org/qtproject/qt5/android/bearer/QtNetworkReceiver.java
deleted file mode 100644
index 805c90548b..0000000000
--- a/src/plugins/bearer/android/jar/src/org/qtproject/qt5/android/bearer/QtNetworkReceiver.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
-
-package org.qtproject.qt5.android.bearer;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.util.Log;
-import android.net.ConnectivityManager;
-
-public class QtNetworkReceiver
-{
- private static final String LOG_TAG = "QtNetworkReceiver";
- private static native void activeNetworkInfoChanged();
- private static BroadcastReceiverPrivate m_broadcastReceiver = null;
- private static final Object m_lock = new Object();
-
- private static class BroadcastReceiverPrivate extends BroadcastReceiver
- {
- @Override
- public void onReceive(Context context, Intent intent)
- {
- activeNetworkInfoChanged();
- }
- }
-
- private QtNetworkReceiver() {}
-
- public static void registerReceiver(final Context context)
- {
- synchronized (m_lock) {
- if (m_broadcastReceiver == null) {
- m_broadcastReceiver = new BroadcastReceiverPrivate();
- IntentFilter intentFilter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
- context.registerReceiver(m_broadcastReceiver, intentFilter);
- }
- }
- }
-
- public static void unregisterReceiver(final Context context)
- {
- synchronized (m_lock) {
- if (m_broadcastReceiver == null)
- return;
-
- context.unregisterReceiver(m_broadcastReceiver);
- }
- }
-
- public static ConnectivityManager getConnectivityManager(final Context context)
- {
- return (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
- }
-}
diff --git a/src/plugins/bearer/android/src/CMakeLists.txt b/src/plugins/bearer/android/src/CMakeLists.txt
deleted file mode 100644
index 5be89e316b..0000000000
--- a/src/plugins/bearer/android/src/CMakeLists.txt
+++ /dev/null
@@ -1,19 +0,0 @@
-# Generated from src.pro.
-
-#####################################################################
-## QAndroidBearerEnginePlugin Plugin:
-#####################################################################
-
-qt_add_plugin(QAndroidBearerEnginePlugin
- OUTPUT_NAME qandroidbearer
- TYPE bearer
- SOURCES
- main.cpp
- qandroidbearerengine.cpp qandroidbearerengine.h
- wrappers/androidconnectivitymanager.cpp wrappers/androidconnectivitymanager.h
- INCLUDE_DIRECTORIES
- wrappers
- PUBLIC_LIBRARIES
- Qt::CorePrivate
- Qt::NetworkPrivate
-)
diff --git a/src/plugins/bearer/android/src/android.json b/src/plugins/bearer/android/src/android.json
deleted file mode 100644
index 6843bd3301..0000000000
--- a/src/plugins/bearer/android/src/android.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "Keys": [ "android" ]
-}
diff --git a/src/plugins/bearer/android/src/main.cpp b/src/plugins/bearer/android/src/main.cpp
deleted file mode 100644
index f3a5074e5d..0000000000
--- a/src/plugins/bearer/android/src/main.cpp
+++ /dev/null
@@ -1,63 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 "qandroidbearerengine.h"
-#include <QtNetwork/private/qbearerplugin_p.h>
-
-#ifndef QT_NO_BEARERMANAGEMENT
-
-QT_BEGIN_NAMESPACE
-
-class QAndroidBearerEnginePlugin : public QBearerEnginePlugin
-{
- Q_OBJECT
- Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QBearerEngineFactoryInterface" FILE "android.json")
-
-public:
- QBearerEngine *create(const QString &key) const override
- {
- return (key == QLatin1String("android")) ? new QAndroidBearerEngine() : 0;
- }
-};
-
-QT_END_NAMESPACE
-
-#include "main.moc"
-
-#endif // QT_NO_BEARERMANAGEMENT
diff --git a/src/plugins/bearer/android/src/qandroidbearerengine.cpp b/src/plugins/bearer/android/src/qandroidbearerengine.cpp
deleted file mode 100644
index ad9895e0cf..0000000000
--- a/src/plugins/bearer/android/src/qandroidbearerengine.cpp
+++ /dev/null
@@ -1,391 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 "qandroidbearerengine.h"
-#include <private/qnetworksession_impl_p.h>
-#include "wrappers/androidconnectivitymanager.h"
-
-#ifndef QT_NO_BEARERMANAGEMENT
-
-QT_BEGIN_NAMESPACE
-
-static QString networkConfType(const AndroidNetworkInfo &networkInfo)
-{
- switch (networkInfo.getType()) {
- case AndroidNetworkInfo::Mobile:
- return QStringLiteral("Mobile");
- case AndroidNetworkInfo::Wifi:
- return QStringLiteral("WiFi");
- case AndroidNetworkInfo::Wimax:
- return QStringLiteral("WiMax");
- case AndroidNetworkInfo::Ethernet:
- return QStringLiteral("Ethernet");
- case AndroidNetworkInfo::Bluetooth:
- return QStringLiteral("Bluetooth");
- default:
- break;
- }
-
- return QString();
-}
-
-static inline bool isMobile(QNetworkConfiguration::BearerType type)
-{
- if (type == QNetworkConfiguration::BearerWLAN
- || type == QNetworkConfiguration::BearerWiMAX
- || type == QNetworkConfiguration::BearerBluetooth
- || type == QNetworkConfiguration::BearerEthernet
- || type == QNetworkConfiguration::BearerUnknown) {
- return false;
- }
-
- return true;
-}
-
-static QNetworkConfiguration::BearerType getBearerType(const AndroidNetworkInfo &networkInfo)
-{
- switch (networkInfo.getType()) {
- case AndroidNetworkInfo::Mobile:
- {
- switch (networkInfo.getSubtype()) {
- case AndroidNetworkInfo::Gprs:
- case AndroidNetworkInfo::Edge:
- case AndroidNetworkInfo::Iden: // 2G
- return QNetworkConfiguration::Bearer2G;
- case AndroidNetworkInfo::Umts: // BearerWCDMA (3 .5 .75 G)
- case AndroidNetworkInfo::Hsdpa: // 3G (?) UMTS
- case AndroidNetworkInfo::Hsupa: // 3G (?) UMTS
- return QNetworkConfiguration::BearerWCDMA;
- case AndroidNetworkInfo::Cdma: // CDMA ISA95[AB]
- case AndroidNetworkInfo::Cdma1xRTT: // BearerCDMA2000 (3G)
- case AndroidNetworkInfo::Ehrpd: // CDMA Bridge thing?!?
- return QNetworkConfiguration::BearerCDMA2000;
- case AndroidNetworkInfo::Evdo0: // BearerEVDO
- case AndroidNetworkInfo::EvdoA: // BearerEVDO
- case AndroidNetworkInfo::EvdoB: // BearerEVDO
- return QNetworkConfiguration::BearerEVDO;
- case AndroidNetworkInfo::Hspa:
- case AndroidNetworkInfo::Hspap: // HSPA+
- return QNetworkConfiguration::BearerHSPA;
- case AndroidNetworkInfo::Lte: // BearerLTE (4G)
- return QNetworkConfiguration::BearerLTE;
- default:
- break;
- }
- }
- case AndroidNetworkInfo::Wifi:
- return QNetworkConfiguration::BearerWLAN;
- case AndroidNetworkInfo::Wimax:
- return QNetworkConfiguration::BearerWiMAX;
- case AndroidNetworkInfo::Bluetooth:
- case AndroidNetworkInfo::MobileDun:
- return QNetworkConfiguration::BearerBluetooth;
- case AndroidNetworkInfo::Ethernet:
- return QNetworkConfiguration::BearerEthernet;
- case AndroidNetworkInfo::MobileMms:
- case AndroidNetworkInfo::MobileSupl:
- case AndroidNetworkInfo::MobileHipri:
- case AndroidNetworkInfo::Dummy:
- case AndroidNetworkInfo::UnknownType:
- break;
- }
-
- return QNetworkConfiguration::BearerUnknown;
-}
-
-QAndroidBearerEngine::QAndroidBearerEngine(QObject *parent)
- : QBearerEngineImpl(parent),
- m_connectivityManager(0)
-{
-}
-
-QAndroidBearerEngine::~QAndroidBearerEngine()
-{
-}
-
-QString QAndroidBearerEngine::getInterfaceFromId(const QString &id)
-{
- const QMutexLocker locker(&mutex);
- return m_configurationInterface.value(id);
-}
-
-bool QAndroidBearerEngine::hasIdentifier(const QString &id)
-{
- const QMutexLocker locker(&mutex);
- return m_configurationInterface.contains(id);
-}
-
-void QAndroidBearerEngine::connectToId(const QString &id)
-{
- Q_EMIT connectionError(id, OperationNotSupported);
-}
-
-void QAndroidBearerEngine::disconnectFromId(const QString &id)
-{
- Q_EMIT connectionError(id, OperationNotSupported);
-}
-
-QNetworkSession::State QAndroidBearerEngine::sessionStateForId(const QString &id)
-{
- const QMutexLocker locker(&mutex);
- QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id);
-
- if ((!ptr || !ptr->isValid) || m_connectivityManager == 0)
- return QNetworkSession::Invalid;
-
- const QMutexLocker configLocker(&ptr->mutex);
- // Don't re-order...
- if ((ptr->state & QNetworkConfiguration::Active) == QNetworkConfiguration::Active) {
- return QNetworkSession::Connected;
- } else if ((ptr->state & QNetworkConfiguration::Discovered) == QNetworkConfiguration::Discovered) {
- return QNetworkSession::Disconnected;
- } else if ((ptr->state & QNetworkConfiguration::Defined) == QNetworkConfiguration::Defined) {
- return QNetworkSession::NotAvailable;
- } else if ((ptr->state & QNetworkConfiguration::Undefined) == QNetworkConfiguration::Undefined) {
- return QNetworkSession::NotAvailable;
- }
-
- return QNetworkSession::Invalid;
-}
-
-QNetworkConfigurationManager::Capabilities QAndroidBearerEngine::capabilities() const
-{
-
- return AndroidTrafficStats::isTrafficStatsSupported()
- ? QNetworkConfigurationManager::ForcedRoaming
- | QNetworkConfigurationManager::DataStatistics
- : QNetworkConfigurationManager::ForcedRoaming;
-
-}
-
-QNetworkSessionPrivate *QAndroidBearerEngine::createSessionBackend()
-{
- return new QNetworkSessionPrivateImpl();
-}
-
-QNetworkConfigurationPrivatePointer QAndroidBearerEngine::defaultConfiguration()
-{
- return QNetworkConfigurationPrivatePointer();
-}
-
-bool QAndroidBearerEngine::requiresPolling() const
-{
- return false;
-}
-
-quint64 QAndroidBearerEngine::bytesWritten(const QString &id)
-{
- QMutexLocker lock(&mutex);
- QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id);
- if (!ptr || !ptr->isValid)
- return 0;
-
- return isMobile(ptr->bearerType)
- ? AndroidTrafficStats::getMobileTxBytes()
- : AndroidTrafficStats::getTotalTxBytes() - AndroidTrafficStats::getMobileTxBytes();
-}
-
-quint64 QAndroidBearerEngine::bytesReceived(const QString &id)
-{
- QMutexLocker lock(&mutex);
- QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id);
- if (!ptr || !ptr->isValid)
- return 0;
-
- return isMobile(ptr->bearerType)
- ? AndroidTrafficStats::getMobileRxBytes()
- : AndroidTrafficStats::getTotalRxBytes() - AndroidTrafficStats::getMobileRxBytes();
-}
-
-quint64 QAndroidBearerEngine::startTime(const QString &id)
-{
- Q_UNUSED(id);
- return Q_UINT64_C(0);
-}
-
-void QAndroidBearerEngine::initialize()
-{
- if (m_connectivityManager != 0)
- return;
-
- m_connectivityManager = AndroidConnectivityManager::getInstance();
- if (m_connectivityManager == 0)
- return;
-
- updateConfigurations();
-
- connect(m_connectivityManager, &AndroidConnectivityManager::activeNetworkChanged,
- this, &QAndroidBearerEngine::updateConfigurations);
-
-}
-
-void QAndroidBearerEngine::requestUpdate()
-{
- updateConfigurations();
-}
-
-void QAndroidBearerEngine::updateConfigurations()
-{
-#ifndef QT_NO_NETWORKINTERFACE
- if (m_connectivityManager == 0)
- return;
-
- {
- QMutexLocker locker(&mutex);
- QStringList oldKeys = accessPointConfigurations.keys();
-
- QList<QNetworkInterface> interfaces = QNetworkInterface::allInterfaces();
- if (interfaces.isEmpty())
- interfaces = QNetworkInterface::allInterfaces();
-
- // Create a configuration for each of the main types (WiFi, Mobile, Bluetooth, WiMax, Ethernet)
- const auto netInfos = m_connectivityManager->getAllNetworkInfo();
- for (const AndroidNetworkInfo &netInfo : netInfos) {
-
- if (!netInfo.isValid())
- continue;
-
- const QString name = networkConfType(netInfo);
- if (name.isEmpty())
- continue;
-
- QNetworkConfiguration::BearerType bearerType = getBearerType(netInfo);
-
- QString interfaceName;
- QNetworkConfiguration::StateFlag state = QNetworkConfiguration::Defined;
- if (netInfo.isAvailable()) {
- if (netInfo.isConnected()) {
- // Attempt to map an interface to this configuration
- while (!interfaces.isEmpty()) {
- QNetworkInterface interface = interfaces.takeFirst();
- // ignore loopback interface
- if (!interface.isValid())
- continue;
-
- if (interface.flags() & QNetworkInterface::IsLoopBack)
- continue;
- // There is no way to get the interface from the NetworkInfo, so
- // look for an active interface...
- if (interface.flags() & QNetworkInterface::IsRunning
- && !interface.addressEntries().isEmpty()) {
- state = QNetworkConfiguration::Active;
- interfaceName = interface.name();
- break;
- }
- }
- }
- }
-
- const QString key = QString(QLatin1String("android:%1:%2")).arg(name).arg(interfaceName);
- const QString id = QString::number(qHash(key));
- m_configurationInterface[id] = interfaceName;
-
- oldKeys.removeAll(id);
- if (accessPointConfigurations.contains(id)) {
- QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id);
- bool changed = false;
- {
- const QMutexLocker confLocker(&ptr->mutex);
-
- if (!ptr->isValid) {
- ptr->isValid = true;
- changed = true;
- }
-
- // Don't reset the bearer type to 'Unknown'
- if (ptr->bearerType != QNetworkConfiguration::BearerUnknown
- && ptr->bearerType != bearerType) {
- ptr->bearerType = bearerType;
- changed = true;
- }
-
- if (ptr->name != name) {
- ptr->name = name;
- changed = true;
- }
-
- if (ptr->id != id) {
- ptr->id = id;
- changed = true;
- }
-
- if (ptr->state != state) {
- ptr->state = state;
- changed = true;
- }
- } // Unlock configuration
-
- if (changed) {
- locker.unlock();
- Q_EMIT configurationChanged(ptr);
- locker.relock();
- }
- } else {
- QNetworkConfigurationPrivatePointer ptr(new QNetworkConfigurationPrivate);
- ptr->name = name;
- ptr->isValid = true;
- ptr->id = id;
- ptr->state = state;
- ptr->type = QNetworkConfiguration::InternetAccessPoint;
- ptr->bearerType = bearerType;
- accessPointConfigurations.insert(id, ptr);
- locker.unlock();
- Q_EMIT configurationAdded(ptr);
- locker.relock();
- }
- }
-
- while (!oldKeys.isEmpty()) {
- QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.take(oldKeys.takeFirst());
- m_configurationInterface.remove(ptr->id);
- locker.unlock();
- Q_EMIT configurationRemoved(ptr);
- locker.relock();
- }
-
- } // Unlock engine
-
-#endif // QT_NO_NETWORKINTERFACE
-
- Q_EMIT updateCompleted();
-}
-
-QT_END_NAMESPACE
-
-#endif // QT_NO_BEARERMANAGEMENT
diff --git a/src/plugins/bearer/android/src/qandroidbearerengine.h b/src/plugins/bearer/android/src/qandroidbearerengine.h
deleted file mode 100644
index 867d04d886..0000000000
--- a/src/plugins/bearer/android/src/qandroidbearerengine.h
+++ /dev/null
@@ -1,95 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 QANDROIDBEARERENGINE_H
-#define QANDROIDBEARERENGINE_H
-
-#include <private/qbearerengine_impl_p.h>
-
-#include <QAbstractEventDispatcher>
-#include <QAbstractNativeEventFilter>
-#include <QtCore/private/qjni_p.h>
-
-#ifndef QT_NO_BEARERMANAGEMENT
-
-QT_BEGIN_NAMESPACE
-
-class QNetworkConfigurationPrivate;
-class QNetworkSessionPrivate;
-class AndroidConnectivityManager;
-
-class QAndroidBearerEngine : public QBearerEngineImpl
-{
- Q_OBJECT
-
-public:
- explicit QAndroidBearerEngine(QObject *parent = 0);
- ~QAndroidBearerEngine() override;
-
- QString getInterfaceFromId(const QString &id) override;
- bool hasIdentifier(const QString &id) override;
- void connectToId(const QString &id) override;
- void disconnectFromId(const QString &id) override;
- QNetworkSession::State sessionStateForId(const QString &id) override;
- QNetworkConfigurationManager::Capabilities capabilities() const override;
- QNetworkSessionPrivate *createSessionBackend() override;
- QNetworkConfigurationPrivatePointer defaultConfiguration() override;
- bool requiresPolling() const override;
- quint64 bytesWritten(const QString &id) override;
- quint64 bytesReceived(const QString &id) override;
- quint64 startTime(const QString &id) override;
-
- Q_INVOKABLE void initialize();
- Q_INVOKABLE void requestUpdate();
-
-private Q_SLOTS:
- void updateConfigurations();
-
-private:
- QJNIObjectPrivate m_networkReceiver;
- AndroidConnectivityManager *m_connectivityManager;
- QMap<QString, QString> m_configurationInterface;
-};
-
-
-QT_END_NAMESPACE
-
-#endif // QT_NO_BEARERMANAGEMENT
-
-#endif // QANDROIDBEARERENGINE_H
diff --git a/src/plugins/bearer/android/src/src.pro b/src/plugins/bearer/android/src/src.pro
deleted file mode 100644
index fcd599dffe..0000000000
--- a/src/plugins/bearer/android/src/src.pro
+++ /dev/null
@@ -1,14 +0,0 @@
-TARGET = qandroidbearer
-
-QT = core-private network-private
-
-HEADERS += qandroidbearerengine.h
-
-SOURCES += main.cpp \
- qandroidbearerengine.cpp
-
-include(wrappers/wrappers.pri)
-
-PLUGIN_TYPE = bearer
-PLUGIN_CLASS_NAME = QAndroidBearerEnginePlugin
-load(qt_plugin)
diff --git a/src/plugins/bearer/android/src/wrappers/androidconnectivitymanager.cpp b/src/plugins/bearer/android/src/wrappers/androidconnectivitymanager.cpp
deleted file mode 100644
index 6787690246..0000000000
--- a/src/plugins/bearer/android/src/wrappers/androidconnectivitymanager.cpp
+++ /dev/null
@@ -1,387 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 "androidconnectivitymanager.h"
-#include <QtCore/private/qjni_p.h>
-#include <QtCore/private/qjnihelpers_p.h>
-
-QT_BEGIN_NAMESPACE
-
-static inline bool exceptionCheckAndClear(JNIEnv *env)
-{
- if (!env->ExceptionCheck())
- return false;
-
-#ifdef QT_DEBUG
- env->ExceptionDescribe();
-#endif // QT_DEBUG
- env->ExceptionClear();
-
- return true;
-}
-
-struct AndroidConnectivityManagerInstance
-{
- AndroidConnectivityManagerInstance()
- : connManager(new AndroidConnectivityManager)
- { }
- ~AndroidConnectivityManagerInstance()
- {
- delete connManager;
- }
-
- AndroidConnectivityManager* connManager;
-};
-
-Q_GLOBAL_STATIC(AndroidConnectivityManagerInstance, androidConnManagerInstance)
-
-static const char networkReceiverClass[] = "org/qtproject/qt5/android/bearer/QtNetworkReceiver";
-static const char trafficStatsClass[] = "android/net/TrafficStats";
-
-/**
- * Returns the number of bytes transmitted over the mobile network since last device boot.
- */
-qint64 AndroidTrafficStats::getMobileTxBytes()
-{
- return QJNIObjectPrivate::callStaticMethod<jlong>(trafficStatsClass,
- "getMobileTxBytes",
- "()J");
-}
-
-/**
- * Returns the number of bytes received over the mobile network since last device boot.
- */
-qint64 AndroidTrafficStats::getMobileRxBytes()
-{
- return QJNIObjectPrivate::callStaticMethod<jlong>(trafficStatsClass,
- "getMobileRxBytes",
- "()J");
-}
-
-/**
- * Returns the total transmitted bytes since last device boot.
- */
-qint64 AndroidTrafficStats::getTotalTxBytes()
-{
- return QJNIObjectPrivate::callStaticMethod<jlong>(trafficStatsClass,
- "getTotalTxBytes",
- "()J");
-}
-
-/**
- * Returns the total received bytes since last device boot.
- */
-qint64 AndroidTrafficStats::getTotalRxBytes()
-{
- return QJNIObjectPrivate::callStaticMethod<jlong>(trafficStatsClass,
- "getTotalRxBytes",
- "()J");
-}
-
-bool AndroidTrafficStats::isTrafficStatsSupported()
-{
- // Before API level 18 DataStatistics might not be supported, so make sure that we get something
- // else then -1 from from getXXBytes().
- return (AndroidTrafficStats::getMobileRxBytes() != -1
- && AndroidTrafficStats::getTotalRxBytes() != -1);
-}
-
-static AndroidNetworkInfo::NetworkState stateForName(const QString &stateName)
-{
- if (stateName == QLatin1String("CONNECTED"))
- return AndroidNetworkInfo::Connected;
- else if (stateName == QLatin1String("CONNECTING"))
- return AndroidNetworkInfo::Connecting;
- else if (stateName == QLatin1String("DISCONNECTED"))
- return AndroidNetworkInfo::Disconnected;
- else if (stateName == QLatin1String("DISCONNECTING"))
- return AndroidNetworkInfo::Disconnecting;
- else if (stateName == QLatin1String("SUSPENDED"))
- return AndroidNetworkInfo::Suspended;
-
- return AndroidNetworkInfo::UnknownState;
-}
-
-AndroidNetworkInfo::NetworkState AndroidNetworkInfo::getDetailedState() const
-{
- QJNIObjectPrivate enumObject = m_networkInfo.callObjectMethod("getDetailedState",
- "()Landroid/net/NetworkInfo$DetailedState;");
- if (!enumObject.isValid())
- return UnknownState;
-
- QJNIObjectPrivate enumName = enumObject.callObjectMethod<jstring>("name");
- if (!enumName.isValid())
- return UnknownState;
-
- return stateForName(enumName.toString());
-}
-
-QString AndroidNetworkInfo::getExtraInfo() const
-{
- QJNIObjectPrivate extraInfo = m_networkInfo.callObjectMethod<jstring>("getExtraInfo");
- if (!extraInfo.isValid())
- return QString();
-
- return extraInfo.toString();
-}
-
-QString AndroidNetworkInfo::getReason() const
-{
- QJNIObjectPrivate reason = m_networkInfo.callObjectMethod<jstring>("getReason");
- if (!reason.isValid())
- return QString();
-
- return reason.toString();
-}
-
-AndroidNetworkInfo::NetworkState AndroidNetworkInfo::getState() const
-{
- QJNIObjectPrivate enumObject = m_networkInfo.callObjectMethod("getState",
- "()Landroid/net/NetworkInfo$State;");
- if (!enumObject.isValid())
- return UnknownState;
-
- QJNIObjectPrivate enumName = enumObject.callObjectMethod<jstring>("name");
- if (!enumName.isValid())
- return UnknownState;
-
- return stateForName(enumName.toString());
-}
-
-AndroidNetworkInfo::NetworkSubType AndroidNetworkInfo::getSubtype() const
-{
- return AndroidNetworkInfo::NetworkSubType(m_networkInfo.callMethod<jint>("getSubtype"));
-}
-
-QString AndroidNetworkInfo::getSubtypeName() const
-{
- QJNIObjectPrivate subtypeName = m_networkInfo.callObjectMethod<jstring>("getSubtypeName");
- if (!subtypeName.isValid())
- return QString();
-
- return subtypeName.toString();
-}
-
-AndroidNetworkInfo::NetworkType AndroidNetworkInfo::getType() const
-{
- return AndroidNetworkInfo::NetworkType(m_networkInfo.callMethod<jint>("getType"));
-}
-
-QString AndroidNetworkInfo::getTypeName() const
-{
- QJNIObjectPrivate typeName = m_networkInfo.callObjectMethod<jstring>("getTypeName");
- if (!typeName.isValid())
- return QString();
-
- return typeName.toString();
-}
-
-bool AndroidNetworkInfo::isAvailable() const
-{
- return m_networkInfo.callMethod<jboolean>("isAvailable");
-}
-
-bool AndroidNetworkInfo::isConnected() const
-{
- return m_networkInfo.callMethod<jboolean>("isConnected");
-}
-
-bool AndroidNetworkInfo::isConnectedOrConnecting() const
-{
- return m_networkInfo.callMethod<jboolean>("isConnectedOrConnecting");
-}
-
-bool AndroidNetworkInfo::isFailover() const
-{
- return m_networkInfo.callMethod<jboolean>("isFailover");
-}
-
-bool AndroidNetworkInfo::isRoaming() const
-{
- return m_networkInfo.callMethod<jboolean>("isRoaming");
-}
-
-bool AndroidNetworkInfo::isValid() const
-{
- return m_networkInfo.isValid();
-}
-
-AndroidConnectivityManager::AndroidConnectivityManager()
-{
- QJNIEnvironmentPrivate env;
- if (!registerNatives(env))
- return;
-
- m_connectivityManager = QJNIObjectPrivate::callStaticObjectMethod(networkReceiverClass,
- "getConnectivityManager",
- "(Landroid/content/Context;)Landroid/net/ConnectivityManager;",
- QtAndroidPrivate::context());
- if (!m_connectivityManager.isValid())
- return;
-
- QJNIObjectPrivate::callStaticMethod<void>(networkReceiverClass,
- "registerReceiver",
- "(Landroid/content/Context;)V",
- QtAndroidPrivate::context());
-}
-
-AndroidConnectivityManager *AndroidConnectivityManager::getInstance()
-{
- return androidConnManagerInstance->connManager->isValid()
- ? androidConnManagerInstance->connManager
- : 0;
-}
-
-AndroidConnectivityManager::~AndroidConnectivityManager()
-{
- QJNIObjectPrivate::callStaticMethod<void>(networkReceiverClass,
- "unregisterReceiver",
- "(Landroid/content/Context;)V",
- QtAndroidPrivate::context());
-}
-
-AndroidNetworkInfo AndroidConnectivityManager::getActiveNetworkInfo() const
-{
- QJNIObjectPrivate networkInfo = m_connectivityManager.callObjectMethod("getActiveNetworkInfo",
- "()Landroid/net/NetworkInfo;");
- return networkInfo;
-}
-
-QList<AndroidNetworkInfo> AndroidConnectivityManager::getAllNetworkInfo() const
-{
- QJNIEnvironmentPrivate env;
- QJNIObjectPrivate objArray = m_connectivityManager.callObjectMethod("getAllNetworkInfo",
- "()[Landroid/net/NetworkInfo;");
- QList<AndroidNetworkInfo> list;
- if (!objArray.isValid())
- return list;
-
- const jsize length = env->GetArrayLength(static_cast<jarray>(objArray.object()));
- if (exceptionCheckAndClear(env))
- return list;
-
- for (int i = 0; i != length; ++i) {
- jobject lref = env->GetObjectArrayElement(static_cast<jobjectArray>(objArray.object()), i);
- if (exceptionCheckAndClear(env))
- break;
-
- list << AndroidNetworkInfo(QJNIObjectPrivate::fromLocalRef(lref));
- }
-
- return list;
-}
-
-bool AndroidConnectivityManager::getBackgroundDataSetting() const
-{
- return m_connectivityManager.callMethod<jboolean>("getBackgroundDataSetting");
-}
-
-AndroidNetworkInfo AndroidConnectivityManager::getNetworkInfo(int networkType) const
-{
- QJNIObjectPrivate networkInfo = m_connectivityManager.callObjectMethod("getNetworkInfo",
- "(I)Landroid/net/NetworkInfo;",
- networkType);
- return networkInfo;
-}
-
-int AndroidConnectivityManager::getNetworkPreference() const
-{
- return m_connectivityManager.callMethod<jint>("getNetworkPreference");
-}
-
-bool AndroidConnectivityManager::isActiveNetworkMetered() const
-{
- return m_connectivityManager.callMethod<jboolean>("isActiveNetworkMetered");
-}
-
-bool AndroidConnectivityManager::isNetworkTypeValid(int networkType)
-{
- return QJNIObjectPrivate::callStaticMethod<jboolean>("android/net/ConnectivityManager",
- "isNetworkTypeValid",
- "(I)Z",
- networkType);
-}
-
-bool AndroidConnectivityManager::requestRouteToHost(int networkType, int hostAddress)
-{
- return m_connectivityManager.callMethod<jboolean>("requestRouteToHost", "(II)Z", networkType, hostAddress);
-}
-
-void AndroidConnectivityManager::setNetworkPreference(int preference)
-{
- m_connectivityManager.callMethod<void>("setNetworkPreference", "(I)V", preference);
-}
-
-int AndroidConnectivityManager::startUsingNetworkFeature(int networkType, const QString &feature)
-{
- QJNIObjectPrivate jfeature = QJNIObjectPrivate::fromString(feature);
- return m_connectivityManager.callMethod<jint>("startUsingNetworkFeature",
- "(ILjava/lang/String;)I",
- networkType,
- jfeature.object());
-}
-
-int AndroidConnectivityManager::stopUsingNetworkFeature(int networkType, const QString &feature)
-{
- QJNIObjectPrivate jfeature = QJNIObjectPrivate::fromString(feature);
- return m_connectivityManager.callMethod<jint>("stopUsingNetworkFeature",
- "(ILjava/lang/String;)I",
- networkType,
- jfeature.object());
-}
-
-static void activeNetworkInfoChanged()
-{
- Q_EMIT androidConnManagerInstance->connManager->activeNetworkChanged();
-}
-
-bool AndroidConnectivityManager::registerNatives(JNIEnv *env)
-{
- QJNIObjectPrivate networkReceiver(networkReceiverClass);
- if (!networkReceiver.isValid())
- return false;
-
- jclass clazz = env->GetObjectClass(networkReceiver.object());
- static JNINativeMethod method = {"activeNetworkInfoChanged", "()V", reinterpret_cast<void *>(activeNetworkInfoChanged)};
- const bool ret = (env->RegisterNatives(clazz, &method, 1) == JNI_OK);
- env->DeleteLocalRef(clazz);
- return ret;
-}
-
-QT_END_NAMESPACE
diff --git a/src/plugins/bearer/android/src/wrappers/androidconnectivitymanager.h b/src/plugins/bearer/android/src/wrappers/androidconnectivitymanager.h
deleted file mode 100644
index 7c410b0087..0000000000
--- a/src/plugins/bearer/android/src/wrappers/androidconnectivitymanager.h
+++ /dev/null
@@ -1,168 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 ANDROIDCONNECTIVITYMANAGER_H
-#define ANDROIDCONNECTIVITYMANAGER_H
-
-#include <QObject>
-#include <QtCore/private/qjni_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class AndroidTrafficStats
-{
-public:
- static qint64 getMobileTxBytes();
- static qint64 getMobileRxBytes();
- static qint64 getTotalTxBytes();
- static qint64 getTotalRxBytes();
- static bool isTrafficStatsSupported();
-};
-
-class AndroidNetworkInfo
-{
-public:
- // Needs to be in sync with the values from the android api.
- enum NetworkState {
- UnknownState,
- Authenticating,
- Blocked,
- CaptivePortalCheck,
- Connected,
- Connecting,
- Disconnected,
- Disconnecting,
- Failed,
- Idle,
- ObtainingIpAddr,
- Scanning,
- Suspended,
- VerifyingPoorLink
- };
-
- enum NetworkType {
- Mobile,
- Wifi,
- MobileMms,
- MobileSupl,
- MobileDun,
- MobileHipri,
- Wimax,
- Bluetooth,
- Dummy,
- Ethernet,
- UnknownType
- };
-
- enum NetworkSubType {
- UnknownSubType,
- Gprs,
- Edge,
- Umts,
- Cdma,
- Evdo0,
- EvdoA,
- Cdma1xRTT,
- Hsdpa,
- Hsupa,
- Hspa,
- Iden,
- EvdoB,
- Lte,
- Ehrpd,
- Hspap
- };
-
- inline AndroidNetworkInfo(const QJNIObjectPrivate &obj) : m_networkInfo(obj)
- { }
-
- NetworkState getDetailedState() const;
- QString getExtraInfo() const;
- QString getReason() const;
- NetworkState getState() const;
- NetworkSubType getSubtype() const;
- QString getSubtypeName() const;
- NetworkType getType() const;
- QString getTypeName() const;
- bool isAvailable() const;
- bool isConnected() const;
- bool isConnectedOrConnecting() const;
- bool isFailover() const;
- bool isRoaming() const;
- bool isValid() const;
-
-private:
- QJNIObjectPrivate m_networkInfo;
-};
-
-class AndroidConnectivityManager : public QObject
-{
- Q_OBJECT
-public:
- static AndroidConnectivityManager *getInstance();
- ~AndroidConnectivityManager();
-
- AndroidNetworkInfo getActiveNetworkInfo() const;
- QList<AndroidNetworkInfo> getAllNetworkInfo() const;
- bool getBackgroundDataSetting() const;
- AndroidNetworkInfo getNetworkInfo(int networkType) const;
- int getNetworkPreference() const;
- bool isActiveNetworkMetered() const;
- static bool isNetworkTypeValid(int networkType);
- bool requestRouteToHost(int networkType, int hostAddress);
- void setNetworkPreference(int preference);
- int startUsingNetworkFeature(int networkType, const QString &feature);
- int stopUsingNetworkFeature(int networkType, const QString &feature);
- inline bool isValid() const
- {
- return m_connectivityManager.isValid();
- }
-
- Q_SIGNAL void activeNetworkChanged();
-
-private:
- friend struct AndroidConnectivityManagerInstance;
- AndroidConnectivityManager();
- bool registerNatives(JNIEnv *env);
- QJNIObjectPrivate m_connectivityManager;
-};
-
-QT_END_NAMESPACE
-
-#endif // ANDROIDCONNECTIVITYMANAGER_H
diff --git a/src/plugins/bearer/android/src/wrappers/wrappers.pri b/src/plugins/bearer/android/src/wrappers/wrappers.pri
deleted file mode 100644
index 209b76e533..0000000000
--- a/src/plugins/bearer/android/src/wrappers/wrappers.pri
+++ /dev/null
@@ -1,6 +0,0 @@
-INCLUDEPATH += $$PWD
-
-HEADERS += \
- $$PWD/androidconnectivitymanager.h
-SOURCES += \
- $$PWD/androidconnectivitymanager.cpp
diff --git a/src/plugins/bearer/bearer.pro b/src/plugins/bearer/bearer.pro
deleted file mode 100644
index afdc613167..0000000000
--- a/src/plugins/bearer/bearer.pro
+++ /dev/null
@@ -1,11 +0,0 @@
-TEMPLATE = subdirs
-QT_FOR_CONFIG += network-private
-
-!android:linux*:qtHaveModule(dbus) {
- SUBDIRS += generic
- SUBDIRS += connman networkmanager
-}
-
-android:!android-embedded: SUBDIRS += android
-
-isEmpty(SUBDIRS):SUBDIRS = generic
diff --git a/src/plugins/bearer/connman/.prev_CMakeLists.txt b/src/plugins/bearer/connman/.prev_CMakeLists.txt
deleted file mode 100644
index 55aaa41491..0000000000
--- a/src/plugins/bearer/connman/.prev_CMakeLists.txt
+++ /dev/null
@@ -1,26 +0,0 @@
-# Generated from connman.pro.
-
-#####################################################################
-## QConnmanEnginePlugin Plugin:
-#####################################################################
-
-qt_add_plugin(QConnmanEnginePlugin
- OUTPUT_NAME qconnmanbearer
- CLASS_NAME QConnmanEnginePlugin
- TYPE bearer
- SOURCES
- main.cpp
- qconnmanengine.cpp qconnmanengine.h
- qconnmanservice_linux.cpp qconnmanservice_linux_p.h
- LIBRARIES
- Qt::LinuxOfonoSupportPrivate
- Qt::NetworkPrivate
- PUBLIC_LIBRARIES
- Qt::Core
- Qt::DBus
- Qt::LinuxOfonoSupport
- Qt::Network
-)
-
-#### Keys ignored in scope 1:.:.:connman.pro:<TRUE>:
-# OTHER_FILES = "connman.json"
diff --git a/src/plugins/bearer/connman/CMakeLists.txt b/src/plugins/bearer/connman/CMakeLists.txt
deleted file mode 100644
index 745f48b6e0..0000000000
--- a/src/plugins/bearer/connman/CMakeLists.txt
+++ /dev/null
@@ -1,22 +0,0 @@
-# Generated from connman.pro.
-
-#####################################################################
-## QConnmanEnginePlugin Plugin:
-#####################################################################
-
-qt_add_plugin(QConnmanEnginePlugin
- OUTPUT_NAME qconnmanbearer
- TYPE bearer
- SOURCES
- main.cpp
- qconnmanengine.cpp qconnmanengine.h
- qconnmanservice_linux.cpp qconnmanservice_linux_p.h
- PUBLIC_LIBRARIES
- Qt::Core
- Qt::DBus
- Qt::LinuxOfonoSupportPrivate
- Qt::NetworkPrivate
-)
-
-#### Keys ignored in scope 1:.:.:connman.pro:<TRUE>:
-# OTHER_FILES = "connman.json"
diff --git a/src/plugins/bearer/connman/connman.json b/src/plugins/bearer/connman/connman.json
deleted file mode 100644
index 7a80b8c9be..0000000000
--- a/src/plugins/bearer/connman/connman.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "Keys": [ "connman" ]
-}
diff --git a/src/plugins/bearer/connman/connman.pro b/src/plugins/bearer/connman/connman.pro
deleted file mode 100644
index 03e94cfe6a..0000000000
--- a/src/plugins/bearer/connman/connman.pro
+++ /dev/null
@@ -1,16 +0,0 @@
-TARGET = qconnmanbearer
-
-QT = core network-private dbus linuxofono_support_private
-
-HEADERS += qconnmanservice_linux_p.h \
- qconnmanengine.h
-
-SOURCES += main.cpp \
- qconnmanservice_linux.cpp \
- qconnmanengine.cpp
-
-OTHER_FILES += connman.json
-
-PLUGIN_TYPE = bearer
-PLUGIN_CLASS_NAME = QConnmanEnginePlugin
-load(qt_plugin)
diff --git a/src/plugins/bearer/connman/main.cpp b/src/plugins/bearer/connman/main.cpp
deleted file mode 100644
index 03c8a7f6c5..0000000000
--- a/src/plugins/bearer/connman/main.cpp
+++ /dev/null
@@ -1,85 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 "qconnmanengine.h"
-
-#include <QtNetwork/private/qbearerplugin_p.h>
-
-#include <QtCore/qdebug.h>
-
-#ifndef QT_NO_DBUS
-
-QT_BEGIN_NAMESPACE
-
-class QConnmanEnginePlugin : public QBearerEnginePlugin
-{
- Q_OBJECT
- Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QBearerEngineFactoryInterface" FILE "connman.json")
-
-public:
- QConnmanEnginePlugin();
- ~QConnmanEnginePlugin();
-
- QBearerEngine *create(const QString &key) const;
-};
-
-QConnmanEnginePlugin::QConnmanEnginePlugin()
-{
-}
-
-QConnmanEnginePlugin::~QConnmanEnginePlugin()
-{
-}
-
-QBearerEngine *QConnmanEnginePlugin::create(const QString &key) const
-{
- if (key == QLatin1String("connman")) {
- QConnmanEngine *engine = new QConnmanEngine;
- if (engine->connmanAvailable())
- return engine;
- else
- delete engine;
- }
- return 0;
-}
-
-QT_END_NAMESPACE
-
-#include "main.moc"
-
-#endif
diff --git a/src/plugins/bearer/connman/qconnmanengine.cpp b/src/plugins/bearer/connman/qconnmanengine.cpp
deleted file mode 100644
index a673834825..0000000000
--- a/src/plugins/bearer/connman/qconnmanengine.cpp
+++ /dev/null
@@ -1,570 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 "qconnmanengine.h"
-#include "qconnmanservice_linux_p.h"
-#include <private/qnetworksession_impl_p.h>
-
-#include <QtNetwork/private/qnetworkconfiguration_p.h>
-
-#include <QtNetwork/qnetworksession.h>
-
-#include <QtCore/qdebug.h>
-#include <QtCore/private/qlocking_p.h>
-
-#include <QtDBus/QtDBus>
-#include <QtDBus/QDBusConnection>
-#include <QtDBus/QDBusInterface>
-#include <QtDBus/QDBusMessage>
-#include <QtDBus/QDBusReply>
-#ifndef QT_NO_DBUS
-
-QT_BEGIN_NAMESPACE
-
-QConnmanEngine::QConnmanEngine(QObject *parent)
-: QBearerEngineImpl(parent),
- connmanManager(new QConnmanManagerInterface(this)),
- ofonoManager(new QOfonoManagerInterface(this)),
- ofonoNetwork(0),
- ofonoContextManager(0)
-{
- qDBusRegisterMetaType<ConnmanMap>();
- qDBusRegisterMetaType<ConnmanMapList>();
- qRegisterMetaType<ConnmanMapList>("ConnmanMapList");
-}
-
-QConnmanEngine::~QConnmanEngine()
-{
-}
-
-bool QConnmanEngine::connmanAvailable() const
-{
- const auto locker = qt_scoped_lock(mutex);
- return connmanManager->isValid();
-}
-
-void QConnmanEngine::initialize()
-{
- const auto locker = qt_scoped_lock(mutex);
- connect(ofonoManager,SIGNAL(modemChanged()),this,SLOT(changedModem()));
-
- ofonoNetwork = new QOfonoNetworkRegistrationInterface(ofonoManager->currentModem(),this);
- ofonoContextManager = new QOfonoDataConnectionManagerInterface(ofonoManager->currentModem(),this);
- connect(ofonoContextManager,SIGNAL(roamingAllowedChanged(bool)),this,SLOT(reEvaluateCellular()));
-
- connect(connmanManager,SIGNAL(servicesChanged(ConnmanMapList,QList<QDBusObjectPath>)),
- this, SLOT(updateServices(ConnmanMapList,QList<QDBusObjectPath>)));
-
- connect(connmanManager,SIGNAL(servicesReady(QStringList)),this,SLOT(servicesReady(QStringList)));
- connect(connmanManager,SIGNAL(scanFinished(bool)),this,SLOT(finishedScan(bool)));
-
- const auto servPaths = connmanManager->getServices();
- for (const QString &servPath : servPaths)
- addServiceConfiguration(servPath);
- Q_EMIT updateCompleted();
-}
-
-void QConnmanEngine::changedModem()
-{
- const auto locker = qt_scoped_lock(mutex);
- if (ofonoNetwork)
- delete ofonoNetwork;
-
- ofonoNetwork = new QOfonoNetworkRegistrationInterface(ofonoManager->currentModem(),this);
-
- if (ofonoContextManager)
- delete ofonoContextManager;
- ofonoContextManager = new QOfonoDataConnectionManagerInterface(ofonoManager->currentModem(),this);
-}
-
-void QConnmanEngine::servicesReady(const QStringList &list)
-{
- const auto locker = qt_scoped_lock(mutex);
- for (const QString &servPath : list)
- addServiceConfiguration(servPath);
-
- Q_EMIT updateCompleted();
-}
-
-QList<QNetworkConfigurationPrivate *> QConnmanEngine::getConfigurations()
-{
- const auto locker = qt_scoped_lock(mutex);
- QList<QNetworkConfigurationPrivate *> fetchedConfigurations;
- QNetworkConfigurationPrivate* cpPriv = 0;
- const int numFoundConfigurations = foundConfigurations.count();
- fetchedConfigurations.reserve(numFoundConfigurations);
-
- for (int i = 0; i < numFoundConfigurations; ++i) {
- QNetworkConfigurationPrivate *config = new QNetworkConfigurationPrivate;
- cpPriv = foundConfigurations.at(i);
-
- config->name = cpPriv->name;
- config->isValid = cpPriv->isValid;
- config->id = cpPriv->id;
- config->state = cpPriv->state;
- config->type = cpPriv->type;
- config->roamingSupported = cpPriv->roamingSupported;
- config->purpose = cpPriv->purpose;
- config->bearerType = cpPriv->bearerType;
-
- fetchedConfigurations.append(config);
- delete config;
- }
- return fetchedConfigurations;
-}
-
-QString QConnmanEngine::getInterfaceFromId(const QString &id)
-{
- const auto locker = qt_scoped_lock(mutex);
- return configInterfaces.value(id);
-}
-
-bool QConnmanEngine::hasIdentifier(const QString &id)
-{
- const auto locker = qt_scoped_lock(mutex);
- return accessPointConfigurations.contains(id);
-}
-
-void QConnmanEngine::connectToId(const QString &id)
-{
- const auto locker = qt_scoped_lock(mutex);
-
- QConnmanServiceInterface *serv = connmanServiceInterfaces.value(id);
-
- if (!serv || !serv->isValid()) {
- emit connectionError(id, QBearerEngineImpl::InterfaceLookupError);
- } else {
- if (serv->type() == QLatin1String("cellular")) {
- if (serv->roaming()) {
- if (!isRoamingAllowed(serv->path())) {
- emit connectionError(id, QBearerEngineImpl::OperationNotSupported);
- return;
- }
- }
- }
- if (serv->autoConnect())
- serv->connect();
- }
-}
-
-void QConnmanEngine::disconnectFromId(const QString &id)
-{
- const auto locker = qt_scoped_lock(mutex);
- QConnmanServiceInterface *serv = connmanServiceInterfaces.value(id);
-
- if (!serv || !serv->isValid()) {
- emit connectionError(id, DisconnectionError);
- } else {
- serv->disconnect();
- }
-}
-
-void QConnmanEngine::requestUpdate()
-{
- const auto locker = qt_scoped_lock(mutex);
- QTimer::singleShot(0, this, SLOT(doRequestUpdate()));
-}
-
-void QConnmanEngine::doRequestUpdate()
-{
- bool scanned = connmanManager->requestScan("wifi");
- if (!scanned)
- Q_EMIT updateCompleted();
-}
-
-void QConnmanEngine::finishedScan(bool error)
-{
- if (error)
- Q_EMIT updateCompleted();
-}
-
-void QConnmanEngine::updateServices(const ConnmanMapList &changed, const QList<QDBusObjectPath> &removed)
-{
- const auto locker = qt_scoped_lock(mutex);
-
- foreach (const QDBusObjectPath &objectPath, removed) {
- removeConfiguration(objectPath.path());
- }
-
- foreach (const ConnmanMap &connmanMap, changed) {
- const QString id = connmanMap.objectPath.path();
- if (accessPointConfigurations.contains(id)) {
- configurationChange(connmanServiceInterfaces.value(id));
- } else {
- addServiceConfiguration(connmanMap.objectPath.path());
- }
- }
- Q_EMIT updateCompleted();
-}
-
-QNetworkSession::State QConnmanEngine::sessionStateForId(const QString &id)
-{
- const auto locker = qt_scoped_lock(mutex);
-
- QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id);
-
- if (!ptr || !ptr->isValid)
- return QNetworkSession::Invalid;
-
- QString service = id;
- QConnmanServiceInterface *serv = connmanServiceInterfaces.value(service);
- if (!serv)
- return QNetworkSession::Invalid;
-
- QString servState = serv->state();
-
- if (serv->favorite() && (servState == QLatin1String("idle") || servState == QLatin1String("failure"))) {
- return QNetworkSession::Disconnected;
- }
-
- if (servState == QLatin1String("association") || servState == QLatin1String("configuration")) {
- return QNetworkSession::Connecting;
- }
-
- if (servState == QLatin1String("online") || servState == QLatin1String("ready")) {
- return QNetworkSession::Connected;
- }
-
- if ((ptr->state & QNetworkConfiguration::Discovered) ==
- QNetworkConfiguration::Discovered) {
- return QNetworkSession::Disconnected;
- } else if ((ptr->state & QNetworkConfiguration::Defined) == QNetworkConfiguration::Defined) {
- return QNetworkSession::NotAvailable;
- } else if ((ptr->state & QNetworkConfiguration::Undefined) ==
- QNetworkConfiguration::Undefined) {
- return QNetworkSession::NotAvailable;
- }
-
- return QNetworkSession::Invalid;
-}
-
-quint64 QConnmanEngine::bytesWritten(const QString &id)
-{//TODO use connman counter API
- const auto locker = qt_scoped_lock(mutex);
- quint64 result = 0;
- QString devFile = getInterfaceFromId(id);
- QFile tx("/sys/class/net/"+devFile+"/statistics/tx_bytes");
- if (tx.open(QIODevice::ReadOnly | QIODevice::Text)) {
- QTextStream in(&tx);
- in >> result;
- tx.close();
- }
-
- return result;
-}
-
-quint64 QConnmanEngine::bytesReceived(const QString &id)
-{//TODO use connman counter API
- const auto locker = qt_scoped_lock(mutex);
- quint64 result = 0;
- QString devFile = getInterfaceFromId(id);
- QFile rx("/sys/class/net/"+devFile+"/statistics/rx_bytes");
- if (rx.open(QIODevice::ReadOnly | QIODevice::Text)) {
- QTextStream in(&rx);
- in >> result;
- rx.close();
- }
- return result;
-}
-
-quint64 QConnmanEngine::startTime(const QString &/*id*/)
-{
- // TODO
- const auto locker = qt_scoped_lock(mutex);
- if (activeTime.isNull()) {
- return 0;
- }
- return activeTime.secsTo(QDateTime::currentDateTime());
-}
-
-QNetworkConfigurationManager::Capabilities QConnmanEngine::capabilities() const
-{
- return QNetworkConfigurationManager::ForcedRoaming |
- QNetworkConfigurationManager::DataStatistics |
- QNetworkConfigurationManager::CanStartAndStopInterfaces |
- QNetworkConfigurationManager::NetworkSessionRequired;
-}
-
-QNetworkSessionPrivate *QConnmanEngine::createSessionBackend()
-{
- return new QNetworkSessionPrivateImpl;
-}
-
-QNetworkConfigurationPrivatePointer QConnmanEngine::defaultConfiguration()
-{
- const auto locker = qt_scoped_lock(mutex);
- const auto servPaths = connmanManager->getServices();
- for (const QString &servPath : servPaths) {
- if (connmanServiceInterfaces.contains(servPath)) {
- if (accessPointConfigurations.contains(servPath))
- return accessPointConfigurations.value(servPath);
- }
- }
- return QNetworkConfigurationPrivatePointer();
-}
-
-void QConnmanEngine::serviceStateChanged(const QString &state)
-{
- QConnmanServiceInterface *service = qobject_cast<QConnmanServiceInterface *>(sender());
- configurationChange(service);
-
- if (state == QLatin1String("failure")) {
- emit connectionError(service->path(), ConnectError);
- }
-}
-
-void QConnmanEngine::configurationChange(QConnmanServiceInterface *serv)
-{
- if (!serv)
- return;
- auto locker = qt_unique_lock(mutex);
- QString id = serv->path();
-
- if (accessPointConfigurations.contains(id)) {
- bool changed = false;
- QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id);
- QString networkName = serv->name();
- QNetworkConfiguration::StateFlags curState = getStateForService(serv->path());
- ptr->mutex.lock();
-
- if (!ptr->isValid) {
- ptr->isValid = true;
- }
-
- if (ptr->name != networkName) {
- ptr->name = networkName;
- changed = true;
- }
-
- if (ptr->state != curState) {
- ptr->state = curState;
- changed = true;
- }
-
- ptr->mutex.unlock();
-
- if (changed) {
- locker.unlock();
- emit configurationChanged(ptr);
- locker.lock();
- }
- }
-
- locker.unlock();
- emit updateCompleted();
-}
-
-QNetworkConfiguration::StateFlags QConnmanEngine::getStateForService(const QString &service)
-{
- const auto locker = qt_scoped_lock(mutex);
- QConnmanServiceInterface *serv = connmanServiceInterfaces.value(service);
- if (!serv)
- return QNetworkConfiguration::Undefined;
-
- QString state = serv->state();
- QNetworkConfiguration::StateFlags flag = QNetworkConfiguration::Defined;
-
- if (serv->type() == QLatin1String("cellular")) {
-
- if (!serv->autoConnect()|| (serv->roaming()
- && !isRoamingAllowed(serv->path()))) {
- flag = (flag | QNetworkConfiguration::Defined);
- } else {
- flag = (flag | QNetworkConfiguration::Discovered);
- }
- } else {
- if (serv->favorite()) {
- if (serv->autoConnect()) {
- flag = (flag | QNetworkConfiguration::Discovered);
- }
- } else {
- flag = QNetworkConfiguration::Undefined;
- }
- }
- if (state == QLatin1String("online") || state == QLatin1String("ready")) {
- flag = (flag | QNetworkConfiguration::Active);
- }
-
- return flag;
-}
-
-QNetworkConfiguration::BearerType QConnmanEngine::typeToBearer(const QString &type)
-{
- if (type == QLatin1String("wifi"))
- return QNetworkConfiguration::BearerWLAN;
- if (type == QLatin1String("ethernet"))
- return QNetworkConfiguration::BearerEthernet;
- if (type == QLatin1String("bluetooth"))
- return QNetworkConfiguration::BearerBluetooth;
- if (type == QLatin1String("cellular")) {
- return ofonoTechToBearerType(type);
- }
- if (type == QLatin1String("wimax"))
- return QNetworkConfiguration::BearerWiMAX;
-
- return QNetworkConfiguration::BearerUnknown;
-}
-
-QNetworkConfiguration::BearerType QConnmanEngine::ofonoTechToBearerType(const QString &/*type*/)
-{
- if (ofonoNetwork) {
- QString currentTechnology = ofonoNetwork->getTechnology();
- if (currentTechnology == QLatin1String("gsm")) {
- return QNetworkConfiguration::Bearer2G;
- } else if (currentTechnology == QLatin1String("edge")) {
- return QNetworkConfiguration::BearerCDMA2000; //wrong, I know
- } else if (currentTechnology == QLatin1String("umts")) {
- return QNetworkConfiguration::BearerWCDMA;
- } else if (currentTechnology == QLatin1String("hspa")) {
- return QNetworkConfiguration::BearerHSPA;
- } else if (currentTechnology == QLatin1String("lte")) {
- return QNetworkConfiguration::BearerLTE;
- }
- }
- return QNetworkConfiguration::BearerUnknown;
-}
-
-bool QConnmanEngine::isRoamingAllowed(const QString &context)
-{
- const auto dcPaths = ofonoContextManager->contexts();
- for (const QString &dcPath : dcPaths) {
- if (dcPath.contains(context.section("_",-1))) {
- return ofonoContextManager->roamingAllowed();
- }
- }
- return false;
-}
-
-void QConnmanEngine::removeConfiguration(const QString &id)
-{
- auto locker = qt_unique_lock(mutex);
-
- if (accessPointConfigurations.contains(id)) {
-
- disconnect(connmanServiceInterfaces.value(id),SIGNAL(stateChanged(QString)),
- this,SLOT(serviceStateChanged(QString)));
- serviceNetworks.removeOne(id);
- QConnmanServiceInterface *service = connmanServiceInterfaces.take(id);
- delete service;
- QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.take(id);
- foundConfigurations.removeOne(ptr.data());
- locker.unlock();
- emit configurationRemoved(ptr);
- }
-}
-
-void QConnmanEngine::addServiceConfiguration(const QString &servicePath)
-{
- auto locker = qt_unique_lock(mutex);
- if (!connmanServiceInterfaces.contains(servicePath)) {
- QConnmanServiceInterface *serv = new QConnmanServiceInterface(servicePath, this);
- connmanServiceInterfaces.insert(serv->path(),serv);
- }
-
- if (!accessPointConfigurations.contains(servicePath)) {
-
- serviceNetworks.append(servicePath);
-
- connect(connmanServiceInterfaces.value(servicePath),SIGNAL(stateChanged(QString)),
- this,SLOT(serviceStateChanged(QString)));
-
- QNetworkConfigurationPrivate* cpPriv = new QNetworkConfigurationPrivate();
- QConnmanServiceInterface *service = connmanServiceInterfaces.value(servicePath);
-
- QString networkName = service->name();
-
- const QString connectionType = service->type();
- if (connectionType == QLatin1String("ethernet")) {
- cpPriv->bearerType = QNetworkConfiguration::BearerEthernet;
- } else if (connectionType == QLatin1String("wifi")) {
- cpPriv->bearerType = QNetworkConfiguration::BearerWLAN;
- } else if (connectionType == QLatin1String("cellular")) {
- cpPriv->bearerType = ofonoTechToBearerType(QLatin1String("cellular"));
- cpPriv->roamingSupported = service->roaming() && isRoamingAllowed(servicePath);
- } else if (connectionType == QLatin1String("wimax")) {
- cpPriv->bearerType = QNetworkConfiguration::BearerWiMAX;
- } else {
- cpPriv->bearerType = QNetworkConfiguration::BearerUnknown;
- }
-
- cpPriv->name = networkName;
- cpPriv->isValid = true;
- cpPriv->id = servicePath;
- cpPriv->type = QNetworkConfiguration::InternetAccessPoint;
-
- if (service->security() == QLatin1String("none")) {
- cpPriv->purpose = QNetworkConfiguration::PublicPurpose;
- } else {
- cpPriv->purpose = QNetworkConfiguration::PrivatePurpose;
- }
-
- cpPriv->state = getStateForService(servicePath);
-
- QNetworkConfigurationPrivatePointer ptr(cpPriv);
- accessPointConfigurations.insert(ptr->id, ptr);
- if (connectionType == QLatin1String("cellular")) {
- foundConfigurations.append(cpPriv);
- } else {
- foundConfigurations.prepend(cpPriv);
- }
- configInterfaces[cpPriv->id] = service->serviceInterface();
-
- locker.unlock();
- Q_EMIT configurationAdded(ptr);
- }
-}
-
-bool QConnmanEngine::requiresPolling() const
-{
- return false;
-}
-
-void QConnmanEngine::reEvaluateCellular()
-{
- const auto servicePaths = connmanManager->getServices();
- for (const QString &servicePath : servicePaths) {
- if (servicePath.contains("cellular") && accessPointConfigurations.contains(servicePath)) {
- configurationChange(connmanServiceInterfaces.value(servicePath));
- }
- }
-}
-
-QT_END_NAMESPACE
-
-#endif // QT_NO_DBUS
diff --git a/src/plugins/bearer/connman/qconnmanengine.h b/src/plugins/bearer/connman/qconnmanengine.h
deleted file mode 100644
index 969eed45b1..0000000000
--- a/src/plugins/bearer/connman/qconnmanengine.h
+++ /dev/null
@@ -1,145 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 QCONNMANENGINE_P_H
-#define QCONNMANENGINE_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 <private/qbearerengine_impl_p.h>
-
-#include "qconnmanservice_linux_p.h"
-#include <private/qofonoservice_linux_p.h>
-
-#include <QMap>
-#include <QVariant>
-
-#ifndef QT_NO_DBUS
-
-QT_BEGIN_NAMESPACE
-
-class QConnmanEngine : public QBearerEngineImpl
-{
- Q_OBJECT
-
-public:
- QConnmanEngine(QObject *parent = nullptr);
- ~QConnmanEngine();
-
- bool connmanAvailable() const;
-
- virtual QString getInterfaceFromId(const QString &id);
- bool hasIdentifier(const QString &id);
-
- virtual void connectToId(const QString &id);
- virtual void disconnectFromId(const QString &id);
-
- Q_INVOKABLE void initialize();
- Q_INVOKABLE void requestUpdate();
-
- QNetworkSession::State sessionStateForId(const QString &id);
- QNetworkSessionPrivate *createSessionBackend();
-
- virtual quint64 bytesWritten(const QString &id);
- virtual quint64 bytesReceived(const QString &id);
- virtual quint64 startTime(const QString &id);
-
- virtual QNetworkConfigurationManager::Capabilities capabilities() const;
- virtual QNetworkConfigurationPrivatePointer defaultConfiguration();
-
- QList<QNetworkConfigurationPrivate *> getConfigurations();
-
-private Q_SLOTS:
-
- void doRequestUpdate();
- void updateServices(const ConnmanMapList &changed, const QList<QDBusObjectPath> &removed);
-
- void servicesReady(const QStringList &);
- void finishedScan(bool error);
- void changedModem();
- void serviceStateChanged(const QString &state);
- void configurationChange(QConnmanServiceInterface * service);
- void reEvaluateCellular();
-private:
- QConnmanManagerInterface *connmanManager;
-
- QOfonoManagerInterface *ofonoManager;
- QOfonoNetworkRegistrationInterface *ofonoNetwork;
- QOfonoDataConnectionManagerInterface *ofonoContextManager;
-
- QList<QNetworkConfigurationPrivate *> foundConfigurations;
-
- QString networkFromId(const QString &id);
-
- QNetworkConfiguration::StateFlags getStateForService(const QString &service);
- QNetworkConfiguration::BearerType typeToBearer(const QString &type);
-
- void removeConfiguration(const QString &servicePath);
- void addServiceConfiguration(const QString &servicePath);
- QDateTime activeTime;
-
-
- QMap<QString,QConnmanTechnologyInterface *> technologies; // techpath, tech interface
- QMap<QString,QString> configInterfaces; // id, interface name
- QList<QString> serviceNetworks; //servpath
-
- QNetworkConfiguration::BearerType ofonoTechToBearerType(const QString &type);
- bool isRoamingAllowed(const QString &context);
- QMap <QString,QConnmanServiceInterface *> connmanServiceInterfaces;
-
-protected:
- bool requiresPolling() const;
-};
-
-
-QT_END_NAMESPACE
-
-#endif // QT_NO_DBUS
-
-#endif
-
diff --git a/src/plugins/bearer/connman/qconnmanservice_linux.cpp b/src/plugins/bearer/connman/qconnmanservice_linux.cpp
deleted file mode 100644
index 35d9c40680..0000000000
--- a/src/plugins/bearer/connman/qconnmanservice_linux.cpp
+++ /dev/null
@@ -1,516 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 <QObject>
-#include <QList>
-#include <QtDBus/QtDBus>
-#include <QtDBus/QDBusConnection>
-#include <QtDBus/QDBusError>
-#include <QtDBus/QDBusInterface>
-#include <QtDBus/QDBusMessage>
-#include <QtDBus/QDBusReply>
-#include <QtDBus/QDBusPendingCallWatcher>
-#include <QtDBus/QDBusObjectPath>
-#include <QtDBus/QDBusPendingCall>
-
-#include "qconnmanservice_linux_p.h"
-
-#ifndef QT_NO_DBUS
-
-QT_BEGIN_NAMESPACE
-
-QDBusArgument &operator<<(QDBusArgument &argument, const ConnmanMap &map)
-{
- argument.beginStructure();
- argument << map.objectPath << map.propertyMap;
- argument.endStructure();
- return argument;
-}
-
-const QDBusArgument &operator>>(const QDBusArgument &argument, ConnmanMap &map)
-{
- argument.beginStructure();
- argument >> map.objectPath >> map.propertyMap;
- argument.endStructure();
- return argument;
-}
-
-QConnmanManagerInterface::QConnmanManagerInterface( QObject *parent)
- : QDBusAbstractInterface(QLatin1String(CONNMAN_SERVICE),
- QLatin1String(CONNMAN_MANAGER_PATH),
- CONNMAN_MANAGER_INTERFACE,
- QDBusConnection::systemBus(), parent)
-{
- qDBusRegisterMetaType<ConnmanMap>();
- qDBusRegisterMetaType<ConnmanMapList>();
-
- QDBusPendingReply<QVariantMap> props_reply = asyncCall(QLatin1String("GetProperties"));
- QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(props_reply, this);
-
- QObject::connect(watcher,SIGNAL(finished(QDBusPendingCallWatcher*)),
- this, SLOT(propertiesReply(QDBusPendingCallWatcher*)));
-
- QDBusConnection::systemBus().connect(QLatin1String(CONNMAN_SERVICE),
- QLatin1String(CONNMAN_MANAGER_PATH),
- QLatin1String(CONNMAN_SERVICE_INTERFACE),
- QLatin1String("PropertyChanged"),
- this,SLOT(changedProperty(QString,QDBusVariant)));
-
-
- QDBusConnection::systemBus().connect(QLatin1String(CONNMAN_SERVICE),
- QLatin1String(CONNMAN_MANAGER_PATH),
- QLatin1String(CONNMAN_SERVICE_INTERFACE),
- QLatin1String("TechnologyAdded"),
- this,SLOT(technologyAdded(QDBusObjectPath,QVariantMap)));
-
- QDBusConnection::systemBus().connect(QLatin1String(CONNMAN_SERVICE),
- QLatin1String(CONNMAN_MANAGER_PATH),
- QLatin1String(CONNMAN_SERVICE_INTERFACE),
- QLatin1String("TechnologyRemoved"),
- this,SLOT(technologyRemoved(QDBusObjectPath)));
-
- QDBusPendingReply<ConnmanMapList> serv_reply = asyncCall(QLatin1String("GetServices"));
- QDBusPendingCallWatcher *watcher2 = new QDBusPendingCallWatcher(serv_reply, this);
-
- QObject::connect(watcher2,SIGNAL(finished(QDBusPendingCallWatcher*)),
- this, SLOT(servicesReply(QDBusPendingCallWatcher*)));
-
-}
-
-QConnmanManagerInterface::~QConnmanManagerInterface()
-{
-}
-
-void QConnmanManagerInterface::changedProperty(const QString &name, const QDBusVariant &value)
-{
- propertiesCacheMap[name] = value.variant();
-}
-
-void QConnmanManagerInterface::propertiesReply(QDBusPendingCallWatcher *call)
-{
- QDBusPendingReply<QVariantMap> props_reply = *call;
-
- if (props_reply.isError()) {
- qDebug() << props_reply.error().message();
- } else {
- propertiesCacheMap = props_reply.value();
- }
- call->deleteLater();
-}
-
-void QConnmanManagerInterface::servicesReply(QDBusPendingCallWatcher *call)
-{
- QDBusPendingReply<ConnmanMapList> serv_reply = *call;
-
- if (serv_reply.isError()) {
- qDebug() << serv_reply.error().message();
- } else {
- servicesList.clear(); //connman list changes order
- const ConnmanMapList connmanobjs = serv_reply.value();
- for (const ConnmanMap &connmanobj : connmanobjs)
- servicesList << connmanobj.objectPath.path();
- Q_EMIT servicesReady(servicesList);
- }
- call->deleteLater();
-}
-
-void QConnmanManagerInterface::connectNotify(const QMetaMethod &signal)
-{
- static const QMetaMethod propertyChangedSignal = QMetaMethod::fromSignal(&QConnmanManagerInterface::propertyChanged);
- if (signal == propertyChangedSignal) {
- if (!connection().connect(QLatin1String(CONNMAN_SERVICE),
- QLatin1String(CONNMAN_MANAGER_PATH),
- QLatin1String(CONNMAN_MANAGER_INTERFACE),
- QLatin1String("PropertyChanged"),
- this,SIGNAL(propertyChanged(QString,QDBusVariant)))) {
- qWarning("PropertyChanged not connected");
- }
- }
-
- static const QMetaMethod servicesChangedSignal = QMetaMethod::fromSignal(&QConnmanManagerInterface::servicesChanged);
- if (signal == servicesChangedSignal) {
- if (!connection().connect(QLatin1String(CONNMAN_SERVICE),
- QLatin1String(CONNMAN_MANAGER_PATH),
- QLatin1String(CONNMAN_MANAGER_INTERFACE),
- QLatin1String("ServicesChanged"),
- this,SLOT(onServicesChanged(ConnmanMapList,QList<QDBusObjectPath>)))) {
- qWarning("servicesChanged not connected");
- }
- }
-}
-
-void QConnmanManagerInterface::onServicesChanged(const ConnmanMapList &changed, const QList<QDBusObjectPath> &removed)
-{
- servicesList.clear(); //connman list changes order
- for (const ConnmanMap &connmanobj : changed) {
- const QString svcPath(connmanobj.objectPath.path());
- servicesList << svcPath;
- }
-
- Q_EMIT servicesChanged(changed, removed);
-}
-
-QVariant QConnmanManagerInterface::getProperty(const QString &property)
-{
- QVariant var;
- var = propertiesCacheMap.value(property);
- return var;
-}
-
-QVariantMap QConnmanManagerInterface::getProperties()
-{
- if (propertiesCacheMap.isEmpty()) {
- QDBusPendingReply<QVariantMap> reply = call(QLatin1String("GetProperties"));
- reply.waitForFinished();
- if (!reply.isError()) {
- propertiesCacheMap = reply.value();
- }
- }
- return propertiesCacheMap;
-}
-
-QString QConnmanManagerInterface::getState()
-{
- return getProperty(QStringLiteral("State")).toString();
-}
-
-bool QConnmanManagerInterface::getOfflineMode()
-{
- QVariant var = getProperty(QStringLiteral("OfflineMode"));
- return qdbus_cast<bool>(var);
-}
-
-QStringList QConnmanManagerInterface::getTechnologies()
-{
- if (technologiesMap.isEmpty()) {
- QDBusPendingReply<ConnmanMapList> reply = call(QLatin1String("GetTechnologies"));
- reply.waitForFinished();
- if (!reply.isError()) {
- const ConnmanMapList maps = reply.value();
- for (const ConnmanMap &map : maps) {
- if (!technologiesMap.contains(map.objectPath.path())) {
- technologyAdded(map.objectPath, map.propertyMap);
- }
- }
- }
- }
- return technologiesMap.keys();
-}
-
-QStringList QConnmanManagerInterface::getServices()
-{
- if (servicesList.isEmpty()) {
- QDBusPendingReply<ConnmanMapList> reply = call(QLatin1String("GetServices"));
- reply.waitForFinished();
- if (!reply.isError()) {
- const ConnmanMapList maps = reply.value();
- for (const ConnmanMap &map : maps)
- servicesList << map.objectPath.path();
- }
- }
- return servicesList;
-}
-
-bool QConnmanManagerInterface::requestScan(const QString &type)
-{
- bool scanned = false;
- if (technologiesMap.isEmpty())
- getTechnologies();
- Q_FOREACH (QConnmanTechnologyInterface *tech, technologiesMap) {
- if (tech->type() == type) {
- tech->scan();
- scanned = true;
- }
- }
- return scanned;
-}
-
-void QConnmanManagerInterface::technologyAdded(const QDBusObjectPath &path, const QVariantMap &)
-{
- if (!technologiesList.contains(path.path())) {
- technologiesList << path.path();
- QConnmanTechnologyInterface *tech;
- tech = new QConnmanTechnologyInterface(path.path(),this);
- technologiesMap.insert(path.path(),tech);
- connect(tech,SIGNAL(scanFinished(bool)),this,SIGNAL(scanFinished(bool)));
- }
-}
-
-void QConnmanManagerInterface::technologyRemoved(const QDBusObjectPath &path)
-{
- if (technologiesList.contains(path.path())) {
- technologiesList.removeOne(path.path());
- QConnmanTechnologyInterface * tech = technologiesMap.take(path.path());
- delete tech;
- }
-}
-
-QConnmanServiceInterface::QConnmanServiceInterface(const QString &dbusPathName,QObject *parent)
- : QDBusAbstractInterface(QLatin1String(CONNMAN_SERVICE),
- dbusPathName,
- CONNMAN_SERVICE_INTERFACE,
- QDBusConnection::systemBus(), parent)
-{
- QDBusPendingReply<QVariantMap> props_reply = asyncCall(QLatin1String("GetProperties"));
-
- QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(props_reply, this);
-
- QObject::connect(watcher,SIGNAL(finished(QDBusPendingCallWatcher*)),
- this, SLOT(propertiesReply(QDBusPendingCallWatcher*)));
-
- QDBusConnection::systemBus().connect(QLatin1String(CONNMAN_SERVICE),
- path(),
- QLatin1String(CONNMAN_SERVICE_INTERFACE),
- QLatin1String("PropertyChanged"),
- this,SLOT(changedProperty(QString,QDBusVariant)));
-}
-
-QConnmanServiceInterface::~QConnmanServiceInterface()
-{
-}
-
-QVariantMap QConnmanServiceInterface::getProperties()
-{
- if (propertiesCacheMap.isEmpty()) {
- QDBusPendingReply<QVariantMap> reply = call(QLatin1String("GetProperties"));
- reply.waitForFinished();
- if (!reply.isError()) {
- propertiesCacheMap = reply.value();
- Q_EMIT propertiesReady();
- }
- }
- return propertiesCacheMap;
-}
-
-void QConnmanServiceInterface::propertiesReply(QDBusPendingCallWatcher *call)
-{
- QDBusPendingReply<QVariantMap> props_reply = *call;
- if (props_reply.isError()) {
- qDebug() << props_reply.error().message();
- return;
- }
- propertiesCacheMap = props_reply.value();
- Q_EMIT propertiesReady();
-}
-
-void QConnmanServiceInterface::connectNotify(const QMetaMethod &signal)
-{
- static const QMetaMethod propertyChangedSignal = QMetaMethod::fromSignal(&QConnmanServiceInterface::propertyChanged);
- if (signal == propertyChangedSignal) {
- QDBusConnection::systemBus().connect(QLatin1String(CONNMAN_SERVICE),
- path(),
- QLatin1String(CONNMAN_SERVICE_INTERFACE),
- QLatin1String("PropertyChanged"),
- this,SIGNAL(propertyChanged(QString,QDBusVariant)));
- }
-}
-
-void QConnmanServiceInterface::changedProperty(const QString &name, const QDBusVariant &value)
-{
- propertiesCacheMap[name] = value.variant();
- if (name == QLatin1String("State"))
- Q_EMIT stateChanged(value.variant().toString());
-}
-
-QVariant QConnmanServiceInterface::getProperty(const QString &property)
-{
- QVariant var;
- QVariantMap map = getProperties();
- var = map.value(property);
- return var;
-}
-
-void QConnmanServiceInterface::connect()
-{
- asyncCall(QLatin1String("Connect"));
-}
-
-void QConnmanServiceInterface::disconnect()
-{
- asyncCall(QLatin1String("Disconnect"));
-}
-
-void QConnmanServiceInterface::remove()
-{
- asyncCall(QLatin1String("Remove"));
-}
-
-// properties
-QString QConnmanServiceInterface::state()
-{
- QVariant var = getProperty(QStringLiteral("State"));
- return qdbus_cast<QString>(var);
-}
-
-QString QConnmanServiceInterface::lastError()
-{
- QVariant var = getProperty(QStringLiteral("Error"));
- return qdbus_cast<QString>(var);
-}
-
-QString QConnmanServiceInterface::name()
-{
- QVariant var = getProperty(QStringLiteral("Name"));
- return qdbus_cast<QString>(var);
-}
-
-QString QConnmanServiceInterface::type()
-{
- QVariant var = getProperty(QStringLiteral("Type"));
- return qdbus_cast<QString>(var);
-}
-
-QString QConnmanServiceInterface::security()
-{
- QVariant var = getProperty(QStringLiteral("Security"));
- return qdbus_cast<QString>(var);
-}
-
-bool QConnmanServiceInterface::favorite()
-{
- QVariant var = getProperty(QStringLiteral("Favorite"));
- return qdbus_cast<bool>(var);
-}
-
-bool QConnmanServiceInterface::autoConnect()
-{
- QVariant var = getProperty(QStringLiteral("AutoConnect"));
- return qdbus_cast<bool>(var);
-}
-
-bool QConnmanServiceInterface::roaming()
-{
- QVariant var = getProperty(QStringLiteral("Roaming"));
- return qdbus_cast<bool>(var);
-}
-
-QVariantMap QConnmanServiceInterface::ethernet()
-{
- QVariant var = getProperty(QStringLiteral("Ethernet"));
- return qdbus_cast<QVariantMap >(var);
-}
-
-QString QConnmanServiceInterface::serviceInterface()
-{
- QVariantMap map = ethernet();
- return map.value(QStringLiteral("Interface")).toString();
-}
-
-bool QConnmanServiceInterface::isOfflineMode()
-{
- QVariant var = getProperty(QStringLiteral("OfflineMode"));
- return qdbus_cast<bool>(var);
-}
-
-QStringList QConnmanServiceInterface::services()
-{
- QVariant var = getProperty(QStringLiteral("Services"));
- return qdbus_cast<QStringList>(var);
-}
-
-//////////////////////////
-QConnmanTechnologyInterface::QConnmanTechnologyInterface(const QString &dbusPathName,QObject *parent)
- : QDBusAbstractInterface(QLatin1String(CONNMAN_SERVICE),
- dbusPathName,
- CONNMAN_TECHNOLOGY_INTERFACE,
- QDBusConnection::systemBus(), parent)
-{
-}
-
-QConnmanTechnologyInterface::~QConnmanTechnologyInterface()
-{
-}
-
-void QConnmanTechnologyInterface::connectNotify(const QMetaMethod &signal)
-{
- static const QMetaMethod propertyChangedSignal = QMetaMethod::fromSignal(&QConnmanTechnologyInterface::propertyChanged);
- if (signal == propertyChangedSignal) {
- QDBusConnection::systemBus().connect(QLatin1String(CONNMAN_SERVICE),
- path(),
- QLatin1String(CONNMAN_TECHNOLOGY_INTERFACE),
- QLatin1String("PropertyChanged"),
- this,SIGNAL(propertyChanged(QString,QDBusVariant)));
- }
-}
-
-QVariantMap QConnmanTechnologyInterface::properties()
-{
- if (propertiesMap.isEmpty()) {
- QDBusPendingReply<QVariantMap> reply = call(QLatin1String("GetProperties"));
- reply.waitForFinished();
- propertiesMap = reply.value();
- }
- return propertiesMap;
-}
-
-QVariant QConnmanTechnologyInterface::getProperty(const QString &property)
-{
- QVariant var;
- QVariantMap map = properties();
- var = map.value(property);
- return var;
-}
-
-QString QConnmanTechnologyInterface::type()
-{
- QVariant var = getProperty(QStringLiteral("Type"));
- return qdbus_cast<QString>(var);
-}
-
-void QConnmanTechnologyInterface::scan()
-{
- QDBusPendingReply<> reply = asyncCall(QLatin1String("Scan"));
- QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this);
- connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
- this, SLOT(scanReply(QDBusPendingCallWatcher*)));
-}
-
-void QConnmanTechnologyInterface::scanReply(QDBusPendingCallWatcher *call)
-{
- QDBusPendingReply<> props_reply = *call;
- if (props_reply.isError()) {
- qDebug() << props_reply.error().message();
- }
- Q_EMIT scanFinished(props_reply.isError());
- call->deleteLater();
-}
-
-QT_END_NAMESPACE
-
-#endif // QT_NO_DBUS
diff --git a/src/plugins/bearer/connman/qconnmanservice_linux_p.h b/src/plugins/bearer/connman/qconnmanservice_linux_p.h
deleted file mode 100644
index 790325f9a1..0000000000
--- a/src/plugins/bearer/connman/qconnmanservice_linux_p.h
+++ /dev/null
@@ -1,230 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 QCONNMANSERVICE_H
-#define QCONNMANSERVICE_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 <QtDBus/QtDBus>
-#include <QtDBus/QDBusConnection>
-#include <QtDBus/QDBusError>
-#include <QtDBus/QDBusInterface>
-#include <QtDBus/QDBusMessage>
-#include <QtDBus/QDBusReply>
-#include <QtDBus/QDBusArgument>
-
-#include <QtDBus/QDBusPendingCallWatcher>
-#include <QtDBus/QDBusObjectPath>
-#include <QtDBus/QDBusContext>
-#include <QMap>
-
-#ifndef QT_NO_DBUS
-
-#ifndef __CONNMAN_DBUS_H
-
-#define CONNMAN_SERVICE "net.connman"
-#define CONNMAN_PATH "/net/connman"
-#define CONNMAN_MANAGER_INTERFACE CONNMAN_SERVICE ".Manager"
-#define CONNMAN_MANAGER_PATH "/"
-#define CONNMAN_SERVICE_INTERFACE CONNMAN_SERVICE ".Service"
-#define CONNMAN_TECHNOLOGY_INTERFACE CONNMAN_SERVICE ".Technology"
-#endif
-
-QT_BEGIN_NAMESPACE
-
-struct ConnmanMap {
- QDBusObjectPath objectPath;
- QVariantMap propertyMap;
-};
-Q_DECLARE_TYPEINFO(ConnmanMap, Q_MOVABLE_TYPE); // QDBusObjectPath is movable, but cannot be
- // marked as such until Qt 6
-typedef QVector<ConnmanMap> ConnmanMapList;
-
-QT_END_NAMESPACE
-
-Q_DECLARE_METATYPE(QT_PREPEND_NAMESPACE(ConnmanMap))
-Q_DECLARE_METATYPE(QT_PREPEND_NAMESPACE(ConnmanMapList))
-
-QT_BEGIN_NAMESPACE
-
-QDBusArgument &operator<<(QDBusArgument &argument, const ConnmanMap &obj);
-const QDBusArgument &operator>>(const QDBusArgument &argument, ConnmanMap &obj);
-
-class QConnmanTechnologyInterface;
-class QConnmanServiceInterface;
-
-class QConnmanManagerInterface : public QDBusAbstractInterface
-{
- Q_OBJECT
-
-public:
-
- QConnmanManagerInterface( QObject *parent = nullptr);
- ~QConnmanManagerInterface();
-
- QDBusObjectPath path() const;
- QVariantMap getProperties();
-
- QString getState();
- bool getOfflineMode();
- QStringList getTechnologies();
- QStringList getServices();
- bool requestScan(const QString &type);
-
- QHash<QString, QConnmanTechnologyInterface *> technologiesMap;
-
-Q_SIGNALS:
- void propertyChanged(const QString &, const QDBusVariant &value);
- void stateChanged(const QString &);
- void propertyChangedContext(const QString &,const QString &,const QDBusVariant &);
- void servicesChanged(const ConnmanMapList&, const QList<QDBusObjectPath> &);
-
- void servicesReady(const QStringList &);
- void scanFinished(bool error);
-
-protected:
- void connectNotify(const QMetaMethod &signal);
- QVariant getProperty(const QString &);
-
-private:
- QVariantMap propertiesCacheMap;
- QStringList servicesList;
- QStringList technologiesList;
-
-private slots:
- void onServicesChanged(const ConnmanMapList&, const QList<QDBusObjectPath> &);
- void changedProperty(const QString &, const QDBusVariant &value);
-
- void propertiesReply(QDBusPendingCallWatcher *call);
- void servicesReply(QDBusPendingCallWatcher *call);
-
- void technologyAdded(const QDBusObjectPath &technology, const QVariantMap &properties);
- void technologyRemoved(const QDBusObjectPath &technology);
-
-};
-
-class QConnmanServiceInterface : public QDBusAbstractInterface
-{
- Q_OBJECT
-
-public:
-
- explicit QConnmanServiceInterface(const QString &dbusPathName,QObject *parent = nullptr);
- ~QConnmanServiceInterface();
-
- QVariantMap getProperties();
- // clearProperty
- void connect();
- void disconnect();
- void remove();
-
-// properties
- QString state();
- QString lastError();
- QString name();
- QString type();
- QString security();
- bool favorite();
- bool autoConnect();
- bool roaming();
- QVariantMap ethernet();
- QString serviceInterface();
-
- bool isOfflineMode();
- QStringList services();
-
-Q_SIGNALS:
- void propertyChanged(const QString &, const QDBusVariant &value);
- void propertyChangedContext(const QString &,const QString &,const QDBusVariant &);
- void propertiesReady();
- void stateChanged(const QString &state);
-
-protected:
- void connectNotify(const QMetaMethod &signal);
- QVariant getProperty(const QString &);
-private:
- QVariantMap propertiesCacheMap;
-private slots:
- void propertiesReply(QDBusPendingCallWatcher *call);
- void changedProperty(const QString &, const QDBusVariant &value);
-
-};
-
-class QConnmanTechnologyInterface : public QDBusAbstractInterface
-{
- Q_OBJECT
-
-public:
-
- explicit QConnmanTechnologyInterface(const QString &dbusPathName,QObject *parent = nullptr);
- ~QConnmanTechnologyInterface();
-
- QString type();
-
- void scan();
-Q_SIGNALS:
- void propertyChanged(const QString &, const QDBusVariant &value);
- void propertyChangedContext(const QString &,const QString &,const QDBusVariant &);
- void scanFinished(bool error);
-protected:
- void connectNotify(const QMetaMethod &signal);
- QVariant getProperty(const QString &);
-private:
- QVariantMap properties();
- QVariantMap propertiesMap;
-private Q_SLOTS:
- void scanReply(QDBusPendingCallWatcher *call);
-
-};
-
-QT_END_NAMESPACE
-
-#endif // QT_NO_DBUS
-
-#endif //QCONNMANSERVICE_H
diff --git a/src/plugins/bearer/corewlan/CMakeLists.txt b/src/plugins/bearer/corewlan/CMakeLists.txt
deleted file mode 100644
index 31e70cc938..0000000000
--- a/src/plugins/bearer/corewlan/CMakeLists.txt
+++ /dev/null
@@ -1,30 +0,0 @@
-# Generated from corewlan.pro.
-
-#####################################################################
-## QCoreWlanEnginePlugin Plugin:
-#####################################################################
-
-qt_add_plugin(QCoreWlanEnginePlugin
- OUTPUT_NAME qcorewlanbearer
- TYPE bearer
- SOURCES
- main.cpp
- qcorewlanengine.h qcorewlanengine.mm
- PUBLIC_LIBRARIES
- ${FWFoundation}
- ${FWSystemConfiguration}
- Qt::CorePrivate
- Qt::NetworkPrivate
-)
-
-#### Keys ignored in scope 1:.:.:corewlan.pro:<TRUE>:
-# OTHER_FILES = "corewlan.json"
-
-## Scopes:
-#####################################################################
-
-qt_extend_target(QCoreWlanEnginePlugin CONDITION QT_FEATURE_corewlan
- PUBLIC_LIBRARIES
- ${FWCoreWLAN}
- ${FWSecurity}
-)
diff --git a/src/plugins/bearer/corewlan/corewlan.json b/src/plugins/bearer/corewlan/corewlan.json
deleted file mode 100644
index b43519ea90..0000000000
--- a/src/plugins/bearer/corewlan/corewlan.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "Keys": [ "corewlan" ]
-}
diff --git a/src/plugins/bearer/corewlan/corewlan.pro b/src/plugins/bearer/corewlan/corewlan.pro
deleted file mode 100644
index 4f08eaba71..0000000000
--- a/src/plugins/bearer/corewlan/corewlan.pro
+++ /dev/null
@@ -1,20 +0,0 @@
-TARGET = qcorewlanbearer
-
-QT = core-private network-private
-LIBS += -framework Foundation -framework SystemConfiguration
-
-qtConfig(corewlan) {
- LIBS += -framework CoreWLAN -framework Security
-}
-
-HEADERS += qcorewlanengine.h
-
-SOURCES += main.cpp
-
-OBJECTIVE_SOURCES += qcorewlanengine.mm
-
-OTHER_FILES += corewlan.json
-
-PLUGIN_TYPE = bearer
-PLUGIN_CLASS_NAME = QCoreWlanEnginePlugin
-load(qt_plugin)
diff --git a/src/plugins/bearer/corewlan/main.cpp b/src/plugins/bearer/corewlan/main.cpp
deleted file mode 100644
index c6663d155c..0000000000
--- a/src/plugins/bearer/corewlan/main.cpp
+++ /dev/null
@@ -1,82 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 "qcorewlanengine.h"
-
-#include <QtNetwork/private/qbearerplugin_p.h>
-
-#include <QtCore/qdebug.h>
-
-#ifndef QT_NO_BEARERMANAGEMENT
-
-QT_BEGIN_NAMESPACE
-
-class QCoreWlanEnginePlugin : public QBearerEnginePlugin
-{
- Q_OBJECT
- Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QBearerEngineFactoryInterface" FILE "corewlan.json")
-
-public:
- QCoreWlanEnginePlugin();
- ~QCoreWlanEnginePlugin();
-
- QBearerEngine *create(const QString &key) const;
-};
-
-QCoreWlanEnginePlugin::QCoreWlanEnginePlugin()
-{
-}
-
-QCoreWlanEnginePlugin::~QCoreWlanEnginePlugin()
-{
-}
-
-QBearerEngine *QCoreWlanEnginePlugin::create(const QString &key) const
-{
- if (key == QLatin1String("corewlan"))
- return new QCoreWlanEngine;
- else
- return 0;
-}
-
-QT_END_NAMESPACE
-
-#include "main.moc"
-
-#endif // QT_NO_BEARERMANAGEMENT
diff --git a/src/plugins/bearer/corewlan/qcorewlanengine.h b/src/plugins/bearer/corewlan/qcorewlanengine.h
deleted file mode 100644
index 8775474c09..0000000000
--- a/src/plugins/bearer/corewlan/qcorewlanengine.h
+++ /dev/null
@@ -1,147 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 QCOREWLANENGINE_H
-#define QCOREWLANENGINE_H
-
-#include <private/qbearerengine_impl_p.h>
-
-#include <QMap>
-#include <QTimer>
-#include <SystemConfiguration/SystemConfiguration.h>
-#include <QThread>
-
-#ifndef QT_NO_BEARERMANAGEMENT
-
-QT_BEGIN_NAMESPACE
-
-class QNetworkConfigurationPrivate;
-class QScanThread;
-
-class QCoreWlanEngine : public QBearerEngineImpl
-{
- friend class QScanThread;
- Q_OBJECT
-
-public:
- QCoreWlanEngine(QObject *parent = 0);
- ~QCoreWlanEngine();
-
- QString getInterfaceFromId(const QString &id);
- bool hasIdentifier(const QString &id);
-
- void connectToId(const QString &id);
- void disconnectFromId(const QString &id);
-
- Q_INVOKABLE void initialize();
- Q_INVOKABLE void requestUpdate();
-
- QNetworkSession::State sessionStateForId(const QString &id);
-
- quint64 bytesWritten(const QString &id);
- quint64 bytesReceived(const QString &id);
- quint64 startTime(const QString &id);
-
- QNetworkConfigurationManager::Capabilities capabilities() const;
-
- QNetworkSessionPrivate *createSessionBackend();
-
- QNetworkConfigurationPrivatePointer defaultConfiguration();
-
- bool requiresPolling() const;
-
-private Q_SLOTS:
- void doRequestUpdate();
- void networksChanged();
- void checkDisconnect();
-
-private:
- bool isWifiReady(const QString &dev);
- QList<QNetworkConfigurationPrivate *> foundConfigurations;
-
- SCDynamicStoreRef storeSession;
- CFRunLoopSourceRef runloopSource;
- bool hasWifi;
- bool scanning;
- QScanThread *scanThread;
-
- quint64 getBytes(const QString &interfaceName,bool b);
- QString disconnectedInterfaceString;
-
-protected:
- void startNetworkChangeLoop();
-
-};
-
-class QScanThread : public QThread
-{
- Q_OBJECT
-
-public:
- QScanThread(QObject *parent = 0);
- ~QScanThread();
-
- void quit();
- QList<QNetworkConfigurationPrivate *> getConfigurations();
- QString interfaceName;
- QMap<QString, QString> configurationInterface;
- void getUserConfigurations();
- QString getNetworkNameFromSsid(const QString &ssid) const;
- QString getSsidFromNetworkName(const QString &name) const;
- bool isKnownSsid(const QString &ssid) const;
- QMap<QString, QMap<QString,QString> > userProfiles;
-
-signals:
- void networksChanged();
-
-protected:
- void run();
-
-private:
- QList<QNetworkConfigurationPrivate *> fetchedConfigurations;
- mutable QMutex mutex;
- QStringList foundNetwork(const QString &id, const QString &ssid, const QNetworkConfiguration::StateFlags state, const QString &interfaceName, const QNetworkConfiguration::Purpose purpose);
-
-};
-
-QT_END_NAMESPACE
-
-#endif // QT_NO_BEARERMANAGEMENT
-
-#endif
diff --git a/src/plugins/bearer/corewlan/qcorewlanengine.mm b/src/plugins/bearer/corewlan/qcorewlanengine.mm
deleted file mode 100644
index 01c6df74d5..0000000000
--- a/src/plugins/bearer/corewlan/qcorewlanengine.mm
+++ /dev/null
@@ -1,862 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 "qcorewlanengine.h"
-#include <private/qnetworksession_impl_p.h>
-
-#include <QtNetwork/private/qnetworkconfiguration_p.h>
-
-#include <QtCore/qthread.h>
-#include <QtCore/qmutex.h>
-#include <QtCore/qcoreapplication.h>
-#include <QtCore/qstringlist.h>
-
-#include <QtCore/qdebug.h>
-
-#include <QDir>
-#ifndef QT_NO_BEARERMANAGEMENT
-
-extern "C" { // Otherwise it won't find CWKeychain* symbols at link time
-#import <CoreWLAN/CoreWLAN.h>
-}
-
-#include "private/qcore_mac_p.h"
-
-#include <net/if.h>
-#include <ifaddrs.h>
-
-@interface QT_MANGLE_NAMESPACE(QNSListener) : NSObject <CWEventDelegate>
-@property (assign) QCoreWlanEngine* engine;
-@end
-QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSListener);
-
-@implementation QNSListener {
- NSNotificationCenter *notificationCenter;
- CWWiFiClient *client;
- QCoreWlanEngine *engine;
- NSLock *locker;
-}
-
-- (instancetype)init
-{
- if ((self = [super init])) {
- [locker lock];
- QMacAutoReleasePool pool;
- notificationCenter = [NSNotificationCenter defaultCenter];
- client = [CWWiFiClient sharedWiFiClient];
- client.delegate = self;
- [client startMonitoringEventWithType:CWEventTypePowerDidChange error:nil];
- [locker unlock];
- }
- return self;
-}
-
-static QNSListener *listener = 0;
-
--(void)dealloc
-{
- client.delegate = nil;
- listener = nil;
- [super dealloc];
-}
-
--(void)setEngine:(QCoreWlanEngine *)coreEngine
-{
- [locker lock];
- if(!engine)
- engine = coreEngine;
- [locker unlock];
-}
-
--(QCoreWlanEngine *)engine
-{
- return engine;
-}
-
--(void)remove
-{
- [locker lock];
- [client stopMonitoringAllEventsAndReturnError:nil];
- [locker unlock];
-}
-
-- (void)powerStateDidChangeForWiFiInterfaceWithName:(NSString *)interfaceName
-{
- Q_UNUSED(interfaceName);
- engine->requestUpdate();
-}
-@end
-
-
-QT_BEGIN_NAMESPACE
-
-void networkChangeCallback(SCDynamicStoreRef/* store*/, CFArrayRef changedKeys, void *info)
-{
- for ( long i = 0; i < CFArrayGetCount(changedKeys); i++) {
-
- QString changed = QString::fromCFString((CFStringRef)CFArrayGetValueAtIndex(changedKeys, i));
- if( changed.contains("/Network/Global/IPv4")) {
- QCoreWlanEngine* wlanEngine = static_cast<QCoreWlanEngine*>(info);
- wlanEngine->requestUpdate();
- }
- }
- return;
-}
-
-
-QScanThread::QScanThread(QObject *parent)
- :QThread(parent)
-{
-}
-
-QScanThread::~QScanThread()
-{
-}
-
-void QScanThread::quit()
-{
- wait();
-}
-
-void QScanThread::run()
-{
- QMacAutoReleasePool pool;
- QStringList found;
- mutex.lock();
- CWInterface *currentInterface = [[CWWiFiClient sharedWiFiClient]
- interfaceWithName:interfaceName.toNSString()];
- mutex.unlock();
- const bool currentInterfaceServiceActive = currentInterface.serviceActive;
-
- if (currentInterface.powerOn) {
- NSError *err = nil;
-
- NSSet* apSet = [currentInterface scanForNetworksWithName:nil error:&err];
-
- if (!err) {
- for (CWNetwork *apNetwork in apSet) {
- const QString networkSsid = QString::fromNSString([apNetwork ssid]);
- const QString id = QString::number(qHash(QLatin1String("corewlan:") + networkSsid));
- found.append(id);
-
- QNetworkConfiguration::StateFlags state = QNetworkConfiguration::Undefined;
- bool known = isKnownSsid(networkSsid);
- if (currentInterfaceServiceActive) {
- if (networkSsid == QString::fromNSString([currentInterface ssid])) {
- state = QNetworkConfiguration::Active;
- }
- }
- if (state == QNetworkConfiguration::Undefined) {
- if(known) {
- state = QNetworkConfiguration::Discovered;
- } else {
- state = QNetworkConfiguration::Undefined;
- }
- }
- QNetworkConfiguration::Purpose purpose = QNetworkConfiguration::UnknownPurpose;
- if ([apNetwork supportsSecurity:kCWSecurityNone]) {
- purpose = QNetworkConfiguration::PublicPurpose;
- } else {
- purpose = QNetworkConfiguration::PrivatePurpose;
- }
-
- found.append(foundNetwork(id, networkSsid, state, interfaceName, purpose));
-
- }
- }
- }
- // add known configurations that are not around.
- for (auto i = userProfiles.cbegin(), end = userProfiles.cend(); i != end; ++i) {
-
- QString networkName = i.key();
- const QString id = QString::number(qHash(QLatin1String("corewlan:") + networkName));
-
- if(!found.contains(id)) {
- QString networkSsid = getSsidFromNetworkName(networkName);
- const QString ssidId = QString::number(qHash(QLatin1String("corewlan:") + networkSsid));
- QNetworkConfiguration::StateFlags state = QNetworkConfiguration::Undefined;
- QString interfaceName;
- if (!i.value().isEmpty())
- interfaceName = i.value().last();
-
- if (currentInterfaceServiceActive) {
- if (networkSsid == QString::fromNSString([currentInterface ssid])) {
- state = QNetworkConfiguration::Active;
- }
- }
- if(state == QNetworkConfiguration::Undefined) {
- if( userProfiles.contains(networkName)
- && found.contains(ssidId)) {
- state = QNetworkConfiguration::Discovered;
- }
- }
-
- if(state == QNetworkConfiguration::Undefined) {
- state = QNetworkConfiguration::Defined;
- }
-
- found.append(foundNetwork(id, networkName, state, interfaceName, QNetworkConfiguration::UnknownPurpose));
- }
- }
- emit networksChanged();
-}
-
-QStringList QScanThread::foundNetwork(const QString &id, const QString &name, const QNetworkConfiguration::StateFlags state, const QString &interfaceName, const QNetworkConfiguration::Purpose purpose)
-{
- QStringList found;
- QMutexLocker locker(&mutex);
- QNetworkConfigurationPrivate *ptr = new QNetworkConfigurationPrivate;
-
- ptr->name = name;
- ptr->isValid = true;
- ptr->id = id;
- ptr->state = state;
- ptr->type = QNetworkConfiguration::InternetAccessPoint;
- ptr->bearerType = QNetworkConfiguration::BearerWLAN;
- ptr->purpose = purpose;
-
- fetchedConfigurations.append( ptr);
- configurationInterface.insert(ptr->id, interfaceName);
-
- locker.unlock();
- locker.relock();
- found.append(id);
- return found;
-}
-
-QList<QNetworkConfigurationPrivate *> QScanThread::getConfigurations()
-{
- QMutexLocker locker(&mutex);
- return qExchange(fetchedConfigurations, {});
-}
-
-void QScanThread::getUserConfigurations()
-{
- QMutexLocker locker(&mutex);
-
- QMacAutoReleasePool pool;
- userProfiles.clear();
-
- NSArray<NSString *> *wifiInterfaces = [CWWiFiClient interfaceNames];
- for (NSString *ifName in wifiInterfaces) {
-
- CWInterface *wifiInterface = [[CWWiFiClient sharedWiFiClient] interfaceWithName:ifName];
-
- NSString *nsInterfaceName = wifiInterface.ssid;
-// add user configured system networks
- SCDynamicStoreRef dynRef = SCDynamicStoreCreate(kCFAllocatorSystemDefault, (CFStringRef)@"Qt corewlan", nil, nil);
- NSDictionary * airportPlist = (NSDictionary *)SCDynamicStoreCopyValue(dynRef, (CFStringRef)[NSString stringWithFormat:@"Setup:/Network/Interface/%@/AirPort", nsInterfaceName]);
- CFRelease(dynRef);
- if(airportPlist != nil) {
- NSDictionary *prefNetDict = [airportPlist objectForKey:@"PreferredNetworks"];
-
- NSArray<NSString *> *thisSsidarray = [prefNetDict valueForKey:@"SSID_STR"];
- for (NSString *ssidkey in thisSsidarray) {
- QString thisSsid = QString::fromNSString(ssidkey);
- if(!userProfiles.contains(thisSsid)) {
- QMap <QString,QString> map;
- map.insert(thisSsid, QString::fromNSString(nsInterfaceName));
- userProfiles.insert(thisSsid, map);
- }
- }
- CFRelease(airportPlist);
- }
-
- // remembered networks
- CWConfiguration *userConfig = [wifiInterface configuration];
- NSOrderedSet *networkProfiles = [userConfig networkProfiles];
- NSEnumerator *enumerator = [networkProfiles objectEnumerator];
- CWNetworkProfile *wProfile;
- while ((wProfile = [enumerator nextObject])) {
- QString networkName = QString::fromNSString([wProfile ssid]);
-
- if (!userProfiles.contains(networkName)) {
- QMap<QString,QString> map;
- map.insert(networkName, QString::fromNSString(nsInterfaceName));
- userProfiles.insert(networkName, map);
- }
- }
-
- // 802.1X user profiles
- QString userProfilePath = QDir::homePath() + "/Library/Preferences/com.apple.eap.profiles.plist";
- NSDictionary* eapDict = [[[NSDictionary alloc] initWithContentsOfFile:userProfilePath.toNSString()] autorelease];
- if(eapDict != nil) {
- NSString *profileStr= @"Profiles";
- NSString *nameStr = @"UserDefinedName";
- NSString *networkSsidStr = @"Wireless Network";
- for (id profileKey in eapDict) {
- if ([profileStr isEqualToString:profileKey]) {
- NSDictionary *itemDict = [eapDict objectForKey:profileKey];
- for (id itemKey in itemDict) {
-
- NSInteger dictSize = [itemKey count];
- id objects[dictSize];
- id keys[dictSize];
-
- [itemKey getObjects:objects andKeys:keys];
- QString networkName;
- QString ssid;
- for (int i = 0; i < dictSize; i++) {
- if([nameStr isEqualToString:keys[i]]) {
- networkName = QString::fromNSString(objects[i]);
- }
- if ([networkSsidStr isEqualToString:keys[i]]) {
- ssid = QString::fromNSString(objects[i]);
- }
- if (!userProfiles.contains(networkName)
- && !ssid.isEmpty()) {
- QMap<QString,QString> map;
- map.insert(ssid, QString::fromNSString(nsInterfaceName));
- userProfiles.insert(networkName, map);
- }
- }
- }
- }
- }
- }
- }
-}
-
-QString QScanThread::getSsidFromNetworkName(const QString &name) const
-{
- QMutexLocker locker(&mutex);
-
- for (auto i = userProfiles.cbegin(), end = userProfiles.cend(); i != end; ++i) {
- for (auto ij = i.value().cbegin(), end = i.value().cend(); ij != end; ++ij) {
- const QString networkNameHash = QString::number(qHash(QLatin1String("corewlan:") +i.key()));
- if(name == i.key() || name == networkNameHash) {
- return ij.key();
- }
- }
- }
- return QString();
-}
-
-QString QScanThread::getNetworkNameFromSsid(const QString &ssid) const
-{
- QMutexLocker locker(&mutex);
-
- for (auto i = userProfiles.cbegin(), end = userProfiles.cend(); i != end; ++i) {
- if (i.value().contains(ssid))
- return i.key();
- }
- return QString();
-}
-
-bool QScanThread::isKnownSsid(const QString &ssid) const
-{
- QMutexLocker locker(&mutex);
-
- for (auto i = userProfiles.cbegin(), end = userProfiles.cend(); i != end; ++i) {
- if (i.value().contains(ssid))
- return true;
- }
- return false;
-}
-
-
-QCoreWlanEngine::QCoreWlanEngine(QObject *parent)
-: QBearerEngineImpl(parent), scanThread(0)
-{
- scanThread = new QScanThread(this);
- connect(scanThread, SIGNAL(networksChanged()),
- this, SLOT(networksChanged()));
-}
-
-QCoreWlanEngine::~QCoreWlanEngine()
-{
- scanThread->wait();
-
- qDeleteAll(qExchange(foundConfigurations, {}));
- [listener remove];
- [listener release];
-}
-
-void QCoreWlanEngine::initialize()
-{
- QMutexLocker locker(&mutex);
- QMacAutoReleasePool pool;
-
- if ([[CWWiFiClient interfaceNames] count] > 0 && !listener) {
- listener = [QNSListener alloc] init];
- listener.engine = this;
- hasWifi = true;
- } else {
- hasWifi = false;
- }
- storeSession = NULL;
-
- startNetworkChangeLoop();
-}
-
-
-QString QCoreWlanEngine::getInterfaceFromId(const QString &id)
-{
- QMutexLocker locker(&mutex);
-
- return scanThread->configurationInterface.value(id);
-}
-
-bool QCoreWlanEngine::hasIdentifier(const QString &id)
-{
- QMutexLocker locker(&mutex);
-
- return scanThread->configurationInterface.contains(id);
-}
-
-void QCoreWlanEngine::connectToId(const QString &id)
-{
- QMutexLocker locker(&mutex);
- QMacAutoReleasePool pool;
- QString interfaceString = getInterfaceFromId(id);
-
- CWInterface *wifiInterface =
- [[CWWiFiClient sharedWiFiClient] interfaceWithName:interfaceString.toNSString()];
-
- if (wifiInterface.powerOn) {
- NSError *err = nil;
- QString wantedSsid;
- QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id);
-
- const QString idHash = QString::number(qHash(QLatin1String("corewlan:") + ptr->name));
- const QString idHash2 = QString::number(qHash(QLatin1String("corewlan:") + scanThread->getNetworkNameFromSsid(ptr->name)));
-
- QString wantedNetwork;
- for (auto i = scanThread->userProfiles.cbegin(), end = scanThread->userProfiles.cend(); i != end; ++i) {
- wantedNetwork = i.key();
- const QString networkNameHash = QString::number(qHash(QLatin1String("corewlan:") + wantedNetwork));
- if (id == networkNameHash) {
- wantedSsid = scanThread->getSsidFromNetworkName(wantedNetwork);
- break;
- }
- }
-
- NSSet *scanSet = [wifiInterface scanForNetworksWithName:wantedSsid.toNSString() error:&err];
-
- if(!err) {
- for (CWNetwork *apNetwork in scanSet) {
- NSData *ssidData = [apNetwork ssidData];
- bool result = false;
-
- SecIdentityRef identity = 0;
- // Check first whether we require IEEE 802.1X authentication for the wanted SSID
- if (CWKeychainCopyWiFiEAPIdentity(kCWKeychainDomainSystem, ssidData, &identity) == errSecSuccess) {
- NSString *username = nil;
- NSString *password = nil;
- if (CWKeychainFindWiFiEAPUsernameAndPassword(kCWKeychainDomainSystem, ssidData, &username, &password) == errSecSuccess) {
- result = [wifiInterface associateToEnterpriseNetwork:apNetwork
- identity:identity username:(NSString *)username password:(NSString *)password
- error:&err];
- [username release];
- [password release];
- }
- CFRelease(identity);
- } else {
- NSString *password = nil;
- if (CWKeychainFindWiFiPassword(kCWKeychainDomainSystem, ssidData, &password) == errSecSuccess) {
- result = [wifiInterface associateToNetwork:apNetwork password:(NSString *)password error:&err];
- [password release];
- }
- }
-
- if (!err) {
- if (!result) {
- emit connectionError(id, ConnectError);
- } else {
- return;
- }
- } else {
- qDebug() <<"associate ERROR"<< QString::fromNSString([err localizedDescription ]);
- }
- } //end scan network
- } else {
- qDebug() <<"scan ERROR"<< QString::fromNSString([err localizedDescription ]);
- }
- emit connectionError(id, InterfaceLookupError);
- }
-
- locker.unlock();
- emit connectionError(id, InterfaceLookupError);
-}
-
-void QCoreWlanEngine::disconnectFromId(const QString &id)
-{
- QMutexLocker locker(&mutex);
-
- QString interfaceString = getInterfaceFromId(id);
- if (interfaceString.isEmpty()) {
- locker.unlock();
- emit connectionError(id, DisconnectionError);
- return;
- }
- QMacAutoReleasePool pool;
-
- CWInterface *wifiInterface =
- [[CWWiFiClient sharedWiFiClient] interfaceWithName:interfaceString.toNSString()];
- disconnectedInterfaceString = interfaceString;
-
- [wifiInterface disassociate];
-
- QTimer::singleShot(1000, this,SLOT(checkDisconnect()));
-}
-
-void QCoreWlanEngine::checkDisconnect()
-{
- QMutexLocker locker(&mutex);
- if (!disconnectedInterfaceString.isEmpty()) {
- QMacAutoReleasePool pool;
-
- CWInterface *wifiInterface = [[CWWiFiClient sharedWiFiClient]
- interfaceWithName:disconnectedInterfaceString.toNSString()];
-
- const QString networkSsid = QString::fromNSString([wifiInterface ssid]);
- if (!networkSsid.isEmpty()) {
- const QString id = QString::number(qHash(QLatin1String("corewlan:") + networkSsid));
- locker.unlock();
- emit connectionError(id, DisconnectionError);
- locker.relock();
- }
- disconnectedInterfaceString.clear();
- }
-}
-
-void QCoreWlanEngine::requestUpdate()
-{
- scanThread->getUserConfigurations();
- doRequestUpdate();
-}
-
-void QCoreWlanEngine::doRequestUpdate()
-{
- QMutexLocker locker(&mutex);
-
- QMacAutoReleasePool pool;
-
- NSArray<NSString *> *wifiInterfaces = [CWWiFiClient interfaceNames];
- for (NSString *ifName in wifiInterfaces) {
- scanThread->interfaceName = QString::fromNSString(ifName);
- scanThread->start();
- }
- locker.unlock();
- if ([wifiInterfaces count] == 0)
- networksChanged();
-}
-
-bool QCoreWlanEngine::isWifiReady(const QString &wifiDeviceName)
-{
- QMutexLocker locker(&mutex);
- bool haswifi = false;
- if(hasWifi) {
- QMacAutoReleasePool pool;
- CWInterface *defaultInterface = [[CWWiFiClient sharedWiFiClient]
- interfaceWithName:wifiDeviceName.toNSString()];
- if (defaultInterface.powerOn) {
- haswifi = true;
- }
- }
- return haswifi;
-}
-
-
-QNetworkSession::State QCoreWlanEngine::sessionStateForId(const QString &id)
-{
- QMutexLocker locker(&mutex);
- QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id);
-
- if (!ptr)
- return QNetworkSession::Invalid;
-
- if (!ptr->isValid) {
- return QNetworkSession::Invalid;
- } else if ((ptr->state & QNetworkConfiguration::Active) == QNetworkConfiguration::Active) {
- return QNetworkSession::Connected;
- } else if ((ptr->state & QNetworkConfiguration::Discovered) ==
- QNetworkConfiguration::Discovered) {
- return QNetworkSession::Disconnected;
- } else if ((ptr->state & QNetworkConfiguration::Defined) == QNetworkConfiguration::Defined) {
- return QNetworkSession::NotAvailable;
- } else if ((ptr->state & QNetworkConfiguration::Undefined) ==
- QNetworkConfiguration::Undefined) {
- return QNetworkSession::NotAvailable;
- }
-
- return QNetworkSession::Invalid;
-}
-
-QNetworkConfigurationManager::Capabilities QCoreWlanEngine::capabilities() const
-{
- return QNetworkConfigurationManager::ForcedRoaming;
-}
-
-void QCoreWlanEngine::startNetworkChangeLoop()
-{
-
- SCDynamicStoreContext dynStoreContext = { 0, this/*(void *)storeSession*/, NULL, NULL, NULL };
- storeSession = SCDynamicStoreCreate(NULL,
- CFSTR("networkChangeCallback"),
- networkChangeCallback,
- &dynStoreContext);
- if (!storeSession ) {
- qWarning() << "could not open dynamic store: error:" << SCErrorString(SCError());
- return;
- }
-
- CFMutableArrayRef notificationKeys;
- notificationKeys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
- CFMutableArrayRef patternsArray;
- patternsArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
-
- CFStringRef storeKey;
- storeKey = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
- kSCDynamicStoreDomainState,
- kSCEntNetIPv4);
- CFArrayAppendValue(notificationKeys, storeKey);
- CFRelease(storeKey);
-
- storeKey = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
- kSCDynamicStoreDomainState,
- kSCCompAnyRegex,
- kSCEntNetIPv4);
- CFArrayAppendValue(patternsArray, storeKey);
- CFRelease(storeKey);
-
- if (!SCDynamicStoreSetNotificationKeys(storeSession , notificationKeys, patternsArray)) {
- qWarning() << "register notification error:"<< SCErrorString(SCError());
- CFRelease(storeSession );
- CFRelease(notificationKeys);
- CFRelease(patternsArray);
- return;
- }
- CFRelease(notificationKeys);
- CFRelease(patternsArray);
-
- runloopSource = SCDynamicStoreCreateRunLoopSource(NULL, storeSession , 0);
- if (!runloopSource) {
- qWarning() << "runloop source error:"<< SCErrorString(SCError());
- CFRelease(storeSession );
- return;
- }
-
- CFRunLoopAddSource(CFRunLoopGetCurrent(), runloopSource, kCFRunLoopDefaultMode);
- return;
-}
-
-QNetworkSessionPrivate *QCoreWlanEngine::createSessionBackend()
-{
- return new QNetworkSessionPrivateImpl;
-}
-
-QNetworkConfigurationPrivatePointer QCoreWlanEngine::defaultConfiguration()
-{
- return QNetworkConfigurationPrivatePointer();
-}
-
-bool QCoreWlanEngine::requiresPolling() const
-{
- return true;
-}
-
-void QCoreWlanEngine::networksChanged()
-{
- QMutexLocker locker(&mutex);
-
- QStringList previous = accessPointConfigurations.keys();
-
- QList<QNetworkConfigurationPrivate *> foundConfigurations = scanThread->getConfigurations();
- while (!foundConfigurations.isEmpty()) {
- QNetworkConfigurationPrivate *cpPriv = foundConfigurations.takeFirst();
-
- previous.removeAll(cpPriv->id);
-
- if (accessPointConfigurations.contains(cpPriv->id)) {
- QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(cpPriv->id);
-
- bool changed = false;
-
- ptr->mutex.lock();
-
- if (ptr->isValid != cpPriv->isValid) {
- ptr->isValid = cpPriv->isValid;
- changed = true;
- }
-
- if (ptr->name != cpPriv->name) {
- ptr->name = cpPriv->name;
- changed = true;
- }
-
- if (ptr->bearerType != cpPriv->bearerType) {
- ptr->bearerType = cpPriv->bearerType;
- changed = true;
- }
-
- if (ptr->state != cpPriv->state) {
- ptr->state = cpPriv->state;
- changed = true;
- }
-
- ptr->mutex.unlock();
-
- if (changed) {
- locker.unlock();
- emit configurationChanged(ptr);
- locker.relock();
- }
-
- delete cpPriv;
- } else {
- QNetworkConfigurationPrivatePointer ptr(cpPriv);
-
- accessPointConfigurations.insert(ptr->id, ptr);
-
- locker.unlock();
- emit configurationAdded(ptr);
- locker.relock();
- }
- }
-
- while (!previous.isEmpty()) {
- QNetworkConfigurationPrivatePointer ptr =
- accessPointConfigurations.take(previous.takeFirst());
-
- locker.unlock();
- emit configurationRemoved(ptr);
- locker.relock();
- }
-
- locker.unlock();
- emit updateCompleted();
-
-}
-
-quint64 QCoreWlanEngine::bytesWritten(const QString &id)
-{
- QMutexLocker locker(&mutex);
- const QString interfaceStr = getInterfaceFromId(id);
- return getBytes(interfaceStr,false);
-}
-
-quint64 QCoreWlanEngine::bytesReceived(const QString &id)
-{
- QMutexLocker locker(&mutex);
- const QString interfaceStr = getInterfaceFromId(id);
- return getBytes(interfaceStr,true);
-}
-
-quint64 QCoreWlanEngine::startTime(const QString &identifier)
-{
- QMutexLocker locker(&mutex);
- QMacAutoReleasePool pool;
- quint64 timestamp = 0;
-
- NSString *filePath = @"/Library/Preferences/SystemConfiguration/com.apple.airport.preferences.plist";
- NSDictionary* plistDict = [[[NSDictionary alloc] initWithContentsOfFile:filePath] autorelease];
- if(plistDict == nil)
- return timestamp;
- NSString *input = @"KnownNetworks";
- NSString *timeStampStr = @"_timeStamp";
-
- NSString *ssidStr = @"SSID_STR";
-
- for (id key in plistDict) {
- if ([input isEqualToString:key]) {
-
- NSDictionary *knownNetworksDict = [plistDict objectForKey:key];
- if(knownNetworksDict == nil)
- return timestamp;
- for (id networkKey in knownNetworksDict) {
- bool isFound = false;
- NSDictionary *itemDict = [knownNetworksDict objectForKey:networkKey];
- if(itemDict == nil)
- return timestamp;
- NSInteger dictSize = [itemDict count];
- id objects[dictSize];
- id keys[dictSize];
-
- [itemDict getObjects:objects andKeys:keys];
- bool ok = false;
- for(int i = 0; i < dictSize; i++) {
- if([ssidStr isEqualToString:keys[i]]) {
- const QString ident = QString::number(qHash(QLatin1String("corewlan:") + QString::fromNSString(objects[i])));
- if(ident == identifier) {
- ok = true;
- }
- }
- if(ok && [timeStampStr isEqualToString:keys[i]]) {
- timestamp = (quint64)[objects[i] timeIntervalSince1970];
- isFound = true;
- break;
- }
- }
- if(isFound)
- break;
- }
- }
- }
- return timestamp;
-}
-
-quint64 QCoreWlanEngine::getBytes(const QString &interfaceName, bool b)
-{
- struct ifaddrs *ifAddressList, *ifAddress;
- struct if_data *if_data;
-
- quint64 bytes = 0;
- ifAddressList = nil;
- if(getifaddrs(&ifAddressList) == 0) {
- for(ifAddress = ifAddressList; ifAddress; ifAddress = ifAddress->ifa_next) {
- if(interfaceName == ifAddress->ifa_name) {
- if_data = (struct if_data*)ifAddress->ifa_data;
- if(b) {
- bytes = if_data->ifi_ibytes;
- break;
- } else {
- bytes = if_data->ifi_obytes;
- break;
- }
- }
- }
- freeifaddrs(ifAddressList);
- }
- return bytes;
-}
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/plugins/bearer/generic/CMakeLists.txt b/src/plugins/bearer/generic/CMakeLists.txt
deleted file mode 100644
index 6d65346b57..0000000000
--- a/src/plugins/bearer/generic/CMakeLists.txt
+++ /dev/null
@@ -1,28 +0,0 @@
-# Generated from generic.pro.
-
-#####################################################################
-## QGenericEnginePlugin Plugin:
-#####################################################################
-
-qt_add_plugin(QGenericEnginePlugin
- OUTPUT_NAME qgenericbearer
- TYPE bearer
- SOURCES
- ../platformdefs_win.h
- main.cpp
- qgenericengine.cpp qgenericengine.h
- PUBLIC_LIBRARIES
- Qt::CorePrivate
- Qt::NetworkPrivate
-)
-
-#### Keys ignored in scope 1:.:.:generic.pro:<TRUE>:
-# OTHER_FILES = "generic.json"
-
-## Scopes:
-#####################################################################
-
-qt_extend_target(QGenericEnginePlugin CONDITION WIN32 AND NOT WINRT
- PUBLIC_LIBRARIES
- iphlpapi
-)
diff --git a/src/plugins/bearer/generic/generic.json b/src/plugins/bearer/generic/generic.json
deleted file mode 100644
index e9357f4c72..0000000000
--- a/src/plugins/bearer/generic/generic.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "Keys": [ "generic" ]
-}
diff --git a/src/plugins/bearer/generic/generic.pro b/src/plugins/bearer/generic/generic.pro
deleted file mode 100644
index 14b858b301..0000000000
--- a/src/plugins/bearer/generic/generic.pro
+++ /dev/null
@@ -1,16 +0,0 @@
-TARGET = qgenericbearer
-
-QT = core-private network-private
-
-HEADERS += qgenericengine.h \
- ../platformdefs_win.h
-SOURCES += qgenericengine.cpp \
- main.cpp
-
-OTHER_FILES += generic.json
-
-win32:!winrt:LIBS += -liphlpapi
-
-PLUGIN_TYPE = bearer
-PLUGIN_CLASS_NAME = QGenericEnginePlugin
-load(qt_plugin)
diff --git a/src/plugins/bearer/generic/main.cpp b/src/plugins/bearer/generic/main.cpp
deleted file mode 100644
index 82a9ce97f4..0000000000
--- a/src/plugins/bearer/generic/main.cpp
+++ /dev/null
@@ -1,78 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 "qgenericengine.h"
-
-#include <QtNetwork/private/qbearerplugin_p.h>
-
-#include <QtCore/qdebug.h>
-
-QT_BEGIN_NAMESPACE
-
-class QGenericEnginePlugin : public QBearerEnginePlugin
-{
- Q_OBJECT
- Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QBearerEngineFactoryInterface" FILE "generic.json")
-
-public:
- QGenericEnginePlugin();
- ~QGenericEnginePlugin();
-
- QBearerEngine *create(const QString &key) const override;
-};
-
-QGenericEnginePlugin::QGenericEnginePlugin()
-{
-}
-
-QGenericEnginePlugin::~QGenericEnginePlugin()
-{
-}
-
-QBearerEngine *QGenericEnginePlugin::create(const QString &key) const
-{
- if (key == QLatin1String("generic"))
- return new QGenericEngine;
- else
- return 0;
-}
-
-QT_END_NAMESPACE
-
-#include "main.moc"
diff --git a/src/plugins/bearer/generic/qgenericengine.cpp b/src/plugins/bearer/generic/qgenericengine.cpp
deleted file mode 100644
index a5fba15789..0000000000
--- a/src/plugins/bearer/generic/qgenericengine.cpp
+++ /dev/null
@@ -1,446 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
-
-// see comment in ../platformdefs_win.h.
-#define WIN32_LEAN_AND_MEAN 1
-
-#include "qgenericengine.h"
-#include <private/qnetworksession_impl_p.h>
-
-#include <QtNetwork/private/qnetworkconfiguration_p.h>
-
-#include <QtCore/qthread.h>
-#include <QtCore/qmutex.h>
-#include <QtCore/qcoreapplication.h>
-#include <QtCore/qstringlist.h>
-
-#include <QtCore/qdebug.h>
-#include <QtCore/private/qcoreapplication_p.h>
-
-#if defined(Q_OS_WIN32)
-// PMIB_TCPTABLE2 is only available since Vista
-#if _WIN32_WINNT < 0x0601
-# undef _WIN32_WINNT
-# define _WIN32_WINNT 0x0601
-#endif // _WIN32_WINNT < 0x0601
-#include "../platformdefs_win.h"
-#include <iphlpapi.h>
-#endif
-
-#ifdef Q_OS_WINRT
-#include <qfunctions_winrt.h>
-
-#include <wrl.h>
-#include <windows.foundation.h>
-#include <windows.foundation.collections.h>
-#include <windows.networking.connectivity.h>
-
-using namespace Microsoft::WRL;
-using namespace Microsoft::WRL::Wrappers;
-using namespace ABI::Windows::Foundation;
-using namespace ABI::Windows::Foundation::Collections;
-using namespace ABI::Windows::Networking;
-using namespace ABI::Windows::Networking::Connectivity;
-#endif // Q_OS_WINRT
-
-// needed as interface is used as parameter name in qGetInterfaceType
-#undef interface
-
-#ifdef Q_OS_LINUX
-#include <sys/socket.h>
-#include <sys/ioctl.h>
-#include <net/if.h>
-#include <net/if_arp.h>
-#include <unistd.h>
-#endif
-
-QT_BEGIN_NAMESPACE
-
-#ifndef QT_NO_NETWORKINTERFACE
-static QNetworkConfiguration::BearerType qGetInterfaceType(const QString &interface)
-{
-#if defined(Q_OS_WIN32)
- // QNetworkInterface::name returns a more friendly name on Windows. That name is not
- // accepted as an identifier for CreateFile so we have to obtain the Luid.
- std::wstring buf = interface.toStdWString();
- if (buf.size() == 0)
- return QNetworkConfiguration::BearerUnknown;
-
- NET_LUID luid;
- NETIO_STATUS status = ConvertInterfaceNameToLuidW(buf.c_str(), &luid);
- if (status != NO_ERROR)
- return QNetworkConfiguration::BearerUnknown;
-
- switch (luid.Info.IfType) {
- case IF_TYPE_ETHERNET_CSMACD:
- case IF_TYPE_ISO88025_TOKENRING:
- case IF_TYPE_PPP:
- case IF_TYPE_SOFTWARE_LOOPBACK:
- return QNetworkConfiguration::BearerEthernet;
- case IF_TYPE_IEEE80211:
- return QNetworkConfiguration::BearerWLAN;
- case IF_TYPE_ATM:
- case IF_TYPE_IEEE1394:
- case IF_TYPE_OTHER:
- case IF_TYPE_TUNNEL:
- return QNetworkConfiguration::BearerUnknown;
- default:
-#ifdef BEARER_MANAGEMENT_DEBUG
- qDebug() << "Interface Type" << luid.Info.IfType;
-#endif
- return QNetworkConfiguration::BearerUnknown;
- }
- return QNetworkConfiguration::BearerUnknown;
-
-#elif defined(Q_OS_LINUX)
- int sock = socket(AF_INET, SOCK_DGRAM, 0);
-
- ifreq request;
- strncpy(request.ifr_name, interface.toLocal8Bit().data(), sizeof(request.ifr_name) - 1);
- request.ifr_name[sizeof(request.ifr_name) - 1] = '\0';
- int result = ioctl(sock, SIOCGIFHWADDR, &request);
- close(sock);
-
- if (result >= 0 && request.ifr_hwaddr.sa_family == ARPHRD_ETHER)
- return QNetworkConfiguration::BearerEthernet;
-#elif defined(Q_OS_WINRT)
- ComPtr<INetworkInformationStatics> networkInfoStatics;
- HRESULT hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Networking_Connectivity_NetworkInformation).Get(), &networkInfoStatics);
- Q_ASSERT_SUCCEEDED(hr);
- ComPtr<IVectorView<ConnectionProfile *>> connectionProfiles;
- hr = networkInfoStatics->GetConnectionProfiles(&connectionProfiles);
- Q_ASSERT_SUCCEEDED(hr);
- if (!connectionProfiles)
- return QNetworkConfiguration::BearerUnknown;
-
- unsigned int size;
- hr = connectionProfiles->get_Size(&size);
- Q_ASSERT_SUCCEEDED(hr);
- for (unsigned int i = 0; i < size; ++i) {
- ComPtr<IConnectionProfile> profile;
- hr = connectionProfiles->GetAt(i, &profile);
- Q_ASSERT_SUCCEEDED(hr);
-
- ComPtr<INetworkAdapter> adapter;
- hr = profile->get_NetworkAdapter(&adapter);
- // Indicates that no internet connection is available/the device is in airplane mode
- if (hr == E_INVALIDARG)
- return QNetworkConfiguration::BearerUnknown;
- Q_ASSERT_SUCCEEDED(hr);
- GUID id;
- hr = adapter->get_NetworkAdapterId(&id);
- Q_ASSERT_SUCCEEDED(hr);
- OLECHAR adapterName[39]={0};
- int length = StringFromGUID2(id, adapterName, 39);
- // "length - 1" as we have to remove the null terminator from it in order to compare
- if (!length
- || QString::fromRawData(reinterpret_cast<const QChar *>(adapterName), length - 1) != interface)
- continue;
-
- ComPtr<IConnectionProfile2> profile2;
- hr = profile.As(&profile2);
- Q_ASSERT_SUCCEEDED(hr);
- boolean isWLan;
- hr = profile2->get_IsWlanConnectionProfile(&isWLan);
- Q_ASSERT_SUCCEEDED(hr);
- if (isWLan)
- return QNetworkConfiguration::BearerWLAN;
-
- boolean isWWan;
- hr = profile2->get_IsWwanConnectionProfile(&isWWan);
- Q_ASSERT_SUCCEEDED(hr);
- if (isWWan) {
- ComPtr<IWwanConnectionProfileDetails> details;
- hr = profile2->get_WwanConnectionProfileDetails(&details);
- Q_ASSERT_SUCCEEDED(hr);
- WwanDataClass dataClass;
- hr = details->GetCurrentDataClass(&dataClass);
- Q_ASSERT_SUCCEEDED(hr);
- switch (dataClass) {
- case WwanDataClass_Edge:
- case WwanDataClass_Gprs:
- return QNetworkConfiguration::Bearer2G;
- case WwanDataClass_Umts:
- return QNetworkConfiguration::BearerWCDMA;
- case WwanDataClass_LteAdvanced:
- return QNetworkConfiguration::BearerLTE;
- case WwanDataClass_Hsdpa:
- case WwanDataClass_Hsupa:
- return QNetworkConfiguration::BearerHSPA;
- case WwanDataClass_Cdma1xRtt:
- case WwanDataClass_Cdma3xRtt:
- case WwanDataClass_CdmaUmb:
- return QNetworkConfiguration::BearerCDMA2000;
- case WwanDataClass_Cdma1xEvdv:
- case WwanDataClass_Cdma1xEvdo:
- case WwanDataClass_Cdma1xEvdoRevA:
- case WwanDataClass_Cdma1xEvdoRevB:
- return QNetworkConfiguration::BearerEVDO;
- case WwanDataClass_Custom:
- case WwanDataClass_None:
- default:
- return QNetworkConfiguration::BearerUnknown;
- }
- }
- return QNetworkConfiguration::BearerEthernet;
- }
-#else
- Q_UNUSED(interface);
-#endif
-
- return QNetworkConfiguration::BearerUnknown;
-}
-#endif
-
-QGenericEngine::QGenericEngine(QObject *parent)
-: QBearerEngineImpl(parent)
-{
- //workaround for deadlock in __cxa_guard_acquire with webkit on macos x
- //initialise the Q_GLOBAL_STATIC in same thread as the AtomicallyInitializedStatic
- (void)QNetworkInterface::interfaceFromIndex(0);
-}
-
-QGenericEngine::~QGenericEngine()
-{
-}
-
-QString QGenericEngine::getInterfaceFromId(const QString &id)
-{
- QMutexLocker locker(&mutex);
-
- return configurationInterface.value(id);
-}
-
-bool QGenericEngine::hasIdentifier(const QString &id)
-{
- QMutexLocker locker(&mutex);
-
- return configurationInterface.contains(id);
-}
-
-void QGenericEngine::connectToId(const QString &id)
-{
- emit connectionError(id, OperationNotSupported);
-}
-
-void QGenericEngine::disconnectFromId(const QString &id)
-{
- emit connectionError(id, OperationNotSupported);
-}
-
-void QGenericEngine::initialize()
-{
- doRequestUpdate();
-}
-
-void QGenericEngine::requestUpdate()
-{
- doRequestUpdate();
-}
-
-void QGenericEngine::doRequestUpdate()
-{
-#ifndef QT_NO_NETWORKINTERFACE
- QMutexLocker locker(&mutex);
-
- // Immediately after connecting with a wireless access point
- // QNetworkInterface::allInterfaces() will sometimes return an empty list. Calling it again a
- // second time results in a non-empty list. If we loose interfaces we will end up removing
- // network configurations which will break current sessions.
- QList<QNetworkInterface> interfaces = QNetworkInterface::allInterfaces();
- if (interfaces.isEmpty())
- interfaces = QNetworkInterface::allInterfaces();
-
- QStringList previous = accessPointConfigurations.keys();
-
- // create configuration for each interface
- while (!interfaces.isEmpty()) {
- QNetworkInterface interface = interfaces.takeFirst();
-
- if (!interface.isValid())
- continue;
-
- // ignore loopback interface
- if (interface.flags() & QNetworkInterface::IsLoopBack)
- continue;
-
-#ifndef Q_OS_WIN
- // ignore WLAN interface handled in separate engine
- if (qGetInterfaceType(interface.name()) == QNetworkConfiguration::BearerWLAN)
- continue;
-#endif
-
- uint identifier;
- if (interface.index())
- identifier = qHash(QLatin1String("generic:") + QString::number(interface.index()));
- else
- identifier = qHash(QLatin1String("generic:") + interface.hardwareAddress());
-
- const QString id = QString::number(identifier);
-
- previous.removeAll(id);
-
- QString name = interface.humanReadableName();
- if (name.isEmpty())
- name = interface.name();
-
- QNetworkConfiguration::StateFlags state = QNetworkConfiguration::Defined;
- if ((interface.flags() & QNetworkInterface::IsRunning) && !interface.addressEntries().isEmpty())
- state |= QNetworkConfiguration::Active;
-
- if (accessPointConfigurations.contains(id)) {
- QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id);
-
- bool changed = false;
-
- ptr->mutex.lock();
-
- if (!ptr->isValid) {
- ptr->isValid = true;
- changed = true;
- }
-
- if (ptr->name != name) {
- ptr->name = name;
- changed = true;
- }
-
- if (ptr->id != id) {
- ptr->id = id;
- changed = true;
- }
-
- if (ptr->state != state) {
- ptr->state = state;
- changed = true;
- }
-
- ptr->mutex.unlock();
-
- if (changed) {
- locker.unlock();
- emit configurationChanged(ptr);
- locker.relock();
- }
- } else {
- QNetworkConfigurationPrivatePointer ptr(new QNetworkConfigurationPrivate);
-
- ptr->name = name;
- ptr->isValid = true;
- ptr->id = id;
- ptr->state = state;
- ptr->type = QNetworkConfiguration::InternetAccessPoint;
- ptr->bearerType = qGetInterfaceType(interface.name());
-
- accessPointConfigurations.insert(id, ptr);
- configurationInterface.insert(id, interface.name());
-
- locker.unlock();
- emit configurationAdded(ptr);
- locker.relock();
- }
- }
-
- while (!previous.isEmpty()) {
- QNetworkConfigurationPrivatePointer ptr =
- accessPointConfigurations.take(previous.takeFirst());
-
- configurationInterface.remove(ptr->id);
-
- locker.unlock();
- emit configurationRemoved(ptr);
- locker.relock();
- }
-
- locker.unlock();
-#endif
-
- emit updateCompleted();
-}
-
-QNetworkSession::State QGenericEngine::sessionStateForId(const QString &id)
-{
- QMutexLocker locker(&mutex);
-
- QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id);
-
- if (!ptr)
- return QNetworkSession::Invalid;
-
- QMutexLocker configLocker(&ptr->mutex);
-
- if (!ptr->isValid) {
- return QNetworkSession::Invalid;
- } else if ((ptr->state & QNetworkConfiguration::Active) == QNetworkConfiguration::Active) {
- return QNetworkSession::Connected;
- } else if ((ptr->state & QNetworkConfiguration::Discovered) ==
- QNetworkConfiguration::Discovered) {
- return QNetworkSession::Disconnected;
- } else if ((ptr->state & QNetworkConfiguration::Defined) == QNetworkConfiguration::Defined) {
- return QNetworkSession::NotAvailable;
- } else if ((ptr->state & QNetworkConfiguration::Undefined) ==
- QNetworkConfiguration::Undefined) {
- return QNetworkSession::NotAvailable;
- }
-
- return QNetworkSession::Invalid;
-}
-
-QNetworkConfigurationManager::Capabilities QGenericEngine::capabilities() const
-{
- return QNetworkConfigurationManager::ForcedRoaming;
-}
-
-QNetworkSessionPrivate *QGenericEngine::createSessionBackend()
-{
- return new QNetworkSessionPrivateImpl;
-}
-
-QNetworkConfigurationPrivatePointer QGenericEngine::defaultConfiguration()
-{
- return QNetworkConfigurationPrivatePointer();
-}
-
-
-bool QGenericEngine::requiresPolling() const
-{
- return true;
-}
-
-QT_END_NAMESPACE
diff --git a/src/plugins/bearer/generic/qgenericengine.h b/src/plugins/bearer/generic/qgenericengine.h
deleted file mode 100644
index 6b8fb4cd0f..0000000000
--- a/src/plugins/bearer/generic/qgenericengine.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 QGENERICENGINE_H
-#define QGENERICENGINE_H
-
-#include <private/qbearerengine_impl_p.h>
-
-#include <QMap>
-#include <QTimer>
-
-QT_BEGIN_NAMESPACE
-
-class QNetworkConfigurationPrivate;
-class QNetworkSessionPrivate;
-
-class QGenericEngine : public QBearerEngineImpl
-{
- Q_OBJECT
-
-public:
- QGenericEngine(QObject *parent = nullptr);
- ~QGenericEngine();
-
- QString getInterfaceFromId(const QString &id) override;
- bool hasIdentifier(const QString &id) override;
-
- void connectToId(const QString &id) override;
- void disconnectFromId(const QString &id) override;
-
- Q_INVOKABLE void initialize();
- Q_INVOKABLE void requestUpdate();
-
- QNetworkSession::State sessionStateForId(const QString &id) override;
-
- QNetworkConfigurationManager::Capabilities capabilities() const override;
-
- QNetworkSessionPrivate *createSessionBackend() override;
-
- QNetworkConfigurationPrivatePointer defaultConfiguration() override;
-
- bool requiresPolling() const override;
-
-private Q_SLOTS:
- void doRequestUpdate();
-
-private:
- QMap<QString, QString> configurationInterface;
-};
-
-QT_END_NAMESPACE
-
-#endif
-
diff --git a/src/plugins/bearer/nativewifi/main.cpp b/src/plugins/bearer/nativewifi/main.cpp
deleted file mode 100644
index 826c0104e4..0000000000
--- a/src/plugins/bearer/nativewifi/main.cpp
+++ /dev/null
@@ -1,127 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 "qnativewifiengine.h"
-#include "platformdefs.h"
-
-#include <QtCore/qmutex.h>
-#include <QtCore/qlibrary.h>
-
-#include <QtNetwork/private/qbearerplugin_p.h>
-
-#include <QtCore/qdebug.h>
-
-#ifndef QT_NO_BEARERMANAGEMENT
-
-QT_BEGIN_NAMESPACE
-
-static bool resolveLibraryInternal()
-{
- QLibrary wlanapiLib(QLatin1String("wlanapi"));
- local_WlanOpenHandle = (WlanOpenHandleProto)
- wlanapiLib.resolve("WlanOpenHandle");
- local_WlanRegisterNotification = (WlanRegisterNotificationProto)
- wlanapiLib.resolve("WlanRegisterNotification");
- local_WlanEnumInterfaces = (WlanEnumInterfacesProto)
- wlanapiLib.resolve("WlanEnumInterfaces");
- local_WlanGetAvailableNetworkList = (WlanGetAvailableNetworkListProto)
- wlanapiLib.resolve("WlanGetAvailableNetworkList");
- local_WlanQueryInterface = (WlanQueryInterfaceProto)
- wlanapiLib.resolve("WlanQueryInterface");
- local_WlanConnect = (WlanConnectProto)
- wlanapiLib.resolve("WlanConnect");
- local_WlanDisconnect = (WlanDisconnectProto)
- wlanapiLib.resolve("WlanDisconnect");
- local_WlanScan = (WlanScanProto)
- wlanapiLib.resolve("WlanScan");
- local_WlanFreeMemory = (WlanFreeMemoryProto)
- wlanapiLib.resolve("WlanFreeMemory");
- local_WlanCloseHandle = (WlanCloseHandleProto)
- wlanapiLib.resolve("WlanCloseHandle");
- return true;
-}
-Q_GLOBAL_STATIC_WITH_ARGS(bool, resolveLibrary, (resolveLibraryInternal()))
-
-class QNativeWifiEnginePlugin : public QBearerEnginePlugin
-{
- Q_OBJECT
- Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QBearerEngineFactoryInterface" FILE "nativewifi.json")
-
-public:
- QNativeWifiEnginePlugin();
- ~QNativeWifiEnginePlugin();
-
- QBearerEngine *create(const QString &key) const;
-};
-
-QNativeWifiEnginePlugin::QNativeWifiEnginePlugin()
-{
-}
-
-QNativeWifiEnginePlugin::~QNativeWifiEnginePlugin()
-{
-}
-
-QBearerEngine *QNativeWifiEnginePlugin::create(const QString &key) const
-{
- if (key != QLatin1String("nativewifi"))
- return 0;
-
- resolveLibrary();
-
- // native wifi dll not available
- if (!local_WlanOpenHandle)
- return 0;
-
- QNativeWifiEngine *engine = new QNativeWifiEngine;
-
- // could not initialise subsystem
- if (engine && !engine->available()) {
- delete engine;
- return 0;
- }
-
- return engine;
-}
-
-QT_END_NAMESPACE
-
-#include "main.moc"
-
-#endif // QT_NO_BEARERMANAGEMENT
diff --git a/src/plugins/bearer/nativewifi/nativewifi.json b/src/plugins/bearer/nativewifi/nativewifi.json
deleted file mode 100644
index f3db199150..0000000000
--- a/src/plugins/bearer/nativewifi/nativewifi.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "Keys": [ "nativewifi" ]
-}
diff --git a/src/plugins/bearer/nativewifi/nativewifi.pro b/src/plugins/bearer/nativewifi/nativewifi.pro
deleted file mode 100644
index 41bde99341..0000000000
--- a/src/plugins/bearer/nativewifi/nativewifi.pro
+++ /dev/null
@@ -1,15 +0,0 @@
-TARGET = qnativewifibearer
-
-QT = core-private network-private
-
-HEADERS += qnativewifiengine.h \
- platformdefs.h
-
-SOURCES += main.cpp \
- qnativewifiengine.cpp
-
-OTHER_FILES += nativewifi.json
-
-PLUGIN_TYPE = bearer
-PLUGIN_CLASS_NAME = QNativeWifiEnginePlugin
-load(qt_plugin)
diff --git a/src/plugins/bearer/nativewifi/platformdefs.h b/src/plugins/bearer/nativewifi/platformdefs.h
deleted file mode 100644
index b8ac40af15..0000000000
--- a/src/plugins/bearer/nativewifi/platformdefs.h
+++ /dev/null
@@ -1,327 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 PLATFORMDEFS_H
-#define PLATFORMDEFS_H
-
-#include <wtypes.h>
-#undef interface
-
-//proper header is wlanapi.h, but that is not included in windows XP
-
-#define WLAN_MAX_NAME_LENGTH 256
-#define WLAN_MAX_PHY_TYPE_NUMBER 8
-#define WLAN_NOTIFICATION_SOURCE_ACM 0x00000008
-#define WLAN_NOTIFICATION_SOURCE_ALL 0x0000ffff
-#define WLAN_AVAILABLE_NETWORK_CONNECTED 1
-#define WLAN_AVAILABLE_NETWORK_HAS_PROFILE 2
-#define DOT11_SSID_MAX_LENGTH 32
-
-QT_BEGIN_NAMESPACE
-
-struct WLAN_NOTIFICATION_DATA {
- DWORD NotificationSource;
- DWORD NotificationCode;
- GUID InterfaceGuid;
- DWORD dwDataSize;
- PVOID pData;
-};
-
-enum WLAN_INTERFACE_STATE {
- wlan_interface_state_not_ready = 0,
- wlan_interface_state_connected,
- wlan_interface_state_ad_hoc_network_formed,
- wlan_interface_state_disconnecting,
- wlan_interface_state_disconnected,
- wlan_interface_state_associating,
- wlan_interface_state_discovering,
- wlan_interface_state_authenticating
-};
-
-struct WLAN_INTERFACE_INFO {
- GUID InterfaceGuid;
- WCHAR strInterfaceDescription[WLAN_MAX_NAME_LENGTH];
- WLAN_INTERFACE_STATE isState;
-};
-
-struct WLAN_INTERFACE_INFO_LIST {
- DWORD dwNumberOfItems;
- DWORD dwIndex;
- WLAN_INTERFACE_INFO InterfaceInfo[1];
-};
-
-struct DOT11_SSID {
- ULONG uSSIDLength;
- UCHAR ucSSID[DOT11_SSID_MAX_LENGTH];
-};
-
-struct NDIS_OBJECT_HEADER {
- UCHAR Type;
- UCHAR Revision;
- USHORT Size;
-};
-
-typedef UCHAR DOT11_MAC_ADDRESS[6];
-struct DOT11_BSSID_LIST {
- NDIS_OBJECT_HEADER Header;
- ULONG uNumberOfEntries;
- ULONG uTotalNumOfEntries;
- DOT11_MAC_ADDRESS BSSIDs[1];
-};
-
-enum DOT11_BSS_TYPE {
- dot11_BSS_type_infrastructure = 1,
- dot11_BSS_type_independent = 2,
- dot11_BSS_type_any = 3
-};
-
-enum DOT11_PHY_TYPE {
- dot11_phy_type_unknown = 0,
- dot11_phy_type_any = dot11_phy_type_unknown,
- dot11_phy_type_fhss = 1,
- dot11_phy_type_dsss = 2,
- dot11_phy_type_irbaseband = 3,
- dot11_phy_type_ofdm = 4,
- dot11_phy_type_hrdsss = 5,
- dot11_phy_type_erp = 6,
- dot11_phy_type_ht = 7,
- dot11_phy_type_IHV_start = 0x80000000,
- dot11_phy_type_IHV_end = 0xffffffff
-};
-
-enum DOT11_AUTH_ALGORITHM {
- DOT11_AUTH_ALGO_80211_OPEN = 1,
- DOT11_AUTH_ALGO_80211_SHARED_KEY = 2,
- DOT11_AUTH_ALGO_WPA = 3,
- DOT11_AUTH_ALGO_WPA_PSK = 4,
- DOT11_AUTH_ALGO_WPA_NONE = 5,
- DOT11_AUTH_ALGO_RSNA = 6,
- DOT11_AUTH_ALGO_RSNA_PSK = 7,
- DOT11_AUTH_ALGO_IHV_START = 0x80000000,
- DOT11_AUTH_ALGO_IHV_END = 0xffffffff
-};
-
-enum DOT11_CIPHER_ALGORITHM {
- DOT11_CIPHER_ALGO_NONE = 0x00,
- DOT11_CIPHER_ALGO_WEP40 = 0x01,
- DOT11_CIPHER_ALGO_TKIP = 0x02,
- DOT11_CIPHER_ALGO_CCMP = 0x04,
- DOT11_CIPHER_ALGO_WEP104 = 0x05,
- DOT11_CIPHER_ALGO_WPA_USE_GROUP = 0x100,
- DOT11_CIPHER_ALGO_RSN_USE_GROUP = 0x100,
- DOT11_CIPHER_ALGO_WEP = 0x101,
- DOT11_CIPHER_ALGO_IHV_START = 0x80000000,
- DOT11_CIPHER_ALGO_IHV_END = 0xffffffff
-};
-
-struct WLAN_AVAILABLE_NETWORK {
- WCHAR strProfileName[WLAN_MAX_NAME_LENGTH];
- DOT11_SSID dot11Ssid;
- DOT11_BSS_TYPE dot11BssType;
- ULONG uNumberOfBssids;
- BOOL bNetworkConnectable;
- DWORD wlanNotConnectableReason;
- ULONG uNumberOfPhyTypes;
- DOT11_PHY_TYPE dot11PhyTypes[WLAN_MAX_PHY_TYPE_NUMBER];
- BOOL bMorePhyTypes;
- ULONG wlanSignalQuality;
- BOOL bSecurityEnabled;
- DOT11_AUTH_ALGORITHM dot11DefaultAuthAlgorithm;
- DOT11_CIPHER_ALGORITHM dot11DefaultCipherAlgorithm;
- DWORD dwFlags;
- DWORD dwReserved;
-};
-
-struct WLAN_AVAILABLE_NETWORK_LIST {
- DWORD dwNumberOfItems;
- DWORD dwIndex;
- WLAN_AVAILABLE_NETWORK Network[1];
-};
-
-enum WLAN_INTF_OPCODE {
- wlan_intf_opcode_autoconf_start = 0x000000000,
- wlan_intf_opcode_autoconf_enabled,
- wlan_intf_opcode_background_scan_enabled,
- wlan_intf_opcode_media_streaming_mode,
- wlan_intf_opcode_radio_state,
- wlan_intf_opcode_bss_type,
- wlan_intf_opcode_interface_state,
- wlan_intf_opcode_current_connection,
- wlan_intf_opcode_channel_number,
- wlan_intf_opcode_supported_infrastructure_auth_cipher_pairs,
- wlan_intf_opcode_supported_adhoc_auth_cipher_pairs,
- wlan_intf_opcode_supported_country_or_region_string_list,
- wlan_intf_opcode_current_operation_mode,
- wlan_intf_opcode_supported_safe_mode,
- wlan_intf_opcode_certified_safe_mode,
- wlan_intf_opcode_autoconf_end = 0x0fffffff,
- wlan_intf_opcode_msm_start = 0x10000100,
- wlan_intf_opcode_statistics,
- wlan_intf_opcode_rssi,
- wlan_intf_opcode_msm_end = 0x1fffffff,
- wlan_intf_opcode_security_start = 0x20010000,
- wlan_intf_opcode_security_end = 0x2fffffff,
- wlan_intf_opcode_ihv_start = 0x30000000,
- wlan_intf_opcode_ihv_end = 0x3fffffff
-};
-
-enum WLAN_OPCODE_VALUE_TYPE {
- wlan_opcode_value_type_query_only = 0,
- wlan_opcode_value_type_set_by_group_policy,
- wlan_opcode_value_type_set_by_user,
- wlan_opcode_value_type_invalid
-};
-
-enum WLAN_CONNECTION_MODE {
- wlan_connection_mode_profile = 0,
- wlan_connection_mode_temporary_profile,
- wlan_connection_mode_discovery_secure,
- wlan_connection_mode_discovery_unsecure,
- wlan_connection_mode_auto,
- wlan_connection_mode_invalid
-};
-
-struct WLAN_CONNECTION_PARAMETERS {
- WLAN_CONNECTION_MODE wlanConnectionMode;
- LPCWSTR strProfile;
- DOT11_SSID *pDot11Ssid;
- DOT11_BSSID_LIST *pDesiredBssidList;
- DOT11_BSS_TYPE dot11BssType;
- DWORD dwFlags;
-};
-
-struct WLAN_RAW_DATA {
- DWORD dwDataSize;
- BYTE DataBlob[1];
-};
-
-enum WLAN_NOTIFICATION_ACM {
- wlan_notification_acm_start = 0,
- wlan_notification_acm_autoconf_enabled,
- wlan_notification_acm_autoconf_disabled,
- wlan_notification_acm_background_scan_enabled,
- wlan_notification_acm_background_scan_disabled,
- wlan_notification_acm_bss_type_change,
- wlan_notification_acm_power_setting_change,
- wlan_notification_acm_scan_complete,
- wlan_notification_acm_scan_fail,
- wlan_notification_acm_connection_start,
- wlan_notification_acm_connection_complete,
- wlan_notification_acm_connection_attempt_fail,
- wlan_notification_acm_filter_list_change,
- wlan_notification_acm_interface_arrival,
- wlan_notification_acm_interface_removal,
- wlan_notification_acm_profile_change,
- wlan_notification_acm_profile_name_change,
- wlan_notification_acm_profiles_exhausted,
- wlan_notification_acm_network_not_available,
- wlan_notification_acm_network_available,
- wlan_notification_acm_disconnecting,
- wlan_notification_acm_disconnected,
- wlan_notification_acm_adhoc_network_state_change,
- wlan_notification_acm_end
-};
-
-struct WLAN_ASSOCIATION_ATTRIBUTES {
- DOT11_SSID dot11Ssid;
- DOT11_BSS_TYPE dot11BssType;
- DOT11_MAC_ADDRESS dot11Bssid;
- DOT11_PHY_TYPE dot11PhyType;
- ULONG uDot11PhyIndex;
- ULONG wlanSignalQuality;
- ULONG ulRxRate;
- ULONG ulTxRate;
-};
-
-struct WLAN_SECURITY_ATTRIBUTES {
- BOOL bSecurityEnabled;
- BOOL bOneXEnabled;
- DOT11_AUTH_ALGORITHM dot11AuthAlgorithm;
- DOT11_CIPHER_ALGORITHM dot11CipherAlgorithm;
-};
-
-struct WLAN_CONNECTION_ATTRIBUTES {
- WLAN_INTERFACE_STATE isState;
- WLAN_CONNECTION_MODE wlanConnectionMode;
- WCHAR strProfileName[WLAN_MAX_NAME_LENGTH];
- WLAN_ASSOCIATION_ATTRIBUTES wlanAssociationAttributes;
- WLAN_SECURITY_ATTRIBUTES wlanSecurityAttributes;
-};
-
-typedef void (WINAPI *WLAN_NOTIFICATION_CALLBACK)(WLAN_NOTIFICATION_DATA *, PVOID);
-
-typedef DWORD (WINAPI *WlanOpenHandleProto)
- (DWORD dwClientVersion, PVOID pReserved, PDWORD pdwNegotiatedVersion, PHANDLE phClientHandle);
-typedef DWORD (WINAPI *WlanRegisterNotificationProto)
- (HANDLE hClientHandle, DWORD dwNotifSource, BOOL bIgnoreDuplicate,
- WLAN_NOTIFICATION_CALLBACK funcCallback, PVOID pCallbackContext,
- PVOID pReserved, PDWORD pdwPrevNotifSource);
-typedef DWORD (WINAPI *WlanEnumInterfacesProto)
- (HANDLE hClientHandle, PVOID pReserved, WLAN_INTERFACE_INFO_LIST **ppInterfaceList);
-typedef DWORD (WINAPI *WlanGetAvailableNetworkListProto)
- (HANDLE hClientHandle, const GUID* pInterfaceGuid, DWORD dwFlags, PVOID pReserved,
- WLAN_AVAILABLE_NETWORK_LIST **ppAvailableNetworkList);
-typedef DWORD (WINAPI *WlanQueryInterfaceProto)
- (HANDLE hClientHandle, const GUID *pInterfaceGuid, WLAN_INTF_OPCODE OpCode, PVOID pReserved,
- PDWORD pdwDataSize, PVOID *ppData, WLAN_OPCODE_VALUE_TYPE *pWlanOpcodeValueType);
-typedef DWORD (WINAPI *WlanConnectProto)
- (HANDLE hClientHandle, const GUID *pInterfaceGuid,
- const WLAN_CONNECTION_PARAMETERS *pConnectionParameters, PVOID pReserved);
-typedef DWORD (WINAPI *WlanDisconnectProto)
- (HANDLE hClientHandle, const GUID *pInterfaceGuid, PVOID pReserved);
-typedef DWORD (WINAPI *WlanScanProto)
- (HANDLE hClientHandle, const GUID *pInterfaceGuid, const DOT11_SSID *pDot11Ssid,
- const WLAN_RAW_DATA *pIeData, PVOID pReserved);
-typedef VOID (WINAPI *WlanFreeMemoryProto)(PVOID pMemory);
-typedef DWORD (WINAPI *WlanCloseHandleProto)(HANDLE hClientHandle, PVOID pReserved);
-
-extern WlanOpenHandleProto local_WlanOpenHandle;
-extern WlanRegisterNotificationProto local_WlanRegisterNotification;
-extern WlanEnumInterfacesProto local_WlanEnumInterfaces;
-extern WlanGetAvailableNetworkListProto local_WlanGetAvailableNetworkList;
-extern WlanQueryInterfaceProto local_WlanQueryInterface;
-extern WlanConnectProto local_WlanConnect;
-extern WlanDisconnectProto local_WlanDisconnect;
-extern WlanScanProto local_WlanScan;
-extern WlanFreeMemoryProto local_WlanFreeMemory;
-extern WlanCloseHandleProto local_WlanCloseHandle;
-
-QT_END_NAMESPACE
-
-#endif // PLATFORMDEFS_H
diff --git a/src/plugins/bearer/nativewifi/qnativewifiengine.cpp b/src/plugins/bearer/nativewifi/qnativewifiengine.cpp
deleted file mode 100644
index ca8700e63b..0000000000
--- a/src/plugins/bearer/nativewifi/qnativewifiengine.cpp
+++ /dev/null
@@ -1,622 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 "qnativewifiengine.h"
-#include "platformdefs.h"
-#include <private/qnetworksession_impl_p.h>
-
-#include <QtNetwork/private/qnetworkconfiguration_p.h>
-
-#include <QtCore/qstringlist.h>
-#include <QtCore/qcoreapplication.h>
-#include <QtCore/qoperatingsystemversion.h>
-
-#include <QtCore/qdebug.h>
-
-#ifndef QT_NO_BEARERMANAGEMENT
-
-QT_BEGIN_NAMESPACE
-
-WlanOpenHandleProto local_WlanOpenHandle = 0;
-WlanRegisterNotificationProto local_WlanRegisterNotification = 0;
-WlanEnumInterfacesProto local_WlanEnumInterfaces = 0;
-WlanGetAvailableNetworkListProto local_WlanGetAvailableNetworkList = 0;
-WlanQueryInterfaceProto local_WlanQueryInterface = 0;
-WlanConnectProto local_WlanConnect = 0;
-WlanDisconnectProto local_WlanDisconnect = 0;
-WlanScanProto local_WlanScan = 0;
-WlanFreeMemoryProto local_WlanFreeMemory = 0;
-WlanCloseHandleProto local_WlanCloseHandle = 0;
-
-void qNotificationCallback(WLAN_NOTIFICATION_DATA *data, QNativeWifiEngine *d)
-{
- Q_UNUSED(d);
-
- if (data->NotificationSource == WLAN_NOTIFICATION_SOURCE_ACM) {
- switch (data->NotificationCode) {
- case wlan_notification_acm_connection_complete:
- case wlan_notification_acm_disconnected:
- case wlan_notification_acm_scan_complete:
- case wlan_notification_acm_scan_fail:
- QMetaObject::invokeMethod(d, "scanComplete", Qt::QueuedConnection);
- break;
- default:
-#ifdef BEARER_MANAGEMENT_DEBUG
- qDebug() << "wlan acm notification" << (int)data->NotificationCode;
-#endif
- break;
- }
- } else {
-#ifdef BEARER_MANAGEMENT_DEBUG
- qDebug() << "wlan notification source" << (int)data->NotificationSource << "code" << (int)data->NotificationCode;
-#endif
- }
-}
-
-QNativeWifiEngine::QNativeWifiEngine(QObject *parent)
-: QBearerEngineImpl(parent), handle(INVALID_HANDLE_VALUE)
-{
- connect(QCoreApplication::instance(), SIGNAL(aboutToQuit()), this, SLOT(closeHandle()));
-}
-
-QNativeWifiEngine::~QNativeWifiEngine()
-{
- closeHandle();
-}
-
-void QNativeWifiEngine::scanComplete()
-{
- QMutexLocker locker(&mutex);
-
- if (!available()) {
- locker.unlock();
- emit updateCompleted();
- return;
- }
-
- // enumerate interfaces
- WLAN_INTERFACE_INFO_LIST *interfaceList;
- DWORD result = local_WlanEnumInterfaces(handle, 0, &interfaceList);
- if (result != ERROR_SUCCESS) {
-#ifdef BEARER_MANAGEMENT_DEBUG
- qDebug("%s: WlanEnumInterfaces failed with error %ld\n", __FUNCTION__, result);
-#endif
-
- locker.unlock();
- emit updateCompleted();
-
- return;
- }
-
- QStringList previous = accessPointConfigurations.keys();
-
- for (unsigned int i = 0; i < interfaceList->dwNumberOfItems; ++i) {
- const WLAN_INTERFACE_INFO &interface = interfaceList->InterfaceInfo[i];
-
- WLAN_AVAILABLE_NETWORK_LIST *networkList;
- result = local_WlanGetAvailableNetworkList(handle, &interface.InterfaceGuid,
- 3, 0, &networkList);
- if (result != ERROR_SUCCESS) {
-#ifdef BEARER_MANAGEMENT_DEBUG
- qDebug("%s: WlanGetAvailableNetworkList failed with error %ld\n",
- __FUNCTION__, result);
-#endif
- continue;
- }
-
- QStringList seenNetworks;
-
- for (unsigned int j = 0; j < networkList->dwNumberOfItems; ++j) {
- WLAN_AVAILABLE_NETWORK &network = networkList->Network[j];
-
- QString networkName;
-
- if (network.strProfileName[0] != 0) {
- networkName = QString::fromWCharArray(network.strProfileName);
- } else {
- networkName = QByteArray(reinterpret_cast<char *>(network.dot11Ssid.ucSSID),
- network.dot11Ssid.uSSIDLength);
- }
-
- const QString id = QString::number(qHash(QLatin1String("WLAN:") + networkName));
-
- previous.removeAll(id);
-
- QNetworkConfiguration::StateFlags state = QNetworkConfiguration::Undefined;
-
- if (!(network.dwFlags & WLAN_AVAILABLE_NETWORK_HAS_PROFILE))
- state = QNetworkConfiguration::Undefined;
-
- if (network.strProfileName[0] != 0) {
- if (network.bNetworkConnectable) {
- if (network.dwFlags & WLAN_AVAILABLE_NETWORK_CONNECTED)
- state = QNetworkConfiguration::Active;
- else
- state = QNetworkConfiguration::Discovered;
- } else {
- state = QNetworkConfiguration::Defined;
- }
- }
-
- if (seenNetworks.contains(networkName))
- continue;
- else
- seenNetworks.append(networkName);
-
- if (accessPointConfigurations.contains(id)) {
- QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id);
-
- bool changed = false;
-
- ptr->mutex.lock();
-
- if (!ptr->isValid) {
- ptr->isValid = true;
- changed = true;
- }
-
- if (ptr->name != networkName) {
- ptr->name = networkName;
- changed = true;
- }
-
- if (ptr->state != state) {
- ptr->state = state;
- changed = true;
- }
-
- ptr->mutex.unlock();
-
- if (changed) {
- locker.unlock();
- emit configurationChanged(ptr);
- locker.relock();
- }
- } else {
- QNetworkConfigurationPrivatePointer ptr(new QNetworkConfigurationPrivate);
-
- ptr->name = networkName;
- ptr->isValid = true;
- ptr->id = id;
- ptr->state = state;
- ptr->type = QNetworkConfiguration::InternetAccessPoint;
- ptr->bearerType = QNetworkConfiguration::BearerWLAN;
-
- accessPointConfigurations.insert(id, ptr);
-
- locker.unlock();
- emit configurationAdded(ptr);
- locker.relock();
- }
- }
-
- local_WlanFreeMemory(networkList);
- }
-
- local_WlanFreeMemory(interfaceList);
-
- while (!previous.isEmpty()) {
- QNetworkConfigurationPrivatePointer ptr =
- accessPointConfigurations.take(previous.takeFirst());
-
- locker.unlock();
- emit configurationRemoved(ptr);
- locker.relock();
- }
-
- locker.unlock();
- emit updateCompleted();
-}
-
-QString QNativeWifiEngine::getInterfaceFromId(const QString &id)
-{
- QMutexLocker locker(&mutex);
-
- if (!available())
- return QString();
-
- // enumerate interfaces
- WLAN_INTERFACE_INFO_LIST *interfaceList;
- DWORD result = local_WlanEnumInterfaces(handle, 0, &interfaceList);
- if (result != ERROR_SUCCESS) {
-#ifdef BEARER_MANAGEMENT_DEBUG
- qDebug("%s: WlanEnumInterfaces failed with error %ld\n", __FUNCTION__, result);
-#endif
- return QString();
- }
-
- for (unsigned int i = 0; i < interfaceList->dwNumberOfItems; ++i) {
- const WLAN_INTERFACE_INFO &interface = interfaceList->InterfaceInfo[i];
-
- DWORD dataSize;
- WLAN_CONNECTION_ATTRIBUTES *connectionAttributes;
- result = local_WlanQueryInterface(handle, &interface.InterfaceGuid,
- wlan_intf_opcode_current_connection, 0, &dataSize,
- reinterpret_cast<PVOID *>(&connectionAttributes), 0);
- if (result != ERROR_SUCCESS) {
-#ifdef BEARER_MANAGEMENT_DEBUG
- if (result != ERROR_INVALID_STATE)
- qDebug("%s: WlanQueryInterface failed with error %ld\n", __FUNCTION__, result);
-#endif
-
- continue;
- }
-
- if (qHash(QLatin1String("WLAN:") +
- QString::fromWCharArray(connectionAttributes->strProfileName)) == id.toUInt()) {
- QString guid("{%1-%2-%3-%4%5-%6%7%8%9%10%11}");
-
- guid = guid.arg(interface.InterfaceGuid.Data1, 8, 16, QChar('0'));
- guid = guid.arg(interface.InterfaceGuid.Data2, 4, 16, QChar('0'));
- guid = guid.arg(interface.InterfaceGuid.Data3, 4, 16, QChar('0'));
- for (int i = 0; i < 8; ++i)
- guid = guid.arg(interface.InterfaceGuid.Data4[i], 2, 16, QChar('0'));
-
- local_WlanFreeMemory(connectionAttributes);
- local_WlanFreeMemory(interfaceList);
-
- return guid.toUpper();
- }
-
- local_WlanFreeMemory(connectionAttributes);
- }
-
- local_WlanFreeMemory(interfaceList);
-
- return QString();
-}
-
-bool QNativeWifiEngine::hasIdentifier(const QString &id)
-{
- QMutexLocker locker(&mutex);
-
- if (!available())
- return false;
-
- // enumerate interfaces
- WLAN_INTERFACE_INFO_LIST *interfaceList;
- DWORD result = local_WlanEnumInterfaces(handle, 0, &interfaceList);
- if (result != ERROR_SUCCESS) {
-#ifdef BEARER_MANAGEMENT_DEBUG
- qDebug("%s: WlanEnumInterfaces failed with error %ld\n", __FUNCTION__, result);
-#endif
- return false;
- }
-
- for (unsigned int i = 0; i < interfaceList->dwNumberOfItems; ++i) {
- const WLAN_INTERFACE_INFO &interface = interfaceList->InterfaceInfo[i];
-
- WLAN_AVAILABLE_NETWORK_LIST *networkList;
- result = local_WlanGetAvailableNetworkList(handle, &interface.InterfaceGuid,
- 3, 0, &networkList);
- if (result != ERROR_SUCCESS) {
-#ifdef BEARER_MANAGEMENT_DEBUG
- qDebug("%s: WlanGetAvailableNetworkList failed with error %ld\n",
- __FUNCTION__, result);
-#endif
- continue;
- }
-
- for (unsigned int j = 0; j < networkList->dwNumberOfItems; ++j) {
- WLAN_AVAILABLE_NETWORK &network = networkList->Network[j];
-
- QString networkName;
-
- if (network.strProfileName[0] != 0) {
- networkName = QString::fromWCharArray(network.strProfileName);
- } else {
- networkName = QByteArray(reinterpret_cast<char *>(network.dot11Ssid.ucSSID),
- network.dot11Ssid.uSSIDLength);
- }
-
- if (qHash(QLatin1String("WLAN:") + networkName) == id.toUInt()) {
- local_WlanFreeMemory(networkList);
- local_WlanFreeMemory(interfaceList);
- return true;
- }
- }
-
- local_WlanFreeMemory(networkList);
- }
-
- local_WlanFreeMemory(interfaceList);
-
- return false;
-}
-
-void QNativeWifiEngine::connectToId(const QString &id)
-{
- QMutexLocker locker(&mutex);
-
- if (!available()) {
- locker.unlock();
- emit connectionError(id, InterfaceLookupError);
- return;
- }
-
- WLAN_INTERFACE_INFO_LIST *interfaceList;
- DWORD result = local_WlanEnumInterfaces(handle, 0, &interfaceList);
- if (result != ERROR_SUCCESS) {
-#ifdef BEARER_MANAGEMENT_DEBUG
- qDebug("%s: WlanEnumInterfaces failed with error %ld\n", __FUNCTION__, result);
-#endif
- locker.unlock();
- emit connectionError(id, InterfaceLookupError);
- return;
- }
-
- QString profile;
-
- for (unsigned int i = 0; i < interfaceList->dwNumberOfItems; ++i) {
- const WLAN_INTERFACE_INFO &interface = interfaceList->InterfaceInfo[i];
-
- WLAN_AVAILABLE_NETWORK_LIST *networkList;
- result = local_WlanGetAvailableNetworkList(handle, &interface.InterfaceGuid,
- 3, 0, &networkList);
- if (result != ERROR_SUCCESS) {
-#ifdef BEARER_MANAGEMENT_DEBUG
- qDebug("%s: WlanGetAvailableNetworkList failed with error %ld\n",
- __FUNCTION__, result);
-#endif
- continue;
- }
-
- for (unsigned int j = 0; j < networkList->dwNumberOfItems; ++j) {
- WLAN_AVAILABLE_NETWORK &network = networkList->Network[j];
-
- profile = QString::fromWCharArray(network.strProfileName);
-
- if (qHash(QLatin1String("WLAN:") + profile) == id.toUInt())
- break;
- else
- profile.clear();
- }
-
- local_WlanFreeMemory(networkList);
-
- if (!profile.isEmpty()) {
- WLAN_CONNECTION_PARAMETERS parameters;
- parameters.wlanConnectionMode = wlan_connection_mode_profile;
- parameters.strProfile = reinterpret_cast<LPCWSTR>(profile.utf16());
- parameters.pDot11Ssid = 0;
- parameters.pDesiredBssidList = 0;
- parameters.dot11BssType = dot11_BSS_type_any;
- parameters.dwFlags = 0;
-
- DWORD result = local_WlanConnect(handle, &interface.InterfaceGuid, &parameters, 0);
- if (result != ERROR_SUCCESS) {
-#ifdef BEARER_MANAGEMENT_DEBUG
- qDebug("%s: WlanConnect failed with error %ld\n", __FUNCTION__, result);
-#endif
- locker.unlock();
- emit connectionError(id, ConnectError);
- locker.relock();
- break;
- }
-
- break;
- }
- }
-
- local_WlanFreeMemory(interfaceList);
-
- if (profile.isEmpty()) {
- locker.unlock();
- emit connectionError(id, InterfaceLookupError);
- }
-}
-
-void QNativeWifiEngine::disconnectFromId(const QString &id)
-{
- QMutexLocker locker(&mutex);
-
- if (!available()) {
- locker.unlock();
- emit connectionError(id, InterfaceLookupError);
- return;
- }
-
- QString interface = getInterfaceFromId(id);
-
- if (interface.isEmpty()) {
- locker.unlock();
- emit connectionError(id, InterfaceLookupError);
- return;
- }
-
- const QVector<QStringRef> split = interface.midRef(1, interface.length() - 2).split(QLatin1Char('-'));
-
- GUID guid;
- guid.Data1 = split.at(0).toUInt(0, 16);
- guid.Data2 = split.at(1).toUShort(0, 16);
- guid.Data3 = split.at(2).toUShort(0, 16);
- guid.Data4[0] = split.at(3).left(2).toUShort(0, 16);
- guid.Data4[1] = split.at(3).right(2).toUShort(0, 16);
- for (int i = 0; i < 6; ++i)
- guid.Data4[i + 2] = split.at(4).mid(i*2, 2).toUShort(0, 16);
-
- DWORD result = local_WlanDisconnect(handle, &guid, 0);
- if (result != ERROR_SUCCESS) {
-#ifdef BEARER_MANAGEMENT_DEBUG
- qDebug("%s: WlanDisconnect failed with error %ld\n", __FUNCTION__, result);
-#endif
- locker.unlock();
- emit connectionError(id, DisconnectionError);
- return;
- }
-}
-
-void QNativeWifiEngine::initialize()
-{
- scanComplete();
-}
-
-void QNativeWifiEngine::requestUpdate()
-{
- QMutexLocker locker(&mutex);
-
- if (!available()) {
- locker.unlock();
- emit updateCompleted();
- return;
- }
-
- // enumerate interfaces
- WLAN_INTERFACE_INFO_LIST *interfaceList;
- DWORD result = local_WlanEnumInterfaces(handle, 0, &interfaceList);
- if (result != ERROR_SUCCESS) {
-#ifdef BEARER_MANAGEMENT_DEBUG
- qDebug("%s: WlanEnumInterfaces failed with error %ld\n", __FUNCTION__, result);
-#endif
-
- locker.unlock();
- emit updateCompleted();
-
- return;
- }
-
- bool requested = false;
- for (unsigned int i = 0; i < interfaceList->dwNumberOfItems; ++i) {
- result = local_WlanScan(handle, &interfaceList->InterfaceInfo[i].InterfaceGuid, 0, 0, 0);
- if (result != ERROR_SUCCESS) {
-#ifdef BEARER_MANAGEMENT_DEBUG
- qDebug("%s: WlanScan failed with error %ld\n", __FUNCTION__, result);
-#endif
- } else {
- requested = true;
- }
- }
-
- local_WlanFreeMemory(interfaceList);
-
- if (!requested) {
- locker.unlock();
- emit updateCompleted();
- }
-}
-
-QNetworkSession::State QNativeWifiEngine::sessionStateForId(const QString &id)
-{
- QMutexLocker locker(&mutex);
-
- QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id);
-
- if (!ptr)
- return QNetworkSession::Invalid;
-
- if (!ptr->isValid) {
- return QNetworkSession::Invalid;
- } else if ((ptr->state & QNetworkConfiguration::Active) == QNetworkConfiguration::Active) {
- return QNetworkSession::Connected;
- } else if ((ptr->state & QNetworkConfiguration::Discovered) ==
- QNetworkConfiguration::Discovered) {
- return QNetworkSession::Disconnected;
- } else if ((ptr->state & QNetworkConfiguration::Defined) == QNetworkConfiguration::Defined) {
- return QNetworkSession::NotAvailable;
- } else if ((ptr->state & QNetworkConfiguration::Undefined) ==
- QNetworkConfiguration::Undefined) {
- return QNetworkSession::NotAvailable;
- }
-
- return QNetworkSession::Invalid;
-}
-
-QNetworkConfigurationManager::Capabilities QNativeWifiEngine::capabilities() const
-{
- return QNetworkConfigurationManager::ForcedRoaming |
- QNetworkConfigurationManager::CanStartAndStopInterfaces;
-}
-
-QNetworkSessionPrivate *QNativeWifiEngine::createSessionBackend()
-{
- return new QNetworkSessionPrivateImpl;
-}
-
-QNetworkConfigurationPrivatePointer QNativeWifiEngine::defaultConfiguration()
-{
- return QNetworkConfigurationPrivatePointer();
-}
-
-bool QNativeWifiEngine::available()
-{
- if (handle != INVALID_HANDLE_VALUE)
- return true;
-
- DWORD clientVersion;
-
- DWORD result = local_WlanOpenHandle(1, 0, &clientVersion, &handle);
- if (result != ERROR_SUCCESS) {
-#ifdef BEARER_MANAGEMENT_DEBUG
- if (result != ERROR_SERVICE_NOT_ACTIVE)
- qDebug("%s: WlanOpenHandle failed with error %ld\n", __FUNCTION__, result);
-#endif
-
- return false;
- }
-
- result = local_WlanRegisterNotification(handle, WLAN_NOTIFICATION_SOURCE_ALL, true,
- WLAN_NOTIFICATION_CALLBACK(qNotificationCallback),
- this, 0, 0);
-#ifdef BEARER_MANAGEMENT_DEBUG
- if (result != ERROR_SUCCESS)
- qDebug("%s: WlanRegisterNotification failed with error %ld\n", __FUNCTION__, result);
-#endif
-
- return handle != INVALID_HANDLE_VALUE;
-}
-
-void QNativeWifiEngine::closeHandle()
-{
- if (handle != INVALID_HANDLE_VALUE) {
- local_WlanCloseHandle(handle, 0);
- handle = INVALID_HANDLE_VALUE;
- }
-}
-
-bool QNativeWifiEngine::requiresPolling() const
-{
- // On Windows XP SP2 and SP3 only connection and disconnection notifications are available.
- // We need to poll for changes in available wireless networks.
- return QOperatingSystemVersion::current()
- <= QOperatingSystemVersion(QOperatingSystemVersion::Windows, 5, 2);
-}
-
-QT_END_NAMESPACE
-
-#endif // QT_NO_BEARERMANAGEMENT
diff --git a/src/plugins/bearer/nativewifi/qnativewifiengine.h b/src/plugins/bearer/nativewifi/qnativewifiengine.h
deleted file mode 100644
index 24e97bf6df..0000000000
--- a/src/plugins/bearer/nativewifi/qnativewifiengine.h
+++ /dev/null
@@ -1,106 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 QNATIVEWIFIENGINE_P_H
-#define QNATIVEWIFIENGINE_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 <private/qbearerengine_impl_p.h>
-
-#include <QtCore/qtimer.h>
-
-#ifndef QT_NO_BEARERMANAGEMENT
-
-QT_BEGIN_NAMESPACE
-
-class QNetworkConfigurationPrivate;
-struct WLAN_NOTIFICATION_DATA;
-
-class QNativeWifiEngine : public QBearerEngineImpl
-{
- Q_OBJECT
-
-public:
- QNativeWifiEngine(QObject *parent = 0);
- ~QNativeWifiEngine();
-
- QString getInterfaceFromId(const QString &id);
- bool hasIdentifier(const QString &id);
-
- void connectToId(const QString &id);
- void disconnectFromId(const QString &id);
-
- Q_INVOKABLE void initialize();
- Q_INVOKABLE void requestUpdate();
-
- QNetworkSession::State sessionStateForId(const QString &id);
-
- QNetworkConfigurationManager::Capabilities capabilities() const;
-
- QNetworkSessionPrivate *createSessionBackend();
-
- QNetworkConfigurationPrivatePointer defaultConfiguration();
-
- bool available();
-
- bool requiresPolling() const;
-
-private Q_SLOTS:
- void scanComplete();
- void closeHandle();
-
-private:
- Qt::HANDLE handle;
-};
-
-QT_END_NAMESPACE
-
-#endif // QT_NO_BEARERMANAGEMENT
-
-#endif
diff --git a/src/plugins/bearer/networkmanager/.prev_CMakeLists.txt b/src/plugins/bearer/networkmanager/.prev_CMakeLists.txt
deleted file mode 100644
index df5927024d..0000000000
--- a/src/plugins/bearer/networkmanager/.prev_CMakeLists.txt
+++ /dev/null
@@ -1,26 +0,0 @@
-# Generated from networkmanager.pro.
-
-#####################################################################
-## QNetworkManagerEnginePlugin Plugin:
-#####################################################################
-
-qt_add_plugin(QNetworkManagerEnginePlugin
- OUTPUT_NAME qnmbearer
- CLASS_NAME QNetworkManagerEnginePlugin
- TYPE bearer
- SOURCES
- main.cpp
- qnetworkmanagerengine.cpp qnetworkmanagerengine.h
- qnetworkmanagerservice.cpp qnetworkmanagerservice.h
- LIBRARIES
- Qt::LinuxOfonoSupportPrivate
- Qt::NetworkPrivate
- PUBLIC_LIBRARIES
- Qt::Core
- Qt::DBus
- Qt::LinuxOfonoSupport
- Qt::Network
-)
-
-#### Keys ignored in scope 1:.:.:networkmanager.pro:<TRUE>:
-# OTHER_FILES = "networkmanager.json"
diff --git a/src/plugins/bearer/networkmanager/CMakeLists.txt b/src/plugins/bearer/networkmanager/CMakeLists.txt
deleted file mode 100644
index 8f26a4c86d..0000000000
--- a/src/plugins/bearer/networkmanager/CMakeLists.txt
+++ /dev/null
@@ -1,22 +0,0 @@
-# Generated from networkmanager.pro.
-
-#####################################################################
-## QNetworkManagerEnginePlugin Plugin:
-#####################################################################
-
-qt_add_plugin(QNetworkManagerEnginePlugin
- OUTPUT_NAME qnmbearer
- TYPE bearer
- SOURCES
- main.cpp
- qnetworkmanagerengine.cpp qnetworkmanagerengine.h
- qnetworkmanagerservice.cpp qnetworkmanagerservice.h
- PUBLIC_LIBRARIES
- Qt::Core
- Qt::DBus
- Qt::LinuxOfonoSupportPrivate
- Qt::NetworkPrivate
-)
-
-#### Keys ignored in scope 1:.:.:networkmanager.pro:<TRUE>:
-# OTHER_FILES = "networkmanager.json"
diff --git a/src/plugins/bearer/networkmanager/main.cpp b/src/plugins/bearer/networkmanager/main.cpp
deleted file mode 100644
index 1773abe55b..0000000000
--- a/src/plugins/bearer/networkmanager/main.cpp
+++ /dev/null
@@ -1,84 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 "qnetworkmanagerengine.h"
-
-#include <QtNetwork/private/qbearerplugin_p.h>
-
-#include <QtCore/qdebug.h>
-
-#ifndef QT_NO_DBUS
-
-QT_BEGIN_NAMESPACE
-
-class QNetworkManagerEnginePlugin : public QBearerEnginePlugin
-{
- Q_OBJECT
- Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QBearerEngineFactoryInterface" FILE "networkmanager.json")
-
-public:
- QNetworkManagerEnginePlugin();
- ~QNetworkManagerEnginePlugin();
-
- QBearerEngine *create(const QString &key) const;
-};
-
-QNetworkManagerEnginePlugin::QNetworkManagerEnginePlugin()
-{
-}
-
-QNetworkManagerEnginePlugin::~QNetworkManagerEnginePlugin()
-{
-}
-
-QBearerEngine *QNetworkManagerEnginePlugin::create(const QString &key) const
-{
- if (key == QLatin1String("networkmanager")) {
- QNetworkManagerEngine *engine = new QNetworkManagerEngine;
- return engine;
- }
-
- return 0;
-}
-
-QT_END_NAMESPACE
-
-#include "main.moc"
-
-#endif // QT_NO_DBUS
diff --git a/src/plugins/bearer/networkmanager/networkmanager.json b/src/plugins/bearer/networkmanager/networkmanager.json
deleted file mode 100644
index 3d408d5c20..0000000000
--- a/src/plugins/bearer/networkmanager/networkmanager.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "Keys": [ "networkmanager" ]
-}
diff --git a/src/plugins/bearer/networkmanager/networkmanager.pro b/src/plugins/bearer/networkmanager/networkmanager.pro
deleted file mode 100644
index 3ca217f974..0000000000
--- a/src/plugins/bearer/networkmanager/networkmanager.pro
+++ /dev/null
@@ -1,16 +0,0 @@
-TARGET = qnmbearer
-
-QT = core network-private dbus linuxofono_support_private
-
-HEADERS += qnetworkmanagerservice.h \
- qnetworkmanagerengine.h
-
-SOURCES += main.cpp \
- qnetworkmanagerservice.cpp \
- qnetworkmanagerengine.cpp
-
-OTHER_FILES += networkmanager.json
-
-PLUGIN_TYPE = bearer
-PLUGIN_CLASS_NAME = QNetworkManagerEnginePlugin
-load(qt_plugin)
diff --git a/src/plugins/bearer/networkmanager/qnetworkmanagerengine.cpp b/src/plugins/bearer/networkmanager/qnetworkmanagerengine.cpp
deleted file mode 100644
index cba2221587..0000000000
--- a/src/plugins/bearer/networkmanager/qnetworkmanagerengine.cpp
+++ /dev/null
@@ -1,935 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 "qnetworkmanagerengine.h"
-#include "qnetworkmanagerservice.h"
-#include <private/qnetworksession_impl_p.h>
-
-#include <QtNetwork/private/qnetworkconfiguration_p.h>
-
-#include <QtNetwork/qnetworksession.h>
-
-#include <QtCore/qdebug.h>
-
-#include <QtDBus>
-#include <QDBusConnection>
-#include <QDBusError>
-#include <QDBusInterface>
-#include <QDBusMessage>
-#include <QDBusReply>
-
-#ifndef QT_NO_DBUS
-
-QT_BEGIN_NAMESPACE
-
-QNetworkManagerEngine::QNetworkManagerEngine(QObject *parent)
-: QBearerEngineImpl(parent),
- managerInterface(NULL),
- systemSettings(NULL),
- ofonoManager(NULL),
- nmAvailable(false)
-{
- qDBusRegisterMetaType<QNmSettingsMap>();
-
- nmWatcher = new QDBusServiceWatcher(NM_DBUS_SERVICE,QDBusConnection::systemBus(),
- QDBusServiceWatcher::WatchForRegistration |
- QDBusServiceWatcher::WatchForUnregistration, this);
- connect(nmWatcher, SIGNAL(serviceRegistered(QString)),
- this, SLOT(nmRegistered(QString)));
- connect(nmWatcher, SIGNAL(serviceUnregistered(QString)),
- this, SLOT(nmUnRegistered(QString)));
-
- ofonoWatcher = new QDBusServiceWatcher("org.ofono",QDBusConnection::systemBus(),
- QDBusServiceWatcher::WatchForRegistration |
- QDBusServiceWatcher::WatchForUnregistration, this);
- connect(ofonoWatcher, SIGNAL(serviceRegistered(QString)),
- this, SLOT(ofonoRegistered(QString)));
- connect(ofonoWatcher, SIGNAL(serviceUnregistered(QString)),
- this, SLOT(ofonoUnRegistered(QString)));
-
- QDBusConnectionInterface *interface = QDBusConnection::systemBus().interface();
-
- if (!interface) return;
-
- if (interface->isServiceRegistered("org.ofono"))
- QMetaObject::invokeMethod(this, "ofonoRegistered", Qt::QueuedConnection);
-
- if (interface->isServiceRegistered(NM_DBUS_SERVICE))
- QMetaObject::invokeMethod(this, "nmRegistered", Qt::QueuedConnection);
-}
-
-QNetworkManagerEngine::~QNetworkManagerEngine()
-{
- qDeleteAll(connections);
- connections.clear();
- qDeleteAll(accessPoints);
- accessPoints.clear();
- qDeleteAll(wirelessDevices);
- wirelessDevices.clear();
- qDeleteAll(activeConnectionsList);
- activeConnectionsList.clear();
- qDeleteAll(interfaceDevices);
- interfaceDevices.clear();
-
- connectionInterfaces.clear();
-
- qDeleteAll(ofonoContextManagers);
- ofonoContextManagers.clear();
-
- qDeleteAll(wiredDevices);
- wiredDevices.clear();
-}
-
-void QNetworkManagerEngine::initialize()
-{
- if (nmAvailable)
- setupConfigurations();
-}
-
-void QNetworkManagerEngine::setupConfigurations()
-{
- QMutexLocker locker(&mutex);
- // Get active connections.
- const auto acPaths = managerInterface->activeConnections();
- for (const QDBusObjectPath &acPath : acPaths) {
-
- if (activeConnectionsList.contains(acPath.path()))
- continue;
-
- QNetworkManagerConnectionActive *activeConnection =
- new QNetworkManagerConnectionActive(acPath.path(),this);
- activeConnectionsList.insert(acPath.path(), activeConnection);
- connect(activeConnection, SIGNAL(propertiesChanged(QMap<QString,QVariant>)),
- this, SLOT(activeConnectionPropertiesChanged(QMap<QString,QVariant>)));
-
- QStringList devices = activeConnection->devices();
- if (!devices.isEmpty()) {
- QNetworkManagerInterfaceDevice device(devices.at(0),this);
- connectionInterfaces.insert(activeConnection->connection().path(),device.networkInterface());
- }
- }
-
- // Get connections.
- const auto settingsPaths = systemSettings->listConnections();
- for (const QDBusObjectPath &settingsPath : settingsPaths) {
- locker.unlock();
- if (!hasIdentifier(settingsPath.path()))
- newConnection(settingsPath, systemSettings); //add system connection configs
- locker.relock();
- }
-
- Q_EMIT updateCompleted();
-}
-
-bool QNetworkManagerEngine::networkManagerAvailable() const
-{
- return nmAvailable;
-}
-
-QString QNetworkManagerEngine::getInterfaceFromId(const QString &settingsPath)
-{
- return connectionInterfaces.value(settingsPath);
-}
-
-bool QNetworkManagerEngine::hasIdentifier(const QString &id)
-{
- QMutexLocker locker(&mutex);
- return accessPointConfigurations.contains(id);
-}
-
-void QNetworkManagerEngine::connectToId(const QString &id)
-{
- QMutexLocker locker(&mutex);
-
- QNetworkManagerSettingsConnection *connection = connectionFromId(id);
-
- if (!connection)
- return;
-
- NMDeviceType connectionType = connection->getType();
-
- QString dbusDevicePath;
- const QString settingsPath = connection->path();
- QString specificPath = configuredAccessPoints.key(settingsPath);
-
- if (isConnectionActive(settingsPath))
- return;
-
- for (auto i = interfaceDevices.cbegin(), end = interfaceDevices.cend(); i != end; ++i) {
- const auto type = i.value()->deviceType();
- if (type == DEVICE_TYPE_ETHERNET || type == DEVICE_TYPE_WIFI || type == DEVICE_TYPE_MODEM) {
- if (type == connectionType) {
- dbusDevicePath = i.key();
- break;
- }
- }
- }
-
- if (specificPath.isEmpty())
- specificPath = "/";
-
- managerInterface->activateConnection(QDBusObjectPath(settingsPath),
- QDBusObjectPath(dbusDevicePath), QDBusObjectPath(specificPath));
-}
-
-void QNetworkManagerEngine::disconnectFromId(const QString &id)
-{
- QMutexLocker locker(&mutex);
-
- QNetworkManagerSettingsConnection *connection = connectionFromId(id);
-
- if (!connection)
- return;
-
- QNmSettingsMap map = connection->getSettings();
- bool connectionAutoconnect = map.value("connection").value("autoconnect",true).toBool(); //if not present is true !!
- if (connectionAutoconnect) { //autoconnect connections will simply be reconnected by nm
- emit connectionError(id, QBearerEngineImpl::OperationNotSupported);
- return;
- }
-
- for (auto i = activeConnectionsList.cbegin(), end = activeConnectionsList.cend(); i != end; ++i) {
- if (id == i.value()->connection().path() && accessPointConfigurations.contains(id)) {
- managerInterface->deactivateConnection(QDBusObjectPath(i.key()));
- break;
- }
- }
-}
-
-void QNetworkManagerEngine::requestUpdate()
-{
- if (managerInterface && managerInterface->wirelessEnabled()) {
- for (auto *wirelessDevice : qAsConst(wirelessDevices))
- wirelessDevice->requestScan();
- }
- QMetaObject::invokeMethod(this, "updateCompleted", Qt::QueuedConnection);
-}
-
-void QNetworkManagerEngine::interfacePropertiesChanged(const QMap<QString, QVariant> &properties)
-{
- QMutexLocker locker(&mutex);
-
- for (auto i = properties.cbegin(), end = properties.cend(); i != end; ++i) {
- if (i.key() == QLatin1String("ActiveConnections")) {
- // Active connections changed, update configurations.
-
- const auto activeConnections = qdbus_cast<QList<QDBusObjectPath> >(qvariant_cast<QDBusArgument>(i.value()));
-
- QStringList identifiers = accessPointConfigurations.keys();
- QStringList priorActiveConnections = activeConnectionsList.keys();
-
- for (const QDBusObjectPath &acPath : activeConnections) {
- priorActiveConnections.removeOne(acPath.path());
- QNetworkManagerConnectionActive *activeConnection =
- activeConnectionsList.value(acPath.path());
-
- if (!activeConnection) {
- activeConnection = new QNetworkManagerConnectionActive(acPath.path(),this);
- activeConnectionsList.insert(acPath.path(), activeConnection);
-
- connect(activeConnection, SIGNAL(propertiesChanged(QMap<QString,QVariant>)),
- this, SLOT(activeConnectionPropertiesChanged(QMap<QString,QVariant>)));
- }
-
- const QString id = activeConnection->connection().path();
-
- identifiers.removeOne(id);
-
- QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id);
- if (ptr) {
- ptr->mutex.lock();
- if (activeConnection->state() == NM_ACTIVE_CONNECTION_STATE_ACTIVATED &&
- (ptr->state & QNetworkConfiguration::Active) != QNetworkConfiguration::Active) {
-
- ptr->state |= QNetworkConfiguration::Active;
-
- if (activeConnectionsList.value(id) && activeConnectionsList.value(id)->defaultRoute()
- && managerInterface->state() < QNetworkManagerInterface::NM_STATE_CONNECTED_GLOBAL) {
- ptr->purpose = QNetworkConfiguration::PrivatePurpose;
- }
- ptr->mutex.unlock();
-
- locker.unlock();
- emit configurationChanged(ptr);
- locker.relock();
- } else {
- ptr->mutex.unlock();
- }
- }
- }
-
- while (!priorActiveConnections.isEmpty())
- delete activeConnectionsList.take(priorActiveConnections.takeFirst());
-
- while (!identifiers.isEmpty()) {
- QNetworkConfigurationPrivatePointer ptr =
- accessPointConfigurations.value(identifiers.takeFirst());
-
- ptr->mutex.lock();
- if ((ptr->state & QNetworkConfiguration::Active) == QNetworkConfiguration::Active) {
- QNetworkConfiguration::StateFlags flag = QNetworkConfiguration::Defined;
- ptr->state = (flag | QNetworkConfiguration::Discovered);
- ptr->mutex.unlock();
-
- locker.unlock();
- emit configurationChanged(ptr);
- locker.relock();
- } else {
- ptr->mutex.unlock();
- }
- }
- }
- }
-}
-
-void QNetworkManagerEngine::activeConnectionPropertiesChanged(const QMap<QString, QVariant> &properties)
-{
- QMutexLocker locker(&mutex);
-
- Q_UNUSED(properties)
-
- QNetworkManagerConnectionActive *activeConnection = qobject_cast<QNetworkManagerConnectionActive *>(sender());
-
- if (!activeConnection)
- return;
-
- const QString id = activeConnection->connection().path();
-
- QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id);
- if (ptr) {
- if (properties.contains(QStringLiteral("State"))) {
- ptr->mutex.lock();
- if (properties.value("State").toUInt() == NM_ACTIVE_CONNECTION_STATE_ACTIVATED) {
- QStringList devices = activeConnection->devices();
- if (!devices.isEmpty()) {
- QNetworkManagerInterfaceDevice device(devices.at(0),this);
- connectionInterfaces.insert(id,device.networkInterface());
- }
-
- ptr->state |= QNetworkConfiguration::Active;
- ptr->mutex.unlock();
-
- locker.unlock();
- emit configurationChanged(ptr);
- locker.relock();
- } else {
- connectionInterfaces.remove(id);
- ptr->mutex.unlock();
- }
- }
- }
-}
-
-void QNetworkManagerEngine::deviceConnectionsChanged(const QStringList &connectionsList)
-{
- QMutexLocker locker(&mutex);
- for (int i = 0; i < connections.count(); ++i) {
- if (connectionsList.contains(connections.at(i)->path()))
- continue;
-
- const QString settingsPath = connections.at(i)->path();
-
- QNetworkConfigurationPrivatePointer ptr =
- accessPointConfigurations.value(settingsPath);
- ptr->mutex.lock();
- QNetworkConfiguration::StateFlags flag = QNetworkConfiguration::Defined;
- ptr->state = (flag | QNetworkConfiguration::Discovered);
- ptr->mutex.unlock();
-
- locker.unlock();
- emit configurationChanged(ptr);
- locker.relock();
- Q_EMIT updateCompleted();
- }
-}
-
-void QNetworkManagerEngine::wiredCarrierChanged(bool carrier)
-{
- QNetworkManagerInterfaceDeviceWired *deviceWired = qobject_cast<QNetworkManagerInterfaceDeviceWired *>(sender());
- if (!deviceWired)
- return;
- QMutexLocker locker(&mutex);
- const auto settingsPaths = systemSettings->listConnections();
- for (const QDBusObjectPath &settingsPath : settingsPaths) {
- for (int i = 0; i < connections.count(); ++i) {
- QNetworkManagerSettingsConnection *connection = connections.at(i);
- if (connection->getType() == DEVICE_TYPE_ETHERNET
- && settingsPath.path() == connection->path()) {
- QNetworkConfigurationPrivatePointer ptr =
- accessPointConfigurations.value(settingsPath.path());
-
- if (ptr) {
- ptr->mutex.lock();
- if (carrier)
- ptr->state |= QNetworkConfiguration::Discovered;
- else
- ptr->state = QNetworkConfiguration::Defined;
- ptr->mutex.unlock();
- locker.unlock();
- emit configurationChanged(ptr);
- return;
- }
- }
- }
- }
-}
-
-void QNetworkManagerEngine::newConnection(const QDBusObjectPath &path,
- QNetworkManagerSettings *settings)
-{
- QMutexLocker locker(&mutex);
- if (!settings)
- settings = qobject_cast<QNetworkManagerSettings *>(sender());
-
- if (!settings) {
- return;
- }
-
- QNetworkManagerSettingsConnection *connection =
- new QNetworkManagerSettingsConnection(settings->service(),
- path.path(),this);
- const QString settingsPath = connection->path();
- if (accessPointConfigurations.contains(settingsPath)) {
- return;
- }
-
- connections.append(connection);
-
- connect(connection,SIGNAL(removed(QString)),this,SLOT(removeConnection(QString)));
- connect(connection,SIGNAL(updated()),this,SLOT(updateConnection()));
- connection->setConnections();
-
- NMDeviceType deviceType = connection->getType();
-
- if (deviceType == DEVICE_TYPE_WIFI) {
- QString apPath;
- for (int i = 0; i < accessPoints.count(); ++i) {
- if (connection->getSsid() == accessPoints.at(i)->ssid()) {
- // remove the corresponding accesspoint from configurations
- apPath = accessPoints.at(i)->path();
- QNetworkConfigurationPrivatePointer ptr
- = accessPointConfigurations.take(apPath);
- if (ptr) {
- locker.unlock();
- emit configurationRemoved(ptr);
- locker.relock();
- }
- }
- }
- if (!configuredAccessPoints.contains(settingsPath))
- configuredAccessPoints.insert(apPath,settingsPath);
- }
-
- QNetworkConfigurationPrivate *cpPriv =
- parseConnection(settingsPath, connection->getSettings());
-
- // Check if connection is active.
- if (isConnectionActive(settingsPath))
- cpPriv->state |= QNetworkConfiguration::Active;
-
- if (deviceType == DEVICE_TYPE_ETHERNET) {
- for (auto interfaceDevice : qAsConst(interfaceDevices)) {
- if (interfaceDevice->deviceType() == deviceType) {
- auto *wiredDevice = wiredDevices.value(interfaceDevice->path());
- if (wiredDevice && wiredDevice->carrier()) {
- cpPriv->state |= QNetworkConfiguration::Discovered;
- }
- }
- }
- }
-
- QNetworkConfigurationPrivatePointer ptr(cpPriv);
- accessPointConfigurations.insert(ptr->id, ptr);
- locker.unlock();
- emit configurationAdded(ptr);
-}
-
-bool QNetworkManagerEngine::isConnectionActive(const QString &settingsPath) const
-{
- for (QNetworkManagerConnectionActive *activeConnection : activeConnectionsList) {
- if (activeConnection->connection().path() == settingsPath) {
- const auto state = activeConnection->state();
- if (state == NM_ACTIVE_CONNECTION_STATE_ACTIVATING
- || state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED) {
- return true;
- } else {
- break;
- }
- }
- }
-
- QNetworkManagerSettingsConnection *settingsConnection = connectionFromId(settingsPath);
- if (settingsConnection && settingsConnection->getType() == DEVICE_TYPE_MODEM) {
- return isActiveContext(settingsConnection->path());
- }
-
- return false;
-}
-
-void QNetworkManagerEngine::removeConnection(const QString &path)
-{
- QMutexLocker locker(&mutex);
-
- QNetworkManagerSettingsConnection *connection =
- qobject_cast<QNetworkManagerSettingsConnection *>(sender());
-
- if (!connection)
- return;
-
- connection->deleteLater();
- connections.removeAll(connection);
-
- const QString id = path;
-
- QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.take(id);
-
- if (ptr) {
- locker.unlock();
- emit configurationRemoved(ptr);
- locker.relock();
- }
-
- // add base AP back into configurations
-
- // removed along with all AP props code...
-}
-
-void QNetworkManagerEngine::updateConnection()
-{
- QMutexLocker locker(&mutex);
-
- QNetworkManagerSettingsConnection *connection =
- qobject_cast<QNetworkManagerSettingsConnection *>(sender());
- if (!connection)
- return;
- const QString settingsPath = connection->path();
-
- QNetworkConfigurationPrivate *cpPriv = parseConnection(settingsPath, connection->getSettings());
-
- // Check if connection is active.
- const auto acPaths = managerInterface->activeConnections();
- for (const QDBusObjectPath &acPath : acPaths) {
- QNetworkManagerConnectionActive activeConnection(acPath.path());
-
- if (activeConnection.connection().path() == settingsPath &&
- activeConnection.state() == NM_ACTIVE_CONNECTION_STATE_ACTIVATED) {
- cpPriv->state |= QNetworkConfiguration::Active;
- break;
- }
- }
-
- QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(cpPriv->id);
-
- ptr->mutex.lock();
-
- ptr->isValid = cpPriv->isValid;
- ptr->name = cpPriv->name;
- ptr->id = cpPriv->id;
- ptr->state = cpPriv->state;
-
- ptr->mutex.unlock();
-
- locker.unlock();
- emit configurationChanged(ptr);
- locker.relock();
- delete cpPriv;
-}
-
-void QNetworkManagerEngine::activationFinished(QDBusPendingCallWatcher *watcher)
-{
- QMutexLocker locker(&mutex);
- QDBusPendingReply<QDBusObjectPath> reply(*watcher);
- watcher->deleteLater();
-
- if (!reply.isError()) {
- QDBusObjectPath result = reply.value();
-
- QNetworkManagerConnectionActive activeConnection(result.path());
-
- const QString id = activeConnection.connection().path();
-
- QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id);
- if (ptr) {
- ptr->mutex.lock();
- if (activeConnection.state() == NM_ACTIVE_CONNECTION_STATE_ACTIVATED &&
- ptr->state != QNetworkConfiguration::Active) {
- ptr->state |= QNetworkConfiguration::Active;
- ptr->mutex.unlock();
-
- locker.unlock();
- emit configurationChanged(ptr);
- locker.relock();
- } else {
- ptr->mutex.unlock();
- }
- }
- }
-}
-
-QNetworkConfigurationPrivate *QNetworkManagerEngine::parseConnection(const QString &settingsPath,
- const QNmSettingsMap &map)
-{
- QMutexLocker locker(&mutex);
- QNetworkConfigurationPrivate *cpPriv = new QNetworkConfigurationPrivate;
- cpPriv->name = map.value("connection").value("id").toString();
- cpPriv->isValid = true;
- cpPriv->id = settingsPath;
- cpPriv->type = QNetworkConfiguration::InternetAccessPoint;
-
- cpPriv->purpose = QNetworkConfiguration::PublicPurpose;
-
- cpPriv->state = QNetworkConfiguration::Defined;
- const QString connectionType = map.value("connection").value("type").toString();
-
- if (connectionType == QLatin1String("802-3-ethernet")) {
- cpPriv->bearerType = QNetworkConfiguration::BearerEthernet;
-
- const auto devicePaths = managerInterface->getDevices();
- for (const QDBusObjectPath &devicePath : devicePaths) {
- QNetworkManagerInterfaceDevice device(devicePath.path(),this);
- if (device.deviceType() == DEVICE_TYPE_ETHERNET) {
- QNetworkManagerInterfaceDeviceWired *wiredDevice = wiredDevices.value(device.path());
- if (wiredDevice && wiredDevice->carrier()) {
- cpPriv->state |= QNetworkConfiguration::Discovered;
- break;
- }
- }
- }
- } else if (connectionType == QLatin1String("802-11-wireless")) {
- cpPriv->bearerType = QNetworkConfiguration::BearerWLAN;
-
- const QString connectionSsid = map.value("802-11-wireless").value("ssid").toString();
- for (int i = 0; i < accessPoints.count(); ++i) {
- if (connectionSsid == accessPoints.at(i)->ssid()
- && map.value("802-11-wireless").value("seen-bssids").toStringList().contains(accessPoints.at(i)->hwAddress())) {
- cpPriv->state |= QNetworkConfiguration::Discovered;
- if (!configuredAccessPoints.contains(accessPoints.at(i)->path())) {
- configuredAccessPoints.insert(accessPoints.at(i)->path(),settingsPath);
-
- const QString accessPointId = accessPoints.at(i)->path();
- QNetworkConfigurationPrivatePointer ptr =
- accessPointConfigurations.take(accessPointId);
-
- if (ptr) {
- locker.unlock();
- emit configurationRemoved(ptr);
- locker.relock();
- }
- }
- break;
- }
- }
- } else if (connectionType == QLatin1String("gsm")) {
-
- const QString connectionPath = map.value("connection").value("id").toString();
- cpPriv->name = contextName(connectionPath);
- cpPriv->bearerType = currentBearerType(connectionPath);
-
- if (ofonoManager && ofonoManager->isValid()) {
- const QString contextPart = connectionPath.section('/', -1);
- for (auto i = ofonoContextManagers.cbegin(), end = ofonoContextManagers.cend(); i != end; ++i) {
- const QString path = i.key() + QLatin1Char('/') +contextPart;
- if (isActiveContext(path)) {
- cpPriv->state |= QNetworkConfiguration::Active;
- break;
- }
- }
- }
- }
-
- return cpPriv;
-}
-
-bool QNetworkManagerEngine::isActiveContext(const QString &contextPath) const
-{
- if (ofonoManager && ofonoManager->isValid()) {
- const QString contextPart = contextPath.section('/', -1);
- for (QOfonoDataConnectionManagerInterface *iface : ofonoContextManagers) {
- const PathPropertiesList list = iface->contextsWithProperties();
- for (int i = 0; i < list.size(); ++i) {
- if (list.at(i).path.path().contains(contextPart)) {
- return list.at(i).properties.value(QStringLiteral("Active")).toBool();
-
- }
- }
- }
- }
- return false;
-}
-
-QNetworkManagerSettingsConnection *QNetworkManagerEngine::connectionFromId(const QString &id) const
-{
- for (int i = 0; i < connections.count(); ++i) {
- QNetworkManagerSettingsConnection *connection = connections.at(i);
- if (id == connection->path())
- return connection;
- }
-
- return 0;
-}
-
-QNetworkSession::State QNetworkManagerEngine::sessionStateForId(const QString &id)
-{
- QMutexLocker locker(&mutex);
- QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id);
-
- if (!ptr)
- return QNetworkSession::Invalid;
-
- if (!ptr->isValid)
- return QNetworkSession::Invalid;
-
- for (QNetworkManagerConnectionActive *activeConnection : qAsConst(activeConnectionsList)) {
- const QString identifier = activeConnection->connection().path();
-
- if (id == identifier) {
- switch (activeConnection->state()) {
- case 0:
- return QNetworkSession::Disconnected;
- case 1:
- return QNetworkSession::Connecting;
- case 2:
- return QNetworkSession::Connected;
- }
- }
- }
-
- if ((ptr->state & QNetworkConfiguration::Discovered) == QNetworkConfiguration::Discovered)
- return QNetworkSession::Disconnected;
- else if ((ptr->state & QNetworkConfiguration::Defined) == QNetworkConfiguration::Defined)
- return QNetworkSession::NotAvailable;
- else if ((ptr->state & QNetworkConfiguration::Undefined) == QNetworkConfiguration::Undefined)
- return QNetworkSession::NotAvailable;
-
- return QNetworkSession::Invalid;
-}
-
-quint64 QNetworkManagerEngine::bytesWritten(const QString &id)
-{
- QMutexLocker locker(&mutex);
-
- QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id);
- if (ptr && (ptr->state & QNetworkConfiguration::Active) == QNetworkConfiguration::Active) {
- const QString networkInterface = connectionInterfaces.value(id);
- if (!networkInterface.isEmpty()) {
- const QString devFile = QLatin1String("/sys/class/net/") +
- networkInterface +
- QLatin1String("/statistics/tx_bytes");
-
- quint64 result = Q_UINT64_C(0);
-
- QFile tx(devFile);
- if (tx.open(QIODevice::ReadOnly | QIODevice::Text)) {
- QTextStream in(&tx);
- in >> result;
- tx.close();
- }
-
- return result;
- }
- }
-
- return Q_UINT64_C(0);
-}
-
-quint64 QNetworkManagerEngine::bytesReceived(const QString &id)
-{
- QMutexLocker locker(&mutex);
-
- QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id);
- if (ptr && (ptr->state & QNetworkConfiguration::Active) == QNetworkConfiguration::Active) {
- const QString networkInterface = connectionInterfaces.value(id);
- if (!networkInterface.isEmpty()) {
- const QString devFile = QLatin1String("/sys/class/net/") +
- networkInterface +
- QLatin1String("/statistics/rx_bytes");
-
- quint64 result = Q_UINT64_C(0);
-
- QFile tx(devFile);
- if (tx.open(QIODevice::ReadOnly | QIODevice::Text)) {
- QTextStream in(&tx);
- in >> result;
- tx.close();
- }
-
- return result;
- }
- }
-
- return Q_UINT64_C(0);
-}
-
-quint64 QNetworkManagerEngine::startTime(const QString &id)
-{
- QMutexLocker locker(&mutex);
-
- QNetworkManagerSettingsConnection *connection = connectionFromId(id);
- if (connection)
- return connection->getTimestamp();
- else
- return Q_UINT64_C(0);
-}
-
-QNetworkConfigurationManager::Capabilities QNetworkManagerEngine::capabilities() const
-{
- return QNetworkConfigurationManager::ForcedRoaming |
- QNetworkConfigurationManager::DataStatistics |
- QNetworkConfigurationManager::CanStartAndStopInterfaces;
-}
-
-QNetworkSessionPrivate *QNetworkManagerEngine::createSessionBackend()
-{
- return new QNetworkSessionPrivateImpl;
-}
-
-QNetworkConfigurationPrivatePointer QNetworkManagerEngine::defaultConfiguration()
-{
- for (QNetworkManagerConnectionActive *activeConnection : qAsConst(activeConnectionsList)) {
- if ((activeConnection->defaultRoute() || activeConnection->default6Route())) {
- return accessPointConfigurations.value(activeConnection->connection().path());
- }
- }
-
- return QNetworkConfigurationPrivatePointer();
-}
-
-QNetworkConfiguration::BearerType QNetworkManagerEngine::currentBearerType(const QString &id) const
-{
- QString contextPart = id.section('/', -1);
- for (auto i = ofonoContextManagers.begin(), end = ofonoContextManagers.end(); i != end; ++i) {
- QString contextPath = i.key() + QLatin1Char('/') +contextPart;
-
- if (i.value()->contexts().contains(contextPath)) {
-
- QString bearer = i.value()->bearer();
-
- if (bearer == QLatin1String("gsm")) {
- return QNetworkConfiguration::Bearer2G;
- } else if (bearer == QLatin1String("edge")) {
- return QNetworkConfiguration::Bearer2G;
- } else if (bearer == QLatin1String("umts")) {
- return QNetworkConfiguration::BearerWCDMA;
- } else if (bearer == QLatin1String("hspa")
- || bearer == QLatin1String("hsdpa")
- || bearer == QLatin1String("hsupa")) {
- return QNetworkConfiguration::BearerHSPA;
- } else if (bearer == QLatin1String("lte")) {
- return QNetworkConfiguration::BearerLTE;
- }
- }
- }
-
- return QNetworkConfiguration::BearerUnknown;
-}
-
-QString QNetworkManagerEngine::contextName(const QString &path) const
-{
- QString contextPart = path.section('/', -1);
- for (QOfonoDataConnectionManagerInterface *iface : ofonoContextManagers) {
- const PathPropertiesList list = iface->contextsWithProperties();
- for (int i = 0; i < list.size(); ++i) {
- if (list.at(i).path.path().contains(contextPart)) {
- return list.at(i).properties.value(QStringLiteral("Name")).toString();
- }
- }
- }
- return path;
-}
-
-void QNetworkManagerEngine::nmRegistered(const QString &)
-{
- if (ofonoManager) {
- delete ofonoManager;
- ofonoManager = NULL;
- }
- managerInterface = new QNetworkManagerInterface(this);
- systemSettings = new QNetworkManagerSettings(NM_DBUS_SERVICE, this);
-
- connect(managerInterface, SIGNAL(activationFinished(QDBusPendingCallWatcher*)),
- this, SLOT(activationFinished(QDBusPendingCallWatcher*)));
- connect(managerInterface, SIGNAL(propertiesChanged(QMap<QString,QVariant>)),
- this, SLOT(interfacePropertiesChanged(QMap<QString,QVariant>)));
- managerInterface->setConnections();
-
- connect(systemSettings, SIGNAL(newConnection(QDBusObjectPath)),
- this, SLOT(newConnection(QDBusObjectPath)));
- systemSettings->setConnections();
- nmAvailable = true;
-
- setupConfigurations();
-}
-
-void QNetworkManagerEngine::nmUnRegistered(const QString &)
-{
- if (systemSettings) {
- delete systemSettings;
- systemSettings = NULL;
- }
- if (managerInterface) {
- delete managerInterface;
- managerInterface = NULL;
- }
-}
-
-void QNetworkManagerEngine::ofonoRegistered(const QString &)
-{
- if (ofonoManager) {
- delete ofonoManager;
- ofonoManager = NULL;
- }
- ofonoManager = new QOfonoManagerInterface(this);
- if (ofonoManager && ofonoManager->isValid()) {
- const auto modems = ofonoManager->getModems();
- for (const QString &modem : modems) {
- QOfonoDataConnectionManagerInterface *ofonoContextManager
- = new QOfonoDataConnectionManagerInterface(modem,this);
- ofonoContextManagers.insert(modem, ofonoContextManager);
- }
- }
-}
-
-void QNetworkManagerEngine::ofonoUnRegistered(const QString &)
-{
- ofonoContextManagers.clear();
-}
-
-QT_END_NAMESPACE
-
-#endif // QT_NO_DBUS
diff --git a/src/plugins/bearer/networkmanager/qnetworkmanagerengine.h b/src/plugins/bearer/networkmanager/qnetworkmanagerengine.h
deleted file mode 100644
index c624d6087d..0000000000
--- a/src/plugins/bearer/networkmanager/qnetworkmanagerengine.h
+++ /dev/null
@@ -1,153 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 QNETWORKMANAGERENGINE_P_H
-#define QNETWORKMANAGERENGINE_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 <private/qbearerengine_impl_p.h>
-
-#include "qnetworkmanagerservice.h"
-
-#include <private/qofonoservice_linux_p.h>
-
-#include <QMap>
-#include <QVariant>
-
-#ifndef QT_NO_DBUS
-
-QT_BEGIN_NAMESPACE
-
-class QNetworkManagerEngine : public QBearerEngineImpl
-{
- Q_OBJECT
-
-public:
- QNetworkManagerEngine(QObject *parent = nullptr);
- ~QNetworkManagerEngine();
-
- bool networkManagerAvailable() const;
-
- QString getInterfaceFromId(const QString &id) override;
- bool hasIdentifier(const QString &id) override;
-
- void connectToId(const QString &id) override;
- void disconnectFromId(const QString &id) override;
-
- Q_INVOKABLE void initialize();
- Q_INVOKABLE void requestUpdate();
-
- QNetworkSession::State sessionStateForId(const QString &id) override;
-
- quint64 bytesWritten(const QString &id) override;
- quint64 bytesReceived(const QString &id) override;
- quint64 startTime(const QString &id) override;
-
- QNetworkConfigurationManager::Capabilities capabilities() const override;
-
- QNetworkSessionPrivate *createSessionBackend() override;
-
- QNetworkConfigurationPrivatePointer defaultConfiguration() override;
-
-private Q_SLOTS:
- void interfacePropertiesChanged(const QMap<QString, QVariant> &properties);
- void activeConnectionPropertiesChanged(const QMap<QString, QVariant> &properties);
-
- void newConnection(const QDBusObjectPath &path, QNetworkManagerSettings *settings = nullptr);
- void removeConnection(const QString &path);
- void updateConnection();
- void activationFinished(QDBusPendingCallWatcher *watcher);
- void deviceConnectionsChanged(const QStringList &activeConnectionsList);
-
- void wiredCarrierChanged(bool);
-
- void nmRegistered(const QString &serviceName = QString());
- void nmUnRegistered(const QString &serviceName = QString());
-
- void ofonoRegistered(const QString &serviceName = QString());
- void ofonoUnRegistered(const QString &serviceName = QString());
-
-private:
- QNetworkConfigurationPrivate *parseConnection(const QString &settingsPath,
- const QNmSettingsMap &map);
- QNetworkManagerSettingsConnection *connectionFromId(const QString &id) const;
-
- QNetworkManagerInterface *managerInterface;
- QNetworkManagerSettings *systemSettings;
- QHash<QString, QNetworkManagerInterfaceDeviceWired *> wiredDevices;
- QHash<QString, QNetworkManagerInterfaceDeviceWireless *> wirelessDevices;
-
- QHash<QString, QNetworkManagerConnectionActive *> activeConnectionsList;
- QList<QNetworkManagerSettingsConnection *> connections;
- QList<QNetworkManagerInterfaceAccessPoint *> accessPoints;
- QHash<QString, QNetworkManagerInterfaceDevice *> interfaceDevices;
-
- QMap<QString,QString> configuredAccessPoints; //ap, settings path
- QHash<QString,QString> connectionInterfaces; // ac, interface
-
- QOfonoManagerInterface *ofonoManager;
- QHash <QString, QOfonoDataConnectionManagerInterface *> ofonoContextManagers;
- QNetworkConfiguration::BearerType currentBearerType(const QString &id) const;
- QString contextName(const QString &path) const;
-
- bool isConnectionActive(const QString &settingsPath) const;
- QDBusServiceWatcher *ofonoWatcher;
- QDBusServiceWatcher *nmWatcher;
-
- bool isActiveContext(const QString &contextPath) const;
- bool nmAvailable;
- void setupConfigurations();
-};
-
-QT_END_NAMESPACE
-
-#endif // QT_NO_DBUS
-
-#endif
-
diff --git a/src/plugins/bearer/networkmanager/qnetworkmanagerservice.cpp b/src/plugins/bearer/networkmanager/qnetworkmanagerservice.cpp
deleted file mode 100644
index 2d6cba1791..0000000000
--- a/src/plugins/bearer/networkmanager/qnetworkmanagerservice.cpp
+++ /dev/null
@@ -1,1019 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 <QObject>
-#include <QList>
-#include <QtDBus/QtDBus>
-#include <QtDBus/QDBusConnection>
-#include <QtDBus/QDBusError>
-#include <QtDBus/QDBusInterface>
-#include <QtDBus/QDBusMessage>
-#include <QtDBus/QDBusReply>
-#include <QtDBus/QDBusPendingCallWatcher>
-#include <QtDBus/QDBusObjectPath>
-#include <QtDBus/QDBusPendingCall>
-
-#include "qnetworkmanagerservice.h"
-
-#ifndef QT_NO_DBUS
-
-#define DBUS_PROPERTIES_INTERFACE "org.freedesktop.DBus.Properties"
-
-QT_BEGIN_NAMESPACE
-
-
-QNetworkManagerInterface::QNetworkManagerInterface(QObject *parent)
- : QDBusAbstractInterface(QLatin1String(NM_DBUS_SERVICE),
- QLatin1String(NM_DBUS_PATH),
- NM_DBUS_INTERFACE,
- QDBusConnection::systemBus(),parent)
-{
- if (!isValid()) {
- return;
- }
-
- PropertiesDBusInterface managerPropertiesInterface(QLatin1String(NM_DBUS_SERVICE),
- QLatin1String(NM_DBUS_PATH),
- DBUS_PROPERTIES_INTERFACE,
- QDBusConnection::systemBus());
- QDBusPendingReply<QVariantMap> propsReply
- = managerPropertiesInterface.call(QDBus::Block, QLatin1String("GetAll"), QLatin1String(NM_DBUS_INTERFACE));
-
- if (!propsReply.isError()) {
- propertyMap = propsReply.value();
- } else {
- qWarning() << "propsReply" << propsReply.error().message();
- }
-
- QDBusPendingReply<QList <QDBusObjectPath> > nmReply
- = call(QLatin1String("GetDevices"));
- nmReply.waitForFinished();
- if (!nmReply.isError()) {
- devicesPathList = nmReply.value();
- } else {
- qWarning() << "nmReply" << nmReply.error().message();
- }
-
- QDBusConnection::systemBus().connect(QLatin1String(NM_DBUS_SERVICE),
- QLatin1String(NM_DBUS_PATH),
- QLatin1String(NM_DBUS_INTERFACE),
- QLatin1String("PropertiesChanged"),
- this,SLOT(propertiesSwap(QMap<QString,QVariant>)));
-}
-
-QNetworkManagerInterface::~QNetworkManagerInterface()
-{
- QDBusConnection::systemBus().disconnect(QLatin1String(NM_DBUS_SERVICE),
- QLatin1String(NM_DBUS_PATH),
- QLatin1String(NM_DBUS_INTERFACE),
- QLatin1String("PropertiesChanged"),
- this,SLOT(propertiesSwap(QMap<QString,QVariant>)));
- QDBusConnection::systemBus().disconnect(QLatin1String(NM_DBUS_SERVICE),
- QLatin1String(NM_DBUS_PATH),
- QLatin1String(NM_DBUS_INTERFACE),
- QLatin1String("DeviceAdded"),
- this,SIGNAL(deviceAdded(QDBusObjectPath)));
- QDBusConnection::systemBus().disconnect(QLatin1String(NM_DBUS_SERVICE),
- QLatin1String(NM_DBUS_PATH),
- QLatin1String(NM_DBUS_INTERFACE),
- QLatin1String("DeviceRemoved"),
- this,SIGNAL(deviceRemoved(QDBusObjectPath)));
-}
-
-bool QNetworkManagerInterface::setConnections()
-{
- if (!isValid())
- return false;
-
- QDBusConnection::systemBus().connect(QLatin1String(NM_DBUS_SERVICE),
- QLatin1String(NM_DBUS_PATH),
- QLatin1String(NM_DBUS_INTERFACE),
- QLatin1String("PropertiesChanged"),
- this,SLOT(propertiesSwap(QMap<QString,QVariant>)));
-
- bool allOk = false;
- if (QDBusConnection::systemBus().connect(QLatin1String(NM_DBUS_SERVICE),
- QLatin1String(NM_DBUS_PATH),
- QLatin1String(NM_DBUS_INTERFACE),
- QLatin1String("DeviceAdded"),
- this,SIGNAL(deviceAdded(QDBusObjectPath)))) {
- allOk = true;
- }
- if (QDBusConnection::systemBus().connect(QLatin1String(NM_DBUS_SERVICE),
- QLatin1String(NM_DBUS_PATH),
- QLatin1String(NM_DBUS_INTERFACE),
- QLatin1String("DeviceRemoved"),
- this,SIGNAL(deviceRemoved(QDBusObjectPath)))) {
- allOk = true;
- }
-
- return allOk;
-}
-
-QList <QDBusObjectPath> QNetworkManagerInterface::getDevices()
-{
- if (devicesPathList.isEmpty()) {
- //qWarning("using blocking call!");
- QDBusReply<QList<QDBusObjectPath> > reply = call(QLatin1String("GetDevices"));
- devicesPathList = reply.value();
- }
- return devicesPathList;
-}
-
-void QNetworkManagerInterface::activateConnection(QDBusObjectPath connectionPath,
- QDBusObjectPath devicePath,
- QDBusObjectPath specificObject)
-{
- QDBusPendingCall pendingCall = asyncCall(QLatin1String("ActivateConnection"),
- QVariant::fromValue(connectionPath),
- QVariant::fromValue(devicePath),
- QVariant::fromValue(specificObject));
-
- QDBusPendingCallWatcher *callWatcher = new QDBusPendingCallWatcher(pendingCall);
- connect(callWatcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
- this, SIGNAL(activationFinished(QDBusPendingCallWatcher*)));
-}
-
-void QNetworkManagerInterface::deactivateConnection(QDBusObjectPath connectionPath)
-{
- asyncCall(QLatin1String("DeactivateConnection"), QVariant::fromValue(connectionPath));
-}
-
-bool QNetworkManagerInterface::wirelessEnabled() const
-{
- if (propertyMap.contains("WirelessEnabled"))
- return propertyMap.value("WirelessEnabled").toBool();
- return false;
-}
-
-bool QNetworkManagerInterface::wirelessHardwareEnabled() const
-{
- if (propertyMap.contains("WirelessHardwareEnabled"))
- return propertyMap.value("WirelessHardwareEnabled").toBool();
- return false;
-}
-
-QList <QDBusObjectPath> QNetworkManagerInterface::activeConnections() const
-{
- if (propertyMap.contains("ActiveConnections")) {
-
- const QDBusArgument &dbusArgs = qvariant_cast<QDBusArgument>(propertyMap.value("ActiveConnections"));
- QDBusObjectPath path;
- QList <QDBusObjectPath> list;
-
- dbusArgs.beginArray();
- while (!dbusArgs.atEnd()) {
- dbusArgs >> path;
- list.append(path);
- }
- dbusArgs.endArray();
-
- return list;
- }
-
- QList <QDBusObjectPath> list;
- list << QDBusObjectPath();
- return list;
-}
-
-QNetworkManagerInterface::NMState QNetworkManagerInterface::state()
-{
- if (propertyMap.contains("State"))
- return static_cast<QNetworkManagerInterface::NMState>(propertyMap.value("State").toUInt());
- return QNetworkManagerInterface::NM_STATE_UNKNOWN;
-}
-
-QString QNetworkManagerInterface::version() const
-{
- if (propertyMap.contains("Version"))
- return propertyMap.value("Version").toString();
- return QString();
-}
-
-void QNetworkManagerInterface::propertiesSwap(QMap<QString,QVariant> map)
-{
- for (auto i = map.cbegin(), end = map.cend(); i != end; ++i) {
- propertyMap.insert(i.key(),i.value());
-
- if (i.key() == QLatin1String("State")) {
- quint32 state = i.value().toUInt();
- if (state == NM_DEVICE_STATE_ACTIVATED
- || state == NM_DEVICE_STATE_DISCONNECTED
- || state == NM_DEVICE_STATE_UNAVAILABLE
- || state == NM_DEVICE_STATE_FAILED) {
- Q_EMIT propertiesChanged(map);
- Q_EMIT stateChanged(state);
- }
- } else if (i.key() == QLatin1String("ActiveConnections")) {
- Q_EMIT propertiesChanged(map);
- }
- }
-}
-
-QNetworkManagerInterfaceAccessPoint::QNetworkManagerInterfaceAccessPoint(const QString &dbusPathName, QObject *parent)
- : QDBusAbstractInterface(QLatin1String(NM_DBUS_SERVICE),
- dbusPathName,
- NM_DBUS_INTERFACE_ACCESS_POINT,
- QDBusConnection::systemBus(),parent)
-{
-}
-
-QNetworkManagerInterfaceAccessPoint::~QNetworkManagerInterfaceAccessPoint()
-{
-}
-
-quint32 QNetworkManagerInterfaceAccessPoint::flags() const
-{
- if (propertyMap.contains("Flags"))
- return propertyMap.value("Flags").toUInt();
- return 0;
-}
-
-quint32 QNetworkManagerInterfaceAccessPoint::wpaFlags() const
-{
- if (propertyMap.contains("WpaFlags"))
- return propertyMap.value("WpaFlags").toUInt();
- return 0;
-}
-
-quint32 QNetworkManagerInterfaceAccessPoint::rsnFlags() const
-{
- if (propertyMap.contains("RsnFlags"))
- return propertyMap.value("RsnFlags").toUInt();
- return 0;
-}
-
-QString QNetworkManagerInterfaceAccessPoint::ssid() const
-{
- if (propertyMap.contains("Ssid"))
- return propertyMap.value("Ssid").toString();
- return QString();
-}
-
-quint32 QNetworkManagerInterfaceAccessPoint::frequency() const
-{
- if (propertyMap.contains("Frequency"))
- return propertyMap.value("Frequency").toUInt();
- return 0;
-}
-
-QString QNetworkManagerInterfaceAccessPoint::hwAddress() const
-{
- if (propertyMap.contains("HwAddress"))
- return propertyMap.value("HwAddress").toString();
- return QString();
-}
-
-quint32 QNetworkManagerInterfaceAccessPoint::mode() const
-{
- if (propertyMap.contains("Mode"))
- return propertyMap.value("Mode").toUInt();
- return 0;
-}
-
-quint32 QNetworkManagerInterfaceAccessPoint::maxBitrate() const
-{
- if (propertyMap.contains("MaxBitrate"))
- return propertyMap.value("MaxBitrate").toUInt();
- return 0;
-}
-
-quint32 QNetworkManagerInterfaceAccessPoint::strength() const
-{
- if (propertyMap.contains("Strength"))
- return propertyMap.value("Strength").toUInt();
- return 0;
-}
-
-void QNetworkManagerInterfaceAccessPoint::propertiesSwap(QMap<QString,QVariant> map)
-{
- for (auto i = map.cbegin(), end = map.cend(); i != end; ++i)
- propertyMap.insert(i.key(),i.value());
-}
-
-QNetworkManagerInterfaceDevice::QNetworkManagerInterfaceDevice(const QString &deviceObjectPath, QObject *parent)
- : QDBusAbstractInterface(QLatin1String(NM_DBUS_SERVICE),
- deviceObjectPath,
- NM_DBUS_INTERFACE_DEVICE,
- QDBusConnection::systemBus(),parent)
-{
-
- if (!isValid()) {
- return;
- }
- PropertiesDBusInterface devicePropertiesInterface(QLatin1String(NM_DBUS_SERVICE),
- deviceObjectPath,
- DBUS_PROPERTIES_INTERFACE,
- QDBusConnection::systemBus(),parent);
-
- QDBusPendingReply<QVariantMap> propsReply
- = devicePropertiesInterface.call(QDBus::Block, QLatin1String("GetAll"), QLatin1String(NM_DBUS_INTERFACE_DEVICE));
-
- if (!propsReply.isError()) {
- propertyMap = propsReply.value();
- }
-
- QDBusConnection::systemBus().connect(QLatin1String(NM_DBUS_SERVICE),
- deviceObjectPath,
- QLatin1String(NM_DBUS_INTERFACE_DEVICE),
- QLatin1String("PropertiesChanged"),
- this,SLOT(propertiesSwap(QMap<QString,QVariant>)));
-}
-
-QNetworkManagerInterfaceDevice::~QNetworkManagerInterfaceDevice()
-{
- QDBusConnection::systemBus().disconnect(QLatin1String(NM_DBUS_SERVICE),
- path(),
- QLatin1String(NM_DBUS_INTERFACE_DEVICE),
- QLatin1String("PropertiesChanged"),
- this,SLOT(propertiesSwap(QMap<QString,QVariant>)));
-}
-
-QString QNetworkManagerInterfaceDevice::udi() const
-{
- if (propertyMap.contains("Udi"))
- return propertyMap.value("Udi").toString();
- return QString();
-}
-
-QString QNetworkManagerInterfaceDevice::networkInterface() const
-{
- if (propertyMap.contains("Interface"))
- return propertyMap.value("Interface").toString();
- return QString();
-}
-
-quint32 QNetworkManagerInterfaceDevice::ip4Address() const
-{
- if (propertyMap.contains("Ip4Address"))
- return propertyMap.value("Ip4Address").toUInt();
- return 0;
-}
-
-quint32 QNetworkManagerInterfaceDevice::state() const
-{
- if (propertyMap.contains("State"))
- return propertyMap.value("State").toUInt();
- return 0;
-}
-
-quint32 QNetworkManagerInterfaceDevice::deviceType() const
-{
- if (propertyMap.contains("DeviceType"))
- return propertyMap.value("DeviceType").toUInt();
- return 0;
-}
-
-QDBusObjectPath QNetworkManagerInterfaceDevice::ip4config() const
-{
- if (propertyMap.contains("Ip4Config"))
- return qvariant_cast<QDBusObjectPath>(propertyMap.value("Ip4Config"));
- return QDBusObjectPath();
-}
-
-void QNetworkManagerInterfaceDevice::propertiesSwap(QMap<QString,QVariant> map)
-{
- for (auto i = map.cbegin(), end = map.cend(); i != end; ++i) {
- if (i.key() == QLatin1String("AvailableConnections")) { //Device
- const QDBusArgument &dbusArgs = qvariant_cast<QDBusArgument>(i.value());
- QDBusObjectPath path;
- QStringList paths;
- dbusArgs.beginArray();
- while (!dbusArgs.atEnd()) {
- dbusArgs >> path;
- paths << path.path();
- }
- dbusArgs.endArray();
- Q_EMIT connectionsChanged(paths);
- }
- propertyMap.insert(i.key(),i.value());
- }
- Q_EMIT propertiesChanged(map);
-}
-
-QNetworkManagerInterfaceDeviceWired::QNetworkManagerInterfaceDeviceWired(const QString &ifaceDevicePath, QObject *parent)
- : QDBusAbstractInterface(QLatin1String(NM_DBUS_SERVICE),
- ifaceDevicePath,
- NM_DBUS_INTERFACE_DEVICE_WIRED,
- QDBusConnection::systemBus(), parent)
-{
- if (!isValid()) {
- return;
- }
- PropertiesDBusInterface deviceWiredPropertiesInterface(QLatin1String(NM_DBUS_SERVICE),
- ifaceDevicePath,
- DBUS_PROPERTIES_INTERFACE,
- QDBusConnection::systemBus(),parent);
-
- QDBusPendingReply<QVariantMap> propsReply
- = deviceWiredPropertiesInterface.call(QDBus::Block, QLatin1String("GetAll"), QLatin1String(NM_DBUS_INTERFACE_DEVICE_WIRED));
-
- if (!propsReply.isError()) {
- propertyMap = propsReply.value();
- }
-
- QDBusConnection::systemBus().connect(QLatin1String(NM_DBUS_SERVICE),
- ifaceDevicePath,
- QLatin1String(NM_DBUS_INTERFACE_DEVICE_WIRED),
- QLatin1String("PropertiesChanged"),
- this,SLOT(propertiesSwap(QMap<QString,QVariant>)));
-}
-
-QNetworkManagerInterfaceDeviceWired::~QNetworkManagerInterfaceDeviceWired()
-{
- QDBusConnection::systemBus().disconnect(QLatin1String(NM_DBUS_SERVICE),
- path(),
- QLatin1String(NM_DBUS_INTERFACE_DEVICE_WIRED),
- QLatin1String("PropertiesChanged"),
- this,SLOT(propertiesSwap(QMap<QString,QVariant>)));
-}
-
-QString QNetworkManagerInterfaceDeviceWired::hwAddress() const
-{
- if (propertyMap.contains("HwAddress"))
- return propertyMap.value("HwAddress").toString();
- return QString();
-}
-
-quint32 QNetworkManagerInterfaceDeviceWired::speed() const
-{
- if (propertyMap.contains("Speed"))
- return propertyMap.value("Speed").toUInt();
- return 0;
-}
-
-bool QNetworkManagerInterfaceDeviceWired::carrier() const
-{
- if (propertyMap.contains("Carrier"))
- return propertyMap.value("Carrier").toBool();
- return false;
-}
-
-QStringList QNetworkManagerInterfaceDeviceWired::availableConnections()
-{
- QStringList list;
- if (propertyMap.contains("AvailableConnections")) {
- const QDBusArgument &dbusArgs = qvariant_cast<QDBusArgument>(propertyMap.value("Carrier"));
- QDBusObjectPath path;
- dbusArgs.beginArray();
- while (!dbusArgs.atEnd()) {
- dbusArgs >> path;
- list << path.path();
- }
- dbusArgs.endArray();
- }
-
- return list;
-}
-
-void QNetworkManagerInterfaceDeviceWired::propertiesSwap(QMap<QString,QVariant> map)
-{
- for (auto i = map.cbegin(), end = map.cend(); i != end; ++i) {
- propertyMap.insert(i.key(),i.value());
- if (i.key() == QLatin1String("Carrier"))
- Q_EMIT carrierChanged(i.value().toBool());
- }
- Q_EMIT propertiesChanged(map);
-}
-
-QNetworkManagerInterfaceDeviceWireless::QNetworkManagerInterfaceDeviceWireless(const QString &ifaceDevicePath, QObject *parent)
- : QDBusAbstractInterface(QLatin1String(NM_DBUS_SERVICE),
- ifaceDevicePath,
- NM_DBUS_INTERFACE_DEVICE_WIRELESS,
- QDBusConnection::systemBus(), parent)
-{
- if (!isValid()) {
- return;
- }
-
- interfacePath = ifaceDevicePath;
- QDBusPendingReply<QList <QDBusObjectPath> > nmReply
- = call(QLatin1String("GetAccessPoints"));
-
- if (!nmReply.isError()) {
- accessPointsList = nmReply.value();
- }
-
- PropertiesDBusInterface deviceWirelessPropertiesInterface(QLatin1String(NM_DBUS_SERVICE),
- interfacePath,
- DBUS_PROPERTIES_INTERFACE,
- QDBusConnection::systemBus(),parent);
-
- QDBusPendingReply<QVariantMap> propsReply
- = deviceWirelessPropertiesInterface.call(QDBus::Block, QLatin1String("GetAll"), QLatin1String(NM_DBUS_INTERFACE_DEVICE_WIRELESS));
-
- if (!propsReply.isError()) {
- propertyMap = propsReply.value();
- }
-
- QDBusConnection::systemBus().connect(QLatin1String(NM_DBUS_SERVICE),
- interfacePath,
- QLatin1String(NM_DBUS_INTERFACE_DEVICE_WIRELESS),
- QLatin1String("PropertiesChanged"),
- this,SLOT(propertiesSwap(QMap<QString,QVariant>)));
-}
-
-QNetworkManagerInterfaceDeviceWireless::~QNetworkManagerInterfaceDeviceWireless()
-{
- QDBusConnection::systemBus().disconnect(QLatin1String(NM_DBUS_SERVICE),
- path(),
- QLatin1String(NM_DBUS_INTERFACE_DEVICE_WIRELESS),
- QLatin1String("PropertiesChanged"),
- this,SLOT(propertiesSwap(QMap<QString,QVariant>)));
-}
-
-bool QNetworkManagerInterfaceDeviceWireless::setConnections()
-{
- return true;
-}
-
-QList <QDBusObjectPath> QNetworkManagerInterfaceDeviceWireless::getAccessPoints()
-{
- if (accessPointsList.isEmpty()) {
- //qWarning("Using blocking call!");
- QDBusReply<QList<QDBusObjectPath> > reply
- = call(QLatin1String("GetAccessPoints"));
- accessPointsList = reply.value();
- }
- return accessPointsList;
-}
-
-QString QNetworkManagerInterfaceDeviceWireless::hwAddress() const
-{
- if (propertyMap.contains("HwAddress"))
- return propertyMap.value("HwAddress").toString();
- return QString();
-}
-
-quint32 QNetworkManagerInterfaceDeviceWireless::mode() const
-{
- if (propertyMap.contains("Mode"))
- return propertyMap.value("Mode").toUInt();
- return 0;
-}
-
-quint32 QNetworkManagerInterfaceDeviceWireless::bitrate() const
-{
- if (propertyMap.contains("Bitrate"))
- return propertyMap.value("Bitrate").toUInt();
- return 0;
-}
-
-QDBusObjectPath QNetworkManagerInterfaceDeviceWireless::activeAccessPoint() const
-{
- if (propertyMap.contains("ActiveAccessPoint"))
- return qvariant_cast<QDBusObjectPath>(propertyMap.value("ActiveAccessPoint"));
- return QDBusObjectPath();
-}
-
-quint32 QNetworkManagerInterfaceDeviceWireless::wirelessCapabilities() const
-{
- if (propertyMap.contains("WirelelessCapabilities"))
- return propertyMap.value("WirelelessCapabilities").toUInt();
- return 0;
-}
-
-void QNetworkManagerInterfaceDeviceWireless::requestScan()
-{
- asyncCall(QLatin1String("RequestScan"));
-}
-
-void QNetworkManagerInterfaceDeviceWireless::propertiesSwap(QMap<QString,QVariant> map)
-{
- for (auto i = map.cbegin(), end = map.cend(); i != end; ++i) {
- propertyMap.insert(i.key(),i.value());
- if (i.key() == QLatin1String("ActiveAccessPoint")) //DeviceWireless
- Q_EMIT propertiesChanged(map);
- }
-}
-
-QNetworkManagerInterfaceDeviceModem::QNetworkManagerInterfaceDeviceModem(const QString &ifaceDevicePath, QObject *parent)
- : QDBusAbstractInterface(QLatin1String(NM_DBUS_SERVICE),
- ifaceDevicePath,
- NM_DBUS_INTERFACE_DEVICE_MODEM,
- QDBusConnection::systemBus(), parent)
-{
- if (!isValid()) {
- return;
- }
- PropertiesDBusInterface deviceModemPropertiesInterface(QLatin1String(NM_DBUS_SERVICE),
- ifaceDevicePath,
- QLatin1String("org.freedesktop.DBus.Properties"),
- QDBusConnection::systemBus(),parent);
-
- QDBusPendingReply<QVariantMap> propsReply
- = deviceModemPropertiesInterface.call(QDBus::Block, QLatin1String("GetAll"), QLatin1String(NM_DBUS_INTERFACE_DEVICE_MODEM));
-
- if (!propsReply.isError()) {
- propertyMap = propsReply.value();
- }
-
- QDBusConnection::systemBus().connect(QLatin1String(NM_DBUS_SERVICE),
- ifaceDevicePath,
- QLatin1String(NM_DBUS_INTERFACE_DEVICE_MODEM),
- QLatin1String("PropertiesChanged"),
- this,SLOT(propertiesSwap(QMap<QString,QVariant>)));
-}
-
-QNetworkManagerInterfaceDeviceModem::~QNetworkManagerInterfaceDeviceModem()
-{
- QDBusConnection::systemBus().disconnect(QLatin1String(NM_DBUS_SERVICE),
- path(),
- QLatin1String(NM_DBUS_PATH_SETTINGS),
- QLatin1String(NM_DBUS_IFACE_SETTINGS),
- QLatin1String("NewConnection"),
- this, SIGNAL(newConnection(QDBusObjectPath)));
-}
-
-QNetworkManagerInterfaceDeviceModem::ModemCapabilities QNetworkManagerInterfaceDeviceModem::modemCapabilities() const
-{
- if (propertyMap.contains("ModemCapabilities"))
- return static_cast<QNetworkManagerInterfaceDeviceModem::ModemCapabilities>(propertyMap.value("ModemCapabilities").toUInt());
- return QNetworkManagerInterfaceDeviceModem::None;
-}
-
-QNetworkManagerInterfaceDeviceModem::ModemCapabilities QNetworkManagerInterfaceDeviceModem::currentCapabilities() const
-{
- if (propertyMap.contains("CurrentCapabilities"))
- return static_cast<QNetworkManagerInterfaceDeviceModem::ModemCapabilities>(propertyMap.value("CurrentCapabilities").toUInt());
- return QNetworkManagerInterfaceDeviceModem::None;
-}
-
-void QNetworkManagerInterfaceDeviceModem::propertiesSwap(QMap<QString,QVariant> map)
-{
- for (auto i = map.cbegin(), end = map.cend(); i != end; ++i)
- propertyMap.insert(i.key(),i.value());
- Q_EMIT propertiesChanged(map);
-}
-
-
-QNetworkManagerSettings::QNetworkManagerSettings(const QString &settingsService, QObject *parent)
- : QDBusAbstractInterface(settingsService,
- NM_DBUS_PATH_SETTINGS,
- NM_DBUS_IFACE_SETTINGS,
- QDBusConnection::systemBus(), parent)
-{
- if (!isValid()) {
- return;
- }
- interfacePath = settingsService;
- QDBusPendingReply<QList <QDBusObjectPath> > nmReply
- = call(QLatin1String("ListConnections"));
-
- if (!nmReply.isError()) {
- connectionsList = nmReply.value();
- }
-}
-
-QNetworkManagerSettings::~QNetworkManagerSettings()
-{
-}
-
-bool QNetworkManagerSettings::setConnections()
-{
- bool allOk = true;
- if (!QDBusConnection::systemBus().connect(interfacePath,
- QLatin1String(NM_DBUS_PATH_SETTINGS),
- QLatin1String(NM_DBUS_IFACE_SETTINGS),
- QLatin1String("NewConnection"),
- this, SIGNAL(newConnection(QDBusObjectPath)))) {
- allOk = false;
- qWarning("NewConnection could not be connected");
- }
-
- return allOk;
-}
-
-QList <QDBusObjectPath> QNetworkManagerSettings::listConnections()
-{
- if (connectionsList.isEmpty()) {
- //qWarning("Using blocking call!");
- QDBusReply<QList<QDBusObjectPath> > reply
- = call(QLatin1String("ListConnections"));
- connectionsList = reply.value();
- }
- return connectionsList;
-}
-
-
-QString QNetworkManagerSettings::getConnectionByUuid(const QString &uuid)
-{
- QDBusReply<QDBusObjectPath > reply = call(QDBus::Block, QLatin1String("GetConnectionByUuid"), uuid);
- return reply.value().path();
-}
-
-QNetworkManagerSettingsConnection::QNetworkManagerSettingsConnection(const QString &settingsService, const QString &connectionObjectPath, QObject *parent)
- : QDBusAbstractInterface(settingsService,
- connectionObjectPath,
- NM_DBUS_IFACE_SETTINGS_CONNECTION,
- QDBusConnection::systemBus(), parent)
-{
- qDBusRegisterMetaType<QNmSettingsMap>();
- if (!isValid()) {
- return;
- }
- interfacepath = connectionObjectPath;
- QDBusPendingReply<QNmSettingsMap> nmReply
- = call(QLatin1String("GetSettings"));
- if (!nmReply.isError()) {
- settingsMap = nmReply.value();
- }
-}
-
-QNetworkManagerSettingsConnection::~QNetworkManagerSettingsConnection()
-{
- QDBusConnection::systemBus().disconnect(service(),
- path(),
- QLatin1String(NM_DBUS_IFACE_SETTINGS_CONNECTION),
- QLatin1String("Updated"),
- this, SIGNAL(updated()));
- QDBusConnection::systemBus().disconnect(service(),
- path(),
- QLatin1String(NM_DBUS_IFACE_SETTINGS_CONNECTION),
- QLatin1String("Removed"),
- this, SIGNAL(slotSettingsRemoved()));
-}
-
-bool QNetworkManagerSettingsConnection::setConnections()
-{
- if (!isValid())
- return false;
-
- QDBusConnection dbusConnection = QDBusConnection::systemBus();
- bool allOk = true;
- if (!dbusConnection.connect(service(),
- interfacepath,
- QLatin1String(NM_DBUS_IFACE_SETTINGS_CONNECTION),
- QLatin1String("Updated"),
- this, SIGNAL(updated()))) {
- allOk = false;
- }
-
- if (!dbusConnection.connect(service(),
- interfacepath,
- QLatin1String(NM_DBUS_IFACE_SETTINGS_CONNECTION),
- QLatin1String("Removed"),
- this, SIGNAL(slotSettingsRemoved()))) {
- allOk = false;
- }
- return allOk;
-}
-
-void QNetworkManagerSettingsConnection::slotSettingsRemoved()
-{
- Q_EMIT removed(interfacepath);
-}
-
-QNmSettingsMap QNetworkManagerSettingsConnection::getSettings()
-{
- if (settingsMap.isEmpty()) {
- //qWarning("Using blocking call!");
- QDBusReply<QNmSettingsMap> reply = call(QLatin1String("GetSettings"));
- settingsMap = reply.value();
- }
- return settingsMap;
-}
-
-NMDeviceType QNetworkManagerSettingsConnection::getType()
-{
- const QString devType =
- settingsMap.value(QLatin1String("connection")).value(QLatin1String("type")).toString();
-
- if (devType == QLatin1String("802-3-ethernet"))
- return DEVICE_TYPE_ETHERNET;
- else if (devType == QLatin1String("802-11-wireless"))
- return DEVICE_TYPE_WIFI;
- else if (devType == QLatin1String("gsm"))
- return DEVICE_TYPE_MODEM;
- else
- return DEVICE_TYPE_UNKNOWN;
-}
-
-bool QNetworkManagerSettingsConnection::isAutoConnect()
-{
- const QVariant autoConnect =
- settingsMap.value(QLatin1String("connection")).value(QLatin1String("autoconnect"));
-
- // NetworkManager default is to auto connect
- if (!autoConnect.isValid())
- return true;
-
- return autoConnect.toBool();
-}
-
-quint64 QNetworkManagerSettingsConnection::getTimestamp()
-{
- return settingsMap.value(QLatin1String("connection"))
- .value(QLatin1String("timestamp")).toUInt();
-}
-
-QString QNetworkManagerSettingsConnection::getId()
-{
- return settingsMap.value(QLatin1String("connection")).value(QLatin1String("id")).toString();
-}
-
-QString QNetworkManagerSettingsConnection::getUuid()
-{
- const QString id = settingsMap.value(QLatin1String("connection"))
- .value(QLatin1String("uuid")).toString();
-
- // is no uuid, return the connection path
- return id.isEmpty() ? path() : id;
-}
-
-QString QNetworkManagerSettingsConnection::getSsid()
-{
- return settingsMap.value(QLatin1String("802-11-wireless"))
- .value(QLatin1String("ssid")).toString();
-}
-
-QString QNetworkManagerSettingsConnection::getMacAddress()
-{
- NMDeviceType type = getType();
-
- if (type == DEVICE_TYPE_ETHERNET) {
- return settingsMap.value(QLatin1String("802-3-ethernet"))
- .value(QLatin1String("mac-address")).toString();
- } else if (type == DEVICE_TYPE_WIFI) {
- return settingsMap.value(QLatin1String("802-11-wireless"))
- .value(QLatin1String("mac-address")).toString();
- } else {
- return QString();
- }
-}
-
-QStringList QNetworkManagerSettingsConnection::getSeenBssids()
-{
- if (getType() == DEVICE_TYPE_WIFI) {
- return settingsMap.value(QLatin1String("802-11-wireless"))
- .value(QLatin1String("seen-bssids")).toStringList();
- } else {
- return QStringList();
- }
-}
-
-QNetworkManagerConnectionActive::QNetworkManagerConnectionActive(const QString &activeConnectionObjectPath, QObject *parent)
- : QDBusAbstractInterface(QLatin1String(NM_DBUS_SERVICE),
- activeConnectionObjectPath,
- NM_DBUS_INTERFACE_ACTIVE_CONNECTION,
- QDBusConnection::systemBus(), parent)
-{
- if (!isValid()) {
- return;
- }
- PropertiesDBusInterface connectionActivePropertiesInterface(QLatin1String(NM_DBUS_SERVICE),
- activeConnectionObjectPath,
- QLatin1String("org.freedesktop.DBus.Properties"),
- QDBusConnection::systemBus());
-
-
- QDBusPendingReply<QVariantMap> propsReply
- = connectionActivePropertiesInterface.call(QDBus::Block, QLatin1String("GetAll"), QLatin1String(NM_DBUS_INTERFACE_ACTIVE_CONNECTION));
-
- if (!propsReply.isError()) {
- propertyMap = propsReply.value();
- } else {
- qWarning() << propsReply.error().message();
- }
-
- QDBusConnection::systemBus().connect(QLatin1String(NM_DBUS_SERVICE),
- activeConnectionObjectPath,
- QLatin1String(NM_DBUS_INTERFACE_ACTIVE_CONNECTION),
- QLatin1String("PropertiesChanged"),
- this,SLOT(propertiesSwap(QMap<QString,QVariant>)));
-}
-
-QNetworkManagerConnectionActive::~QNetworkManagerConnectionActive()
-{
- QDBusConnection::systemBus().disconnect(QLatin1String(NM_DBUS_SERVICE),
- path(),
- QLatin1String(NM_DBUS_INTERFACE_ACTIVE_CONNECTION),
- QLatin1String("PropertiesChanged"),
- this,SLOT(propertiesSwap(QMap<QString,QVariant>)));
-}
-
-QDBusObjectPath QNetworkManagerConnectionActive::connection() const
-{
- if (propertyMap.contains("Connection"))
- return qvariant_cast<QDBusObjectPath>(propertyMap.value("Connection"));
- return QDBusObjectPath();
-}
-
-QDBusObjectPath QNetworkManagerConnectionActive::specificObject() const
-{
- if (propertyMap.contains("SpecificObject"))
- return qvariant_cast<QDBusObjectPath>(propertyMap.value("SpecificObject"));
- return QDBusObjectPath();
-}
-
-QStringList QNetworkManagerConnectionActive::devices() const
-{
- QStringList list;
- if (propertyMap.contains("Devices")) {
- const QDBusArgument &dbusArgs = qvariant_cast<QDBusArgument>(propertyMap.value("Devices"));
- QDBusObjectPath path;
-
- dbusArgs.beginArray();
- while (!dbusArgs.atEnd()) {
- dbusArgs >> path;
- list.append(path.path());
- }
- dbusArgs.endArray();
- }
- return list;
-}
-
-quint32 QNetworkManagerConnectionActive::state() const
-{
- if (propertyMap.contains("State"))
- return propertyMap.value("State").toUInt();
- return 0;
-}
-
-bool QNetworkManagerConnectionActive::defaultRoute() const
-{
- if (propertyMap.contains("Default"))
- return propertyMap.value("Default").toBool();
- return false;
-}
-
-bool QNetworkManagerConnectionActive::default6Route() const
-{
- if (propertyMap.contains("Default6"))
- return propertyMap.value("Default6").toBool();
- return false;
-}
-
-void QNetworkManagerConnectionActive::propertiesSwap(QMap<QString,QVariant> map)
-{
- for (auto i = map.cbegin(), end = map.cend(); i != end; ++i) {
- propertyMap.insert(i.key(),i.value());
- if (i.key() == QLatin1String("State")) {
- quint32 state = i.value().toUInt();
- if (state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED
- || state == NM_ACTIVE_CONNECTION_STATE_DEACTIVATED) {
- Q_EMIT propertiesChanged(map);
- }
- }
- }
-}
-
-QNetworkManagerIp4Config::QNetworkManagerIp4Config( const QString &deviceObjectPath, QObject *parent)
- : QDBusAbstractInterface(QLatin1String(NM_DBUS_SERVICE),
- deviceObjectPath,
- NM_DBUS_INTERFACE_IP4_CONFIG,
- QDBusConnection::systemBus(), parent)
-{
- if (!isValid()) {
- return;
- }
-}
-
-QNetworkManagerIp4Config::~QNetworkManagerIp4Config()
-{
-}
-
-QStringList QNetworkManagerIp4Config::domains() const
-{
- return property("Domains").toStringList();
-}
-
-QT_END_NAMESPACE
-
-#endif // QT_NO_DBUS
diff --git a/src/plugins/bearer/networkmanager/qnetworkmanagerservice.h b/src/plugins/bearer/networkmanager/qnetworkmanagerservice.h
deleted file mode 100644
index bff7a71097..0000000000
--- a/src/plugins/bearer/networkmanager/qnetworkmanagerservice.h
+++ /dev/null
@@ -1,500 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 QNETWORKMANAGERSERVICE_H
-#define QNETWORKMANAGERSERVICE_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 <QtDBus/QtDBus>
-#include <QtDBus/QDBusConnection>
-#include <QtDBus/QDBusError>
-#include <QtDBus/QDBusInterface>
-#include <QtDBus/QDBusMessage>
-#include <QtDBus/QDBusReply>
-
-#include <QtDBus/QDBusPendingCallWatcher>
-#include <QtDBus/QDBusObjectPath>
-#include <QtDBus/QDBusContext>
-#include <QtDBus/QDBusAbstractInterface>
-#include <QMap>
-
-#ifndef QT_NO_DBUS
-
-#ifndef NETWORK_MANAGER_H
-typedef enum NMDeviceType
-{
- DEVICE_TYPE_UNKNOWN = 0,
- DEVICE_TYPE_ETHERNET,
- DEVICE_TYPE_WIFI,
- DEVICE_TYPE_MODEM = 8
-} NMDeviceType;
-
-typedef enum
-{
- NM_DEVICE_STATE_UNKNOWN = 0,
- NM_DEVICE_STATE_UNMANAGED = 10,
- NM_DEVICE_STATE_UNAVAILABLE = 20,
- NM_DEVICE_STATE_DISCONNECTED = 30,
- NM_DEVICE_STATE_PREPARE = 40,
- NM_DEVICE_STATE_CONFIG = 50,
- NM_DEVICE_STATE_NEED_AUTH = 60,
- NM_DEVICE_STATE_IP_CONFIG = 70,
- NM_DEVICE_STATE_ACTIVATED = 100,
- NM_DEVICE_STATE_DEACTIVATING = 110,
- NM_DEVICE_STATE_FAILED = 120
-} NMDeviceState;
-
-typedef enum
-{
- NM_ACTIVE_CONNECTION_STATE_UNKNOWN = 0,
- NM_ACTIVE_CONNECTION_STATE_ACTIVATING,
- NM_ACTIVE_CONNECTION_STATE_ACTIVATED,
- NM_ACTIVE_CONNECTION_STATE_DEACTIVATED = 4
-} NMActiveConnectionState;
-
-#define NM_DBUS_SERVICE "org.freedesktop.NetworkManager"
-
-#define NM_DBUS_PATH "/org/freedesktop/NetworkManager"
-#define NM_DBUS_INTERFACE "org.freedesktop.NetworkManager"
-#define NM_DBUS_INTERFACE_DEVICE NM_DBUS_INTERFACE ".Device"
-#define NM_DBUS_INTERFACE_DEVICE_WIRED NM_DBUS_INTERFACE_DEVICE ".Wired"
-#define NM_DBUS_INTERFACE_DEVICE_WIRELESS NM_DBUS_INTERFACE_DEVICE ".Wireless"
-#define NM_DBUS_INTERFACE_DEVICE_MODEM NM_DBUS_INTERFACE_DEVICE ".Modem"
-#define NM_DBUS_PATH_ACCESS_POINT NM_DBUS_PATH "/AccessPoint"
-#define NM_DBUS_INTERFACE_ACCESS_POINT NM_DBUS_INTERFACE ".AccessPoint"
-
-#define NM_DBUS_PATH_SETTINGS "/org/freedesktop/NetworkManager/Settings"
-
-#define NM_DBUS_IFACE_SETTINGS_CONNECTION "org.freedesktop.NetworkManager.Settings.Connection"
-#define NM_DBUS_IFACE_SETTINGS "org.freedesktop.NetworkManager.Settings"
-#define NM_DBUS_INTERFACE_ACTIVE_CONNECTION NM_DBUS_INTERFACE ".Connection.Active"
-#define NM_DBUS_INTERFACE_IP4_CONFIG NM_DBUS_INTERFACE ".IP4Config"
-
-#define NM_DBUS_SERVICE_USER_SETTINGS "org.freedesktop.NetworkManagerUserSettings"
-#define NM_DBUS_SERVICE_SYSTEM_SETTINGS "org.freedesktop.NetworkManagerSystemSettings"
-
-#define NM_802_11_AP_FLAGS_NONE 0x00000000
-#define NM_802_11_AP_FLAGS_PRIVACY 0x00000001
-#endif
-
-QT_BEGIN_NAMESPACE
-
-typedef QMap< QString, QMap<QString,QVariant> > QNmSettingsMap;
-typedef QList<quint32> ServerThing;
-
-QT_END_NAMESPACE
-
-Q_DECLARE_METATYPE(QT_PREPEND_NAMESPACE(QNmSettingsMap))
-Q_DECLARE_METATYPE(QT_PREPEND_NAMESPACE(ServerThing))
-
-QT_BEGIN_NAMESPACE
-
-class QNetworkManagerInterface : public QDBusAbstractInterface
-{
- Q_OBJECT
-
-public:
- typedef enum
- {
- NM_STATE_UNKNOWN = 0,
- NM_STATE_ASLEEP = 10,
- NM_STATE_DISCONNECTED = 20,
- NM_STATE_DISCONNECTING = 30,
- NM_STATE_CONNECTING = 40,
- NM_STATE_CONNECTED_LOCAL = 50,
- NM_STATE_CONNECTED_SITE = 60,
- NM_STATE_CONNECTED_GLOBAL = 70
- } NMState;
-
- QNetworkManagerInterface(QObject *parent = nullptr);
- ~QNetworkManagerInterface();
-
- QList <QDBusObjectPath> getDevices();
- void activateConnection(QDBusObjectPath connection,QDBusObjectPath device, QDBusObjectPath specificObject);
- void deactivateConnection(QDBusObjectPath connectionPath);
-
- QDBusObjectPath path() const;
-
- bool wirelessEnabled() const;
- bool wirelessHardwareEnabled() const;
- QList <QDBusObjectPath> activeConnections() const;
- NMState state();
- QString version() const;
- bool setConnections();
-
-Q_SIGNALS:
- void deviceAdded(QDBusObjectPath);
- void deviceRemoved(QDBusObjectPath);
- void propertiesChanged(QMap<QString,QVariant>);
- void stateChanged(quint32);
- void activationFinished(QDBusPendingCallWatcher*);
- void propertiesReady();
- void devicesListReady();
-
-private Q_SLOTS:
- void propertiesSwap(QMap<QString,QVariant>);
-
-private:
- QVariantMap propertyMap;
- QList<QDBusObjectPath> devicesPathList;
-
-};
-
-class QNetworkManagerInterfaceAccessPoint : public QDBusAbstractInterface
-{
- Q_OBJECT
-
-public:
-
- enum DeviceState {
- Unknown = 0,
- Unmanaged,
- Unavailable,
- Disconnected,
- Prepare,
- Config,
- NeedAuthentication,
- IpConfig,
- Activated,
- Failed
- };
-
- enum ApFlag {
- ApNone = 0x0,
- Privacy = 0x1
- };
-
- Q_DECLARE_FLAGS(ApFlags, ApFlag)
-
- enum ApSecurityFlag {
- ApSecurityNone = 0x0,
- PairWep40 = 0x1,
- PairWep104 = 0x2,
- PairTkip = 0x4,
- PairCcmp = 0x8,
- GroupWep40 = 0x10,
- GroupWep104 = 0x20,
- GroupTkip = 0x40,
- GroupCcmp = 0x80,
- KeyPsk = 0x100,
- Key8021x = 0x200
- };
-
- Q_DECLARE_FLAGS(ApSecurityFlags, ApSecurityFlag)
-
- explicit QNetworkManagerInterfaceAccessPoint(const QString &dbusPathName, QObject *parent = nullptr);
- ~QNetworkManagerInterfaceAccessPoint();
-
- quint32 flags() const;
- quint32 wpaFlags() const;
- quint32 rsnFlags() const;
- QString ssid() const;
- quint32 frequency() const;
- QString hwAddress() const;
- quint32 mode() const;
- quint32 maxBitrate() const;
- quint32 strength() const;
- // bool setConnections();
-
-Q_SIGNALS:
- void propertiesChanged(QMap<QString,QVariant>);
- void propertiesReady();
-
-private Q_SLOTS:
- void propertiesSwap(QMap<QString,QVariant>);
-
-private:
- QVariantMap propertyMap;
-};
-
-class QNetworkManagerInterfaceDevice : public QDBusAbstractInterface
-{
- Q_OBJECT
-
-public:
-
- explicit QNetworkManagerInterfaceDevice(const QString &deviceObjectPath, QObject *parent = nullptr);
- ~QNetworkManagerInterfaceDevice();
-
- QString udi() const;
- QString networkInterface() const;
- quint32 ip4Address() const;
- quint32 state() const;
- quint32 deviceType() const;
-
- QDBusObjectPath ip4config() const;
-
-Q_SIGNALS:
- void stateChanged(const QString &, quint32);
- void propertiesChanged(QMap<QString,QVariant>);
- void connectionsChanged(QStringList);
- void propertiesReady();
-private Q_SLOTS:
- void propertiesSwap(QMap<QString,QVariant>);
-private:
- QVariantMap propertyMap;
-};
-
-class QNetworkManagerInterfaceDeviceWired : public QDBusAbstractInterface
-{
- Q_OBJECT
-
-public:
-
- explicit QNetworkManagerInterfaceDeviceWired(const QString &ifaceDevicePath,
- QObject *parent = nullptr);
- ~QNetworkManagerInterfaceDeviceWired();
-
- QString hwAddress() const;
- quint32 speed() const;
- bool carrier() const;
- QStringList availableConnections();
-
-Q_SIGNALS:
- void propertiesChanged(QMap<QString,QVariant>);
- void propertiesReady();
- void carrierChanged(bool);
-
-private Q_SLOTS:
- void propertiesSwap(QMap<QString,QVariant>);
-
-private:
- QVariantMap propertyMap;
-};
-
-class QNetworkManagerInterfaceDeviceWireless : public QDBusAbstractInterface
-{
- Q_OBJECT
-
-public:
-
- enum DeviceCapability {
- None = 0x0,
- Wep40 = 0x1,
- Wep104 = 0x2,
- Tkip = 0x4,
- Ccmp = 0x8,
- Wpa = 0x10,
- Rsn = 0x20
- };
-
- explicit QNetworkManagerInterfaceDeviceWireless(const QString &ifaceDevicePath,
- QObject *parent = nullptr);
- ~QNetworkManagerInterfaceDeviceWireless();
-
- QList <QDBusObjectPath> getAccessPoints();
-
- QString hwAddress() const;
- quint32 mode() const;
- quint32 bitrate() const;
- QDBusObjectPath activeAccessPoint() const;
- quint32 wirelessCapabilities() const;
- bool setConnections();
-
- void requestScan();
-Q_SIGNALS:
- void propertiesChanged(QMap<QString,QVariant>);
- void propertiesReady();
-
-private Q_SLOTS:
- void propertiesSwap(QMap<QString,QVariant>);
-
-private:
- QVariantMap propertyMap;
- QList <QDBusObjectPath> accessPointsList;
- QString interfacePath;
-};
-
-class QNetworkManagerInterfaceDeviceModem : public QDBusAbstractInterface
-{
- Q_OBJECT
-
-public:
-
- enum ModemCapability {
- None = 0x0,
- Pots = 0x1,
- Cmda_Edvo = 0x2,
- Gsm_Umts = 0x4,
- Lte = 0x08
- };
- Q_DECLARE_FLAGS(ModemCapabilities, ModemCapability)
-
- explicit QNetworkManagerInterfaceDeviceModem(const QString &ifaceDevicePath,
- QObject *parent = nullptr);
- ~QNetworkManagerInterfaceDeviceModem();
-
- ModemCapabilities modemCapabilities() const;
- ModemCapabilities currentCapabilities() const;
-
-Q_SIGNALS:
- void propertiesChanged(QMap<QString,QVariant>);
- void propertiesReady();
-
-private Q_SLOTS:
- void propertiesSwap(QMap<QString,QVariant>);
-
-private:
- QVariantMap propertyMap;
-};
-
-Q_DECLARE_OPERATORS_FOR_FLAGS(QNetworkManagerInterfaceDeviceModem::ModemCapabilities)
-
-class QNetworkManagerSettings : public QDBusAbstractInterface
-{
- Q_OBJECT
-
-public:
-
- explicit QNetworkManagerSettings(const QString &settingsService, QObject *parent = nullptr);
- ~QNetworkManagerSettings();
-
- QList <QDBusObjectPath> listConnections();
- QString getConnectionByUuid(const QString &uuid);
- bool setConnections();
-
-Q_SIGNALS:
- void newConnection(QDBusObjectPath);
- void connectionsListReady();
-private:
- QList <QDBusObjectPath> connectionsList;
- QString interfacePath;
-};
-
-class QNetworkManagerSettingsConnection : public QDBusAbstractInterface
-{
- Q_OBJECT
-
-public:
-
- QNetworkManagerSettingsConnection(const QString &settingsService, const QString &connectionObjectPath, QObject *parent = nullptr);
- ~QNetworkManagerSettingsConnection();
-
- QNmSettingsMap getSettings();
- bool setConnections();
- NMDeviceType getType();
- bool isAutoConnect();
- quint64 getTimestamp();
- QString getId();
- QString getUuid();
- QString getSsid();
- QString getMacAddress();
- QStringList getSeenBssids();
-
-Q_SIGNALS:
- void updated();
- void removed(const QString &path);
- void settingsReady();
-
-private Q_SLOTS:
- void slotSettingsRemoved();
-private:
- QNmSettingsMap settingsMap;
- QString interfacepath;
-};
-
-class QNetworkManagerConnectionActive : public QDBusAbstractInterface
-{
- Q_OBJECT
-
-public:
-
- enum ActiveConnectionState {
- Unknown = 0,
- Activating = 1,
- Activated = 2
- };
-
- explicit QNetworkManagerConnectionActive(const QString &dbusPathName, QObject *parent = nullptr);
- ~ QNetworkManagerConnectionActive();
-
- QDBusObjectPath connection() const;
- QDBusObjectPath specificObject() const;
- QStringList devices() const;
- quint32 state() const;
- bool defaultRoute() const;
- bool default6Route() const;
-
-
-Q_SIGNALS:
- void propertiesChanged(QMap<QString,QVariant>);
- void propertiesReady();
-
-private Q_SLOTS:
- void propertiesSwap(QMap<QString,QVariant>);
-
-private:
- QVariantMap propertyMap;
-};
-
-class QNetworkManagerIp4Config : public QDBusAbstractInterface
-{
- Q_OBJECT
-
-public:
- explicit QNetworkManagerIp4Config(const QString &dbusPathName, QObject *parent = nullptr);
- ~QNetworkManagerIp4Config();
-
- QStringList domains() const;
-};
-
-class PropertiesDBusInterface : public QDBusAbstractInterface
-{
-public:
- PropertiesDBusInterface(const QString &service, const QString &path,
- const QString &interface, const QDBusConnection &connection,
- QObject *parent = nullptr)
- : QDBusAbstractInterface(service, path, interface.toLatin1().data(), connection, parent)
- {}
-};
-
-QT_END_NAMESPACE
-
-#endif // QT_NO_DBUS
-#endif //QNETWORKMANAGERSERVICE_H
diff --git a/src/plugins/bearer/nla/main.cpp b/src/plugins/bearer/nla/main.cpp
deleted file mode 100644
index 8e45c071e8..0000000000
--- a/src/plugins/bearer/nla/main.cpp
+++ /dev/null
@@ -1,78 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 "qnlaengine.h"
-
-#include <QtNetwork/private/qbearerplugin_p.h>
-
-#include <QtCore/qdebug.h>
-
-QT_BEGIN_NAMESPACE
-
-class QNlaEnginePlugin : public QBearerEnginePlugin
-{
- Q_OBJECT
- Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QBearerEngineFactoryInterface" FILE "nla.json")
-
-public:
- QNlaEnginePlugin();
- ~QNlaEnginePlugin();
-
- QBearerEngine *create(const QString &key) const;
-};
-
-QNlaEnginePlugin::QNlaEnginePlugin()
-{
-}
-
-QNlaEnginePlugin::~QNlaEnginePlugin()
-{
-}
-
-QBearerEngine *QNlaEnginePlugin::create(const QString &key) const
-{
- if (key == QLatin1String("nla"))
- return new QNlaEngine;
- else
- return 0;
-}
-
-QT_END_NAMESPACE
-
-#include "main.moc"
diff --git a/src/plugins/bearer/nla/nla.json b/src/plugins/bearer/nla/nla.json
deleted file mode 100644
index 2554d2c5c4..0000000000
--- a/src/plugins/bearer/nla/nla.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "Keys": [ "nla" ]
-}
diff --git a/src/plugins/bearer/nla/nla.pro b/src/plugins/bearer/nla/nla.pro
deleted file mode 100644
index 2582dc7cd4..0000000000
--- a/src/plugins/bearer/nla/nla.pro
+++ /dev/null
@@ -1,17 +0,0 @@
-TARGET = qnlabearer
-
-QT = core core-private network network-private
-
-QMAKE_USE_PRIVATE += ws2_32
-
-HEADERS += qnlaengine.h \
- ../platformdefs_win.h
-
-SOURCES += main.cpp \
- qnlaengine.cpp
-
-OTHER_FILES += nla.json
-
-PLUGIN_TYPE = bearer
-PLUGIN_CLASS_NAME = QNlaEnginePlugin
-load(qt_plugin)
diff --git a/src/plugins/bearer/nla/qnlaengine.cpp b/src/plugins/bearer/nla/qnlaengine.cpp
deleted file mode 100644
index ab3c0d0e3a..0000000000
--- a/src/plugins/bearer/nla/qnlaengine.cpp
+++ /dev/null
@@ -1,639 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 "qnlaengine.h"
-#include <private/qnetworksession_impl_p.h>
-
-#include <QtNetwork/private/qnetworkconfiguration_p.h>
-
-#include <QtCore/qthread.h>
-#include <QtCore/qmutex.h>
-#include <QtCore/qcoreapplication.h>
-#include <QtCore/qstringlist.h>
-
-#include <QtCore/qdebug.h>
-
-#include "../platformdefs_win.h"
-
-QT_BEGIN_NAMESPACE
-
-QWindowsSockInit2::QWindowsSockInit2()
-: version(0)
-{
- //### should we try for 2.2 on all platforms ??
- WSAData wsadata;
-
- // IPv6 requires Winsock v2.0 or better.
- if (WSAStartup(MAKEWORD(2,0), &wsadata) != 0) {
- qWarning("QBearerManagementAPI: WinSock v2.0 initialization failed.");
- } else {
- version = 0x20;
- }
-}
-
-QWindowsSockInit2::~QWindowsSockInit2()
-{
- WSACleanup();
-}
-
-#ifdef BEARER_MANAGEMENT_DEBUG
-static void printBlob(NLA_BLOB *blob)
-{
- qDebug() << "==== BEGIN NLA_BLOB ====" << Qt::endl
-
- << "type:" << blob->header.type << Qt::endl
- << "size:" << blob->header.dwSize << Qt::endl
- << "next offset:" << blob->header.nextOffset;
-
- switch (blob->header.type) {
- case NLA_RAW_DATA:
- qDebug() << "Raw Data" << Qt::endl
- << '\t' << blob->data.rawData;
- break;
- case NLA_INTERFACE:
- qDebug() << "Interface" << Qt::endl
- << "\ttype:" << blob->data.interfaceData.dwType << Qt::endl
- << "\tspeed:" << blob->data.interfaceData.dwSpeed << Qt::endl
- << "\tadapter:" << blob->data.interfaceData.adapterName;
- break;
- case NLA_802_1X_LOCATION:
- qDebug() << "802.1x Location" << Qt::endl
- << '\t' << blob->data.locationData.information;
- break;
- case NLA_CONNECTIVITY:
- qDebug() << "Connectivity" << Qt::endl
- << "\ttype:" << blob->data.connectivity.type << Qt::endl
- << "\tinternet:" << blob->data.connectivity.internet;
- break;
- case NLA_ICS:
- qDebug() << "ICS" << Qt::endl
- << "\tspeed:" << blob->data.ICS.remote.speed << Qt::endl
- << "\ttype:" << blob->data.ICS.remote.type << Qt::endl
- << "\tstate:" << blob->data.ICS.remote.state << Qt::endl
- << "\tmachine name:" << blob->data.ICS.remote.machineName << Qt::endl
- << "\tshared adapter name:" << blob->data.ICS.remote.sharedAdapterName;
- break;
- default:
- qDebug("UNKNOWN BLOB TYPE");
- }
-
- qDebug("===== END NLA_BLOB =====");
-}
-#endif
-
-static QNetworkConfiguration::BearerType qGetInterfaceType(const QString &interface)
-{
- unsigned long oid;
- DWORD bytesWritten;
-
- NDIS_MEDIUM medium;
- NDIS_PHYSICAL_MEDIUM physicalMedium;
-
- HANDLE handle = CreateFile((TCHAR *)QString::fromLatin1("\\\\.\\%1").arg(interface).utf16(), 0,
- FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
- if (handle == INVALID_HANDLE_VALUE)
- return QNetworkConfiguration::BearerUnknown;
-
- oid = OID_GEN_MEDIA_SUPPORTED;
- bytesWritten = 0;
- bool result = DeviceIoControl(handle, IOCTL_NDIS_QUERY_GLOBAL_STATS, &oid, sizeof(oid),
- &medium, sizeof(medium), &bytesWritten, 0);
- if (!result) {
- CloseHandle(handle);
- return QNetworkConfiguration::BearerUnknown;
- }
-
- oid = OID_GEN_PHYSICAL_MEDIUM;
- bytesWritten = 0;
- result = DeviceIoControl(handle, IOCTL_NDIS_QUERY_GLOBAL_STATS, &oid, sizeof(oid),
- &physicalMedium, sizeof(physicalMedium), &bytesWritten, 0);
- if (!result) {
- CloseHandle(handle);
-
- if (medium == NdisMedium802_3)
- return QNetworkConfiguration::BearerEthernet;
- else
- return QNetworkConfiguration::BearerUnknown;
- }
-
- CloseHandle(handle);
-
- if (medium == NdisMedium802_3) {
- switch (physicalMedium) {
- case NdisPhysicalMediumWirelessLan:
- return QNetworkConfiguration::BearerWLAN;
- case NdisPhysicalMediumBluetooth:
- return QNetworkConfiguration::BearerBluetooth;
- case NdisPhysicalMediumWiMax:
- return QNetworkConfiguration::BearerWiMAX;
- default:
-#ifdef BEARER_MANAGEMENT_DEBUG
- qDebug() << "Physical Medium" << physicalMedium;
-#endif
- return QNetworkConfiguration::BearerEthernet;
- }
- }
-
-#ifdef BEARER_MANAGEMENT_DEBUG
- qDebug() << medium << physicalMedium;
-#endif
-
- return QNetworkConfiguration::BearerUnknown;
-}
-
-class QNlaThread : public QThread
-{
- Q_OBJECT
-
-public:
- QNlaThread(QNlaEngine *parent = 0);
- ~QNlaThread();
-
- QList<QNetworkConfigurationPrivate *> getConfigurations();
-
- void forceUpdate();
-
-protected:
- virtual void run();
-
-private:
- void updateConfigurations(QList<QNetworkConfigurationPrivate *> &configs);
- DWORD parseBlob(NLA_BLOB *blob, QNetworkConfigurationPrivate *cpPriv) const;
- QNetworkConfigurationPrivate *parseQuerySet(const WSAQUERYSET *querySet) const;
- void fetchConfigurations();
-
-signals:
- void networksChanged();
-
-private:
- QMutex mutex;
- HANDLE handle;
- bool done;
- QList<QNetworkConfigurationPrivate *> fetchedConfigurations;
-};
-
-QNlaThread::QNlaThread(QNlaEngine *parent)
-: QThread(parent), handle(0), done(false)
-{
-}
-
-QNlaThread::~QNlaThread()
-{
- mutex.lock();
-
- done = true;
-
- if (handle) {
- /* cancel completion event */
- if (WSALookupServiceEnd(handle) == SOCKET_ERROR) {
-#ifdef BEARER_MANAGEMENT_DEBUG
- qDebug("WSALookupServiceEnd error %d", WSAGetLastError());
-#endif
- }
- }
- mutex.unlock();
-
- wait();
-}
-
-QList<QNetworkConfigurationPrivate *> QNlaThread::getConfigurations()
-{
- QMutexLocker locker(&mutex);
-
- QList<QNetworkConfigurationPrivate *> foundConfigurations = fetchedConfigurations;
- fetchedConfigurations.clear();
-
- return foundConfigurations;
-}
-
-void QNlaThread::forceUpdate()
-{
- mutex.lock();
-
- if (handle) {
- /* cancel completion event */
- if (WSALookupServiceEnd(handle) == SOCKET_ERROR) {
-#ifdef BEARER_MANAGEMENT_DEBUG
- qDebug("WSALookupServiceEnd error %d", WSAGetLastError());
-#endif
- }
- handle = 0;
- }
- mutex.unlock();
-}
-
-void QNlaThread::run()
-{
- WSAEVENT changeEvent = WSACreateEvent();
- if (changeEvent == WSA_INVALID_EVENT)
- return;
-
- while (true) {
- fetchConfigurations();
-
- WSAQUERYSET qsRestrictions;
-
- memset(&qsRestrictions, 0, sizeof(qsRestrictions));
- qsRestrictions.dwSize = sizeof(qsRestrictions);
- qsRestrictions.dwNameSpace = NS_NLA;
-
- mutex.lock();
- if (done) {
- mutex.unlock();
- break;
- }
- int result = WSALookupServiceBegin(&qsRestrictions, LUP_RETURN_ALL, &handle);
- mutex.unlock();
-
- if (result == SOCKET_ERROR)
- break;
-
- WSACOMPLETION completion;
- WSAOVERLAPPED overlapped;
-
- memset(&overlapped, 0, sizeof(overlapped));
- overlapped.hEvent = changeEvent;
-
- memset(&completion, 0, sizeof(completion));
- completion.Type = NSP_NOTIFY_EVENT;
- completion.Parameters.Event.lpOverlapped = &overlapped;
-
- DWORD bytesReturned = 0;
- result = WSANSPIoctl(handle, SIO_NSP_NOTIFY_CHANGE, 0, 0, 0, 0,
- &bytesReturned, &completion);
- if (result == SOCKET_ERROR) {
- if (WSAGetLastError() != WSA_IO_PENDING)
- break;
- }
-
- // Not interested in unrelated IO completion events
- // although we also don't want to block them
- while (WaitForSingleObjectEx(changeEvent, WSA_INFINITE, true) != WAIT_IO_COMPLETION &&
- handle)
- {
- }
-
- mutex.lock();
- if (handle) {
- result = WSALookupServiceEnd(handle);
- if (result == SOCKET_ERROR) {
- mutex.unlock();
- break;
- }
- handle = 0;
- }
- mutex.unlock();
- }
-
- WSACloseEvent(changeEvent);
-}
-
-void QNlaThread::updateConfigurations(QList<QNetworkConfigurationPrivate *> &configs)
-{
- mutex.lock();
-
- while (!fetchedConfigurations.isEmpty())
- delete fetchedConfigurations.takeFirst();
-
- fetchedConfigurations = configs;
-
- mutex.unlock();
-
- emit networksChanged();
-}
-
-DWORD QNlaThread::parseBlob(NLA_BLOB *blob, QNetworkConfigurationPrivate *cpPriv) const
-{
-#ifdef BEARER_MANAGEMENT_DEBUG
- printBlob(blob);
-#endif
-
- switch (blob->header.type) {
- case NLA_RAW_DATA:
-#ifdef BEARER_MANAGEMENT_DEBUG
- qDebug("%s: unhandled header type NLA_RAW_DATA", __FUNCTION__);
-#endif
- break;
- case NLA_INTERFACE:
- cpPriv->state = QNetworkConfiguration::Active;
- if (QNlaEngine *engine = qobject_cast<QNlaEngine *>(parent())) {
- engine->configurationInterface[cpPriv->id.toUInt()] =
- QString::fromLatin1(blob->data.interfaceData.adapterName);
- }
- break;
- case NLA_802_1X_LOCATION:
-#ifdef BEARER_MANAGEMENT_DEBUG
- qDebug("%s: unhandled header type NLA_802_1X_LOCATION", __FUNCTION__);
-#endif
- break;
- case NLA_CONNECTIVITY:
-#ifdef BEARER_MANAGEMENT_DEBUG
- qDebug("%s: unhandled header type NLA_CONNECTIVITY", __FUNCTION__);
-#endif
- break;
- case NLA_ICS:
-#ifdef BEARER_MANAGEMENT_DEBUG
- qDebug("%s: unhandled header type NLA_ICS", __FUNCTION__);
-#endif
- break;
- default:
-#ifdef BEARER_MANAGEMENT_DEBUG
- qDebug("%s: unhandled header type %d", __FUNCTION__, blob->header.type);
-#endif
- ;
- }
-
- return blob->header.nextOffset;
-}
-
-QNetworkConfigurationPrivate *QNlaThread::parseQuerySet(const WSAQUERYSET *querySet) const
-{
- QNetworkConfigurationPrivate *cpPriv = new QNetworkConfigurationPrivate;
-
- cpPriv->name = QString::fromWCharArray(querySet->lpszServiceInstanceName);
- cpPriv->isValid = true;
- cpPriv->id = QString::number(qHash(QLatin1String("NLA:") + cpPriv->name));
- cpPriv->state = QNetworkConfiguration::Defined;
- cpPriv->type = QNetworkConfiguration::InternetAccessPoint;
-
-#ifdef BEARER_MANAGEMENT_DEBUG
- qDebug() << "size:" << querySet->dwSize;
- qDebug() << "service instance name:" << QString::fromUtf16(querySet->lpszServiceInstanceName);
- qDebug() << "service class id:" << querySet->lpServiceClassId;
- qDebug() << "version:" << querySet->lpVersion;
- qDebug() << "comment:" << QString::fromUtf16(querySet->lpszComment);
- qDebug() << "namespace:" << querySet->dwNameSpace;
- qDebug() << "namespace provider id:" << querySet->lpNSProviderId;
- qDebug() << "context:" << QString::fromUtf16(querySet->lpszContext);
- qDebug() << "number of protocols:" << querySet->dwNumberOfProtocols;
- qDebug() << "protocols:" << querySet->lpafpProtocols;
- qDebug() << "query string:" << QString::fromUtf16(querySet->lpszQueryString);
- qDebug() << "number of cs addresses:" << querySet->dwNumberOfCsAddrs;
- qDebug() << "cs addresses:" << querySet->lpcsaBuffer;
- qDebug() << "output flags:" << querySet->dwOutputFlags;
-#endif
-
- if (querySet->lpBlob) {
-#ifdef BEARER_MANAGEMENT_DEBUG
- qDebug() << "blob size:" << querySet->lpBlob->cbSize;
- qDebug() << "blob data:" << querySet->lpBlob->pBlobData;
-#endif
-
- DWORD offset = 0;
- do {
- NLA_BLOB *blob = reinterpret_cast<NLA_BLOB *>(querySet->lpBlob->pBlobData + offset);
- DWORD nextOffset = parseBlob(blob, cpPriv);
- if (nextOffset == offset)
- break;
- else
- offset = nextOffset;
- } while (offset != 0 && offset < querySet->lpBlob->cbSize);
- }
-
- if (QNlaEngine *engine = qobject_cast<QNlaEngine *>(parent())) {
- const QString interface = engine->getInterfaceFromId(cpPriv->id);
- cpPriv->bearerType = qGetInterfaceType(interface);
- }
-
- return cpPriv;
-}
-
-void QNlaThread::fetchConfigurations()
-{
- QList<QNetworkConfigurationPrivate *> foundConfigurations;
-
- WSAQUERYSET qsRestrictions;
- HANDLE hLookup = 0;
-
- memset(&qsRestrictions, 0, sizeof(qsRestrictions));
- qsRestrictions.dwSize = sizeof(qsRestrictions);
- qsRestrictions.dwNameSpace = NS_NLA;
-
- int result = WSALookupServiceBegin(&qsRestrictions, LUP_RETURN_ALL | LUP_DEEP, &hLookup);
- if (result == SOCKET_ERROR) {
- mutex.lock();
- fetchedConfigurations.clear();
- mutex.unlock();
- }
-
- char buffer[0x10000];
- while (result == 0) {
- DWORD bufferLength = sizeof(buffer);
- result = WSALookupServiceNext(hLookup, LUP_RETURN_ALL,
- &bufferLength, reinterpret_cast<WSAQUERYSET *>(buffer));
-
- if (result == SOCKET_ERROR)
- break;
-
- QNetworkConfigurationPrivate *cpPriv =
- parseQuerySet(reinterpret_cast<WSAQUERYSET *>(buffer));
-
- foundConfigurations.append(cpPriv);
- }
-
- if (hLookup) {
- result = WSALookupServiceEnd(hLookup);
- if (result == SOCKET_ERROR) {
-#ifdef BEARER_MANAGEMENT_DEBUG
- qDebug("WSALookupServiceEnd error %d", WSAGetLastError());
-#endif
- }
- }
-
- updateConfigurations(foundConfigurations);
-}
-
-QNlaEngine::QNlaEngine(QObject *parent)
-: QBearerEngineImpl(parent), nlaThread(0)
-{
- nlaThread = new QNlaThread(this);
- connect(nlaThread, SIGNAL(networksChanged()),
- this, SLOT(networksChanged()));
- nlaThread->start();
-
- qApp->processEvents(QEventLoop::ExcludeUserInputEvents);
-}
-
-QNlaEngine::~QNlaEngine()
-{
- delete nlaThread;
-}
-
-void QNlaEngine::networksChanged()
-{
- QMutexLocker locker(&mutex);
-
- QStringList previous = accessPointConfigurations.keys();
-
- QList<QNetworkConfigurationPrivate *> foundConfigurations = nlaThread->getConfigurations();
- while (!foundConfigurations.isEmpty()) {
- QNetworkConfigurationPrivate *cpPriv = foundConfigurations.takeFirst();
-
- previous.removeAll(cpPriv->id);
-
- if (accessPointConfigurations.contains(cpPriv->id)) {
- QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(cpPriv->id);
-
- bool changed = false;
-
- ptr->mutex.lock();
-
- if (ptr->isValid != cpPriv->isValid) {
- ptr->isValid = cpPriv->isValid;
- changed = true;
- }
-
- if (ptr->name != cpPriv->name) {
- ptr->name = cpPriv->name;
- changed = true;
- }
-
- if (ptr->state != cpPriv->state) {
- ptr->state = cpPriv->state;
- changed = true;
- }
-
- ptr->mutex.unlock();
-
- if (changed) {
- locker.unlock();
- emit configurationChanged(ptr);
- locker.relock();
- }
-
- delete cpPriv;
- } else {
- QNetworkConfigurationPrivatePointer ptr(cpPriv);
-
- accessPointConfigurations.insert(ptr->id, ptr);
-
- locker.unlock();
- emit configurationAdded(ptr);
- locker.relock();
- }
- }
-
- while (!previous.isEmpty()) {
- QNetworkConfigurationPrivatePointer ptr =
- accessPointConfigurations.take(previous.takeFirst());
-
- locker.unlock();
- emit configurationRemoved(ptr);
- locker.relock();
- }
-
- locker.unlock();
- emit updateCompleted();
-}
-
-QString QNlaEngine::getInterfaceFromId(const QString &id)
-{
- QMutexLocker locker(&mutex);
-
- return configurationInterface.value(id.toUInt());
-}
-
-bool QNlaEngine::hasIdentifier(const QString &id)
-{
- QMutexLocker locker(&mutex);
-
- return configurationInterface.contains(id.toUInt());
-}
-
-void QNlaEngine::connectToId(const QString &id)
-{
- emit connectionError(id, OperationNotSupported);
-}
-
-void QNlaEngine::disconnectFromId(const QString &id)
-{
- emit connectionError(id, OperationNotSupported);
-}
-
-void QNlaEngine::requestUpdate()
-{
- QMutexLocker locker(&mutex);
-
- nlaThread->forceUpdate();
-}
-
-QNetworkSession::State QNlaEngine::sessionStateForId(const QString &id)
-{
- QMutexLocker locker(&mutex);
-
- QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id);
-
- if (!ptr)
- return QNetworkSession::Invalid;
-
- if (!ptr->isValid) {
- return QNetworkSession::Invalid;
- } else if ((ptr->state & QNetworkConfiguration::Active) == QNetworkConfiguration::Active) {
- return QNetworkSession::Connected;
- } else if ((ptr->state & QNetworkConfiguration::Discovered) ==
- QNetworkConfiguration::Discovered) {
- return QNetworkSession::Disconnected;
- } else if ((ptr->state & QNetworkConfiguration::Defined) == QNetworkConfiguration::Defined) {
- return QNetworkSession::NotAvailable;
- } else if ((ptr->state & QNetworkConfiguration::Undefined) ==
- QNetworkConfiguration::Undefined) {
- return QNetworkSession::NotAvailable;
- }
-
- return QNetworkSession::Invalid;
-}
-
-QNetworkConfigurationManager::Capabilities QNlaEngine::capabilities() const
-{
- return QNetworkConfigurationManager::ForcedRoaming;
-}
-
-QNetworkSessionPrivate *QNlaEngine::createSessionBackend()
-{
- return new QNetworkSessionPrivateImpl;
-}
-
-QNetworkConfigurationPrivatePointer QNlaEngine::defaultConfiguration()
-{
- return QNetworkConfigurationPrivatePointer();
-}
-
-#include "qnlaengine.moc"
-QT_END_NAMESPACE
-
diff --git a/src/plugins/bearer/nla/qnlaengine.h b/src/plugins/bearer/nla/qnlaengine.h
deleted file mode 100644
index 90efa50201..0000000000
--- a/src/plugins/bearer/nla/qnlaengine.h
+++ /dev/null
@@ -1,110 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 QNLAENGINE_P_H
-#define QNLAENGINE_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 <private/qbearerengine_impl_p.h>
-
-#include <QtNetwork/private/qnativesocketengine_p.h>
-
-#include <QMap>
-
-QT_BEGIN_NAMESPACE
-
-class QNetworkConfigurationPrivate;
-class QNlaThread;
-
-class QWindowsSockInit2
-{
-public:
- QWindowsSockInit2();
- ~QWindowsSockInit2();
- int version;
-};
-
-class QNlaEngine : public QBearerEngineImpl
-{
- Q_OBJECT
-
- friend class QNlaThread;
-
-public:
- QNlaEngine(QObject *parent = 0);
- ~QNlaEngine();
-
- QString getInterfaceFromId(const QString &id);
- bool hasIdentifier(const QString &id);
-
- void connectToId(const QString &id);
- void disconnectFromId(const QString &id);
-
- Q_INVOKABLE void requestUpdate();
-
- QNetworkSession::State sessionStateForId(const QString &id);
-
- QNetworkConfigurationManager::Capabilities capabilities() const;
-
- QNetworkSessionPrivate *createSessionBackend();
-
- QNetworkConfigurationPrivatePointer defaultConfiguration();
-
-private Q_SLOTS:
- void networksChanged();
-
-private:
- QWindowsSockInit2 winSock;
- QNlaThread *nlaThread;
- QMap<uint, QString> configurationInterface;
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/plugins/bearer/platformdefs_win.h b/src/plugins/bearer/platformdefs_win.h
deleted file mode 100644
index 0477dc45c3..0000000000
--- a/src/plugins/bearer/platformdefs_win.h
+++ /dev/null
@@ -1,142 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 QPLATFORMDEFS_WIN_H
-#define QPLATFORMDEFS_WIN_H
-
-// Since we need to include winsock2.h, we need to define WIN32_LEAN_AND_MEAN
-// somewhere above so windows.h won't include winsock.h.
-#include <winsock2.h>
-#include <mswsock.h>
-#undef interface
-#include <wincrypt.h>
-#include <winioctl.h>
-
-QT_BEGIN_NAMESPACE
-
-#ifndef NS_NLA
-
-#define NS_NLA 15
-
-#ifndef NLA_NAMESPACE_GUID
-enum NLA_BLOB_DATA_TYPE {
- NLA_RAW_DATA = 0,
- NLA_INTERFACE = 1,
- NLA_802_1X_LOCATION = 2,
- NLA_CONNECTIVITY = 3,
- NLA_ICS = 4
-};
-
-enum NLA_CONNECTIVITY_TYPE {
- NLA_NETWORK_AD_HOC = 0,
- NLA_NETWORK_MANAGED = 1,
- NLA_NETWORK_UNMANAGED = 2,
- NLA_NETWORK_UNKNOWN = 3
-};
-
-enum NLA_INTERNET {
- NLA_INTERNET_UNKNOWN = 0,
- NLA_INTERNET_NO = 1,
- NLA_INTERNET_YES = 2
-};
-
-struct NLA_BLOB {
- struct {
- NLA_BLOB_DATA_TYPE type;
- DWORD dwSize;
- DWORD nextOffset;
- } header;
-
- union {
- // NLA_RAW_DATA
- CHAR rawData[1];
-
- // NLA_INTERFACE
- struct {
- DWORD dwType;
- DWORD dwSpeed;
- CHAR adapterName[1];
- } interfaceData;
-
- // NLA_802_1X_LOCATION
- struct {
- CHAR information[1];
- } locationData;
-
- // NLA_CONNECTIVITY
- struct {
- NLA_CONNECTIVITY_TYPE type;
- NLA_INTERNET internet;
- } connectivity;
-
- // NLA_ICS
- struct {
- struct {
- DWORD speed;
- DWORD type;
- DWORD state;
- WCHAR machineName[256];
- WCHAR sharedAdapterName[256];
- } remote;
- } ICS;
- } data;
-};
-#endif // NLA_NAMESPACE_GUID
-
-#endif
-
-enum NDIS_MEDIUM {
- NdisMedium802_3 = 0,
-};
-
-enum NDIS_PHYSICAL_MEDIUM {
- NdisPhysicalMediumWirelessLan = 1,
- NdisPhysicalMediumBluetooth = 10,
- NdisPhysicalMediumWiMax = 12,
-};
-
-#define OID_GEN_MEDIA_SUPPORTED 0x00010103
-#define OID_GEN_PHYSICAL_MEDIUM 0x00010202
-
-#define IOCTL_NDIS_QUERY_GLOBAL_STATS \
- CTL_CODE(FILE_DEVICE_PHYSICAL_NETCARD, 0, METHOD_OUT_DIRECT, FILE_ANY_ACCESS)
-
-QT_END_NAMESPACE
-
-#endif // QPLATFORMDEFS_WIN_H
diff --git a/src/plugins/doc/snippets/code/src_plugins_platforms_qnx_qqnxwindow.cpp b/src/plugins/doc/snippets/code/src_plugins_platforms_qnx_qqnxwindow.cpp
index ce82533c3e..6b6e2966b2 100644
--- a/src/plugins/doc/snippets/code/src_plugins_platforms_qnx_qqnxwindow.cpp
+++ b/src/plugins/doc/snippets/code/src_plugins_platforms_qnx_qqnxwindow.cpp
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2018 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$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//! [0]
QQuickView *view = new QQuickView(parent);
diff --git a/src/plugins/generic/.prev_CMakeLists.txt b/src/plugins/generic/.prev_CMakeLists.txt
deleted file mode 100644
index b3851ffbd1..0000000000
--- a/src/plugins/generic/.prev_CMakeLists.txt
+++ /dev/null
@@ -1,23 +0,0 @@
-# Generated from generic.pro.
-
-if(QT_FEATURE_evdev)
- add_subdirectory(evdevmouse)
- add_subdirectory(evdevtouch)
- add_subdirectory(evdevkeyboard)
-endif()
-if(QT_FEATURE_evdev AND QT_FEATURE_tabletevent)
- add_subdirectory(evdevtablet)
-endif()
-if(QT_FEATURE_tslib)
- add_subdirectory(tslib)
-endif()
-if(QT_FEATURE_tuiotouch)
- add_subdirectory(tuiotouch)
-endif()
-if(QT_FEATURE_libinput)
- add_subdirectory(libinput)
-endif()
-if(FREEBSD)
- add_subdirectory(bsdkeyboard)
- add_subdirectory(bsdmouse)
-endif()
diff --git a/src/plugins/generic/CMakeLists.txt b/src/plugins/generic/CMakeLists.txt
index f5890d0961..6d3cf2a925 100644
--- a/src/plugins/generic/CMakeLists.txt
+++ b/src/plugins/generic/CMakeLists.txt
@@ -1,4 +1,5 @@
-# Generated from generic.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
if(QT_FEATURE_evdev)
add_subdirectory(evdevmouse)
@@ -18,6 +19,6 @@ if(QT_FEATURE_libinput)
add_subdirectory(libinput)
endif()
if(FREEBSD)
- # add_subdirectory(bsdkeyboard) # special case TODO
- # add_subdirectory(bsdmouse) # special case TODO
+ # add_subdirectory(bsdkeyboard) # TODO: QTBUG-112770
+ # add_subdirectory(bsdmouse) # TODO: QTBUG-112770
endif()
diff --git a/src/plugins/generic/bsdkeyboard/bsdkeyboard.pro b/src/plugins/generic/bsdkeyboard/bsdkeyboard.pro
deleted file mode 100644
index c14c38c839..0000000000
--- a/src/plugins/generic/bsdkeyboard/bsdkeyboard.pro
+++ /dev/null
@@ -1,16 +0,0 @@
-TARGET = qbsdkeyboardplugin
-
-PLUGIN_TYPE = generic
-PLUGIN_EXTENDS = -
-PLUGIN_CLASS_NAME = QBsdKeyboardPlugin
-load(qt_plugin)
-
-QT += core gui-private
-
-HEADERS = qbsdkeyboard.h
-SOURCES = main.cpp \
- qbsdkeyboard.cpp
-
-OTHER_FILES += \
- qbsdkeyboard.json
-
diff --git a/src/plugins/generic/bsdkeyboard/main.cpp b/src/plugins/generic/bsdkeyboard/main.cpp
index b65d500230..3308d5007e 100644
--- a/src/plugins/generic/bsdkeyboard/main.cpp
+++ b/src/plugins/generic/bsdkeyboard/main.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2015-2016 Oleksandr Tymoshenko <gonzo@bluezbox.com>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2015-2016 Oleksandr Tymoshenko <gonzo@bluezbox.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtGui/qgenericplugin.h>
#include "qbsdkeyboard.h"
diff --git a/src/plugins/generic/bsdkeyboard/qbsdkeyboard.cpp b/src/plugins/generic/bsdkeyboard/qbsdkeyboard.cpp
index 784ec54542..f2f177e9a2 100644
--- a/src/plugins/generic/bsdkeyboard/qbsdkeyboard.cpp
+++ b/src/plugins/generic/bsdkeyboard/qbsdkeyboard.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2015-2016 Oleksandr Tymoshenko <gonzo@bluezbox.com>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2015-2016 Oleksandr Tymoshenko <gonzo@bluezbox.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qbsdkeyboard.h"
diff --git a/src/plugins/generic/bsdkeyboard/qbsdkeyboard.h b/src/plugins/generic/bsdkeyboard/qbsdkeyboard.h
index 46d8988d3a..6ae3ca2317 100644
--- a/src/plugins/generic/bsdkeyboard/qbsdkeyboard.h
+++ b/src/plugins/generic/bsdkeyboard/qbsdkeyboard.h
@@ -1,48 +1,12 @@
-/****************************************************************************
-**
-** Copyright (C) 2015-2016 Oleksandr Tymoshenko <gonzo@bluezbox.com>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2015-2016 Oleksandr Tymoshenko <gonzo@bluezbox.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QBSDKEYBOARD_H
#define QBSDKEYBOARD_H
#include <qobject.h>
#include <QDataStream>
-#include <QVector>
+#include <QList>
QT_BEGIN_NAMESPACE
@@ -137,7 +101,7 @@ private:
bool m_numLock = false;
bool m_scrollLock = false;
- QVector<QBsdKeyboardMap::Mapping> m_keymap;
+ QList<QBsdKeyboardMap::Mapping> m_keymap;
};
QT_END_NAMESPACE
diff --git a/src/plugins/generic/bsdkeyboard/qbsdkeyboard_defaultmap.h b/src/plugins/generic/bsdkeyboard/qbsdkeyboard_defaultmap.h
index 69c03b3daf..e229f757dc 100644
--- a/src/plugins/generic/bsdkeyboard/qbsdkeyboard_defaultmap.h
+++ b/src/plugins/generic/bsdkeyboard/qbsdkeyboard_defaultmap.h
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Copyright (C) 2015-2016 Oleksandr Tymoshenko <gonzo@bluezbox.com>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// Copyright (C) 2015-2016 Oleksandr Tymoshenko <gonzo@bluezbox.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QBSDKEYBOARD_DEFAULTMAP_P_H
#define QBSDKEYBOARD_DEFAULTMAP_P_H
diff --git a/src/plugins/generic/bsdmouse/bsdmouse.pro b/src/plugins/generic/bsdmouse/bsdmouse.pro
deleted file mode 100644
index 11949b95d5..0000000000
--- a/src/plugins/generic/bsdmouse/bsdmouse.pro
+++ /dev/null
@@ -1,16 +0,0 @@
-TARGET = qbsdmouseplugin
-
-PLUGIN_TYPE = generic
-PLUGIN_EXTENDS = -
-PLUGIN_CLASS_NAME = QBsdMousePlugin
-load(qt_plugin)
-
-QT += core-private gui-private
-
-HEADERS = qbsdmouse.h
-SOURCES = main.cpp \
- qbsdmouse.cpp
-
-OTHER_FILES += \
- qbsdmouse.json
-
diff --git a/src/plugins/generic/bsdmouse/main.cpp b/src/plugins/generic/bsdmouse/main.cpp
index d676d5a1bb..59d995f8b9 100644
--- a/src/plugins/generic/bsdmouse/main.cpp
+++ b/src/plugins/generic/bsdmouse/main.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2015-2016 Oleksandr Tymoshenko <gonzo@bluezbox.com>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2015-2016 Oleksandr Tymoshenko <gonzo@bluezbox.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtGui/qgenericplugin.h>
#include "qbsdmouse.h"
diff --git a/src/plugins/generic/bsdmouse/qbsdmouse.cpp b/src/plugins/generic/bsdmouse/qbsdmouse.cpp
index 55905199b8..d4ed6bba2d 100644
--- a/src/plugins/generic/bsdmouse/qbsdmouse.cpp
+++ b/src/plugins/generic/bsdmouse/qbsdmouse.cpp
@@ -1,44 +1,9 @@
-/****************************************************************************
-**
-** Copyright (C) 2015-2016 Oleksandr Tymoshenko <gonzo@bluezbox.com>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2015-2016 Oleksandr Tymoshenko <gonzo@bluezbox.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qbsdmouse.h"
+#include <QFile>
#include <QSocketNotifier>
#include <QStringList>
#include <QPoint>
diff --git a/src/plugins/generic/bsdmouse/qbsdmouse.h b/src/plugins/generic/bsdmouse/qbsdmouse.h
index 724b9c8484..7c503f7cc4 100644
--- a/src/plugins/generic/bsdmouse/qbsdmouse.h
+++ b/src/plugins/generic/bsdmouse/qbsdmouse.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2015-2016 Oleksandr Tymoshenko <gonzo@bluezbox.com>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2015-2016 Oleksandr Tymoshenko <gonzo@bluezbox.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QBSDMOUSE_H
#define QBSDMOUSE_H
diff --git a/src/plugins/generic/evdevkeyboard/CMakeLists.txt b/src/plugins/generic/evdevkeyboard/CMakeLists.txt
index 86f5c36124..53be12face 100644
--- a/src/plugins/generic/evdevkeyboard/CMakeLists.txt
+++ b/src/plugins/generic/evdevkeyboard/CMakeLists.txt
@@ -1,22 +1,20 @@
-# Generated from evdevkeyboard.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## QEvdevKeyboardPlugin Plugin:
#####################################################################
-qt_add_plugin(QEvdevKeyboardPlugin
+qt_internal_add_plugin(QEvdevKeyboardPlugin
OUTPUT_NAME qevdevkeyboardplugin
- TYPE generic
+ PLUGIN_TYPE generic
+ DEFAULT_IF FALSE
SOURCES
main.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Core
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
Qt::InputSupportPrivate
)
-
-#### Keys ignored in scope 1:.:.:evdevkeyboard.pro:<TRUE>:
-# OTHER_FILES = "evdevkeyboard.json"
-# PLUGIN_EXTENDS = "-"
diff --git a/src/plugins/generic/evdevkeyboard/evdevkeyboard.pro b/src/plugins/generic/evdevkeyboard/evdevkeyboard.pro
deleted file mode 100644
index 73fddf4d26..0000000000
--- a/src/plugins/generic/evdevkeyboard/evdevkeyboard.pro
+++ /dev/null
@@ -1,13 +0,0 @@
-TARGET = qevdevkeyboardplugin
-
-QT += core-private gui-private input_support-private
-
-SOURCES = main.cpp
-
-OTHER_FILES += \
- evdevkeyboard.json
-
-PLUGIN_TYPE = generic
-PLUGIN_EXTENDS = -
-PLUGIN_CLASS_NAME = QEvdevKeyboardPlugin
-load(qt_plugin)
diff --git a/src/plugins/generic/evdevkeyboard/main.cpp b/src/plugins/generic/evdevkeyboard/main.cpp
index 5c170e1a06..2931fea907 100644
--- a/src/plugins/generic/evdevkeyboard/main.cpp
+++ b/src/plugins/generic/evdevkeyboard/main.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtGui/qgenericplugin.h>
#include <QtInputSupport/private/qevdevkeyboardmanager_p.h>
@@ -63,7 +27,8 @@ QObject* QEvdevKeyboardPlugin::create(const QString &key,
{
if (!key.compare(QLatin1String("EvdevKeyboard"), Qt::CaseInsensitive))
return new QEvdevKeyboardManager(key, specification);
- return 0;
+
+ return nullptr;
}
QT_END_NAMESPACE
diff --git a/src/plugins/generic/evdevmouse/CMakeLists.txt b/src/plugins/generic/evdevmouse/CMakeLists.txt
index 2ed6c1b6d4..e0836ecccc 100644
--- a/src/plugins/generic/evdevmouse/CMakeLists.txt
+++ b/src/plugins/generic/evdevmouse/CMakeLists.txt
@@ -1,22 +1,20 @@
-# Generated from evdevmouse.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## QEvdevMousePlugin Plugin:
#####################################################################
-qt_add_plugin(QEvdevMousePlugin
+qt_internal_add_plugin(QEvdevMousePlugin
OUTPUT_NAME qevdevmouseplugin
- TYPE generic
+ PLUGIN_TYPE generic
+ DEFAULT_IF FALSE
SOURCES
main.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Core
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
Qt::InputSupportPrivate
)
-
-#### Keys ignored in scope 1:.:.:evdevmouse.pro:<TRUE>:
-# OTHER_FILES = "evdevmouse.json"
-# PLUGIN_EXTENDS = "-"
diff --git a/src/plugins/generic/evdevmouse/evdevmouse.pro b/src/plugins/generic/evdevmouse/evdevmouse.pro
deleted file mode 100644
index f3a8558ef2..0000000000
--- a/src/plugins/generic/evdevmouse/evdevmouse.pro
+++ /dev/null
@@ -1,13 +0,0 @@
-TARGET = qevdevmouseplugin
-
-QT += core-private gui-private input_support-private
-
-SOURCES = main.cpp
-
-OTHER_FILES += \
- evdevmouse.json
-
-PLUGIN_TYPE = generic
-PLUGIN_EXTENDS = -
-PLUGIN_CLASS_NAME = QEvdevMousePlugin
-load(qt_plugin)
diff --git a/src/plugins/generic/evdevmouse/main.cpp b/src/plugins/generic/evdevmouse/main.cpp
index 1b8517f4c4..9629d2c927 100644
--- a/src/plugins/generic/evdevmouse/main.cpp
+++ b/src/plugins/generic/evdevmouse/main.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtGui/qgenericplugin.h>
#include <QtInputSupport/private/qevdevmousemanager_p.h>
@@ -63,7 +27,8 @@ QObject* QEvdevMousePlugin::create(const QString &key,
{
if (!key.compare(QLatin1String("EvdevMouse"), Qt::CaseInsensitive))
return new QEvdevMouseManager(key, specification);
- return 0;
+
+ return nullptr;
}
QT_END_NAMESPACE
diff --git a/src/plugins/generic/evdevtablet/CMakeLists.txt b/src/plugins/generic/evdevtablet/CMakeLists.txt
index 93dd10a0e1..ef21469f70 100644
--- a/src/plugins/generic/evdevtablet/CMakeLists.txt
+++ b/src/plugins/generic/evdevtablet/CMakeLists.txt
@@ -1,22 +1,20 @@
-# Generated from evdevtablet.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## QEvdevTabletPlugin Plugin:
#####################################################################
-qt_add_plugin(QEvdevTabletPlugin
+qt_internal_add_plugin(QEvdevTabletPlugin
OUTPUT_NAME qevdevtabletplugin
- TYPE generic
+ PLUGIN_TYPE generic
+ DEFAULT_IF FALSE
SOURCES
main.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Core
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
Qt::InputSupportPrivate
)
-
-#### Keys ignored in scope 1:.:.:evdevtablet.pro:<TRUE>:
-# OTHER_FILES = "evdevtablet.json"
-# PLUGIN_EXTENDS = "-"
diff --git a/src/plugins/generic/evdevtablet/evdevtablet.pro b/src/plugins/generic/evdevtablet/evdevtablet.pro
deleted file mode 100644
index 1409cd83c9..0000000000
--- a/src/plugins/generic/evdevtablet/evdevtablet.pro
+++ /dev/null
@@ -1,13 +0,0 @@
-TARGET = qevdevtabletplugin
-
-SOURCES = main.cpp
-
-QT += core-private gui-private input_support-private
-
-OTHER_FILES += \
- evdevtablet.json
-
-PLUGIN_TYPE = generic
-PLUGIN_EXTENDS = -
-PLUGIN_CLASS_NAME = QEvdevTabletPlugin
-load(qt_plugin)
diff --git a/src/plugins/generic/evdevtablet/main.cpp b/src/plugins/generic/evdevtablet/main.cpp
index f43a32910d..6313c09921 100644
--- a/src/plugins/generic/evdevtablet/main.cpp
+++ b/src/plugins/generic/evdevtablet/main.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtGui/qgenericplugin.h>
#include <QtInputSupport/private/qevdevtabletmanager_p.h>
@@ -63,7 +27,7 @@ QObject* QEvdevTabletPlugin::create(const QString &key,
if (!key.compare(QLatin1String("EvdevTablet"), Qt::CaseInsensitive))
return new QEvdevTabletManager(key, spec);
- return 0;
+ return nullptr;
}
QT_END_NAMESPACE
diff --git a/src/plugins/generic/evdevtouch/CMakeLists.txt b/src/plugins/generic/evdevtouch/CMakeLists.txt
index e4a4d40c2a..f3f489586a 100644
--- a/src/plugins/generic/evdevtouch/CMakeLists.txt
+++ b/src/plugins/generic/evdevtouch/CMakeLists.txt
@@ -1,22 +1,20 @@
-# Generated from evdevtouch.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## QEvdevTouchScreenPlugin Plugin:
#####################################################################
-qt_add_plugin(QEvdevTouchScreenPlugin
+qt_internal_add_plugin(QEvdevTouchScreenPlugin
OUTPUT_NAME qevdevtouchplugin
- TYPE generic
+ PLUGIN_TYPE generic
+ DEFAULT_IF FALSE
SOURCES
main.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Core
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
Qt::InputSupportPrivate
)
-
-#### Keys ignored in scope 1:.:.:evdevtouch.pro:<TRUE>:
-# OTHER_FILES = "evdevtouch.json"
-# PLUGIN_EXTENDS = "-"
diff --git a/src/plugins/generic/evdevtouch/evdevtouch.pro b/src/plugins/generic/evdevtouch/evdevtouch.pro
deleted file mode 100644
index 3ca646aaca..0000000000
--- a/src/plugins/generic/evdevtouch/evdevtouch.pro
+++ /dev/null
@@ -1,13 +0,0 @@
-TARGET = qevdevtouchplugin
-
-SOURCES = main.cpp
-
-QT += core-private gui-private input_support-private
-
-OTHER_FILES += \
- evdevtouch.json
-
-PLUGIN_TYPE = generic
-PLUGIN_EXTENDS = -
-PLUGIN_CLASS_NAME = QEvdevTouchScreenPlugin
-load(qt_plugin)
diff --git a/src/plugins/generic/evdevtouch/main.cpp b/src/plugins/generic/evdevtouch/main.cpp
index f1a0ad53ab..f39f9645bc 100644
--- a/src/plugins/generic/evdevtouch/main.cpp
+++ b/src/plugins/generic/evdevtouch/main.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtGui/qgenericplugin.h>
#include <QtInputSupport/private/qevdevtouchmanager_p.h>
@@ -63,7 +27,7 @@ QObject* QEvdevTouchScreenPlugin::create(const QString &key,
if (!key.compare(QLatin1String("EvdevTouch"), Qt::CaseInsensitive))
return new QEvdevTouchManager(key, spec);
- return 0;
+ return nullptr;
}
QT_END_NAMESPACE
diff --git a/src/plugins/generic/generic.pro b/src/plugins/generic/generic.pro
deleted file mode 100644
index 980aa1a506..0000000000
--- a/src/plugins/generic/generic.pro
+++ /dev/null
@@ -1,24 +0,0 @@
-TEMPLATE = subdirs
-QT_FOR_CONFIG += gui-private
-
-qtConfig(evdev) {
- SUBDIRS += evdevmouse evdevtouch evdevkeyboard
- qtConfig(tabletevent): \
- SUBDIRS += evdevtablet
-}
-
-qtConfig(tslib) {
- SUBDIRS += tslib
-}
-
-qtConfig(tuiotouch) {
- SUBDIRS += tuiotouch
-}
-
-qtConfig(libinput) {
- SUBDIRS += libinput
-}
-
-freebsd {
- SUBDIRS += bsdkeyboard bsdmouse
-}
diff --git a/src/plugins/generic/libinput/CMakeLists.txt b/src/plugins/generic/libinput/CMakeLists.txt
index b772623307..f92b3d5353 100644
--- a/src/plugins/generic/libinput/CMakeLists.txt
+++ b/src/plugins/generic/libinput/CMakeLists.txt
@@ -1,22 +1,20 @@
-# Generated from libinput.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## QLibInputPlugin Plugin:
#####################################################################
-qt_add_plugin(QLibInputPlugin
+qt_internal_add_plugin(QLibInputPlugin
OUTPUT_NAME qlibinputplugin
- TYPE generic
+ PLUGIN_TYPE generic
+ DEFAULT_IF FALSE
SOURCES
main.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Core
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
Qt::InputSupportPrivate
)
-
-#### Keys ignored in scope 1:.:.:libinput.pro:<TRUE>:
-# OTHER_FILES = "libinput.json"
-# PLUGIN_EXTENDS = "-"
diff --git a/src/plugins/generic/libinput/libinput.pro b/src/plugins/generic/libinput/libinput.pro
deleted file mode 100644
index 434bf7b945..0000000000
--- a/src/plugins/generic/libinput/libinput.pro
+++ /dev/null
@@ -1,12 +0,0 @@
-TARGET = qlibinputplugin
-
-QT += core-private gui-private input_support-private
-
-SOURCES = main.cpp
-
-OTHER_FILES = libinput.json
-
-PLUGIN_TYPE = generic
-PLUGIN_EXTENDS = -
-PLUGIN_CLASS_NAME = QLibInputPlugin
-load(qt_plugin)
diff --git a/src/plugins/generic/libinput/main.cpp b/src/plugins/generic/libinput/main.cpp
index 6d1e76c0f0..a191fd3d9b 100644
--- a/src/plugins/generic/libinput/main.cpp
+++ b/src/plugins/generic/libinput/main.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtGui/qgenericplugin.h>
#include <QtInputSupport/private/qlibinputhandler_p.h>
@@ -48,7 +12,7 @@ class QLibInputPlugin : public QGenericPlugin
Q_PLUGIN_METADATA(IID QGenericPluginFactoryInterface_iid FILE "libinput.json")
public:
- QObject *create(const QString &key, const QString &specification);
+ QObject *create(const QString &key, const QString &specification) override;
};
QObject *QLibInputPlugin::create(const QString &key, const QString &specification)
@@ -56,7 +20,7 @@ QObject *QLibInputPlugin::create(const QString &key, const QString &specificatio
if (!key.compare(QLatin1String("libinput"), Qt::CaseInsensitive))
return new QLibInputHandler(key, specification);
- return 0;
+ return nullptr;
}
QT_END_NAMESPACE
diff --git a/src/plugins/generic/tslib/.prev_CMakeLists.txt b/src/plugins/generic/tslib/.prev_CMakeLists.txt
deleted file mode 100644
index 3e82a077c3..0000000000
--- a/src/plugins/generic/tslib/.prev_CMakeLists.txt
+++ /dev/null
@@ -1,23 +0,0 @@
-# Generated from tslib.pro.
-
-#####################################################################
-## QTsLibPlugin Plugin:
-#####################################################################
-
-qt_add_plugin(QTsLibPlugin
- OUTPUT_NAME qtslibplugin
- TYPE generic
- SOURCES
- main.cpp
- PUBLIC_LIBRARIES
- PkgConfig::Tslib
- Qt::Core
- Qt::CorePrivate
- Qt::Gui
- Qt::GuiPrivate
- Qt::InputSupportPrivate
-)
-
-#### Keys ignored in scope 1:.:.:tslib.pro:<TRUE>:
-# OTHER_FILES = "tslib.json"
-# PLUGIN_EXTENDS = "-"
diff --git a/src/plugins/generic/tslib/CMakeLists.txt b/src/plugins/generic/tslib/CMakeLists.txt
index 964e322a55..8512133799 100644
--- a/src/plugins/generic/tslib/CMakeLists.txt
+++ b/src/plugins/generic/tslib/CMakeLists.txt
@@ -1,17 +1,19 @@
-# Generated from tslib.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
-qt_find_package(Tslib) # special case
+qt_find_package(Tslib)
#####################################################################
## QTsLibPlugin Plugin:
#####################################################################
-qt_add_plugin(QTsLibPlugin
+qt_internal_add_plugin(QTsLibPlugin
OUTPUT_NAME qtslibplugin
- TYPE generic
+ PLUGIN_TYPE generic
+ DEFAULT_IF FALSE
SOURCES
main.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
PkgConfig::Tslib
Qt::Core
Qt::CorePrivate
@@ -19,7 +21,3 @@ qt_add_plugin(QTsLibPlugin
Qt::GuiPrivate
Qt::InputSupportPrivate
)
-
-#### Keys ignored in scope 1:.:.:tslib.pro:<TRUE>:
-# OTHER_FILES = "tslib.json"
-# PLUGIN_EXTENDS = "-"
diff --git a/src/plugins/generic/tslib/main.cpp b/src/plugins/generic/tslib/main.cpp
index fb9e0c35f3..c2f4ccb105 100644
--- a/src/plugins/generic/tslib/main.cpp
+++ b/src/plugins/generic/tslib/main.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtGui/qgenericplugin.h>
#include <QtInputSupport/private/qtslib_p.h>
@@ -48,7 +12,7 @@ class QTsLibPlugin : public QGenericPlugin
Q_PLUGIN_METADATA(IID QGenericPluginFactoryInterface_iid FILE "tslib.json")
public:
- QObject* create(const QString &key, const QString &specification);
+ QObject* create(const QString &key, const QString &specification) override;
};
QObject* QTsLibPlugin::create(const QString &key,
@@ -58,7 +22,7 @@ QObject* QTsLibPlugin::create(const QString &key,
|| !key.compare(QLatin1String("TslibRaw"), Qt::CaseInsensitive))
return new QTsLibMouseHandler(key, specification);
- return 0;
+ return nullptr;
}
QT_END_NAMESPACE
diff --git a/src/plugins/generic/tslib/tslib.pro b/src/plugins/generic/tslib/tslib.pro
deleted file mode 100644
index 7c3a0bf607..0000000000
--- a/src/plugins/generic/tslib/tslib.pro
+++ /dev/null
@@ -1,14 +0,0 @@
-TARGET = qtslibplugin
-
-SOURCES = main.cpp
-
-QT += core-private gui-private input_support-private
-
-QMAKE_USE += tslib
-
-OTHER_FILES += tslib.json
-
-PLUGIN_TYPE = generic
-PLUGIN_EXTENDS = -
-PLUGIN_CLASS_NAME = QTsLibPlugin
-load(qt_plugin)
diff --git a/src/plugins/generic/tuiotouch/CMakeLists.txt b/src/plugins/generic/tuiotouch/CMakeLists.txt
index 82db49d4c3..b03ed9e360 100644
--- a/src/plugins/generic/tuiotouch/CMakeLists.txt
+++ b/src/plugins/generic/tuiotouch/CMakeLists.txt
@@ -1,12 +1,14 @@
-# Generated from tuiotouch.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## QTuioTouchPlugin Plugin:
#####################################################################
-qt_add_plugin(QTuioTouchPlugin
+qt_internal_add_plugin(QTuioTouchPlugin
OUTPUT_NAME qtuiotouchplugin
- TYPE generic
+ PLUGIN_TYPE generic
+ DEFAULT_IF FALSE
SOURCES
main.cpp
qoscbundle.cpp qoscbundle_p.h
@@ -16,14 +18,10 @@ qt_add_plugin(QTuioTouchPlugin
qtuiotoken_p.h
DEFINES
QT_NO_FOREACH
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Core
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
Qt::Network
)
-
-#### Keys ignored in scope 1:.:.:tuiotouch.pro:<TRUE>:
-# OTHER_FILES = "tuiotouch.json"
-# PLUGIN_EXTENDS = "-"
diff --git a/src/plugins/generic/tuiotouch/main.cpp b/src/plugins/generic/tuiotouch/main.cpp
index b424458e9f..037a5d64a0 100644
--- a/src/plugins/generic/tuiotouch/main.cpp
+++ b/src/plugins/generic/tuiotouch/main.cpp
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 Robin Burchell <robin.burchell@viroteck.net>
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and 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$
-**
-****************************************************************************/
+// Copyright (C) 2014 Robin Burchell <robin.burchell@viroteck.net>
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtGui/qgenericplugin.h>
#include <QCoreApplication>
@@ -53,7 +17,7 @@ class QTuioTouchPlugin : public QGenericPlugin
public:
QTuioTouchPlugin();
- QObject* create(const QString &key, const QString &specification);
+ QObject* create(const QString &key, const QString &specification) override;
};
QTuioTouchPlugin::QTuioTouchPlugin()
@@ -66,7 +30,7 @@ QObject* QTuioTouchPlugin::create(const QString &key,
if (!key.compare(QLatin1String("TuioTouch"), Qt::CaseInsensitive))
return new QTuioHandler(spec);
- return 0;
+ return nullptr;
}
QT_END_NAMESPACE
diff --git a/src/plugins/generic/tuiotouch/qoscbundle.cpp b/src/plugins/generic/tuiotouch/qoscbundle.cpp
index e9166922a1..195762d62c 100644
--- a/src/plugins/generic/tuiotouch/qoscbundle.cpp
+++ b/src/plugins/generic/tuiotouch/qoscbundle.cpp
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 Robin Burchell <robin.burchell@viroteck.net>
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and 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$
-**
-****************************************************************************/
+// Copyright (C) 2014 Robin Burchell <robin.burchell@viroteck.net>
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qoscbundle_p.h"
#include "qtuio_p.h"
@@ -80,7 +44,7 @@ QOscBundle::QOscBundle(const QByteArray &data)
// "followed by an OSC Time
// Tag, followed by zero or more OSC Bundle Elements. The OSC-timetag is a
// 64-bit fixed point time tag whose semantics are described below."
- if (parsedBytes > (quint32)data.size() || data.size() - parsedBytes < sizeof(quint64))
+ if (parsedBytes > (quint32)data.size() || data.size() - parsedBytes < qsizetype(sizeof(quint64)))
return;
// "Time tags are represented by a 64 bit fixed point number. The first 32
@@ -101,7 +65,7 @@ QOscBundle::QOscBundle(const QByteArray &data)
if (oscTimeEpoch == 0 && oscTimePico == 1) {
// "The time tag value consisting of 63 zero bits followed by a
- // one in the least signifigant bit is a special case meaning
+ // one in the least significant bit is a special case meaning
// "immediately.""
isImmediate = true;
}
@@ -113,7 +77,7 @@ QOscBundle::QOscBundle(const QByteArray &data)
//
// in practice, a bundle can contain multiple bundles or messages,
// though, and each is prefixed by a size.
- if (data.size() - parsedBytes < sizeof(quint32))
+ if (data.size() - parsedBytes < qsizetype(sizeof(quint32)))
return;
quint32 size = qFromBigEndian<quint32>((const uchar*)data.constData() + parsedBytes);
diff --git a/src/plugins/generic/tuiotouch/qoscbundle_p.h b/src/plugins/generic/tuiotouch/qoscbundle_p.h
index cb3ec4d251..8c4e37fa8f 100644
--- a/src/plugins/generic/tuiotouch/qoscbundle_p.h
+++ b/src/plugins/generic/tuiotouch/qoscbundle_p.h
@@ -1,49 +1,13 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 Robin Burchell <robin.burchell@viroteck.net>
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and 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$
-**
-****************************************************************************/
+// Copyright (C) 2014 Robin Burchell <robin.burchell@viroteck.net>
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QOSCBUNDLE_P_H
#define QOSCBUNDLE_P_H
#include "qoscmessage_p.h"
-#include <QtCore/QVector>
+#include <QtCore/QList>
QT_BEGIN_NAMESPACE
@@ -51,24 +15,24 @@ class QByteArray;
class QOscBundle
{
- QOscBundle(); // for QVector, don't use
- friend class QVector<QOscBundle>;
+ QOscBundle(); // for QList, don't use
+ friend class QList<QOscBundle>;
public:
explicit QOscBundle(const QByteArray &data);
bool isValid() const { return m_isValid; }
- QVector<QOscBundle> bundles() const { return m_bundles; }
- QVector<QOscMessage> messages() const { return m_messages; }
+ QList<QOscBundle> bundles() const { return m_bundles; }
+ QList<QOscMessage> messages() const { return m_messages; }
private:
bool m_isValid;
bool m_immediate;
quint32 m_timeEpoch;
quint32 m_timePico;
- QVector<QOscBundle> m_bundles;
- QVector<QOscMessage> m_messages;
+ QList<QOscBundle> m_bundles;
+ QList<QOscMessage> m_messages;
};
-Q_DECLARE_TYPEINFO(QOscBundle, Q_MOVABLE_TYPE);
+Q_DECLARE_TYPEINFO(QOscBundle, Q_RELOCATABLE_TYPE);
QT_END_NAMESPACE
diff --git a/src/plugins/generic/tuiotouch/qoscmessage.cpp b/src/plugins/generic/tuiotouch/qoscmessage.cpp
index 3c30caa923..97a4b9e6a0 100644
--- a/src/plugins/generic/tuiotouch/qoscmessage.cpp
+++ b/src/plugins/generic/tuiotouch/qoscmessage.cpp
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 Robin Burchell <robin.burchell@viroteck.net>
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and 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$
-**
-****************************************************************************/
+// Copyright (C) 2014 Robin Burchell <robin.burchell@viroteck.net>
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qoscmessage_p.h"
#include "qtuio_p.h"
@@ -92,7 +56,7 @@ QOscMessage::QOscMessage(const QByteArray &data)
return;
arguments.append(aString);
} else if (typeTag == 'i') { // int32
- if (parsedBytes > (quint32)data.size() || data.size() - parsedBytes < sizeof(quint32))
+ if (parsedBytes > (quint32)data.size() || data.size() - parsedBytes < qsizetype(sizeof(quint32)))
return;
quint32 anInt = qFromBigEndian<quint32>(data.constData() + parsedBytes);
@@ -101,10 +65,10 @@ QOscMessage::QOscMessage(const QByteArray &data)
// TODO: is int32 in OSC signed, or unsigned?
arguments.append((int)anInt);
} else if (typeTag == 'f') { // float32
- if (parsedBytes > (quint32)data.size() || data.size() - parsedBytes < sizeof(quint32))
+ if (parsedBytes > (quint32)data.size() || data.size() - parsedBytes < qsizetype(sizeof(quint32)))
return;
- Q_STATIC_ASSERT(sizeof(float) == sizeof(quint32));
+ static_assert(sizeof(float) == sizeof(quint32));
union {
quint32 u;
float f;
diff --git a/src/plugins/generic/tuiotouch/qoscmessage_p.h b/src/plugins/generic/tuiotouch/qoscmessage_p.h
index 76d40ceb18..d896c6a1dc 100644
--- a/src/plugins/generic/tuiotouch/qoscmessage_p.h
+++ b/src/plugins/generic/tuiotouch/qoscmessage_p.h
@@ -1,49 +1,12 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 Robin Burchell <robin.burchell@viroteck.net>
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and 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$
-**
-****************************************************************************/
+// Copyright (C) 2014 Robin Burchell <robin.burchell@viroteck.net>
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QOSCMESSAGE_P_H
#define QOSCMESSAGE_P_H
#include <QtCore/QByteArray>
#include <QtCore/QVariant>
-#include <QtCore/QVector>
#include <QtCore/QList>
@@ -51,22 +14,22 @@ QT_BEGIN_NAMESPACE
class QOscMessage
{
- QOscMessage(); // for QVector, don't use
- friend class QVector<QOscMessage>;
+ QOscMessage(); // for QList, don't use
+ friend class QList<QOscMessage>;
public:
explicit QOscMessage(const QByteArray &data);
bool isValid() const { return m_isValid; }
QByteArray addressPattern() const { return m_addressPattern; }
- QList<QVariant> arguments() const { return m_arguments; }
+ QVariantList arguments() const { return m_arguments; }
private:
bool m_isValid;
QByteArray m_addressPattern;
- QList<QVariant> m_arguments;
+ QVariantList m_arguments;
};
-Q_DECLARE_TYPEINFO(QOscMessage, Q_MOVABLE_TYPE);
+Q_DECLARE_TYPEINFO(QOscMessage, Q_RELOCATABLE_TYPE);
QT_END_NAMESPACE
diff --git a/src/plugins/generic/tuiotouch/qtuio_p.h b/src/plugins/generic/tuiotouch/qtuio_p.h
index 3ae5fd4571..211ec9d873 100644
--- a/src/plugins/generic/tuiotouch/qtuio_p.h
+++ b/src/plugins/generic/tuiotouch/qtuio_p.h
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 Robin Burchell <robin.burchell@viroteck.net>
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and 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$
-**
-****************************************************************************/
+// Copyright (C) 2014 Robin Burchell <robin.burchell@viroteck.net>
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QTUIO_P_H
#define QTUIO_P_H
diff --git a/src/plugins/generic/tuiotouch/qtuiocursor_p.h b/src/plugins/generic/tuiotouch/qtuiocursor_p.h
index 46134e6f3f..74c0bd265f 100644
--- a/src/plugins/generic/tuiotouch/qtuiocursor_p.h
+++ b/src/plugins/generic/tuiotouch/qtuiocursor_p.h
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 Robin Burchell <robin.burchell@viroteck.net>
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and 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$
-**
-****************************************************************************/
+// Copyright (C) 2014 Robin Burchell <robin.burchell@viroteck.net>
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QTUIOCURSOR_P_H
#define QTUIOCURSOR_P_H
@@ -55,7 +19,7 @@ public:
, m_vx(0)
, m_vy(0)
, m_acceleration(0)
- , m_state(Qt::TouchPointPressed)
+ , m_state(QEventPoint::State::Pressed)
{
}
@@ -63,9 +27,9 @@ public:
void setX(float x)
{
- if (state() == Qt::TouchPointStationary &&
+ if (state() == QEventPoint::State::Stationary &&
!qFuzzyCompare(m_x + 2.0, x + 2.0)) { // +2 because 1 is a valid value, and qFuzzyCompare can't cope with 0.0
- setState(Qt::TouchPointMoved);
+ setState(QEventPoint::State::Updated);
}
m_x = x;
}
@@ -73,9 +37,9 @@ public:
void setY(float y)
{
- if (state() == Qt::TouchPointStationary &&
+ if (state() == QEventPoint::State::Stationary &&
!qFuzzyCompare(m_y + 2.0, y + 2.0)) { // +2 because 1 is a valid value, and qFuzzyCompare can't cope with 0.0
- setState(Qt::TouchPointMoved);
+ setState(QEventPoint::State::Updated);
}
m_y = y;
}
@@ -90,8 +54,8 @@ public:
void setAcceleration(float acceleration) { m_acceleration = acceleration; }
float acceleration() const { return m_acceleration; }
- void setState(const Qt::TouchPointState &state) { m_state = state; }
- Qt::TouchPointState state() const { return m_state; }
+ void setState(const QEventPoint::State &state) { m_state = state; }
+ QEventPoint::State state() const { return m_state; }
private:
int m_id;
@@ -100,9 +64,9 @@ private:
float m_vx;
float m_vy;
float m_acceleration;
- Qt::TouchPointState m_state;
+ QEventPoint::State m_state;
};
-Q_DECLARE_TYPEINFO(QTuioCursor, Q_MOVABLE_TYPE); // Q_PRIMITIVE_TYPE: not possible, m_state is = 1, not 0.
+Q_DECLARE_TYPEINFO(QTuioCursor, Q_RELOCATABLE_TYPE); // Q_PRIMITIVE_TYPE: not possible, m_state is = 1, not 0.
QT_END_NAMESPACE
diff --git a/src/plugins/generic/tuiotouch/qtuiohandler.cpp b/src/plugins/generic/tuiotouch/qtuiohandler.cpp
index 6ad4597b19..2815368e84 100644
--- a/src/plugins/generic/tuiotouch/qtuiohandler.cpp
+++ b/src/plugins/generic/tuiotouch/qtuiohandler.cpp
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 Robin Burchell <robin.burchell@viroteck.net>
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and 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$
-**
-****************************************************************************/
+// Copyright (C) 2014 Robin Burchell <robin.burchell@viroteck.net>
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qtuiohandler_p.h"
@@ -47,7 +11,7 @@
#include <qpa/qwindowsysteminterface.h>
-#include <QTouchDevice>
+#include <QPointingDevice>
#include <QWindow>
#include <QGuiApplication>
@@ -68,7 +32,6 @@ Q_LOGGING_CATEGORY(lcTuioSet, "qt.qpa.tuio.set")
static bool forceDelivery = qEnvironmentVariableIsSet("QT_TUIOTOUCH_DELIVER_WITHOUT_FOCUS");
QTuioHandler::QTuioHandler(const QString &specification)
- : m_device(new QTouchDevice) // not leaked, QTouchDevice cleans up registered devices itself
{
QStringList args = specification.split(':');
int portNumber = 3333;
@@ -76,7 +39,7 @@ QTuioHandler::QTuioHandler(const QString &specification)
bool invertx = false;
bool inverty = false;
- for (int i = 0; i < args.count(); ++i) {
+ for (int i = 0; i < args.size(); ++i) {
if (args.at(i).startsWith("udp=")) {
QString portString = args.at(i).section('=', 1, 1);
portNumber = portString.toInt();
@@ -96,6 +59,7 @@ QTuioHandler::QTuioHandler(const QString &specification)
case 180:
case 270:
rotationAngle = argValue;
+ break;
default:
break;
}
@@ -111,13 +75,17 @@ QTuioHandler::QTuioHandler(const QString &specification)
if (inverty)
m_transform *= QTransform::fromTranslate(0.5, 0.5).scale(1.0, -1.0).translate(-0.5, -0.5);
- m_device->setName("TUIO"); // TODO: multiple based on SOURCE?
- m_device->setType(QTouchDevice::TouchScreen);
- m_device->setCapabilities(QTouchDevice::Position |
- QTouchDevice::Area |
- QTouchDevice::Velocity |
- QTouchDevice::NormalizedPosition);
- QWindowSystemInterface::registerTouchDevice(m_device);
+ // not leaked, QPointingDevice cleans up registered devices itself
+ // TODO register each device based on SOURCE, not just an all-purpose generic touchscreen
+ // TODO define seats when multiple connections occur
+ m_device = new QPointingDevice(QLatin1String("TUIO"), 1, QInputDevice::DeviceType::TouchScreen,
+ QPointingDevice::PointerType::Finger,
+ QInputDevice::Capability::Position |
+ QInputDevice::Capability::Area |
+ QInputDevice::Capability::Velocity |
+ QInputDevice::Capability::NormalizedPosition,
+ 16, 0);
+ QWindowSystemInterface::registerInputDevice(m_device);
if (!m_socket.bind(QHostAddress::Any, portNumber)) {
qCWarning(lcTuioHandler) << "Failed to bind TUIO socket: " << m_socket.errorString();
@@ -155,7 +123,7 @@ void QTuioHandler::processPackets()
// messages. The FSEQ frame ID is incremented for each delivered bundle,
// while redundant bundles can be marked using the frame sequence ID
// -1."
- QVector<QOscMessage> messages;
+ QList<QOscMessage> messages;
QOscBundle bundle(datagram);
if (bundle.isValid()) {
@@ -169,10 +137,10 @@ void QTuioHandler::processPackets()
messages.push_back(msg);
}
- for (const QOscMessage &message : qAsConst(messages)) {
+ for (const QOscMessage &message : std::as_const(messages)) {
if (message.addressPattern() == "/tuio/2Dcur") {
QList<QVariant> arguments = message.arguments();
- if (arguments.count() == 0) {
+ if (arguments.size() == 0) {
qCWarning(lcTuioHandler, "Ignoring TUIO message with no arguments");
continue;
}
@@ -192,7 +160,7 @@ void QTuioHandler::processPackets()
}
} else if (message.addressPattern() == "/tuio/2Dobj") {
QList<QVariant> arguments = message.arguments();
- if (arguments.count() == 0) {
+ if (arguments.size() == 0) {
qCWarning(lcTuioHandler, "Ignoring TUIO message with no arguments");
continue;
}
@@ -221,8 +189,8 @@ void QTuioHandler::processPackets()
void QTuioHandler::process2DCurSource(const QOscMessage &message)
{
QList<QVariant> arguments = message.arguments();
- if (arguments.count() != 2) {
- qCWarning(lcTuioSource) << "Ignoring malformed TUIO source message: " << arguments.count();
+ if (arguments.size() != 2) {
+ qCWarning(lcTuioSource) << "Ignoring malformed TUIO source message: " << arguments.size();
return;
}
@@ -247,7 +215,7 @@ void QTuioHandler::process2DCurAlive(const QOscMessage &message)
QMap<int, QTuioCursor> oldActiveCursors = m_activeCursors;
QMap<int, QTuioCursor> newActiveCursors;
- for (int i = 1; i < arguments.count(); ++i) {
+ for (int i = 1; i < arguments.size(); ++i) {
if (QMetaType::Type(arguments.at(i).userType()) != QMetaType::Int) {
qCWarning(lcTuioHandler) << "Ignoring malformed TUIO alive message (bad argument on position" << i << arguments << ')';
return;
@@ -257,12 +225,12 @@ void QTuioHandler::process2DCurAlive(const QOscMessage &message)
if (!oldActiveCursors.contains(cursorId)) {
// newly active
QTuioCursor cursor(cursorId);
- cursor.setState(Qt::TouchPointPressed);
+ cursor.setState(QEventPoint::State::Pressed);
newActiveCursors.insert(cursorId, cursor);
} else {
// we already know about it, remove it so it isn't marked as released
QTuioCursor cursor = oldActiveCursors.value(cursorId);
- cursor.setState(Qt::TouchPointStationary); // position change in SET will update if needed
+ cursor.setState(QEventPoint::State::Stationary); // position change in SET will update if needed
newActiveCursors.insert(cursorId, cursor);
oldActiveCursors.remove(cursorId);
}
@@ -288,8 +256,8 @@ void QTuioHandler::process2DCurAlive(const QOscMessage &message)
void QTuioHandler::process2DCurSet(const QOscMessage &message)
{
QList<QVariant> arguments = message.arguments();
- if (arguments.count() < 7) {
- qCWarning(lcTuioSet) << "Ignoring malformed TUIO set message with too few arguments: " << arguments.count();
+ if (arguments.size() < 7) {
+ qCWarning(lcTuioSet) << "Ignoring malformed TUIO set message with too few arguments: " << arguments.size();
return;
}
@@ -359,7 +327,7 @@ void QTuioHandler::process2DCurFseq(const QOscMessage &message)
Q_UNUSED(message); // TODO: do we need to do anything with the frame id?
QWindow *win = QGuiApplication::focusWindow();
- if (!win && QGuiApplication::topLevelWindows().length() > 0 && forceDelivery)
+ if (!win && QGuiApplication::topLevelWindows().size() > 0 && forceDelivery)
win = QGuiApplication::topLevelWindows().at(0);
if (!win)
@@ -368,14 +336,14 @@ void QTuioHandler::process2DCurFseq(const QOscMessage &message)
QList<QWindowSystemInterface::TouchPoint> tpl;
tpl.reserve(m_activeCursors.size() + m_deadCursors.size());
- for (const QTuioCursor &tc : qAsConst(m_activeCursors)) {
+ for (const QTuioCursor &tc : std::as_const(m_activeCursors)) {
QWindowSystemInterface::TouchPoint tp = cursorToTouchPoint(tc, win);
tpl.append(tp);
}
- for (const QTuioCursor &tc : qAsConst(m_deadCursors)) {
+ for (const QTuioCursor &tc : std::as_const(m_deadCursors)) {
QWindowSystemInterface::TouchPoint tp = cursorToTouchPoint(tc, win);
- tp.state = Qt::TouchPointReleased;
+ tp.state = QEventPoint::State::Released;
tpl.append(tp);
}
QWindowSystemInterface::handleTouchEvent(win, m_device, tpl);
@@ -386,8 +354,8 @@ void QTuioHandler::process2DCurFseq(const QOscMessage &message)
void QTuioHandler::process2DObjSource(const QOscMessage &message)
{
QList<QVariant> arguments = message.arguments();
- if (arguments.count() != 2) {
- qCWarning(lcTuioSource, ) << "Ignoring malformed TUIO source message: " << arguments.count();
+ if (arguments.size() != 2) {
+ qCWarning(lcTuioSource ) << "Ignoring malformed TUIO source message: " << arguments.size();
return;
}
@@ -412,7 +380,7 @@ void QTuioHandler::process2DObjAlive(const QOscMessage &message)
QMap<int, QTuioToken> oldActiveTokens = m_activeTokens;
QMap<int, QTuioToken> newActiveTokens;
- for (int i = 1; i < arguments.count(); ++i) {
+ for (int i = 1; i < arguments.size(); ++i) {
if (QMetaType::Type(arguments.at(i).userType()) != QMetaType::Int) {
qCWarning(lcTuioHandler) << "Ignoring malformed TUIO alive message (bad argument on position" << i << arguments << ')';
return;
@@ -422,12 +390,12 @@ void QTuioHandler::process2DObjAlive(const QOscMessage &message)
if (!oldActiveTokens.contains(sessionId)) {
// newly active
QTuioToken token(sessionId);
- token.setState(Qt::TouchPointPressed);
+ token.setState(QEventPoint::State::Pressed);
newActiveTokens.insert(sessionId, token);
} else {
// we already know about it, remove it so it isn't marked as released
QTuioToken token = oldActiveTokens.value(sessionId);
- token.setState(Qt::TouchPointStationary); // position change in SET will update if needed
+ token.setState(QEventPoint::State::Stationary); // position change in SET will update if needed
newActiveTokens.insert(sessionId, token);
oldActiveTokens.remove(sessionId);
}
@@ -453,8 +421,8 @@ void QTuioHandler::process2DObjAlive(const QOscMessage &message)
void QTuioHandler::process2DObjSet(const QOscMessage &message)
{
QList<QVariant> arguments = message.arguments();
- if (arguments.count() < 7) {
- qCWarning(lcTuioSet) << "Ignoring malformed TUIO set message with too few arguments: " << arguments.count();
+ if (arguments.size() < 7) {
+ qCWarning(lcTuioSet) << "Ignoring malformed TUIO set message with too few arguments: " << arguments.size();
return;
}
@@ -508,7 +476,6 @@ QWindowSystemInterface::TouchPoint QTuioHandler::tokenToTouchPoint(const QTuioTo
QWindowSystemInterface::TouchPoint tp;
tp.id = tc.id();
tp.uniqueId = tc.classId(); // TODO TUIO 2.0: populate a QVariant, and register the mapping from int to arbitrary UID data
- tp.flags = QTouchEvent::TouchPoint::Token;
tp.pressure = 1.0f;
tp.normalPosition = QPointF(tc.x(), tc.y());
@@ -533,7 +500,7 @@ void QTuioHandler::process2DObjFseq(const QOscMessage &message)
Q_UNUSED(message); // TODO: do we need to do anything with the frame id?
QWindow *win = QGuiApplication::focusWindow();
- if (!win && QGuiApplication::topLevelWindows().length() > 0 && forceDelivery)
+ if (!win && QGuiApplication::topLevelWindows().size() > 0 && forceDelivery)
win = QGuiApplication::topLevelWindows().at(0);
if (!win)
@@ -542,14 +509,14 @@ void QTuioHandler::process2DObjFseq(const QOscMessage &message)
QList<QWindowSystemInterface::TouchPoint> tpl;
tpl.reserve(m_activeTokens.size() + m_deadTokens.size());
- for (const QTuioToken & t : qAsConst(m_activeTokens)) {
+ for (const QTuioToken & t : std::as_const(m_activeTokens)) {
QWindowSystemInterface::TouchPoint tp = tokenToTouchPoint(t, win);
tpl.append(tp);
}
- for (const QTuioToken & t : qAsConst(m_deadTokens)) {
+ for (const QTuioToken & t : std::as_const(m_deadTokens)) {
QWindowSystemInterface::TouchPoint tp = tokenToTouchPoint(t, win);
- tp.state = Qt::TouchPointReleased;
+ tp.state = QEventPoint::State::Released;
tp.velocity = QVector2D();
tpl.append(tp);
}
@@ -560,3 +527,5 @@ void QTuioHandler::process2DObjFseq(const QOscMessage &message)
QT_END_NAMESPACE
+#include "moc_qtuiohandler_p.cpp"
+
diff --git a/src/plugins/generic/tuiotouch/qtuiohandler_p.h b/src/plugins/generic/tuiotouch/qtuiohandler_p.h
index 2e444f2a0d..2c72a1ee15 100644
--- a/src/plugins/generic/tuiotouch/qtuiohandler_p.h
+++ b/src/plugins/generic/tuiotouch/qtuiohandler_p.h
@@ -1,57 +1,21 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 Robin Burchell <robin.burchell@viroteck.net>
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and 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$
-**
-****************************************************************************/
+// Copyright (C) 2014 Robin Burchell <robin.burchell@viroteck.net>
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QTUIOHANDLER_P_H
#define QTUIOHANDLER_P_H
+#include <QList>
#include <QObject>
#include <QMap>
#include <QUdpSocket>
-#include <QVector>
#include <QTransform>
#include <qpa/qwindowsysteminterface.h>
QT_BEGIN_NAMESPACE
-class QTouchDevice;
+class QPointingDevice;
class QOscMessage;
class QTuioCursor;
class QTuioToken;
@@ -59,6 +23,7 @@ class QTuioToken;
class QTuioHandler : public QObject
{
Q_OBJECT
+ Q_MOC_INCLUDE("qoscmessage_p.h")
public:
explicit QTuioHandler(const QString &specification);
@@ -79,12 +44,12 @@ private:
QWindowSystemInterface::TouchPoint cursorToTouchPoint(const QTuioCursor &tc, QWindow *win);
QWindowSystemInterface::TouchPoint tokenToTouchPoint(const QTuioToken &tc, QWindow *win);
- QTouchDevice *m_device;
+ QPointingDevice *m_device = nullptr;
QUdpSocket m_socket;
QMap<int, QTuioCursor> m_activeCursors;
- QVector<QTuioCursor> m_deadCursors;
+ QList<QTuioCursor> m_deadCursors;
QMap<int, QTuioToken> m_activeTokens;
- QVector<QTuioToken> m_deadTokens;
+ QList<QTuioToken> m_deadTokens;
QTransform m_transform;
};
diff --git a/src/plugins/generic/tuiotouch/qtuiotoken_p.h b/src/plugins/generic/tuiotouch/qtuiotoken_p.h
index b784190d53..18f93abb54 100644
--- a/src/plugins/generic/tuiotouch/qtuiotoken_p.h
+++ b/src/plugins/generic/tuiotouch/qtuiotoken_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QTUIOOBJECT_P_H
#define QTUIOOBJECT_P_H
@@ -66,7 +30,7 @@ public:
, m_angle(0)
, m_angularVelocity(0)
, m_angularAcceleration(0)
- , m_state(Qt::TouchPointPressed)
+ , m_state(QEventPoint::State::Pressed)
{
}
@@ -77,9 +41,9 @@ public:
void setX(float x)
{
- if (state() == Qt::TouchPointStationary &&
+ if (state() == QEventPoint::State::Stationary &&
!qFuzzyCompare(m_x + 2.0, x + 2.0)) { // +2 because 1 is a valid value, and qFuzzyCompare can't cope with 0.0
- setState(Qt::TouchPointMoved);
+ setState(QEventPoint::State::Updated);
}
m_x = x;
}
@@ -87,9 +51,9 @@ public:
void setY(float y)
{
- if (state() == Qt::TouchPointStationary &&
+ if (state() == QEventPoint::State::Stationary &&
!qFuzzyCompare(m_y + 2.0, y + 2.0)) { // +2 because 1 is a valid value, and qFuzzyCompare can't cope with 0.0
- setState(Qt::TouchPointMoved);
+ setState(QEventPoint::State::Updated);
}
m_y = y;
}
@@ -109,9 +73,9 @@ public:
{
if (angle > M_PI)
angle = angle - M_PI * 2.0; // zero is pointing upwards, and is the default; but we want to have negative angles when rotating left
- if (state() == Qt::TouchPointStationary &&
+ if (state() == QEventPoint::State::Stationary &&
!qFuzzyCompare(m_angle + 2.0, angle + 2.0)) { // +2 because 1 is a valid value, and qFuzzyCompare can't cope with 0.0
- setState(Qt::TouchPointMoved);
+ setState(QEventPoint::State::Updated);
}
m_angle = angle;
}
@@ -122,8 +86,8 @@ public:
float angularAcceleration() const { return m_angularAcceleration; }
void setAngularAcceleration(float angularAcceleration) { m_angularAcceleration = angularAcceleration; }
- void setState(const Qt::TouchPointState &state) { m_state = state; }
- Qt::TouchPointState state() const { return m_state; }
+ void setState(const QEventPoint::State &state) { m_state = state; }
+ QEventPoint::State state() const { return m_state; }
private:
int m_id; // sessionID, temporary object ID
@@ -136,9 +100,9 @@ private:
float m_angle;
float m_angularVelocity;
float m_angularAcceleration;
- Qt::TouchPointState m_state;
+ QEventPoint::State m_state;
};
-Q_DECLARE_TYPEINFO(QTuioToken, Q_MOVABLE_TYPE); // Q_PRIMITIVE_TYPE: not possible: m_id, m_classId == -1
+Q_DECLARE_TYPEINFO(QTuioToken, Q_RELOCATABLE_TYPE); // Q_PRIMITIVE_TYPE: not possible: m_id, m_classId == -1
QT_END_NAMESPACE
diff --git a/src/plugins/generic/tuiotouch/tuiotouch.pro b/src/plugins/generic/tuiotouch/tuiotouch.pro
deleted file mode 100644
index 08f7036c92..0000000000
--- a/src/plugins/generic/tuiotouch/tuiotouch.pro
+++ /dev/null
@@ -1,28 +0,0 @@
-TARGET = qtuiotouchplugin
-
-QT += \
- core-private \
- gui-private \
- network
-
-SOURCES += \
- main.cpp \
- qoscbundle.cpp \
- qoscmessage.cpp \
- qtuiohandler.cpp
-
-HEADERS += \
- qoscbundle_p.h \
- qoscmessage_p.h \
- qtuiohandler_p.h \
- qtuiocursor_p.h \
- qtuiotoken_p.h
-
-OTHER_FILES += \
- tuiotouch.json
-
-DEFINES += QT_NO_FOREACH
-PLUGIN_TYPE = generic
-PLUGIN_EXTENDS = -
-PLUGIN_CLASS_NAME = QTuioTouchPlugin
-load(qt_plugin)
diff --git a/src/plugins/imageformats/CMakeLists.txt b/src/plugins/imageformats/CMakeLists.txt
index 00fefbdc0d..c5ab716d00 100644
--- a/src/plugins/imageformats/CMakeLists.txt
+++ b/src/plugins/imageformats/CMakeLists.txt
@@ -1,4 +1,5 @@
-# Generated from imageformats.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
if(QT_FEATURE_ico)
add_subdirectory(ico)
diff --git a/src/plugins/imageformats/gif/.prev_CMakeLists.txt b/src/plugins/imageformats/gif/.prev_CMakeLists.txt
deleted file mode 100644
index b4923b81b1..0000000000
--- a/src/plugins/imageformats/gif/.prev_CMakeLists.txt
+++ /dev/null
@@ -1,19 +0,0 @@
-# Generated from gif.pro.
-
-#####################################################################
-## QGifPlugin Plugin:
-#####################################################################
-
-qt_add_plugin(QGifPlugin
- OUTPUT_NAME qgif
- TYPE imageformats
- SOURCES
- main.cpp main.h
- qgifhandler.cpp qgifhandler_p.h
- PUBLIC_LIBRARIES
- Qt::Core
- Qt::Gui
-)
-
-#### Keys ignored in scope 1:.:.:gif.pro:<TRUE>:
-# OTHER_FILES = "gif.json"
diff --git a/src/plugins/imageformats/gif/CMakeLists.txt b/src/plugins/imageformats/gif/CMakeLists.txt
index c6780e32e9..b56859a264 100644
--- a/src/plugins/imageformats/gif/CMakeLists.txt
+++ b/src/plugins/imageformats/gif/CMakeLists.txt
@@ -1,20 +1,17 @@
-# Generated from gif.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## QGifPlugin Plugin:
#####################################################################
-qt_add_plugin(QGifPlugin
+qt_internal_add_plugin(QGifPlugin
OUTPUT_NAME qgif
- TYPE imageformats
+ PLUGIN_TYPE imageformats
SOURCES
- main.cpp main.h
+ main.cpp
qgifhandler.cpp qgifhandler_p.h
- LIBRARIES # special case
- Qt::GuiPrivate # special case
- PUBLIC_LIBRARIES # special case
- Qt::Gui # special case
+ LIBRARIES
+ Qt::Gui
+ Qt::GuiPrivate
)
-
-#### Keys ignored in scope 1:.:.:gif.pro:<TRUE>:
-# OTHER_FILES = "gif.json"
diff --git a/src/plugins/imageformats/gif/gif.pro b/src/plugins/imageformats/gif/gif.pro
deleted file mode 100644
index c2625be85a..0000000000
--- a/src/plugins/imageformats/gif/gif.pro
+++ /dev/null
@@ -1,10 +0,0 @@
-TARGET = qgif
-
-SOURCES += main.cpp qgifhandler.cpp
-HEADERS += main.h qgifhandler_p.h
-
-OTHER_FILES += gif.json
-
-PLUGIN_TYPE = imageformats
-PLUGIN_CLASS_NAME = QGifPlugin
-load(qt_plugin)
diff --git a/src/plugins/imageformats/gif/main.cpp b/src/plugins/imageformats/gif/main.cpp
index 993871420c..f98b586407 100644
--- a/src/plugins/imageformats/gif/main.cpp
+++ b/src/plugins/imageformats/gif/main.cpp
@@ -1,47 +1,9 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <qimageiohandler.h>
#include <qstringlist.h>
-#include "main.h"
-
#ifdef QT_NO_IMAGEFORMAT_GIF
#undef QT_NO_IMAGEFORMAT_GIF
#endif
@@ -49,6 +11,17 @@
QT_BEGIN_NAMESPACE
+class QGifPlugin : public QImageIOPlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QImageIOHandlerFactoryInterface" FILE "gif.json")
+public:
+ QGifPlugin();
+ ~QGifPlugin();
+
+ Capabilities capabilities(QIODevice *device, const QByteArray &format) const override;
+ QImageIOHandler *create(QIODevice *device, const QByteArray &format = QByteArray()) const override;
+};
QGifPlugin::QGifPlugin()
{
@@ -74,3 +47,5 @@ QImageIOHandler *QGifPlugin::create(QIODevice *device, const QByteArray &format)
}
QT_END_NAMESPACE
+
+#include "main.moc"
diff --git a/src/plugins/imageformats/gif/main.h b/src/plugins/imageformats/gif/main.h
deleted file mode 100644
index 84913a31d7..0000000000
--- a/src/plugins/imageformats/gif/main.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 <qimageiohandler.h>
-#include <qstringlist.h>
-
-#ifdef QT_NO_IMAGEFORMAT_GIF
-#undef QT_NO_IMAGEFORMAT_GIF
-#endif
-#include <qgifhandler_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class QGifPlugin : public QImageIOPlugin
-{
- Q_OBJECT
- Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QImageIOHandlerFactoryInterface" FILE "gif.json")
-public:
- QGifPlugin();
- ~QGifPlugin();
-
- Capabilities capabilities(QIODevice *device, const QByteArray &format) const override;
- QImageIOHandler *create(QIODevice *device, const QByteArray &format = QByteArray()) const override;
-};
-
-QT_END_NAMESPACE
diff --git a/src/plugins/imageformats/gif/qgifhandler.cpp b/src/plugins/imageformats/gif/qgifhandler.cpp
index c92cc3ea61..8ad4ff7510 100644
--- a/src/plugins/imageformats/gif/qgifhandler.cpp
+++ b/src/plugins/imageformats/gif/qgifhandler.cpp
@@ -1,60 +1,21 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-** WARNING:
-** A separate license from Unisys may be required to use the gif
-** reader. See http://www.unisys.com/about__unisys/lzw/
-** for information from Unisys
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qgifhandler_p.h"
#include <qimage.h>
#include <qiodevice.h>
+#include <qloggingcategory.h>
#include <qvariant.h>
QT_BEGIN_NAMESPACE
+Q_LOGGING_CATEGORY(lcGif, "qt.gui.imageio.gif")
+
#define Q_TRANSPARENT 0x00ffffff
// avoid going through QImage::scanLine() which calls detach
-#define FAST_SCAN_LINE(bits, bpl, y) (bits + (y) * bpl)
-
+#define FAST_SCAN_LINE(bits, bpl, y) (bits + qptrdiff(y) * bpl)
/*
Incremental image decoder for GIF image format.
@@ -70,7 +31,7 @@ public:
int decode(QImage *image, const uchar* buffer, int length,
int *nextFrameDelay, int *loopCount);
- static void scan(QIODevice *device, QVector<QSize> *imageSizes, int *loopCount);
+ static void scan(QIODevice *device, QList<QSize> *imageSizes, int *loopCount);
bool newFrame;
bool partialNewFrame;
@@ -78,6 +39,10 @@ public:
private:
void fillRect(QImage *image, int x, int y, int w, int h, QRgb col);
inline QRgb color(uchar index) const;
+ static bool withinSizeLimit(int width, int height)
+ {
+ return quint64(width) * height < 16384 * 16384; // Reject unreasonable header values
+ }
// GIF specific stuff
QRgb* globalcmap;
@@ -246,7 +211,7 @@ int QGIFFormat::decode(QImage *image, const uchar *buffer, int length,
}
image->detach();
- int bpl = image->bytesPerLine();
+ qsizetype bpl = image->bytesPerLine();
unsigned char *bits = image->bits();
#define LM(l, m) (((m)<<8)|l)
@@ -339,9 +304,9 @@ int QGIFFormat::decode(QImage *image, const uchar *buffer, int length,
// disbelieve ridiculous logical screen sizes,
// unless the image frames are also large.
- if (swidth/10 > qMax(newwidth,200))
+ if (swidth/10 > qMax(newwidth,16384))
swidth = -1;
- if (sheight/10 > qMax(newheight,200))
+ if (sheight/10 > qMax(newheight,16384))
sheight = -1;
if (swidth <= 0)
@@ -351,7 +316,14 @@ int QGIFFormat::decode(QImage *image, const uchar *buffer, int length,
QImage::Format format = trans_index >= 0 ? QImage::Format_ARGB32 : QImage::Format_RGB32;
if (image->isNull()) {
- (*image) = QImage(swidth, sheight, format);
+ if (!withinSizeLimit(swidth, sheight)) {
+ state = Error;
+ return -1;
+ }
+ if (!QImageIOHandler::allocateImage(QSize(swidth, sheight), format, image)) {
+ state = Error;
+ return -1;
+ }
bpl = image->bytesPerLine();
bits = image->bits();
if (bits)
@@ -412,17 +384,21 @@ int QGIFFormat::decode(QImage *image, const uchar *buffer, int length,
if (backingstore.width() < w
|| backingstore.height() < h) {
+
+ if (!withinSizeLimit(w, h)) {
+ state = Error;
+ return -1;
+ }
// We just use the backing store as a byte array
- backingstore = QImage(qMax(backingstore.width(), w),
- qMax(backingstore.height(), h),
- QImage::Format_RGB32);
- if (backingstore.isNull()) {
+ QSize bsSize(qMax(backingstore.width(), w), qMax(backingstore.height(), h));
+ if (!QImageIOHandler::allocateImage(bsSize, QImage::Format_RGB32,
+ &backingstore)) {
state = Error;
return -1;
}
memset(backingstore.bits(), 0, backingstore.sizeInBytes());
}
- const int dest_bpl = backingstore.bytesPerLine();
+ const qsizetype dest_bpl = backingstore.bytesPerLine();
unsigned char *dest_data = backingstore.bits();
for (int ln=0; ln<h; ln++) {
memcpy(FAST_SCAN_LINE(dest_data, dest_bpl, ln),
@@ -478,8 +454,14 @@ int QGIFFormat::decode(QImage *image, const uchar *buffer, int length,
break;
case ImageDataBlock:
count++;
- accum|=(ch<<bitcount);
- bitcount+=8;
+ if (bitcount != -32768) {
+ if (bitcount < 0 || bitcount > 31) {
+ state = Error;
+ return -1;
+ }
+ accum |= (ch << bitcount);
+ bitcount += 8;
+ }
while (bitcount>=code_size && state==ImageDataBlock) {
int code=accum&((1<<code_size)-1);
bitcount-=code_size;
@@ -629,7 +611,8 @@ int QGIFFormat::decode(QImage *image, const uchar *buffer, int length,
count++;
if (count==hold[0]+1) {
disposePrevious(image);
- disposal=Disposal((hold[1]>>2)&0x7);
+ uint dBits = (hold[1] >> 2) & 0x7;
+ disposal = (dBits <= RestoreImage) ? Disposal(dBits) : NoDisposal;
//UNUSED: waitforuser=!!((hold[1]>>1)&0x1);
int delay=count>3 ? LM(hold[2], hold[3]) : 1;
// IE and mozilla use a minimum delay of 10. With the minimum delay of 10
@@ -669,9 +652,9 @@ int QGIFFormat::decode(QImage *image, const uchar *buffer, int length,
/*!
Scans through the data stream defined by \a device and returns the image
- sizes found in the stream in the \a imageSizes vector.
+ sizes found in the stream in the \a imageSizes list.
*/
-void QGIFFormat::scan(QIODevice *device, QVector<QSize> *imageSizes, int *loopCount)
+void QGIFFormat::scan(QIODevice *device, QList<QSize> *imageSizes, int *loopCount)
{
if (!device)
return;
@@ -1100,7 +1083,7 @@ bool QGifHandler::canRead() const
bool QGifHandler::canRead(QIODevice *device)
{
if (!device) {
- qWarning("QGifHandler::canRead() called with no device");
+ qCWarning(lcGif, "QGifHandler::canRead() called with no device");
return false;
}
@@ -1163,9 +1146,9 @@ QVariant QGifHandler::option(ImageOption option) const
}
// before the first frame is read, or we have an empty data stream
if (frameNumber == -1)
- return (imageSizes.count() > 0) ? QVariant(imageSizes.at(0)) : QVariant();
+ return (imageSizes.size() > 0) ? QVariant(imageSizes.at(0)) : QVariant();
// after the last frame has been read, the next size is undefined
- if (frameNumber >= imageSizes.count() - 1)
+ if (frameNumber >= imageSizes.size() - 1)
return QVariant();
// and the last case: the size of the next frame
return imageSizes.at(frameNumber + 1);
@@ -1192,7 +1175,7 @@ int QGifHandler::imageCount() const
QGIFFormat::scan(device(), &imageSizes, &loopCnt);
scanIsCached = true;
}
- return imageSizes.count();
+ return imageSizes.size();
}
int QGifHandler::loopCount() const
@@ -1215,11 +1198,4 @@ int QGifHandler::currentImageNumber() const
return frameNumber;
}
-#if QT_DEPRECATED_SINCE(5, 13)
-QByteArray QGifHandler::name() const
-{
- return "gif";
-}
-#endif
-
QT_END_NAMESPACE
diff --git a/src/plugins/imageformats/gif/qgifhandler_p.h b/src/plugins/imageformats/gif/qgifhandler_p.h
index c6592043ce..a27acf174d 100644
--- a/src/plugins/imageformats/gif/qgifhandler_p.h
+++ b/src/plugins/imageformats/gif/qgifhandler_p.h
@@ -1,46 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-** WARNING:
-** A separate license from Unisys may be required to use the gif
-** reader. See http://www.unisys.com/about__unisys/lzw/
-** for information from Unisys
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QGIFHANDLER_P_H
#define QGIFHANDLER_P_H
@@ -73,10 +32,6 @@ public:
bool read(QImage *image) override;
bool write(const QImage &image) override;
-#if QT_DEPRECATED_SINCE(5, 13)
- QByteArray name() const override;
-#endif
-
static bool canRead(QIODevice *device);
QVariant option(ImageOption option) const override;
@@ -98,7 +53,7 @@ private:
mutable int nextDelay;
mutable int loopCnt;
int frameNumber;
- mutable QVector<QSize> imageSizes;
+ mutable QList<QSize> imageSizes;
mutable bool scanIsCached;
};
diff --git a/src/plugins/imageformats/ico/.prev_CMakeLists.txt b/src/plugins/imageformats/ico/.prev_CMakeLists.txt
deleted file mode 100644
index 6151d6fd07..0000000000
--- a/src/plugins/imageformats/ico/.prev_CMakeLists.txt
+++ /dev/null
@@ -1,21 +0,0 @@
-# Generated from ico.pro.
-
-#####################################################################
-## QICOPlugin Plugin:
-#####################################################################
-
-qt_add_plugin(QICOPlugin
- OUTPUT_NAME qico
- TYPE imageformats
- SOURCES
- main.cpp main.h
- qicohandler.cpp qicohandler.h
- LIBRARIES
- Qt::CorePrivate
- PUBLIC_LIBRARIES
- Qt::Core
- Qt::Gui
-)
-
-#### Keys ignored in scope 1:.:.:ico.pro:<TRUE>:
-# OTHER_FILES = "ico.json"
diff --git a/src/plugins/imageformats/ico/CMakeLists.txt b/src/plugins/imageformats/ico/CMakeLists.txt
index 1174848d5e..c9cd0f0d40 100644
--- a/src/plugins/imageformats/ico/CMakeLists.txt
+++ b/src/plugins/imageformats/ico/CMakeLists.txt
@@ -1,20 +1,19 @@
-# Generated from ico.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## QICOPlugin Plugin:
#####################################################################
-qt_add_plugin(QICOPlugin
+qt_internal_add_plugin(QICOPlugin
OUTPUT_NAME qico
- TYPE imageformats
+ PLUGIN_TYPE imageformats
SOURCES
- main.cpp main.h
+ main.cpp
qicohandler.cpp qicohandler.h
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Core
Qt::CorePrivate
Qt::Gui
+ NO_UNITY_BUILD
)
-
-#### Keys ignored in scope 1:.:.:ico.pro:<TRUE>:
-# OTHER_FILES = "ico.json"
diff --git a/src/plugins/imageformats/ico/ico.pro b/src/plugins/imageformats/ico/ico.pro
deleted file mode 100644
index c8bb37eff2..0000000000
--- a/src/plugins/imageformats/ico/ico.pro
+++ /dev/null
@@ -1,10 +0,0 @@
-TARGET = qico
-
-HEADERS += main.h qicohandler.h
-SOURCES += main.cpp qicohandler.cpp
-OTHER_FILES += ico.json
-QT += core-private
-
-PLUGIN_TYPE = imageformats
-PLUGIN_CLASS_NAME = QICOPlugin
-load(qt_plugin)
diff --git a/src/plugins/imageformats/ico/main.cpp b/src/plugins/imageformats/ico/main.cpp
index b00d8c7fd3..d5199fa18b 100644
--- a/src/plugins/imageformats/ico/main.cpp
+++ b/src/plugins/imageformats/ico/main.cpp
@@ -1,46 +1,25 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#include "main.h"
+#include <qimageiohandler.h>
+#include <qdebug.h>
+
+#ifdef QT_NO_IMAGEFORMAT_ICO
+#undef QT_NO_IMAGEFORMAT_ICO
+#endif
+#include "qicohandler.h"
QT_BEGIN_NAMESPACE
+class QICOPlugin : public QImageIOPlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QImageIOHandlerFactoryInterface" FILE "ico.json")
+public:
+ Capabilities capabilities(QIODevice *device, const QByteArray &format) const override;
+ QImageIOHandler *create(QIODevice *device, const QByteArray &format = QByteArray()) const override;
+};
+
QImageIOPlugin::Capabilities QICOPlugin::capabilities(QIODevice *device, const QByteArray &format) const
{
if (format == "ico" || format == "cur")
@@ -67,3 +46,5 @@ QImageIOHandler *QICOPlugin::create(QIODevice *device, const QByteArray &format)
}
QT_END_NAMESPACE
+
+#include "main.moc"
diff --git a/src/plugins/imageformats/ico/main.h b/src/plugins/imageformats/ico/main.h
deleted file mode 100644
index b5875183c1..0000000000
--- a/src/plugins/imageformats/ico/main.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 <qimageiohandler.h>
-#include <qdebug.h>
-
-#ifdef QT_NO_IMAGEFORMAT_ICO
-#undef QT_NO_IMAGEFORMAT_ICO
-#endif
-#include "qicohandler.h"
-
-QT_BEGIN_NAMESPACE
-
-class QICOPlugin : public QImageIOPlugin
-{
- Q_OBJECT
- Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QImageIOHandlerFactoryInterface" FILE "ico.json")
-public:
- Capabilities capabilities(QIODevice *device, const QByteArray &format) const override;
- QImageIOHandler *create(QIODevice *device, const QByteArray &format = QByteArray()) const override;
-};
-
-QT_END_NAMESPACE
diff --git a/src/plugins/imageformats/ico/qicohandler.cpp b/src/plugins/imageformats/ico/qicohandler.cpp
index eb50f52bd6..18b39766f5 100644
--- a/src/plugins/imageformats/ico/qicohandler.cpp
+++ b/src/plugins/imageformats/ico/qicohandler.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
/*!
\class QtIcoHandler
@@ -50,12 +14,17 @@
#include <QtCore/qendian.h>
#include <private/qendian_p.h>
#include <QtGui/QImage>
-#include <QtCore/QFile>
#include <QtCore/QBuffer>
+#include <QtCore/QFile>
+#include <QtCore/QLoggingCategory>
#include <qvariant.h>
QT_BEGIN_NAMESPACE
+Q_LOGGING_CATEGORY(lcIco, "qt.gui.imageio.ico")
+
+namespace {
+
// These next two structs represent how the icon information is stored
// in an ICO file.
typedef struct
@@ -95,6 +64,8 @@ typedef struct { // BMP information header
} BMP_INFOHDR ,*LPBMP_INFOHDR;
#define BMP_INFOHDR_SIZE 40
+}
+
class ICOReader
{
public:
@@ -103,9 +74,9 @@ public:
QImage iconAt(int index);
static bool canRead(QIODevice *iodev);
- static QVector<QImage> read(QIODevice *device);
+ static QList<QImage> read(QIODevice *device);
- static bool write(QIODevice *device, const QVector<QImage> &images);
+ static bool write(QIODevice *device, const QList<QImage> &images);
bool readIconEntry(int index, ICONDIRENTRY * iconEntry);
@@ -205,9 +176,7 @@ bool ICOReader::canRead(QIODevice *iodev)
ICONDIR ikonDir;
if (readIconDir(iodev, &ikonDir)) {
- qint64 readBytes = ICONDIR_SIZE;
if (readIconDirEntry(iodev, &ikonDir.idEntries[0])) {
- readBytes += ICONDIRENTRY_SIZE;
// ICO format does not have a magic identifier, so we read 6 different values, which will hopefully be enough to identify the file.
if ( ikonDir.idReserved == 0
&& (ikonDir.idType == 1 || ikonDir.idType == 2)
@@ -356,7 +325,7 @@ void ICOReader::read1BitBMP(QImage & image)
if (iod) {
int h = image.height();
- int bpl = image.bytesPerLine();
+ qsizetype bpl = image.bytesPerLine();
while (--h >= 0) {
if (iod->read((char*)image.scanLine(h),bpl) != bpl) {
@@ -405,7 +374,7 @@ void ICOReader::read8BitBMP(QImage & image)
if (iod) {
int h = icoAttrib.h;
- int bpl = image.bytesPerLine();
+ qsizetype bpl = image.bytesPerLine();
while (--h >= 0) {
if (iod->read((char *)image.scanLine(h), bpl) != bpl) {
@@ -425,7 +394,7 @@ void ICOReader::read16_24_32BMP(QImage & image)
QRgb *p;
QRgb *end;
uchar *buf = new uchar[image.bytesPerLine()];
- int bpl = ((icoAttrib.w*icoAttrib.nbits+31)/32)*4;
+ qsizetype bpl = ((qsizetype(icoAttrib.w)*icoAttrib.nbits+31)/32)*4;
uchar *b;
while (--h >= 0) {
@@ -465,7 +434,9 @@ QImage ICOReader::iconAt(int index)
static const uchar pngMagicData[] = { 137, 80, 78, 71, 13, 10, 26, 10 };
- iod->seek(iconEntry.dwImageOffset);
+ if (!iod->seek(iconEntry.dwImageOffset)
+ || iconEntry.dwBytesInRes > iod->bytesAvailable())
+ return img;
const QByteArray pngMagic = QByteArray::fromRawData((const char*)pngMagicData, sizeof(pngMagicData));
const bool isPngImage = (iod->read(pngMagic.size()) == pngMagic);
@@ -491,8 +462,12 @@ QImage ICOReader::iconAt(int index)
case 4:
icoAttrib.depth = 8;
break;
- default:
+ case 1:
icoAttrib.depth = 1;
+ break;
+ default:
+ return img;
+ break;
}
if (icoAttrib.depth == 32) // there's no colormap
icoAttrib.ncolors = 0;
@@ -517,13 +492,14 @@ QImage ICOReader::iconAt(int index)
else if (icoAttrib.ncolors > 0)
format = QImage::Format_Indexed8;
- QImage image(icoAttrib.w, icoAttrib.h, format);
- if (!image.isNull()) {
+ QImage image;
+ const QSize size(icoAttrib.w, icoAttrib.h);
+ if (QImageIOHandler::allocateImage(size, format, &image)) {
findColorInfo(image);
if (!image.isNull()) {
readBMP(image);
if (!image.isNull()) {
- if (icoAttrib.depth == 32) {
+ if (icoAttrib.nbits == 32) {
img = std::move(image).convertToFormat(QImage::Format_ARGB32_Premultiplied);
} else {
QImage mask(image.width(), image.height(), QImage::Format_Mono);
@@ -559,9 +535,9 @@ QImage ICOReader::iconAt(int index)
\sa write()
*/
-QVector<QImage> ICOReader::read(QIODevice *device)
+QList<QImage> ICOReader::read(QIODevice *device)
{
- QVector<QImage> images;
+ QList<QImage> images;
ICOReader reader(device);
const int N = reader.count();
@@ -585,18 +561,18 @@ QVector<QImage> ICOReader::read(QIODevice *device)
\sa read()
*/
-bool ICOReader::write(QIODevice *device, const QVector<QImage> &images)
+bool ICOReader::write(QIODevice *device, const QList<QImage> &images)
{
bool retValue = false;
- if (images.count()) {
+ if (images.size()) {
qint64 origOffset = device->pos();
ICONDIR id;
id.idReserved = 0;
id.idType = 1;
- id.idCount = images.count();
+ id.idCount = images.size();
ICONDIRENTRY * entries = new ICONDIRENTRY[id.idCount];
BMP_INFOHDR * bmpHeaders = new BMP_INFOHDR[id.idCount];
@@ -759,6 +735,8 @@ bool QtIcoHandler::supportsOption(ImageOption option) const
*/
bool QtIcoHandler::canRead() const
{
+ if (knownCanRead)
+ return true;
bool bCanRead = false;
QIODevice *device = QImageIOHandler::device();
if (device) {
@@ -766,8 +744,9 @@ bool QtIcoHandler::canRead() const
if (bCanRead)
setFormat("ico");
} else {
- qWarning("QtIcoHandler::canRead() called with no device");
+ qCWarning(lcIco, "QtIcoHandler::canRead() called with no device");
}
+ knownCanRead = bCanRead;
return bCanRead;
}
@@ -804,22 +783,11 @@ bool QtIcoHandler::read(QImage *image)
bool QtIcoHandler::write(const QImage &image)
{
QIODevice *device = QImageIOHandler::device();
- QVector<QImage> imgs;
+ QList<QImage> imgs;
imgs.append(image);
return ICOReader::write(device, imgs);
}
-#if QT_DEPRECATED_SINCE(5, 13)
-/*!
- * Return the common identifier of the format.
- * For ICO format this will return "ico".
- */
-QByteArray QtIcoHandler::name() const
-{
- return "ico";
-}
-#endif
-
/*! \reimp
*/
diff --git a/src/plugins/imageformats/ico/qicohandler.h b/src/plugins/imageformats/ico/qicohandler.h
index 328dfce47e..61c3eea465 100644
--- a/src/plugins/imageformats/ico/qicohandler.h
+++ b/src/plugins/imageformats/ico/qicohandler.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QTICOHANDLER_H
#define QTICOHANDLER_H
@@ -54,10 +18,6 @@ public:
bool read(QImage *image) override;
bool write(const QImage &image) override;
-#if QT_DEPRECATED_SINCE(5, 13)
- QByteArray name() const override;
-#endif
-
int imageCount() const override;
bool jumpToImage(int imageNumber) override;
bool jumpToNextImage() override;
@@ -70,7 +30,7 @@ public:
private:
int m_currentIconIndex;
ICOReader *m_pICOReader;
-
+ mutable bool knownCanRead = false;
};
QT_END_NAMESPACE
diff --git a/src/plugins/imageformats/imageformats.pro b/src/plugins/imageformats/imageformats.pro
deleted file mode 100644
index 9d1c0c8fdf..0000000000
--- a/src/plugins/imageformats/imageformats.pro
+++ /dev/null
@@ -1,6 +0,0 @@
-TEMPLATE = subdirs
-QT_FOR_CONFIG += gui-private
-
-qtConfig(ico): SUBDIRS += ico
-qtConfig(jpeg): SUBDIRS += jpeg
-qtConfig(gif): SUBDIRS += gif
diff --git a/src/plugins/imageformats/jpeg/.prev_CMakeLists.txt b/src/plugins/imageformats/jpeg/.prev_CMakeLists.txt
deleted file mode 100644
index 25b5861122..0000000000
--- a/src/plugins/imageformats/jpeg/.prev_CMakeLists.txt
+++ /dev/null
@@ -1,22 +0,0 @@
-# Generated from jpeg.pro.
-
-#####################################################################
-## QJpegPlugin Plugin:
-#####################################################################
-
-qt_add_plugin(QJpegPlugin
- OUTPUT_NAME qjpeg
- TYPE imageformats
- SOURCES
- main.cpp main.h
- qjpeghandler.cpp qjpeghandler_p.h
- PUBLIC_LIBRARIES
- JPEG::JPEG
- Qt::Core
- Qt::CorePrivate
- Qt::Gui
- Qt::GuiPrivate
-)
-
-#### Keys ignored in scope 1:.:.:jpeg.pro:<TRUE>:
-# OTHER_FILES = "jpeg.json"
diff --git a/src/plugins/imageformats/jpeg/CMakeLists.txt b/src/plugins/imageformats/jpeg/CMakeLists.txt
index 6aaa6538ec..6b077a7647 100644
--- a/src/plugins/imageformats/jpeg/CMakeLists.txt
+++ b/src/plugins/imageformats/jpeg/CMakeLists.txt
@@ -1,24 +1,29 @@
-# Generated from jpeg.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
-qt_find_package(JPEG) # special case
+qt_find_package(WrapJpeg PROVIDED_TARGETS WrapJpeg::WrapJpeg)
#####################################################################
## QJpegPlugin Plugin:
#####################################################################
-qt_add_plugin(QJpegPlugin
+qt_internal_add_plugin(QJpegPlugin
OUTPUT_NAME qjpeg
- TYPE imageformats
+ PLUGIN_TYPE imageformats
SOURCES
- main.cpp main.h
+ main.cpp
qjpeghandler.cpp qjpeghandler_p.h
- PUBLIC_LIBRARIES
- JPEG::JPEG
+ LIBRARIES
Qt::Core
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
+ WrapJpeg::WrapJpeg
)
-#### Keys ignored in scope 1:.:.:jpeg.pro:<TRUE>:
-# OTHER_FILES = "jpeg.json"
+# Fails to build on Windows with a static Qt, PCH enabled and
+# the vendored libjpeg sources, due to 'boolean'
+# redefinition in jmorecfg.h and rpcndr.h.
+if(WIN32 AND NOT BUILD_SHARED_LIBS)
+ qt_update_ignore_pch_source(QJpegPlugin "qjpeghandler.cpp")
+endif()
diff --git a/src/plugins/imageformats/jpeg/jpeg.pro b/src/plugins/imageformats/jpeg/jpeg.pro
deleted file mode 100644
index 89476e62f5..0000000000
--- a/src/plugins/imageformats/jpeg/jpeg.pro
+++ /dev/null
@@ -1,18 +0,0 @@
-TARGET = qjpeg
-
-QT += core-private gui-private
-
-SOURCES += main.cpp qjpeghandler.cpp
-HEADERS += main.h qjpeghandler_p.h
-
-qtConfig(system-jpeg) {
- QMAKE_USE += libjpeg
-} else {
- include($$PWD/../../../3rdparty/libjpeg.pri)
-}
-
-OTHER_FILES += jpeg.json
-
-PLUGIN_TYPE = imageformats
-PLUGIN_CLASS_NAME = QJpegPlugin
-load(qt_plugin)
diff --git a/src/plugins/imageformats/jpeg/main.cpp b/src/plugins/imageformats/jpeg/main.cpp
index 83f13c4a9d..c869d07650 100644
--- a/src/plugins/imageformats/jpeg/main.cpp
+++ b/src/plugins/imageformats/jpeg/main.cpp
@@ -1,43 +1,8 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#include "main.h"
+#include <qimageiohandler.h>
+#include <qstringlist.h>
#ifdef QT_NO_IMAGEFORMAT_JPEG
#undef QT_NO_IMAGEFORMAT_JPEG
@@ -46,6 +11,15 @@
QT_BEGIN_NAMESPACE
+class QJpegPlugin : public QImageIOPlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QImageIOHandlerFactoryInterface" FILE "jpeg.json")
+public:
+ Capabilities capabilities(QIODevice *device, const QByteArray &format) const override;
+ QImageIOHandler *create(QIODevice *device, const QByteArray &format = QByteArray()) const override;
+};
+
QImageIOPlugin::Capabilities QJpegPlugin::capabilities(QIODevice *device, const QByteArray &format) const
{
if (format == "jpeg" || format == "jpg")
@@ -72,3 +46,5 @@ QImageIOHandler *QJpegPlugin::create(QIODevice *device, const QByteArray &format
}
QT_END_NAMESPACE
+
+#include "main.moc"
diff --git a/src/plugins/imageformats/jpeg/main.h b/src/plugins/imageformats/jpeg/main.h
deleted file mode 100644
index 1845c8c124..0000000000
--- a/src/plugins/imageformats/jpeg/main.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 <qimageiohandler.h>
-#include <qstringlist.h>
-
-#ifdef QT_NO_IMAGEFORMAT_JPEG
-#undef QT_NO_IMAGEFORMAT_JPEG
-#endif
-
-QT_BEGIN_NAMESPACE
-
-class QJpegPlugin : public QImageIOPlugin
-{
- Q_OBJECT
- Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QImageIOHandlerFactoryInterface" FILE "jpeg.json")
-public:
- Capabilities capabilities(QIODevice *device, const QByteArray &format) const override;
- QImageIOHandler *create(QIODevice *device, const QByteArray &format = QByteArray()) const override;
-};
-
-QT_END_NAMESPACE
diff --git a/src/plugins/imageformats/jpeg/qjpeghandler.cpp b/src/plugins/imageformats/jpeg/qjpeghandler.cpp
index c31e2db3c5..59b73587c5 100644
--- a/src/plugins/imageformats/jpeg/qjpeghandler.cpp
+++ b/src/plugins/imageformats/jpeg/qjpeghandler.cpp
@@ -1,52 +1,17 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qjpeghandler_p.h"
-#include <qimage.h>
+#include <qbuffer.h>
#include <qcolorspace.h>
#include <qcolortransform.h>
#include <qdebug.h>
-#include <qvariant.h>
-#include <qvector.h>
-#include <qbuffer.h>
+#include <qimage.h>
+#include <qlist.h>
+#include <qloggingcategory.h>
#include <qmath.h>
+#include <qvariant.h>
#include <private/qicc_p.h>
#include <private/qsimd_p.h>
#include <private/qimage_p.h> // for qt_getImageText
@@ -60,13 +25,6 @@
// including jpeglib.h seems to be a little messy
extern "C" {
-// jpeglib.h->jmorecfg.h tries to typedef int boolean; but this conflicts with
-// some Windows headers that may or may not have been included
-#ifdef HAVE_BOOLEAN
-# undef HAVE_BOOLEAN
-#endif
-#define boolean jboolean
-
#define XMD_H // shut JPEGlib up
#include <jpeglib.h>
#ifdef const
@@ -75,6 +33,9 @@ extern "C" {
}
QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(lcJpeg, "qt.gui.imageio.jpeg")
+
QT_WARNING_DISABLE_GCC("-Wclobbered")
Q_GUI_EXPORT void QT_FASTCALL qt_convert_rgb888_to_rgb32(quint32 *dst, const uchar *src, int len);
@@ -88,10 +49,8 @@ extern "C" {
static void my_error_exit (j_common_ptr cinfo)
{
+ (*cinfo->err->output_message)(cinfo);
my_error_mgr* myerr = (my_error_mgr*) cinfo->err;
- char buffer[JMSG_LENGTH_MAX];
- (*cinfo->err->format_message)(cinfo, buffer);
- qWarning("%s", buffer);
longjmp(myerr->setjmp_buffer, 1);
}
@@ -99,7 +58,7 @@ static void my_output_message(j_common_ptr cinfo)
{
char buffer[JMSG_LENGTH_MAX];
(*cinfo->err->format_message)(cinfo, buffer);
- qWarning("%s", buffer);
+ qCWarning(lcJpeg,"%s", buffer);
}
}
@@ -213,9 +172,14 @@ inline static bool read_jpeg_format(QImage::Format &format, j_decompress_ptr cin
format = QImage::Format_Grayscale8;
break;
case 3:
- case 4:
format = QImage::Format_RGB32;
break;
+ case 4:
+ if (cinfo->out_color_space == JCS_CMYK)
+ format = QImage::Format_CMYK8888;
+ else
+ format = QImage::Format_RGB32;
+ break;
default:
result = false;
break;
@@ -233,24 +197,26 @@ static bool ensureValidImage(QImage *dest, struct jpeg_decompress_struct *info,
format = QImage::Format_Grayscale8;
break;
case 3:
- case 4:
format = QImage::Format_RGB32;
break;
+ case 4:
+ if (info->out_color_space == JCS_CMYK)
+ format = QImage::Format_CMYK8888;
+ else
+ format = QImage::Format_RGB32;
+ break;
default:
return false; // unsupported format
}
- if (dest->size() != size || dest->format() != format)
- *dest = QImage(size, format);
-
- return !dest->isNull();
+ return QImageIOHandler::allocateImage(size, format, dest);
}
static bool read_jpeg_image(QImage *outImage,
QSize scaledSize, QRect scaledClipRect,
QRect clipRect, int quality,
Rgb888ToRgb32Converter converter,
- j_decompress_ptr info, struct my_error_mgr* err )
+ j_decompress_ptr info, struct my_error_mgr* err, bool invertCMYK)
{
if (!setjmp(err->setjmp_buffer)) {
// -1 means default quality.
@@ -333,7 +299,7 @@ static bool read_jpeg_image(QImage *outImage,
}
// If high quality not required, use fast decompression
- if( quality < HIGH_QUALITY_THRESHOLD ) {
+ if ( quality < HIGH_QUALITY_THRESHOLD ) {
info->dct_method = JDCT_IFAST;
info->do_fancy_upsampling = FALSE;
}
@@ -359,7 +325,7 @@ static bool read_jpeg_image(QImage *outImage,
// Allocate memory for the clipped QImage.
if (!ensureValidImage(outImage, info, clip.size()))
- longjmp(err->setjmp_buffer, 1);
+ return false;
// Avoid memcpy() overhead if grayscale with no clipping.
bool quickGray = (info->output_components == 1 &&
@@ -392,14 +358,15 @@ static bool read_jpeg_image(QImage *outImage,
QRgb *out = (QRgb*)outImage->scanLine(y);
converter(out, in, clip.width());
} else if (info->out_color_space == JCS_CMYK) {
- // Convert CMYK->RGB.
uchar *in = rows[0] + clip.x() * 4;
- QRgb *out = (QRgb*)outImage->scanLine(y);
- for (int i = 0; i < clip.width(); ++i) {
- int k = in[3];
- *out++ = qRgb(k * in[0] / 255, k * in[1] / 255,
- k * in[2] / 255);
- in += 4;
+ quint32 *out = (quint32*)outImage->scanLine(y);
+ if (invertCMYK) {
+ for (int i = 0; i < clip.width(); ++i) {
+ *out++ = 0xffffffffu - (in[0] | in[1] << 8 | in[2] << 16 | in[3] << 24);
+ in += 4;
+ }
+ } else {
+ memcpy(out, in, clip.width() * 4);
}
} else if (info->output_components == 1) {
// Grayscale.
@@ -435,8 +402,10 @@ static bool read_jpeg_image(QImage *outImage,
*outImage = outImage->copy(scaledClipRect);
return !outImage->isNull();
}
- else
+ else {
+ my_output_message(j_common_ptr(info));
return false;
+ }
}
struct my_jpeg_destination_mgr : public jpeg_destination_mgr {
@@ -501,7 +470,7 @@ static inline void set_text(const QImage &image, j_compress_ptr cinfo, const QSt
if (!comment.isEmpty())
comment += ": ";
comment += it.value().toUtf8();
- if (comment.length() > maxMarkerSize)
+ if (comment.size() > maxMarkerSize)
comment.truncate(maxMarkerSize);
jpeg_write_marker(cinfo, JPEG_COM, (const JOCTET *)comment.constData(), comment.size());
}
@@ -519,7 +488,7 @@ static inline void write_icc_profile(const QImage &image, j_compress_ptr cinfo)
const int markers = (iccProfile.size() + (maxIccMarkerSize - 1)) / maxIccMarkerSize;
Q_ASSERT(markers < 256);
for (int marker = 1; marker <= markers; ++marker) {
- const int len = std::min(iccProfile.size() - index, maxIccMarkerSize);
+ const int len = qMin(iccProfile.size() - index, maxIccMarkerSize);
const QByteArray block = iccSignature
+ QByteArray(1, char(marker)) + QByteArray(1, char(markers))
+ iccProfile.mid(index, len);
@@ -535,10 +504,11 @@ static bool do_write_jpeg_image(struct jpeg_compress_struct &cinfo,
int sourceQuality,
const QString &description,
bool optimize,
- bool progressive)
+ bool progressive,
+ bool invertCMYK)
{
bool success = false;
- const QVector<QRgb> cmap = image.colorTable();
+ const QList<QRgb> cmap = image.colorTable();
if (image.format() == QImage::Format_Invalid || image.format() == QImage::Format_Alpha8)
return false;
@@ -575,10 +545,15 @@ static bool do_write_jpeg_image(struct jpeg_compress_struct &cinfo,
cinfo.in_color_space = gray ? JCS_GRAYSCALE : JCS_RGB;
break;
case QImage::Format_Grayscale8:
+ case QImage::Format_Grayscale16:
gray = true;
cinfo.input_components = 1;
cinfo.in_color_space = JCS_GRAYSCALE;
break;
+ case QImage::Format_CMYK8888:
+ cinfo.input_components = 4;
+ cinfo.in_color_space = JCS_CMYK;
+ break;
default:
cinfo.input_components = 3;
cinfo.in_color_space = JCS_RGB;
@@ -611,7 +586,7 @@ static bool do_write_jpeg_image(struct jpeg_compress_struct &cinfo,
jpeg_start_compress(&cinfo, TRUE);
set_text(image, &cinfo, description);
- if (cinfo.in_color_space == JCS_RGB)
+ if (cinfo.in_color_space == JCS_RGB || cinfo.in_color_space == JCS_CMYK)
write_icc_profile(image, &cinfo);
row_pointer[0] = new uchar[cinfo.image_width*cinfo.input_components];
@@ -673,6 +648,12 @@ static bool do_write_jpeg_image(struct jpeg_compress_struct &cinfo,
case QImage::Format_Grayscale8:
memcpy(row, image.constScanLine(cinfo.next_scanline), w);
break;
+ case QImage::Format_Grayscale16:
+ {
+ QImage rowImg = image.copy(0, cinfo.next_scanline, w, 1).convertToFormat(QImage::Format_Grayscale8);
+ memcpy(row, rowImg.constScanLine(0), w);
+ }
+ break;
case QImage::Format_RGB888:
memcpy(row, image.constScanLine(cinfo.next_scanline), w * 3);
break;
@@ -689,6 +670,17 @@ static bool do_write_jpeg_image(struct jpeg_compress_struct &cinfo,
}
}
break;
+ case QImage::Format_CMYK8888: {
+ auto *cmykIn = reinterpret_cast<const quint32 *>(image.constScanLine(cinfo.next_scanline));
+ auto *cmykOut = reinterpret_cast<quint32 *>(row);
+ if (invertCMYK) {
+ for (int i = 0; i < w; ++i)
+ cmykOut[i] = 0xffffffffu - cmykIn[i];
+ } else {
+ memcpy(cmykOut, cmykIn, w * 4);
+ }
+ break;
+ }
default:
{
// (Testing shows that this way is actually faster than converting to RGB888 + memcpy)
@@ -710,6 +702,7 @@ static bool do_write_jpeg_image(struct jpeg_compress_struct &cinfo,
jpeg_destroy_compress(&cinfo);
success = true;
} else {
+ my_output_message(j_common_ptr(&cinfo));
jpeg_destroy_compress(&cinfo);
success = false;
}
@@ -723,7 +716,8 @@ static bool write_jpeg_image(const QImage &image,
int sourceQuality,
const QString &description,
bool optimize,
- bool progressive)
+ bool progressive,
+ bool invertCMYK)
{
// protect these objects from the setjmp/longjmp pair inside
// do_write_jpeg_image (by making them non-local).
@@ -734,7 +728,7 @@ static bool write_jpeg_image(const QImage &image,
const bool success = do_write_jpeg_image(cinfo, row_pointer,
image, device,
sourceQuality, description,
- optimize, progressive);
+ optimize, progressive, invertCMYK);
delete [] row_pointer[0];
return success;
@@ -757,7 +751,7 @@ public:
~QJpegHandlerPrivate()
{
- if(iod_src)
+ if (iod_src)
{
jpeg_destroy_decompress(&info);
delete iod_src;
@@ -779,6 +773,21 @@ public:
QStringList readTexts;
QByteArray iccProfile;
+ // Photoshop historically invertes the quantities in CMYK JPEG files:
+ // 0 means 100% ink, 255 means no ink. Every reader does the same,
+ // for compatibility reasons.
+ // Use such an interpretation by default, but also offer the alternative
+ // of not inverting the channels.
+ // This is just a "fancy" API; it could be reduced to a boolean setting
+ // for CMYK files.
+ enum class SubType {
+ Automatic,
+ Inverted_CMYK,
+ CMYK,
+ NSubTypes
+ };
+ SubType subType = SubType::Automatic;
+
struct jpeg_decompress_struct info;
struct my_jpeg_source_mgr * iod_src;
struct my_error_mgr err;
@@ -793,6 +802,14 @@ public:
QJpegHandler *q;
};
+static const char SupportedJPEGSubtypes[][14] = {
+ "Automatic",
+ "Inverted_CMYK",
+ "CMYK"
+};
+
+static_assert(std::size(SupportedJPEGSubtypes) == size_t(QJpegHandlerPrivate::SubType::NSubTypes));
+
static bool readExifHeader(QDataStream &stream)
{
char prefix[6];
@@ -916,7 +933,7 @@ static QImageIOHandler::Transformations exif2Qt(int exifOrientation)
case 8: // rotate 270 CW
return QImageIOHandler::TransformationRotate270;
}
- qWarning("Invalid EXIF orientation");
+ qCWarning(lcJpeg, "Invalid EXIF orientation");
return QImageIOHandler::TransformationNone;
}
@@ -925,7 +942,7 @@ static QImageIOHandler::Transformations exif2Qt(int exifOrientation)
*/
bool QJpegHandlerPrivate::readJpegHeader(QIODevice *device)
{
- if(state == Ready)
+ if (state == Ready)
{
state = Error;
iod_src = new my_jpeg_source_mgr(device);
@@ -956,6 +973,7 @@ bool QJpegHandlerPrivate::readJpegHeader(QIODevice *device)
for (jpeg_saved_marker_ptr marker = info.marker_list; marker != nullptr; marker = marker->next) {
if (marker->marker == JPEG_COM) {
+#ifndef QT_NO_IMAGEIO_TEXT_LOADING
QString key, value;
QString s = QString::fromUtf8((const char *)marker->data, marker->data_length);
int index = s.indexOf(QLatin1String(": "));
@@ -971,6 +989,7 @@ bool QJpegHandlerPrivate::readJpegHeader(QIODevice *device)
description += key + QLatin1String(": ") + value.simplified();
readTexts.append(key);
readTexts.append(value);
+#endif
} else if (marker->marker == JPEG_APP0 + 1) {
exifData.append((const char*)marker->data, marker->data_length);
} else if (marker->marker == JPEG_APP0 + 2) {
@@ -990,24 +1009,25 @@ bool QJpegHandlerPrivate::readJpegHeader(QIODevice *device)
state = ReadHeader;
return true;
}
- else
- {
+ else {
+ my_output_message(j_common_ptr(&info));
return false;
}
}
- else if(state == Error)
+ else if (state == Error)
return false;
return true;
}
bool QJpegHandlerPrivate::read(QImage *image)
{
- if(state == Ready)
+ if (state == Ready)
readJpegHeader(q->device());
- if(state == ReadHeader)
+ if (state == ReadHeader)
{
- bool success = read_jpeg_image(image, scaledSize, scaledClipRect, clipRect, quality, rgb888ToRgb32ConverterPtr, &info, &err);
+ const bool invertCMYK = subType != QJpegHandlerPrivate::SubType::CMYK;
+ bool success = read_jpeg_image(image, scaledSize, scaledClipRect, clipRect, quality, rgb888ToRgb32ConverterPtr, &info, &err, invertCMYK);
if (success) {
for (int i = 0; i < readTexts.size()-1; i+=2)
image->setText(readTexts.at(i), readTexts.at(i+1));
@@ -1058,7 +1078,7 @@ QJpegHandler::~QJpegHandler()
bool QJpegHandler::canRead() const
{
- if(d->state == QJpegHandlerPrivate::Ready && !canRead(device()))
+ if (d->state == QJpegHandlerPrivate::Ready && !canRead(device()))
return false;
if (d->state != QJpegHandlerPrivate::Error && d->state != QJpegHandlerPrivate::ReadingEnd) {
@@ -1072,7 +1092,7 @@ bool QJpegHandler::canRead() const
bool QJpegHandler::canRead(QIODevice *device)
{
if (!device) {
- qWarning("QJpegHandler::canRead() called with no device");
+ qCWarning(lcJpeg, "QJpegHandler::canRead() called with no device");
return false;
}
@@ -1093,13 +1113,14 @@ extern void qt_imageTransform(QImage &src, QImageIOHandler::Transformations orie
bool QJpegHandler::write(const QImage &image)
{
+ const bool invertCMYK = d->subType != QJpegHandlerPrivate::SubType::CMYK;
if (d->transformation != QImageIOHandler::TransformationNone) {
// We don't support writing EXIF headers so apply the transform to the data.
QImage img = image;
qt_imageTransform(img, d->transformation);
- return write_jpeg_image(img, device(), d->quality, d->description, d->optimize, d->progressive);
+ return write_jpeg_image(img, device(), d->quality, d->description, d->optimize, d->progressive, invertCMYK);
}
- return write_jpeg_image(image, device(), d->quality, d->description, d->optimize, d->progressive);
+ return write_jpeg_image(image, device(), d->quality, d->description, d->optimize, d->progressive, invertCMYK);
}
bool QJpegHandler::supportsOption(ImageOption option) const
@@ -1110,6 +1131,8 @@ bool QJpegHandler::supportsOption(ImageOption option) const
|| option == ClipRect
|| option == Description
|| option == Size
+ || option == SubType
+ || option == SupportedSubTypes
|| option == ImageFormat
|| option == OptimizedWrite
|| option == ProgressiveScanWrite
@@ -1133,6 +1156,13 @@ QVariant QJpegHandler::option(ImageOption option) const
case Size:
d->readJpegHeader(device());
return d->size;
+ case SubType:
+ return QByteArray(SupportedJPEGSubtypes[int(d->subType)]);
+ case SupportedSubTypes: {
+ QByteArrayList list(std::begin(SupportedJPEGSubtypes),
+ std::end(SupportedJPEGSubtypes));
+ return QVariant::fromValue(list);
+ }
case ImageFormat:
d->readJpegHeader(device());
return d->format;
@@ -1168,6 +1198,16 @@ void QJpegHandler::setOption(ImageOption option, const QVariant &value)
case Description:
d->description = value.toString();
break;
+ case SubType: {
+ const QByteArray subType = value.toByteArray();
+ for (size_t i = 0; i < std::size(SupportedJPEGSubtypes); ++i) {
+ if (subType == SupportedJPEGSubtypes[i]) {
+ d->subType = QJpegHandlerPrivate::SubType(i);
+ break;
+ }
+ }
+ break;
+ }
case OptimizedWrite:
d->optimize = value.toBool();
break;
@@ -1178,17 +1218,11 @@ void QJpegHandler::setOption(ImageOption option, const QVariant &value)
int transformation = value.toInt();
if (transformation > 0 && transformation < 8)
d->transformation = QImageIOHandler::Transformations(transformation);
+ break;
}
default:
break;
}
}
-#if QT_DEPRECATED_SINCE(5, 13)
-QByteArray QJpegHandler::name() const
-{
- return "jpeg";
-}
-#endif
-
QT_END_NAMESPACE
diff --git a/src/plugins/imageformats/jpeg/qjpeghandler_p.h b/src/plugins/imageformats/jpeg/qjpeghandler_p.h
index fafa930c11..e246f7a6e1 100644
--- a/src/plugins/imageformats/jpeg/qjpeghandler_p.h
+++ b/src/plugins/imageformats/jpeg/qjpeghandler_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QJPEGHANDLER_P_H
#define QJPEGHANDLER_P_H
@@ -68,10 +32,6 @@ public:
bool read(QImage *image) override;
bool write(const QImage &image) override;
-#if QT_DEPRECATED_SINCE(5, 13)
- QByteArray name() const override;
-#endif
-
static bool canRead(QIODevice *device);
QVariant option(ImageOption option) const override;
diff --git a/src/plugins/networkinformation/CMakeLists.txt b/src/plugins/networkinformation/CMakeLists.txt
new file mode 100644
index 0000000000..04da816264
--- /dev/null
+++ b/src/plugins/networkinformation/CMakeLists.txt
@@ -0,0 +1,22 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+if(WIN32 AND QT_FEATURE_networklistmanager)
+ add_subdirectory(networklistmanager)
+endif()
+
+if(LINUX AND TARGET Qt::DBus)
+ add_subdirectory(networkmanager)
+endif()
+
+if(APPLE)
+ add_subdirectory(scnetworkreachability)
+endif()
+
+if(ANDROID)
+ add_subdirectory(android)
+endif()
+
+if(QT_FEATURE_glib AND TARGET GLIB2::GOBJECT AND TARGET GLIB2::GIO)
+ add_subdirectory(glib)
+endif()
diff --git a/src/plugins/networkinformation/android/CMakeLists.txt b/src/plugins/networkinformation/android/CMakeLists.txt
new file mode 100644
index 0000000000..07d9201bbb
--- /dev/null
+++ b/src/plugins/networkinformation/android/CMakeLists.txt
@@ -0,0 +1,46 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+
+set(java_sources
+ jar/src/org/qtproject/qt/android/networkinformation/QtAndroidNetworkInformation.java
+)
+
+qt_internal_add_jar(Qt${QtBase_VERSION_MAJOR}AndroidNetworkInformationBackend
+ INCLUDE_JARS ${QT_ANDROID_JAR}
+ SOURCES ${java_sources}
+ OUTPUT_DIR "${QT_BUILD_DIR}/jar"
+)
+
+qt_path_join(destination ${INSTALL_DATADIR} "jar")
+
+install_jar(Qt${QtBase_VERSION_MAJOR}AndroidNetworkInformationBackend
+ DESTINATION ${destination}
+ COMPONENT Devel
+)
+
+qt_internal_add_plugin(QAndroidNetworkInformationPlugin
+ OUTPUT_NAME qandroidnetworkinformation
+ CLASS_NAME QAndroidNetworkInformationBackendFactory
+ PLUGIN_TYPE networkinformation
+ DEFAULT_IF ANDROID
+ SOURCES
+ qandroidnetworkinformationbackend.cpp
+ wrapper/androidconnectivitymanager.cpp wrapper/androidconnectivitymanager.h
+ LIBRARIES
+ Qt::NetworkPrivate
+)
+
+set_property(
+ TARGET
+ QAndroidNetworkInformationPlugin
+ APPEND PROPERTY QT_ANDROID_BUNDLED_JAR_DEPENDENCIES
+ jar/Qt${QtBase_VERSION_MAJOR}AndroidNetworkInformationBackend.jar
+)
+
+set_property(
+ TARGET
+ QAndroidNetworkInformationPlugin
+ APPEND PROPERTY QT_ANDROID_PERMISSIONS
+ android.permission.ACCESS_NETWORK_STATE
+)
diff --git a/src/plugins/networkinformation/android/jar/.gitignore b/src/plugins/networkinformation/android/jar/.gitignore
new file mode 100644
index 0000000000..364420a59a
--- /dev/null
+++ b/src/plugins/networkinformation/android/jar/.gitignore
@@ -0,0 +1,6 @@
+.gradle/
+build/
+gradle/
+gradlew
+gradlew.bat
+local.properties
diff --git a/src/plugins/networkinformation/android/jar/build.gradle b/src/plugins/networkinformation/android/jar/build.gradle
new file mode 100644
index 0000000000..68a9381ad2
--- /dev/null
+++ b/src/plugins/networkinformation/android/jar/build.gradle
@@ -0,0 +1,51 @@
+// This is mainly used to allow Android Studio to easily read this folder as an android project.
+
+buildscript {
+ repositories {
+ google()
+ mavenCentral()
+ }
+
+ dependencies {
+ classpath 'com.android.tools.build:gradle:8.0.2'
+ }
+}
+
+apply plugin: 'com.android.library'
+
+dependencies {
+ implementation fileTree(dir: "libs", include: ["*.jar"])
+}
+
+repositories {
+ google()
+ mavenCentral()
+}
+
+android {
+ compileSdk 34
+
+ defaultConfig {
+ minSdkVersion 23
+ }
+
+ sourceSets {
+ main {
+ java.srcDir 'src/'
+ resources.srcDir 'libs/'
+ manifest.srcFile 'AndroidManifest.xml'
+ res.srcDirs = ['res/']
+ }
+ }
+
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+
+ android {
+ lintOptions {
+ abortOnError true
+ }
+ }
+}
diff --git a/src/plugins/networkinformation/android/jar/settings.gradle b/src/plugins/networkinformation/android/jar/settings.gradle
new file mode 100644
index 0000000000..cbb1ff361b
--- /dev/null
+++ b/src/plugins/networkinformation/android/jar/settings.gradle
@@ -0,0 +1 @@
+rootProject.name = "QtAndroidNetworkInformationBackend"
diff --git a/src/plugins/networkinformation/android/jar/src/org/qtproject/qt/android/networkinformation/QtAndroidNetworkInformation.java b/src/plugins/networkinformation/android/jar/src/org/qtproject/qt/android/networkinformation/QtAndroidNetworkInformation.java
new file mode 100644
index 0000000000..6a56c506b0
--- /dev/null
+++ b/src/plugins/networkinformation/android/jar/src/org/qtproject/qt/android/networkinformation/QtAndroidNetworkInformation.java
@@ -0,0 +1,160 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+package org.qtproject.qt.android.networkinformation;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.ConnectivityManager.NetworkCallback;
+import android.net.NetworkRequest;
+import android.net.NetworkCapabilities;
+import android.net.Network;
+import android.os.Build;
+
+public class QtAndroidNetworkInformation {
+ private static final String LOG_TAG = "QtAndroidNetworkInformation";
+
+ private static native void networkConnectivityChanged(int connectivity);
+ private static native void genericInfoChanged(boolean captivePortal, boolean metered);
+ private static native void transportMediumChanged(int transportMedium);
+
+ private static QtNetworkInformationCallback m_callback = null;
+ private static final Object m_lock = new Object();
+
+ // Keep synchronized with AndroidConnectivity in androidconnectivitymanager.h
+ enum AndroidConnectivity {
+ Connected, Unknown, Disconnected
+ }
+
+ // Keep synchronized with AndroidTransport in androidconnectivitymanager.h
+ enum Transport {
+ Unknown,
+ Bluetooth,
+ Cellular,
+ Ethernet,
+ LoWPAN,
+ Usb,
+ WiFi,
+ WiFiAware,
+ }
+
+ private static class QtNetworkInformationCallback extends NetworkCallback {
+ public AndroidConnectivity previousState = null;
+ public Transport previousTransport = null;
+
+ QtNetworkInformationCallback() {
+ }
+
+ @Override
+ public void onCapabilitiesChanged(Network network, NetworkCapabilities capabilities) {
+ AndroidConnectivity s;
+ if (!capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET))
+ s = AndroidConnectivity.Disconnected;
+ else if (capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED))
+ s = AndroidConnectivity.Connected;
+ else
+ s = AndroidConnectivity.Unknown; // = we _may_ have Internet access
+
+ final Transport transport = getTransport(capabilities);
+ if (transport == Transport.Unknown) // If we don't have any transport media: override
+ s = AndroidConnectivity.Unknown;
+
+ setState(s);
+ setTransportMedium(transport);
+
+ final boolean captive
+ = capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL);
+ final boolean metered
+ = !capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
+ genericInfoChanged(captive, metered);
+ }
+
+ private Transport getTransport(NetworkCapabilities capabilities)
+ {
+ if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
+ return Transport.WiFi;
+ } else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
+ return Transport.Cellular;
+ } else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_BLUETOOTH)) {
+ return Transport.Bluetooth;
+ } else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET)) {
+ return Transport.Ethernet;
+ } else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI_AWARE)) {
+ // Build.VERSION_CODES.O
+ return Transport.WiFiAware;
+ } else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_LOWPAN)) {
+ // Build.VERSION_CODES.O_MR1
+ return Transport.LoWPAN;
+ }/* else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_USB)) {
+ // Build.VERSION_CODES.S
+ return Transport.Usb;
+ }*/ // @todo: Uncomment once we can use SDK 31
+ return Transport.Unknown;
+ }
+
+ private void setState(AndroidConnectivity s) {
+ if (previousState != s) {
+ previousState = s;
+ networkConnectivityChanged(s.ordinal());
+ }
+ }
+
+ private void setTransportMedium(Transport t) {
+ if (previousTransport != t) {
+ previousTransport = t;
+ transportMediumChanged(t.ordinal());
+ }
+ }
+
+ @Override
+ public void onLost(Network network) {
+ setState(AndroidConnectivity.Disconnected);
+ }
+ }
+
+ private QtAndroidNetworkInformation() {
+ }
+
+ public static AndroidConnectivity state() {
+ if (m_callback != null && m_callback.previousState != null)
+ return m_callback.previousState;
+ return AndroidConnectivity.Unknown;
+ }
+
+ @SuppressLint("MissingPermission")
+ public static void registerReceiver(final Context context) {
+ synchronized (m_lock) {
+ if (m_callback == null) {
+ ConnectivityManager manager = getConnectivityManager(context);
+ m_callback = new QtNetworkInformationCallback();
+ NetworkRequest.Builder builder = new NetworkRequest.Builder();
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R)
+ builder = builder.clearCapabilities();
+ builder = builder.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
+ builder = builder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED);
+ builder = builder.addCapability(NetworkCapabilities.NET_CAPABILITY_FOREGROUND);
+ }
+ NetworkRequest request = builder.build();
+
+ // Can't use registerDefaultNetworkCallback because it doesn't let us know when
+ // the network disconnects!
+ manager.registerNetworkCallback(request, m_callback);
+ }
+ }
+ }
+
+ public static void unregisterReceiver(final Context context) {
+ synchronized (m_lock) {
+ if (m_callback != null) {
+ getConnectivityManager(context).unregisterNetworkCallback(m_callback);
+ m_callback = null;
+ }
+ }
+ }
+
+ public static ConnectivityManager getConnectivityManager(final Context context) {
+ return (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
+ }
+}
diff --git a/src/plugins/networkinformation/android/qandroidnetworkinformationbackend.cpp b/src/plugins/networkinformation/android/qandroidnetworkinformationbackend.cpp
new file mode 100644
index 0000000000..44e4d447d2
--- /dev/null
+++ b/src/plugins/networkinformation/android/qandroidnetworkinformationbackend.cpp
@@ -0,0 +1,147 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <QtNetwork/private/qnetworkinformation_p.h>
+
+#include "wrapper/androidconnectivitymanager.h"
+
+#include <QtCore/qglobal.h>
+
+QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(lcNetInfoAndroid)
+Q_LOGGING_CATEGORY(lcNetInfoAndroid, "qt.network.info.android");
+
+static QString backendName() {
+ return QString::fromUtf16(QNetworkInformationBackend::PluginNames
+ [QNetworkInformationBackend::PluginNamesAndroidIndex]);
+}
+
+class QAndroidNetworkInformationBackend : public QNetworkInformationBackend
+{
+ Q_OBJECT
+public:
+ QAndroidNetworkInformationBackend();
+ ~QAndroidNetworkInformationBackend() { m_valid = false; }
+
+ QString name() const override { return backendName(); }
+ QNetworkInformation::Features featuresSupported() const override
+ {
+ return featuresSupportedStatic();
+ }
+
+ static QNetworkInformation::Features featuresSupportedStatic()
+ {
+ using Feature = QNetworkInformation::Feature;
+ return QNetworkInformation::Features(Feature::Reachability | Feature::CaptivePortal
+ | Feature::TransportMedium);
+ }
+
+ bool isValid() { return m_valid; }
+
+private:
+ Q_DISABLE_COPY_MOVE(QAndroidNetworkInformationBackend);
+
+ void updateConnectivity(AndroidConnectivityManager::AndroidConnectivity connectivity);
+ void updateTransportMedium(AndroidConnectivityManager::AndroidTransport transport);
+
+ bool m_valid = false;
+};
+
+class QAndroidNetworkInformationBackendFactory : public QNetworkInformationBackendFactory
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID QNetworkInformationBackendFactory_iid)
+ Q_INTERFACES(QNetworkInformationBackendFactory)
+public:
+ QAndroidNetworkInformationBackendFactory() = default;
+ ~QAndroidNetworkInformationBackendFactory() = default;
+ QString name() const override { return backendName(); }
+ QNetworkInformation::Features featuresSupported() const override
+ {
+ return QAndroidNetworkInformationBackend::featuresSupportedStatic();
+ }
+
+ QNetworkInformationBackend *
+ create(QNetworkInformation::Features requiredFeatures) const override
+ {
+ if ((requiredFeatures & featuresSupported()) != requiredFeatures)
+ return nullptr;
+ auto backend = new QAndroidNetworkInformationBackend();
+ if (!backend->isValid())
+ delete std::exchange(backend, nullptr);
+ return backend;
+ }
+
+private:
+ Q_DISABLE_COPY_MOVE(QAndroidNetworkInformationBackendFactory);
+};
+
+QAndroidNetworkInformationBackend::QAndroidNetworkInformationBackend()
+{
+ auto conman = AndroidConnectivityManager::getInstance();
+ if (!conman)
+ return;
+ m_valid = true;
+ setReachability(QNetworkInformation::Reachability::Unknown);
+ connect(conman, &AndroidConnectivityManager::connectivityChanged, this,
+ &QAndroidNetworkInformationBackend::updateConnectivity);
+
+ connect(conman, &AndroidConnectivityManager::captivePortalChanged, this,
+ &QAndroidNetworkInformationBackend::setBehindCaptivePortal);
+
+ connect(conman, &AndroidConnectivityManager::transportMediumChanged, this,
+ &QAndroidNetworkInformationBackend::updateTransportMedium);
+
+ connect(conman, &AndroidConnectivityManager::meteredChanged, this,
+ &QAndroidNetworkInformationBackend::setMetered);
+}
+
+void QAndroidNetworkInformationBackend::updateConnectivity(
+ AndroidConnectivityManager::AndroidConnectivity connectivity)
+{
+ using AndroidConnectivity = AndroidConnectivityManager::AndroidConnectivity;
+ static const auto mapState = [](AndroidConnectivity state) {
+ switch (state) {
+ case AndroidConnectivity::Connected:
+ return QNetworkInformation::Reachability::Online;
+ case AndroidConnectivity::Disconnected:
+ return QNetworkInformation::Reachability::Disconnected;
+ case AndroidConnectivity::Unknown:
+ default:
+ return QNetworkInformation::Reachability::Unknown;
+ }
+ };
+
+ setReachability(mapState(connectivity));
+}
+
+void QAndroidNetworkInformationBackend::updateTransportMedium(
+ AndroidConnectivityManager::AndroidTransport transport)
+{
+ using AndroidTransport = AndroidConnectivityManager::AndroidTransport;
+ using TransportMedium = QNetworkInformation::TransportMedium;
+ static const auto mapTransport = [](AndroidTransport state) -> TransportMedium {
+ switch (state) {
+ case AndroidTransport::Cellular:
+ return TransportMedium::Cellular;
+ case AndroidTransport::WiFi:
+ return TransportMedium::WiFi;
+ case AndroidTransport::Bluetooth:
+ return TransportMedium::Bluetooth;
+ case AndroidTransport::Ethernet:
+ return TransportMedium::Ethernet;
+ // These are not covered yet (but may be in the future)
+ case AndroidTransport::Usb:
+ case AndroidTransport::LoWPAN:
+ case AndroidTransport::WiFiAware:
+ case AndroidTransport::Unknown:
+ return TransportMedium::Unknown;
+ }
+ };
+
+ setTransportMedium(mapTransport(transport));
+}
+
+QT_END_NAMESPACE
+
+#include "qandroidnetworkinformationbackend.moc"
diff --git a/src/plugins/networkinformation/android/wrapper/androidconnectivitymanager.cpp b/src/plugins/networkinformation/android/wrapper/androidconnectivitymanager.cpp
new file mode 100644
index 0000000000..3c9f952968
--- /dev/null
+++ b/src/plugins/networkinformation/android/wrapper/androidconnectivitymanager.cpp
@@ -0,0 +1,97 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "androidconnectivitymanager.h"
+
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qjnienvironment.h>
+
+QT_BEGIN_NAMESPACE
+
+using namespace QNativeInterface;
+
+struct AndroidConnectivityManagerInstance
+{
+ AndroidConnectivityManagerInstance() : connManager(new AndroidConnectivityManager) { }
+ std::unique_ptr<AndroidConnectivityManager> connManager = nullptr;
+};
+Q_GLOBAL_STATIC(AndroidConnectivityManagerInstance, androidConnManagerInstance)
+
+static const char networkInformationClass[] =
+ "org/qtproject/qt/android/networkinformation/QtAndroidNetworkInformation";
+
+static void networkConnectivityChanged(JNIEnv *env, jobject obj, jint enumValue)
+{
+ Q_UNUSED(env);
+ Q_UNUSED(obj);
+ const auto connectivity =
+ static_cast<AndroidConnectivityManager::AndroidConnectivity>(enumValue);
+ Q_EMIT androidConnManagerInstance->connManager->connectivityChanged(connectivity);
+}
+Q_DECLARE_JNI_NATIVE_METHOD(networkConnectivityChanged)
+
+static void genericInfoChanged(JNIEnv *env, jobject obj, jboolean captivePortal, jboolean metered)
+{
+ Q_UNUSED(env);
+ Q_UNUSED(obj);
+ Q_EMIT androidConnManagerInstance->connManager->captivePortalChanged(captivePortal);
+ Q_EMIT androidConnManagerInstance->connManager->meteredChanged(metered);
+}
+Q_DECLARE_JNI_NATIVE_METHOD(genericInfoChanged)
+
+static void transportMediumChanged(JNIEnv *env, jobject obj, jint enumValue)
+{
+ Q_UNUSED(env);
+ Q_UNUSED(obj);
+ const auto transport = static_cast<AndroidConnectivityManager::AndroidTransport>(enumValue);
+ emit androidConnManagerInstance->connManager->transportMediumChanged(transport);
+}
+Q_DECLARE_JNI_NATIVE_METHOD(transportMediumChanged)
+
+Q_DECLARE_JNI_CLASS(ConnectivityManager, "android/net/ConnectivityManager")
+
+AndroidConnectivityManager::AndroidConnectivityManager()
+{
+ if (!registerNatives())
+ return;
+
+ QJniObject::callStaticMethod<void>(networkInformationClass, "registerReceiver",
+ QAndroidApplication::context());
+}
+
+AndroidConnectivityManager *AndroidConnectivityManager::getInstance()
+{
+ if (!androidConnManagerInstance())
+ return nullptr;
+ return androidConnManagerInstance->connManager->isValid()
+ ? androidConnManagerInstance->connManager.get()
+ : nullptr;
+}
+
+bool AndroidConnectivityManager::isValid() const
+{
+ return registerNatives();
+}
+
+AndroidConnectivityManager::~AndroidConnectivityManager()
+{
+ QJniObject::callStaticMethod<void>(networkInformationClass, "unregisterReceiver",
+ QAndroidApplication::context());
+}
+
+bool AndroidConnectivityManager::registerNatives() const
+{
+ static const bool registered = []() {
+ QJniEnvironment env;
+ return env.registerNativeMethods(networkInformationClass, {
+ Q_JNI_NATIVE_METHOD(networkConnectivityChanged),
+ Q_JNI_NATIVE_METHOD(genericInfoChanged),
+ Q_JNI_NATIVE_METHOD(transportMediumChanged),
+ });
+ }();
+ return registered;
+}
+
+QT_END_NAMESPACE
+
+#include "moc_androidconnectivitymanager.cpp"
diff --git a/src/plugins/networkinformation/android/wrapper/androidconnectivitymanager.h b/src/plugins/networkinformation/android/wrapper/androidconnectivitymanager.h
new file mode 100644
index 0000000000..d15faf0e8e
--- /dev/null
+++ b/src/plugins/networkinformation/android/wrapper/androidconnectivitymanager.h
@@ -0,0 +1,54 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef ANDROIDCONNECTIVITYMANAGER_H
+#define ANDROIDCONNECTIVITYMANAGER_H
+
+#include <QObject>
+#include <QtCore/qjniobject.h>
+
+QT_BEGIN_NAMESPACE
+
+class AndroidConnectivityManager : public QObject
+{
+ Q_OBJECT
+public:
+ // Keep synchronized with AndroidConnectivity in QtAndroidNetworkInformation.java
+ enum class AndroidConnectivity { Connected, Unknown, Disconnected };
+ Q_ENUM(AndroidConnectivity);
+
+ // Keep synchronized with Transport in QtAndroidNetworkInformation.java
+ enum class AndroidTransport {
+ Unknown,
+ Bluetooth,
+ Cellular,
+ Ethernet,
+ LoWPAN,
+ Usb,
+ WiFi,
+ WiFiAware,
+ };
+ Q_ENUM(AndroidTransport);
+
+ static AndroidConnectivityManager *getInstance();
+ ~AndroidConnectivityManager();
+
+ inline bool isValid() const;
+
+Q_SIGNALS:
+ void connectivityChanged(AndroidConnectivity connectivity);
+ void captivePortalChanged(bool state);
+ void transportMediumChanged(AndroidTransport transport);
+ void meteredChanged(bool state);
+
+private:
+ friend struct AndroidConnectivityManagerInstance;
+ AndroidConnectivityManager();
+ bool registerNatives() const;
+
+ Q_DISABLE_COPY_MOVE(AndroidConnectivityManager);
+};
+
+QT_END_NAMESPACE
+
+#endif // ANDROIDCONNECTIVITYMANAGER_H
diff --git a/src/plugins/networkinformation/glib/CMakeLists.txt b/src/plugins/networkinformation/glib/CMakeLists.txt
new file mode 100644
index 0000000000..019f4f1358
--- /dev/null
+++ b/src/plugins/networkinformation/glib/CMakeLists.txt
@@ -0,0 +1,17 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+qt_internal_add_plugin(QGlibNetworkInformationPlugin
+ OUTPUT_NAME qglib
+ CLASS_NAME QGlibNetworkInformationBackendFactory
+ PLUGIN_TYPE networkinformation
+ DEFAULT_IF LINUX
+ SOURCES
+ qglibnetworkinformationbackend.cpp
+ LIBRARIES
+ Qt::NetworkPrivate
+ GLIB2::GOBJECT
+ GLIB2::GIO
+ DEFINES
+ QT_NO_SIGNALS_SLOTS_KEYWORDS
+)
diff --git a/src/plugins/networkinformation/glib/qglibnetworkinformationbackend.cpp b/src/plugins/networkinformation/glib/qglibnetworkinformationbackend.cpp
new file mode 100644
index 0000000000..0b45eb9ce3
--- /dev/null
+++ b/src/plugins/networkinformation/glib/qglibnetworkinformationbackend.cpp
@@ -0,0 +1,137 @@
+// Copyright (C) 2021 Ilya Fedin <fedin-ilja2010@ya.ru>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <QtNetwork/private/qnetworkinformation_p.h>
+
+#include <QtCore/qglobal.h>
+#include <QtCore/private/qobject_p.h>
+
+#include <gio/gio.h>
+
+QT_BEGIN_NAMESPACE
+
+using namespace Qt::StringLiterals;
+
+Q_DECLARE_LOGGING_CATEGORY(lcNetInfoGlib)
+Q_LOGGING_CATEGORY(lcNetInfoGlib, "qt.network.info.glib");
+
+namespace {
+QNetworkInformation::Reachability reachabilityFromGNetworkConnectivity(GNetworkConnectivity connectivity)
+{
+ switch (connectivity) {
+ case G_NETWORK_CONNECTIVITY_LOCAL:
+ return QNetworkInformation::Reachability::Disconnected;
+ case G_NETWORK_CONNECTIVITY_LIMITED:
+ case G_NETWORK_CONNECTIVITY_PORTAL:
+ return QNetworkInformation::Reachability::Site;
+ case G_NETWORK_CONNECTIVITY_FULL:
+ return QNetworkInformation::Reachability::Online;
+ }
+ return QNetworkInformation::Reachability::Unknown;
+}
+}
+
+static QString backendName = QStringLiteral("glib");
+
+class QGlibNetworkInformationBackend : public QNetworkInformationBackend
+{
+ Q_OBJECT
+public:
+ QGlibNetworkInformationBackend();
+ ~QGlibNetworkInformationBackend();
+
+ QString name() const override { return backendName; }
+ QNetworkInformation::Features featuresSupported() const override
+ {
+ if (!isValid())
+ return {};
+ return featuresSupportedStatic();
+ }
+
+ static QNetworkInformation::Features featuresSupportedStatic()
+ {
+ using Feature = QNetworkInformation::Feature;
+ return QNetworkInformation::Features(Feature::Reachability | Feature::CaptivePortal
+ | Feature::Metered);
+ }
+
+ bool isValid() const;
+
+private:
+ Q_DISABLE_COPY_MOVE(QGlibNetworkInformationBackend)
+
+ static void updateConnectivity(QGlibNetworkInformationBackend *backend);
+ static void updateMetered(QGlibNetworkInformationBackend *backend);
+
+ GNetworkMonitor *networkMonitor = nullptr;
+ gulong connectivityHandlerId = 0;
+ gulong meteredHandlerId = 0;
+};
+
+class QGlibNetworkInformationBackendFactory : public QNetworkInformationBackendFactory
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID QNetworkInformationBackendFactory_iid)
+ Q_INTERFACES(QNetworkInformationBackendFactory)
+public:
+ QGlibNetworkInformationBackendFactory() = default;
+ ~QGlibNetworkInformationBackendFactory() = default;
+ QString name() const override { return backendName; }
+ QNetworkInformation::Features featuresSupported() const override
+ {
+ return QGlibNetworkInformationBackend::featuresSupportedStatic();
+ }
+
+ QNetworkInformationBackend *create(QNetworkInformation::Features requiredFeatures) const override
+ {
+ if ((requiredFeatures & featuresSupported()) != requiredFeatures)
+ return nullptr;
+ auto backend = new QGlibNetworkInformationBackend();
+ if (!backend->isValid())
+ delete std::exchange(backend, nullptr);
+ return backend;
+ }
+private:
+ Q_DISABLE_COPY_MOVE(QGlibNetworkInformationBackendFactory)
+};
+
+QGlibNetworkInformationBackend::QGlibNetworkInformationBackend()
+: networkMonitor(g_network_monitor_get_default())
+{
+ updateConnectivity(this);
+ updateMetered(this);
+
+ connectivityHandlerId = g_signal_connect_swapped(networkMonitor, "notify::connectivity",
+ G_CALLBACK(updateConnectivity), this);
+
+ meteredHandlerId = g_signal_connect_swapped(networkMonitor, "notify::network-metered",
+ G_CALLBACK(updateMetered), this);
+}
+
+QGlibNetworkInformationBackend::~QGlibNetworkInformationBackend()
+{
+ g_signal_handler_disconnect(networkMonitor, meteredHandlerId);
+ g_signal_handler_disconnect(networkMonitor, connectivityHandlerId);
+}
+
+bool QGlibNetworkInformationBackend::isValid() const
+{
+ return QLatin1StringView(G_OBJECT_TYPE_NAME(networkMonitor)) != "GNetworkMonitorBase"_L1;
+}
+
+void QGlibNetworkInformationBackend::updateConnectivity(QGlibNetworkInformationBackend *backend)
+{
+ const auto connectivityState = g_network_monitor_get_connectivity(backend->networkMonitor);
+ const bool behindPortal = (connectivityState == G_NETWORK_CONNECTIVITY_PORTAL);
+ backend->setReachability(reachabilityFromGNetworkConnectivity(connectivityState));
+ backend->setBehindCaptivePortal(behindPortal);
+}
+
+void QGlibNetworkInformationBackend::updateMetered(QGlibNetworkInformationBackend *backend)
+{
+ backend->setMetered(g_network_monitor_get_network_metered(backend->networkMonitor));
+}
+
+QT_END_NAMESPACE
+
+#include "qglibnetworkinformationbackend.moc"
diff --git a/src/plugins/networkinformation/networklistmanager/CMakeLists.txt b/src/plugins/networkinformation/networklistmanager/CMakeLists.txt
new file mode 100644
index 0000000000..acd3754f4e
--- /dev/null
+++ b/src/plugins/networkinformation/networklistmanager/CMakeLists.txt
@@ -0,0 +1,25 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+qt_internal_add_plugin(QNLMNIPlugin
+ OUTPUT_NAME qnetworklistmanager
+ CLASS_NAME QNetworkListManagerNetworkInformationBackendFactory
+ PLUGIN_TYPE networkinformation
+ DEFAULT_IF WIN32 AND QT_FEATURE_networklistmanager
+ EXCEPTIONS
+ SOURCES
+ qnetworklistmanagernetworkinformationbackend.cpp
+ qnetworklistmanagerevents.h qnetworklistmanagerevents.cpp
+ LIBRARIES
+ Qt::NetworkPrivate
+)
+
+qt_internal_extend_target(QNLMNIPlugin CONDITION WIN32
+ LIBRARIES
+ runtimeobject
+ oleaut32
+)
+
+# Don't repeat the target name in AUTOGEN_BUILD_DIR to work around issues with overlong paths.
+set_property(TARGET QNLMNIPlugin PROPERTY
+ AUTOGEN_BUILD_DIR "${CMAKE_CURRENT_BINARY_DIR}/autogen")
diff --git a/src/plugins/networkinformation/networklistmanager/qnetworklistmanagerevents.cpp b/src/plugins/networkinformation/networklistmanager/qnetworklistmanagerevents.cpp
new file mode 100644
index 0000000000..caa5046751
--- /dev/null
+++ b/src/plugins/networkinformation/networklistmanager/qnetworklistmanagerevents.cpp
@@ -0,0 +1,268 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qnetworklistmanagerevents.h"
+#include <QtCore/private/qsystemerror_p.h>
+
+#include <QtCore/qpointer.h>
+
+#include <mutex>
+
+#if QT_CONFIG(cpp_winrt)
+#include <QtCore/private/qt_winrtbase_p.h>
+
+#include <winrt/Windows.Networking.Connectivity.h>
+#endif // QT_CONFIG(cpp_winrt)
+
+QT_BEGIN_NAMESPACE
+
+namespace {
+template<typename T>
+bool QueryInterfaceImpl(IUnknown *from, REFIID riid, void **ppvObject)
+{
+ if (riid == __uuidof(T)) {
+ *ppvObject = static_cast<T *>(from);
+ from->AddRef();
+ return true;
+ }
+ return false;
+}
+}
+
+QNetworkListManagerEvents::QNetworkListManagerEvents() : QObject(nullptr)
+{
+ auto hr = CoCreateInstance(CLSID_NetworkListManager, nullptr, CLSCTX_INPROC_SERVER,
+ IID_INetworkListManager, &networkListManager);
+ if (FAILED(hr)) {
+ qCWarning(lcNetInfoNLM) << "Could not get a NetworkListManager instance:"
+ << QSystemError::windowsComString(hr);
+ return;
+ }
+
+ ComPtr<IConnectionPointContainer> connectionPointContainer;
+ hr = networkListManager.As(&connectionPointContainer);
+ if (SUCCEEDED(hr)) {
+ hr = connectionPointContainer->FindConnectionPoint(IID_INetworkListManagerEvents,
+ &connectionPoint);
+ }
+ if (FAILED(hr)) {
+ qCWarning(lcNetInfoNLM) << "Failed to get connection point for network list manager events:"
+ << QSystemError::windowsComString(hr);
+ }
+}
+
+QNetworkListManagerEvents::~QNetworkListManagerEvents()
+{
+ Q_ASSERT(ref == 0);
+}
+
+HRESULT STDMETHODCALLTYPE QNetworkListManagerEvents::QueryInterface(REFIID riid, void **ppvObject)
+{
+ if (!ppvObject)
+ return E_INVALIDARG;
+
+ return QueryInterfaceImpl<IUnknown>(this, riid, ppvObject)
+ || QueryInterfaceImpl<INetworkListManagerEvents>(this, riid, ppvObject)
+ ? S_OK
+ : E_NOINTERFACE;
+}
+
+HRESULT STDMETHODCALLTYPE
+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
+ emit connectivityChanged(newConnectivity);
+ return S_OK;
+}
+
+bool QNetworkListManagerEvents::start()
+{
+ if (!connectionPoint) {
+ qCWarning(lcNetInfoNLM, "Initialization failed, can't start!");
+ return false;
+ }
+ auto hr = connectionPoint->Advise(this, &cookie);
+ if (FAILED(hr)) {
+ qCWarning(lcNetInfoNLM) << "Failed to subscribe to network connectivity events:"
+ << QSystemError::windowsComString(hr);
+ return false;
+ }
+
+ // Update connectivity since it might have changed since this class was constructed
+ NLM_CONNECTIVITY connectivity;
+ hr = networkListManager->GetConnectivity(&connectivity);
+ if (FAILED(hr)) {
+ qCWarning(lcNetInfoNLM) << "Could not get connectivity:"
+ << QSystemError::windowsComString(hr);
+ } else {
+ emit connectivityChanged(connectivity);
+ }
+
+#if QT_CONFIG(cpp_winrt)
+ using namespace winrt::Windows::Networking::Connectivity;
+ using winrt::Windows::Foundation::IInspectable;
+ try {
+ // Register for changes in the network and store a token to unregister later:
+ token = NetworkInformation::NetworkStatusChanged(
+ [owner = QPointer(this)](const IInspectable sender) {
+ Q_UNUSED(sender);
+ if (owner) {
+ std::scoped_lock locker(owner->winrtLock);
+ if (owner->token)
+ owner->emitWinRTUpdates();
+ }
+ });
+ } catch (const winrt::hresult_error &ex) {
+ qCWarning(lcNetInfoNLM) << "Failed to register network status changed callback:"
+ << QSystemError::windowsComString(ex.code());
+ }
+
+ // Emit initial state
+ emitWinRTUpdates();
+#endif
+
+ return true;
+}
+
+void QNetworkListManagerEvents::stop()
+{
+ Q_ASSERT(connectionPoint);
+ auto hr = connectionPoint->Unadvise(cookie);
+ if (FAILED(hr)) {
+ qCWarning(lcNetInfoNLM) << "Failed to unsubscribe from network connectivity events:"
+ << QSystemError::windowsComString(hr);
+ } else {
+ cookie = 0;
+ }
+ // Even if we fail we should still try to unregister from winrt events:
+
+#if QT_CONFIG(cpp_winrt)
+ // Try to synchronize unregistering with potentially in-progress callbacks
+ std::scoped_lock locker(winrtLock);
+ if (token) {
+ using namespace winrt::Windows::Networking::Connectivity;
+ // Pass the token we stored earlier to unregister:
+ NetworkInformation::NetworkStatusChanged(token);
+ token = {};
+ }
+#endif
+}
+
+bool QNetworkListManagerEvents::checkBehindCaptivePortal()
+{
+ if (!networkListManager)
+ return false;
+ ComPtr<IEnumNetworks> networks;
+ HRESULT hr =
+ networkListManager->GetNetworks(NLM_ENUM_NETWORK_CONNECTED, networks.GetAddressOf());
+ if (FAILED(hr) || networks == nullptr)
+ return false;
+
+ // @note: This checks all connected networks, but that might not be necessary
+ ComPtr<INetwork> network;
+ hr = networks->Next(1, network.GetAddressOf(), nullptr);
+ while (SUCCEEDED(hr) && network != nullptr) {
+ ComPtr<IPropertyBag> propertyBag;
+ hr = network.As(&propertyBag);
+ if (SUCCEEDED(hr) && propertyBag != nullptr) {
+ VARIANT variant;
+ VariantInit(&variant);
+ const auto scopedVariantClear = qScopeGuard([&variant]() { VariantClear(&variant); });
+
+ const wchar_t *versions[] = { L"NA_InternetConnectivityV6", L"NA_InternetConnectivityV4" };
+ for (const auto version : versions) {
+ hr = propertyBag->Read(version, &variant, nullptr);
+ if (SUCCEEDED(hr)
+ && (V_UINT(&variant) & NLM_INTERNET_CONNECTIVITY_WEBHIJACK)
+ == NLM_INTERNET_CONNECTIVITY_WEBHIJACK) {
+ return true;
+ }
+ }
+ }
+
+ hr = networks->Next(1, network.GetAddressOf(), nullptr);
+ }
+
+ return false;
+}
+
+#if QT_CONFIG(cpp_winrt)
+namespace {
+using namespace winrt::Windows::Networking::Connectivity;
+// NB: this isn't part of "network list manager", but sadly NLM doesn't have an
+// equivalent API (at least not that I've found...)!
+[[nodiscard]]
+QNetworkInformation::TransportMedium getTransportMedium(const ConnectionProfile &profile)
+{
+ if (profile.IsWwanConnectionProfile())
+ return QNetworkInformation::TransportMedium::Cellular;
+ if (profile.IsWlanConnectionProfile())
+ return QNetworkInformation::TransportMedium::WiFi;
+
+ NetworkAdapter adapter(nullptr);
+ try {
+ adapter = profile.NetworkAdapter();
+ } catch (const winrt::hresult_error &ex) {
+ qCWarning(lcNetInfoNLM) << "Failed to obtain network adapter:"
+ << QSystemError::windowsComString(ex.code());
+ // pass, we will return Unknown anyway
+ }
+ if (adapter == nullptr)
+ return QNetworkInformation::TransportMedium::Unknown;
+
+ // Note: Bluetooth is given an iana iftype of 6, which is the same as Ethernet.
+ // In Windows itself there is clearly a distinction between a Bluetooth PAN
+ // and an Ethernet LAN, though it is not clear how they make this distinction.
+ auto fromIanaId = [](quint32 ianaId) -> QNetworkInformation::TransportMedium {
+ // https://www.iana.org/assignments/ianaiftype-mib/ianaiftype-mib
+ switch (ianaId) {
+ case 6:
+ return QNetworkInformation::TransportMedium::Ethernet;
+ case 71: // Should be handled before entering this lambda
+ return QNetworkInformation::TransportMedium::WiFi;
+ }
+ return QNetworkInformation::TransportMedium::Unknown;
+ };
+
+ return fromIanaId(adapter.IanaInterfaceType());
+}
+
+[[nodiscard]] bool getMetered(const ConnectionProfile &profile)
+{
+ ConnectionCost cost(nullptr);
+ try {
+ cost = profile.GetConnectionCost();
+ } catch (const winrt::hresult_error &ex) {
+ qCWarning(lcNetInfoNLM) << "Failed to obtain connection cost:"
+ << QSystemError::windowsComString(ex.code());
+ // pass, we return false if we get an empty object back anyway
+ }
+ if (cost == nullptr)
+ return false;
+ NetworkCostType type = cost.NetworkCostType();
+ return type == NetworkCostType::Fixed || type == NetworkCostType::Variable;
+}
+} // unnamed namespace
+
+void QNetworkListManagerEvents::emitWinRTUpdates()
+{
+ using namespace winrt::Windows::Networking::Connectivity;
+ ConnectionProfile profile = nullptr;
+ try {
+ profile = NetworkInformation::GetInternetConnectionProfile();
+ } catch (const winrt::hresult_error &ex) {
+ qCWarning(lcNetInfoNLM) << "Failed to obtain connection profile:"
+ << QSystemError::windowsComString(ex.code());
+ // pass, we would just return early if we get an empty object back anyway
+ }
+ if (profile == nullptr)
+ return;
+ emit transportMediumChanged(getTransportMedium(profile));
+ emit isMeteredChanged(getMetered(profile));
+}
+#endif // QT_CONFIG(cpp_winrt)
+
+QT_END_NAMESPACE
+
+#include "moc_qnetworklistmanagerevents.cpp"
diff --git a/src/plugins/networkinformation/networklistmanager/qnetworklistmanagerevents.h b/src/plugins/networkinformation/networklistmanager/qnetworklistmanagerevents.h
new file mode 100644
index 0000000000..d91cd8a4cc
--- /dev/null
+++ b/src/plugins/networkinformation/networklistmanager/qnetworklistmanagerevents.h
@@ -0,0 +1,79 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QNETWORKLISTMANAGEREVENTS_H
+#define QNETWORKLISTMANAGEREVENTS_H
+
+#include <QtNetwork/private/qtnetworkglobal_p.h>
+
+#include <QtNetwork/qnetworkinformation.h>
+
+#include <QtCore/qstring.h>
+#include <QtCore/qobject.h>
+#include <QtCore/qloggingcategory.h>
+#include <QtCore/qmutex.h>
+
+#include <objbase.h>
+#include <ocidl.h>
+#include <netlistmgr.h>
+#include <wrl/client.h>
+#include <wrl/wrappers/corewrappers.h>
+
+#if QT_CONFIG(cpp_winrt)
+#include <QtCore/private/qt_winrtbase_p.h>
+#endif
+
+using namespace Microsoft::WRL;
+
+QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(lcNetInfoNLM)
+
+class QNetworkListManagerEvents : public QObject, public INetworkListManagerEvents
+{
+ Q_OBJECT
+public:
+ QNetworkListManagerEvents();
+ virtual ~QNetworkListManagerEvents();
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject) override;
+
+ ULONG STDMETHODCALLTYPE AddRef() override { return ++ref; }
+ ULONG STDMETHODCALLTYPE Release() override
+ {
+ if (--ref == 0) {
+ delete this;
+ return 0;
+ }
+ return ref;
+ }
+
+ HRESULT STDMETHODCALLTYPE ConnectivityChanged(NLM_CONNECTIVITY newConnectivity) override;
+
+ [[nodiscard]] bool start();
+ void stop();
+
+ [[nodiscard]] bool checkBehindCaptivePortal();
+
+signals:
+ void connectivityChanged(NLM_CONNECTIVITY);
+ void transportMediumChanged(QNetworkInformation::TransportMedium);
+ void isMeteredChanged(bool);
+
+private:
+ ComPtr<INetworkListManager> networkListManager = nullptr;
+ ComPtr<IConnectionPoint> connectionPoint = nullptr;
+
+#if QT_CONFIG(cpp_winrt)
+ void emitWinRTUpdates();
+
+ winrt::event_token token;
+ QMutex winrtLock;
+#endif
+
+ QAtomicInteger<ULONG> ref = 0;
+ DWORD cookie = 0;
+};
+
+QT_END_NAMESPACE
+
+#endif // QNETWORKLISTMANAGEREVENTS_H
diff --git a/src/plugins/networkinformation/networklistmanager/qnetworklistmanagernetworkinformationbackend.cpp b/src/plugins/networkinformation/networklistmanager/qnetworklistmanagernetworkinformationbackend.cpp
new file mode 100644
index 0000000000..766648486e
--- /dev/null
+++ b/src/plugins/networkinformation/networklistmanager/qnetworklistmanagernetworkinformationbackend.cpp
@@ -0,0 +1,199 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <QtNetwork/private/qnetworkinformation_p.h>
+
+#include "qnetworklistmanagerevents.h"
+
+#include <QtCore/qglobal.h>
+#include <QtCore/private/qobject_p.h>
+#include <QtCore/qscopeguard.h>
+
+#include <QtCore/private/qfunctions_win_p.h>
+
+QT_BEGIN_NAMESPACE
+
+// Declared in qnetworklistmanagerevents.h
+Q_LOGGING_CATEGORY(lcNetInfoNLM, "qt.network.info.netlistmanager");
+
+static QString backendName()
+{
+ return QString::fromUtf16(QNetworkInformationBackend::PluginNames
+ [QNetworkInformationBackend::PluginNamesWindowsIndex]);
+}
+
+namespace {
+bool testCONNECTIVITY(NLM_CONNECTIVITY connectivity, NLM_CONNECTIVITY flag)
+{
+ return (connectivity & flag) == flag;
+}
+
+QNetworkInformation::Reachability reachabilityFromNLM_CONNECTIVITY(NLM_CONNECTIVITY connectivity)
+{
+ if (connectivity == NLM_CONNECTIVITY_DISCONNECTED)
+ return QNetworkInformation::Reachability::Disconnected;
+ if (testCONNECTIVITY(connectivity, NLM_CONNECTIVITY_IPV6_INTERNET)
+ || testCONNECTIVITY(connectivity, NLM_CONNECTIVITY_IPV4_INTERNET)) {
+ return QNetworkInformation::Reachability::Online;
+ }
+ if (testCONNECTIVITY(connectivity, NLM_CONNECTIVITY_IPV6_SUBNET)
+ || testCONNECTIVITY(connectivity, NLM_CONNECTIVITY_IPV4_SUBNET)) {
+ return QNetworkInformation::Reachability::Site;
+ }
+ if (testCONNECTIVITY(connectivity, NLM_CONNECTIVITY_IPV6_LOCALNETWORK)
+ || testCONNECTIVITY(connectivity, NLM_CONNECTIVITY_IPV4_LOCALNETWORK)) {
+ return QNetworkInformation::Reachability::Local;
+ }
+ if (testCONNECTIVITY(connectivity, NLM_CONNECTIVITY_IPV6_NOTRAFFIC)
+ || testCONNECTIVITY(connectivity, NLM_CONNECTIVITY_IPV4_NOTRAFFIC)) {
+ return QNetworkInformation::Reachability::Unknown;
+ }
+
+ return QNetworkInformation::Reachability::Unknown;
+}
+}
+
+class QNetworkListManagerNetworkInformationBackend : public QNetworkInformationBackend
+{
+ Q_OBJECT
+public:
+ QNetworkListManagerNetworkInformationBackend();
+ ~QNetworkListManagerNetworkInformationBackend();
+
+ QString name() const override { return backendName(); }
+ QNetworkInformation::Features featuresSupported() const override
+ {
+ return featuresSupportedStatic();
+ }
+
+ static QNetworkInformation::Features featuresSupportedStatic()
+ {
+ return QNetworkInformation::Features(QNetworkInformation::Feature::Reachability
+ | QNetworkInformation::Feature::CaptivePortal
+#if QT_CONFIG(cpp_winrt)
+ | QNetworkInformation::Feature::TransportMedium
+ | QNetworkInformation::Feature::Metered
+#endif
+ );
+ }
+
+ [[nodiscard]] bool start();
+ void stop();
+
+private:
+ bool event(QEvent *event) override;
+ void setConnectivity(NLM_CONNECTIVITY newConnectivity);
+ void checkCaptivePortal();
+
+ QComHelper comHelper;
+
+ ComPtr<QNetworkListManagerEvents> managerEvents;
+
+ NLM_CONNECTIVITY connectivity = NLM_CONNECTIVITY_DISCONNECTED;
+
+ bool monitoring = false;
+};
+
+class QNetworkListManagerNetworkInformationBackendFactory : public QNetworkInformationBackendFactory
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID QNetworkInformationBackendFactory_iid)
+ Q_INTERFACES(QNetworkInformationBackendFactory)
+public:
+ QNetworkListManagerNetworkInformationBackendFactory() = default;
+ ~QNetworkListManagerNetworkInformationBackendFactory() = default;
+ QString name() const override { return backendName(); }
+ QNetworkInformation::Features featuresSupported() const override
+ {
+ return QNetworkListManagerNetworkInformationBackend::featuresSupportedStatic();
+ }
+
+ QNetworkInformationBackend *
+ create(QNetworkInformation::Features requiredFeatures) const override
+ {
+ if ((requiredFeatures & featuresSupported()) != requiredFeatures)
+ return nullptr;
+ auto backend = new QNetworkListManagerNetworkInformationBackend();
+ if (!backend->start()) {
+ qCWarning(lcNetInfoNLM) << "Failed to start listening to events";
+ delete backend;
+ backend = nullptr;
+ }
+ return backend;
+ }
+};
+
+QNetworkListManagerNetworkInformationBackend::QNetworkListManagerNetworkInformationBackend()
+{
+ if (!comHelper.isValid())
+ return;
+
+ managerEvents = new QNetworkListManagerEvents();
+ connect(managerEvents.Get(), &QNetworkListManagerEvents::connectivityChanged, this,
+ &QNetworkListManagerNetworkInformationBackend::setConnectivity);
+
+ connect(managerEvents.Get(), &QNetworkListManagerEvents::transportMediumChanged, this,
+ &QNetworkListManagerNetworkInformationBackend::setTransportMedium);
+
+ connect(managerEvents.Get(), &QNetworkListManagerEvents::isMeteredChanged, this,
+ &QNetworkListManagerNetworkInformationBackend::setMetered);
+}
+
+QNetworkListManagerNetworkInformationBackend::~QNetworkListManagerNetworkInformationBackend()
+{
+ stop();
+}
+
+void QNetworkListManagerNetworkInformationBackend::setConnectivity(NLM_CONNECTIVITY newConnectivity)
+{
+ if (reachabilityFromNLM_CONNECTIVITY(connectivity)
+ != reachabilityFromNLM_CONNECTIVITY(newConnectivity)) {
+ connectivity = newConnectivity;
+ setReachability(reachabilityFromNLM_CONNECTIVITY(newConnectivity));
+
+ // @future: only check if signal is connected
+ checkCaptivePortal();
+ }
+}
+
+void QNetworkListManagerNetworkInformationBackend::checkCaptivePortal()
+{
+ setBehindCaptivePortal(managerEvents->checkBehindCaptivePortal());
+}
+
+bool QNetworkListManagerNetworkInformationBackend::event(QEvent *event)
+{
+ if (event->type() == QEvent::ThreadChange)
+ qFatal("Moving QNetworkListManagerNetworkInformationBackend to different thread is not supported");
+
+ return QObject::event(event);
+}
+
+bool QNetworkListManagerNetworkInformationBackend::start()
+{
+ Q_ASSERT(!monitoring);
+
+ if (!comHelper.isValid())
+ return false;
+
+ if (!managerEvents)
+ managerEvents = new QNetworkListManagerEvents();
+
+ if (managerEvents->start())
+ monitoring = true;
+ return monitoring;
+}
+
+void QNetworkListManagerNetworkInformationBackend::stop()
+{
+ if (monitoring) {
+ Q_ASSERT(managerEvents);
+ managerEvents->stop();
+ monitoring = false;
+ managerEvents.Reset();
+ }
+}
+
+QT_END_NAMESPACE
+
+#include "qnetworklistmanagernetworkinformationbackend.moc"
diff --git a/src/plugins/networkinformation/networkmanager/CMakeLists.txt b/src/plugins/networkinformation/networkmanager/CMakeLists.txt
new file mode 100644
index 0000000000..9d76dbe7b4
--- /dev/null
+++ b/src/plugins/networkinformation/networkmanager/CMakeLists.txt
@@ -0,0 +1,17 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+qt_internal_add_plugin(QNetworkManagerNetworkInformationPlugin
+ OUTPUT_NAME qnetworkmanager
+ CLASS_NAME QNetworkManagerNetworkInformationBackendFactory
+ PLUGIN_TYPE networkinformation
+ DEFAULT_IF LINUX
+ SOURCES
+ qnetworkmanagernetworkinformationbackend.h
+ qnetworkmanagernetworkinformationbackend.cpp
+ qnetworkmanagerservice.h
+ qnetworkmanagerservice.cpp
+ LIBRARIES
+ Qt::DBus
+ Qt::NetworkPrivate
+)
diff --git a/src/plugins/networkinformation/networkmanager/qnetworkmanagernetworkinformationbackend.cpp b/src/plugins/networkinformation/networkmanager/qnetworkmanagernetworkinformationbackend.cpp
new file mode 100644
index 0000000000..f583d1dcf6
--- /dev/null
+++ b/src/plugins/networkinformation/networkmanager/qnetworkmanagernetworkinformationbackend.cpp
@@ -0,0 +1,181 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qnetworkmanagernetworkinformationbackend.h"
+
+#include <QtCore/qglobal.h>
+#include <QtCore/private/qobject_p.h>
+
+#include <QtDBus/qdbusmessage.h>
+
+QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(lcNetInfoNLM)
+Q_LOGGING_CATEGORY(lcNetInfoNM, "qt.network.info.networkmanager");
+
+namespace {
+QNetworkInformation::Reachability reachabilityFromNMState(QNetworkManagerInterface::NMState state)
+{
+ switch (state) {
+ case QNetworkManagerInterface::NM_STATE_UNKNOWN:
+ case QNetworkManagerInterface::NM_STATE_ASLEEP:
+ case QNetworkManagerInterface::NM_STATE_CONNECTING:
+ return QNetworkInformation::Reachability::Unknown;
+ case QNetworkManagerInterface::NM_STATE_DISCONNECTING: // No point in starting new connections:
+ case QNetworkManagerInterface::NM_STATE_DISCONNECTED:
+ return QNetworkInformation::Reachability::Disconnected;
+ case QNetworkManagerInterface::NM_STATE_CONNECTED_LOCAL:
+ return QNetworkInformation::Reachability::Local;
+ case QNetworkManagerInterface::NM_STATE_CONNECTED_SITE:
+ return QNetworkInformation::Reachability::Site;
+ case QNetworkManagerInterface::NM_STATE_CONNECTED_GLOBAL:
+ return QNetworkInformation::Reachability::Online;
+ }
+ return QNetworkInformation::Reachability::Unknown;
+}
+
+QNetworkInformation::TransportMedium
+transportMediumFromDeviceType(QNetworkManagerInterface::NMDeviceType type)
+{
+ switch (type) {
+ case QNetworkManagerInterface::NM_DEVICE_TYPE_ETHERNET:
+ return QNetworkInformation::TransportMedium::Ethernet;
+ case QNetworkManagerInterface::NM_DEVICE_TYPE_WIFI:
+ return QNetworkInformation::TransportMedium::WiFi;
+ case QNetworkManagerInterface::NM_DEVICE_TYPE_BT:
+ return QNetworkInformation::TransportMedium::Bluetooth;
+ case QNetworkManagerInterface::NM_DEVICE_TYPE_MODEM:
+ return QNetworkInformation::TransportMedium::Cellular;
+
+ case QNetworkManagerInterface::NM_DEVICE_TYPE_UNKNOWN:
+ case QNetworkManagerInterface::NM_DEVICE_TYPE_GENERIC:
+ case QNetworkManagerInterface::NM_DEVICE_TYPE_UNUSED1:
+ case QNetworkManagerInterface::NM_DEVICE_TYPE_UNUSED2:
+ case QNetworkManagerInterface::NM_DEVICE_TYPE_OLPC_MESH:
+ case QNetworkManagerInterface::NM_DEVICE_TYPE_WIMAX:
+ case QNetworkManagerInterface::NM_DEVICE_TYPE_INFINIBAND:
+ case QNetworkManagerInterface::NM_DEVICE_TYPE_BOND:
+ case QNetworkManagerInterface::NM_DEVICE_TYPE_VLAN:
+ case QNetworkManagerInterface::NM_DEVICE_TYPE_ADSL:
+ case QNetworkManagerInterface::NM_DEVICE_TYPE_BRIDGE:
+ case QNetworkManagerInterface::NM_DEVICE_TYPE_TEAM:
+ case QNetworkManagerInterface::NM_DEVICE_TYPE_TUN:
+ case QNetworkManagerInterface::NM_DEVICE_TYPE_IP_TUNNEL:
+ case QNetworkManagerInterface::NM_DEVICE_TYPE_MACVLAN:
+ case QNetworkManagerInterface::NM_DEVICE_TYPE_VXLAN:
+ case QNetworkManagerInterface::NM_DEVICE_TYPE_VETH:
+ case QNetworkManagerInterface::NM_DEVICE_TYPE_MACSEC:
+ case QNetworkManagerInterface::NM_DEVICE_TYPE_DUMMY:
+ case QNetworkManagerInterface::NM_DEVICE_TYPE_PPP:
+ case QNetworkManagerInterface::NM_DEVICE_TYPE_OVS_INTERFACE:
+ case QNetworkManagerInterface::NM_DEVICE_TYPE_OVS_PORT:
+ case QNetworkManagerInterface::NM_DEVICE_TYPE_OVS_BRIDGE:
+ case QNetworkManagerInterface::NM_DEVICE_TYPE_WPAN:
+ case QNetworkManagerInterface::NM_DEVICE_TYPE_6LOWPAN:
+ case QNetworkManagerInterface::NM_DEVICE_TYPE_WIREGUARD:
+ case QNetworkManagerInterface::NM_DEVICE_TYPE_WIFI_P2P:
+ case QNetworkManagerInterface::NM_DEVICE_TYPE_VRF:
+ break;
+ }
+ // While the list is exhaustive of the enum there can be additional
+ // entries added in NetworkManager that isn't listed here
+ return QNetworkInformation::TransportMedium::Unknown;
+}
+
+bool isMeteredFromNMMetered(QNetworkManagerInterface::NMMetered metered)
+{
+ switch (metered) {
+ case QNetworkManagerInterface::NM_METERED_YES:
+ case QNetworkManagerInterface::NM_METERED_GUESS_YES:
+ return true;
+ case QNetworkManagerInterface::NM_METERED_NO:
+ case QNetworkManagerInterface::NM_METERED_GUESS_NO:
+ case QNetworkManagerInterface::NM_METERED_UNKNOWN:
+ return false;
+ }
+ Q_UNREACHABLE_RETURN(false);
+}
+} // unnamed namespace
+
+static QString backendName()
+{
+ return QStringView(QNetworkInformationBackend::PluginNames
+ [QNetworkInformationBackend::PluginNamesLinuxIndex]).toString();
+}
+
+QString QNetworkManagerNetworkInformationBackend::name() const
+{
+ return backendName();
+}
+
+class QNetworkManagerNetworkInformationBackendFactory : public QNetworkInformationBackendFactory
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID QNetworkInformationBackendFactory_iid)
+ Q_INTERFACES(QNetworkInformationBackendFactory)
+public:
+ QNetworkManagerNetworkInformationBackendFactory() = default;
+ ~QNetworkManagerNetworkInformationBackendFactory() = default;
+ QString name() const override { return backendName(); }
+ QNetworkInformation::Features featuresSupported() const override
+ {
+ if (!QNetworkManagerInterfaceBase::networkManagerAvailable())
+ return {};
+ return QNetworkManagerNetworkInformationBackend::featuresSupportedStatic();
+ }
+
+ QNetworkInformationBackend *create(QNetworkInformation::Features requiredFeatures) const override
+ {
+ if ((requiredFeatures & featuresSupported()) != requiredFeatures)
+ return nullptr;
+ if (!QNetworkManagerInterfaceBase::networkManagerAvailable())
+ return nullptr;
+ auto backend = new QNetworkManagerNetworkInformationBackend();
+ if (!backend->isValid())
+ delete std::exchange(backend, nullptr);
+ return backend;
+ }
+private:
+ Q_DISABLE_COPY_MOVE(QNetworkManagerNetworkInformationBackendFactory)
+};
+
+QNetworkManagerNetworkInformationBackend::QNetworkManagerNetworkInformationBackend()
+{
+ if (!iface.isValid())
+ return;
+ iface.setBackend(this);
+ onStateChanged(iface.state());
+ onConnectivityChanged(iface.connectivityState());
+ onDeviceTypeChanged(iface.deviceType());
+ onMeteredChanged(iface.meteredState());
+}
+
+void QNetworkManagerNetworkInformationBackend::onStateChanged(
+ QNetworkManagerInterface::NMState newState)
+{
+ setReachability(reachabilityFromNMState(newState));
+}
+
+void QNetworkManagerNetworkInformationBackend::onConnectivityChanged(
+ QNetworkManagerInterface::NMConnectivityState connectivityState)
+{
+ const bool behindPortal =
+ (connectivityState == QNetworkManagerInterface::NM_CONNECTIVITY_PORTAL);
+ setBehindCaptivePortal(behindPortal);
+}
+
+void QNetworkManagerNetworkInformationBackend::onDeviceTypeChanged(
+ QNetworkManagerInterface::NMDeviceType newDevice)
+{
+ setTransportMedium(transportMediumFromDeviceType(newDevice));
+}
+
+void QNetworkManagerNetworkInformationBackend::onMeteredChanged(
+ QNetworkManagerInterface::NMMetered metered)
+{
+ setMetered(isMeteredFromNMMetered(metered));
+};
+
+QT_END_NAMESPACE
+
+#include "qnetworkmanagernetworkinformationbackend.moc"
+#include "moc_qnetworkmanagernetworkinformationbackend.cpp"
diff --git a/src/plugins/networkinformation/networkmanager/qnetworkmanagernetworkinformationbackend.h b/src/plugins/networkinformation/networkmanager/qnetworkmanagernetworkinformationbackend.h
new file mode 100644
index 0000000000..3b60f0949c
--- /dev/null
+++ b/src/plugins/networkinformation/networkmanager/qnetworkmanagernetworkinformationbackend.h
@@ -0,0 +1,60 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QNETWORKMANAGERINFORMATIONBACKEND_H
+#define QNETWORKMANAGERINFORMATIONBACKEND_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 <QtNetwork/private/qnetworkinformation_p.h>
+#include "qnetworkmanagerservice.h"
+
+QT_BEGIN_NAMESPACE
+
+class QNetworkManagerNetworkInformationBackend : public QNetworkInformationBackend
+{
+ Q_OBJECT
+public:
+ QNetworkManagerNetworkInformationBackend();
+ ~QNetworkManagerNetworkInformationBackend() = default;
+
+ QString name() const override;
+ QNetworkInformation::Features featuresSupported() const override
+ {
+ if (!isValid())
+ return {};
+ return featuresSupportedStatic();
+ }
+
+ static QNetworkInformation::Features featuresSupportedStatic()
+ {
+ using Feature = QNetworkInformation::Feature;
+ return QNetworkInformation::Features(Feature::Reachability | Feature::CaptivePortal
+ | Feature::TransportMedium | Feature::Metered);
+ }
+
+ bool isValid() const { return iface.isValid(); }
+
+ void onStateChanged(QNetworkManagerInterface::NMState state);
+ void onConnectivityChanged(QNetworkManagerInterface::NMConnectivityState connectivityState);
+ void onDeviceTypeChanged(QNetworkManagerInterface::NMDeviceType deviceType);
+ void onMeteredChanged(QNetworkManagerInterface::NMMetered metered);
+
+private:
+ Q_DISABLE_COPY_MOVE(QNetworkManagerNetworkInformationBackend)
+
+ QNetworkManagerInterface iface;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/plugins/networkinformation/networkmanager/qnetworkmanagerservice.cpp b/src/plugins/networkinformation/networkmanager/qnetworkmanagerservice.cpp
new file mode 100644
index 0000000000..c055555cac
--- /dev/null
+++ b/src/plugins/networkinformation/networkmanager/qnetworkmanagerservice.cpp
@@ -0,0 +1,220 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qnetworkmanagerservice.h"
+#include "qnetworkmanagernetworkinformationbackend.h"
+
+#include <QObject>
+#include <QList>
+#include <QtDBus/QDBusConnection>
+#include <QtDBus/QDBusError>
+#include <QtDBus/QDBusInterface>
+#include <QtDBus/QDBusMessage>
+#include <QtDBus/QDBusReply>
+#include <QtDBus/QDBusPendingCallWatcher>
+#include <QtDBus/QDBusObjectPath>
+#include <QtDBus/QDBusPendingCall>
+
+#define DBUS_PROPERTIES_INTERFACE "org.freedesktop.DBus.Properties"_L1
+
+#define NM_DBUS_INTERFACE "org.freedesktop.NetworkManager"
+#define NM_DBUS_SERVICE NM_DBUS_INTERFACE ""_L1
+
+#define NM_DBUS_PATH "/org/freedesktop/NetworkManager"_L1
+#define NM_CONNECTION_DBUS_INTERFACE NM_DBUS_SERVICE ".Connection.Active"_L1
+#define NM_DEVICE_DBUS_INTERFACE NM_DBUS_SERVICE ".Device"_L1
+
+QT_BEGIN_NAMESPACE
+
+using namespace Qt::StringLiterals;
+
+namespace {
+constexpr QLatin1StringView propertiesChangedKey = "PropertiesChanged"_L1;
+const QString &stateKey()
+{
+ static auto key = u"State"_s;
+ return key;
+}
+const QString &connectivityKey()
+{
+ static auto key = u"Connectivity"_s;
+ return key;
+}
+const QString &primaryConnectionKey()
+{
+ static auto key = u"PrimaryConnection"_s;
+ return key;
+}
+}
+
+QNetworkManagerInterfaceBase::QNetworkManagerInterfaceBase(QObject *parent)
+ : QDBusAbstractInterface(NM_DBUS_SERVICE, NM_DBUS_PATH,
+ NM_DBUS_INTERFACE, QDBusConnection::systemBus(), parent)
+{
+}
+
+bool QNetworkManagerInterfaceBase::networkManagerAvailable()
+{
+ return QNetworkManagerInterfaceBase().isValid();
+}
+
+QNetworkManagerInterface::QNetworkManagerInterface(QObject *parent)
+ : QNetworkManagerInterfaceBase(parent)
+{
+ if (!QDBusAbstractInterface::isValid())
+ return;
+
+ PropertiesDBusInterface managerPropertiesInterface(
+ NM_DBUS_SERVICE, NM_DBUS_PATH, DBUS_PROPERTIES_INTERFACE,
+ QDBusConnection::systemBus());
+ QList<QVariant> argumentList;
+ argumentList << NM_DBUS_SERVICE;
+ QDBusPendingReply<QVariantMap> propsReply = managerPropertiesInterface.callWithArgumentList(
+ QDBus::Block, "GetAll"_L1, argumentList);
+ if (propsReply.isError()) {
+ validDBusConnection = false;
+ if (auto error = propsReply.error(); error.type() != QDBusError::AccessDenied)
+ qWarning() << "Failed to query NetworkManager properties:" << error.message();
+ return;
+ }
+ propertyMap = propsReply.value();
+
+ validDBusConnection = QDBusConnection::systemBus().connect(NM_DBUS_SERVICE, NM_DBUS_PATH,
+ DBUS_PROPERTIES_INTERFACE, propertiesChangedKey, this,
+ SLOT(setProperties(QString,QMap<QString,QVariant>,QList<QString>)));
+}
+
+QNetworkManagerInterface::~QNetworkManagerInterface()
+{
+ QDBusConnection::systemBus().disconnect(NM_DBUS_SERVICE, NM_DBUS_PATH,
+ DBUS_PROPERTIES_INTERFACE, propertiesChangedKey, this,
+ SLOT(setProperties(QString,QMap<QString,QVariant>,QList<QString>)));
+}
+
+QNetworkManagerInterface::NMState QNetworkManagerInterface::state() const
+{
+ auto it = propertyMap.constFind(stateKey());
+ if (it != propertyMap.cend())
+ return static_cast<QNetworkManagerInterface::NMState>(it->toUInt());
+ return QNetworkManagerInterface::NM_STATE_UNKNOWN;
+}
+
+QNetworkManagerInterface::NMConnectivityState QNetworkManagerInterface::connectivityState() const
+{
+ auto it = propertyMap.constFind(connectivityKey());
+ if (it != propertyMap.cend())
+ return static_cast<NMConnectivityState>(it->toUInt());
+ return QNetworkManagerInterface::NM_CONNECTIVITY_UNKNOWN;
+}
+
+static std::optional<QDBusInterface> getPrimaryDevice(const QDBusObjectPath &devicePath)
+{
+ const QDBusInterface connection(NM_DBUS_SERVICE, devicePath.path(),
+ NM_CONNECTION_DBUS_INTERFACE, QDBusConnection::systemBus());
+ if (!connection.isValid())
+ return std::nullopt;
+
+ const auto devicePaths = connection.property("Devices").value<QList<QDBusObjectPath>>();
+ if (devicePaths.isEmpty())
+ return std::nullopt;
+
+ const QDBusObjectPath primaryDevicePath = devicePaths.front();
+ return std::make_optional<QDBusInterface>(NM_DBUS_SERVICE, primaryDevicePath.path(),
+ NM_DEVICE_DBUS_INTERFACE,
+ QDBusConnection::systemBus());
+}
+
+std::optional<QDBusObjectPath> QNetworkManagerInterface::primaryConnectionDevicePath() const
+{
+ auto it = propertyMap.constFind(primaryConnectionKey());
+ if (it != propertyMap.cend())
+ return it->value<QDBusObjectPath>();
+ return std::nullopt;
+}
+
+auto QNetworkManagerInterface::deviceType() const -> NMDeviceType
+{
+ if (const auto path = primaryConnectionDevicePath())
+ return extractDeviceType(*path);
+ return NM_DEVICE_TYPE_UNKNOWN;
+}
+
+auto QNetworkManagerInterface::meteredState() const -> NMMetered
+{
+ if (const auto path = primaryConnectionDevicePath())
+ return extractDeviceMetered(*path);
+ return NM_METERED_UNKNOWN;
+}
+
+auto QNetworkManagerInterface::extractDeviceType(const QDBusObjectPath &devicePath) const
+ -> NMDeviceType
+{
+ const auto primaryDevice = getPrimaryDevice(devicePath);
+ if (!primaryDevice)
+ return NM_DEVICE_TYPE_UNKNOWN;
+ if (!primaryDevice->isValid())
+ return NM_DEVICE_TYPE_UNKNOWN;
+ const QVariant deviceType = primaryDevice->property("DeviceType");
+ if (!deviceType.isValid())
+ return NM_DEVICE_TYPE_UNKNOWN;
+ return static_cast<NMDeviceType>(deviceType.toUInt());
+}
+
+auto QNetworkManagerInterface::extractDeviceMetered(const QDBusObjectPath &devicePath) const
+ -> NMMetered
+{
+ const auto primaryDevice = getPrimaryDevice(devicePath);
+ if (!primaryDevice)
+ return NM_METERED_UNKNOWN;
+ if (!primaryDevice->isValid())
+ return NM_METERED_UNKNOWN;
+ const QVariant metered = primaryDevice->property("Metered");
+ if (!metered.isValid())
+ return NM_METERED_UNKNOWN;
+ return static_cast<NMMetered>(metered.toUInt());
+}
+
+void QNetworkManagerInterface::setBackend(QNetworkManagerNetworkInformationBackend *ourBackend)
+{
+ backend = ourBackend;
+}
+
+void QNetworkManagerInterface::setProperties(const QString &interfaceName,
+ const QMap<QString, QVariant> &map,
+ const QStringList &invalidatedProperties)
+{
+ Q_UNUSED(interfaceName);
+ Q_UNUSED(invalidatedProperties);
+
+ for (auto i = map.cbegin(), end = map.cend(); i != end; ++i) {
+ bool valueChanged = true;
+
+ auto it = propertyMap.lowerBound(i.key());
+ if (it != propertyMap.end() && it.key() == i.key()) {
+ valueChanged = (it.value() != i.value());
+ *it = *i;
+ } else {
+ propertyMap.insert(it, i.key(), i.value());
+ }
+
+ if (valueChanged) {
+ if (i.key() == stateKey()) {
+ quint32 state = i.value().toUInt();
+ backend->onStateChanged(static_cast<NMState>(state));
+ } else if (i.key() == connectivityKey()) {
+ quint32 state = i.value().toUInt();
+ backend->onConnectivityChanged(static_cast<NMConnectivityState>(state));
+ } else if (i.key() == primaryConnectionKey()) {
+ const QDBusObjectPath devicePath = i->value<QDBusObjectPath>();
+ backend->onDeviceTypeChanged(extractDeviceType(devicePath));
+ backend->onMeteredChanged(extractDeviceMetered(devicePath));
+ } else if (i.key() == "Metered"_L1) {
+ backend->onMeteredChanged(static_cast<NMMetered>(i->toUInt()));
+ }
+ }
+ }
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qnetworkmanagerservice.cpp"
diff --git a/src/plugins/networkinformation/networkmanager/qnetworkmanagerservice.h b/src/plugins/networkinformation/networkmanager/qnetworkmanagerservice.h
new file mode 100644
index 0000000000..5201e8485b
--- /dev/null
+++ b/src/plugins/networkinformation/networkmanager/qnetworkmanagerservice.h
@@ -0,0 +1,173 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QNETWORKMANAGERSERVICE_H
+#define QNETWORKMANAGERSERVICE_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/qvariant.h>
+#include <QtCore/qmap.h>
+#include <QtDBus/qdbusabstractinterface.h>
+
+#include <optional>
+
+// Matches 'NMDeviceState' from https://developer.gnome.org/NetworkManager/stable/nm-dbus-types.html
+enum NMDeviceState {
+ NM_DEVICE_STATE_UNKNOWN = 0,
+ NM_DEVICE_STATE_UNMANAGED = 10,
+ NM_DEVICE_STATE_UNAVAILABLE = 20,
+ NM_DEVICE_STATE_DISCONNECTED = 30,
+ NM_DEVICE_STATE_PREPARE = 40,
+ NM_DEVICE_STATE_CONFIG = 50,
+ NM_DEVICE_STATE_NEED_AUTH = 60,
+ NM_DEVICE_STATE_IP_CONFIG = 70,
+ NM_DEVICE_STATE_ACTIVATED = 100,
+ NM_DEVICE_STATE_DEACTIVATING = 110,
+ NM_DEVICE_STATE_FAILED = 120
+};
+
+QT_BEGIN_NAMESPACE
+
+class QDBusObjectPath;
+class QNetworkManagerNetworkInformationBackend;
+
+// This tiny class exists for the purpose of seeing if NetworkManager is available without
+// initializing everything the derived/full class needs.
+class QNetworkManagerInterfaceBase : public QDBusAbstractInterface
+{
+ Q_OBJECT
+public:
+ explicit QNetworkManagerInterfaceBase(QObject *parent = nullptr);
+ ~QNetworkManagerInterfaceBase() = default;
+
+ static bool networkManagerAvailable();
+
+private:
+ Q_DISABLE_COPY_MOVE(QNetworkManagerInterfaceBase)
+};
+
+class QNetworkManagerInterface final : public QNetworkManagerInterfaceBase
+{
+ Q_OBJECT
+
+public:
+ // Matches 'NMState' from https://developer.gnome.org/NetworkManager/stable/nm-dbus-types.html
+ enum NMState {
+ NM_STATE_UNKNOWN = 0,
+ NM_STATE_ASLEEP = 10,
+ NM_STATE_DISCONNECTED = 20,
+ NM_STATE_DISCONNECTING = 30,
+ NM_STATE_CONNECTING = 40,
+ NM_STATE_CONNECTED_LOCAL = 50,
+ NM_STATE_CONNECTED_SITE = 60,
+ NM_STATE_CONNECTED_GLOBAL = 70
+ };
+ Q_ENUM(NMState);
+ // Matches 'NMConnectivityState' from
+ // https://developer.gnome.org/NetworkManager/stable/nm-dbus-types.html#NMConnectivityState
+ enum NMConnectivityState {
+ NM_CONNECTIVITY_UNKNOWN = 0,
+ NM_CONNECTIVITY_NONE = 1,
+ NM_CONNECTIVITY_PORTAL = 2,
+ NM_CONNECTIVITY_LIMITED = 3,
+ NM_CONNECTIVITY_FULL = 4,
+ };
+ Q_ENUM(NMConnectivityState);
+ // Matches 'NMDeviceType' from
+ // https://developer-old.gnome.org/NetworkManager/stable/nm-dbus-types.html#NMDeviceType
+ enum NMDeviceType {
+ NM_DEVICE_TYPE_UNKNOWN = 0,
+ NM_DEVICE_TYPE_GENERIC = 14,
+ NM_DEVICE_TYPE_ETHERNET = 1,
+ NM_DEVICE_TYPE_WIFI = 2,
+ NM_DEVICE_TYPE_UNUSED1 = 3,
+ NM_DEVICE_TYPE_UNUSED2 = 4,
+ NM_DEVICE_TYPE_BT = 5,
+ NM_DEVICE_TYPE_OLPC_MESH = 6,
+ NM_DEVICE_TYPE_WIMAX = 7,
+ NM_DEVICE_TYPE_MODEM = 8,
+ NM_DEVICE_TYPE_INFINIBAND = 9,
+ NM_DEVICE_TYPE_BOND = 10,
+ NM_DEVICE_TYPE_VLAN = 11,
+ NM_DEVICE_TYPE_ADSL = 12,
+ NM_DEVICE_TYPE_BRIDGE = 13,
+ NM_DEVICE_TYPE_TEAM = 15,
+ NM_DEVICE_TYPE_TUN = 16,
+ NM_DEVICE_TYPE_IP_TUNNEL = 17,
+ NM_DEVICE_TYPE_MACVLAN = 18,
+ NM_DEVICE_TYPE_VXLAN = 19,
+ NM_DEVICE_TYPE_VETH = 20,
+ NM_DEVICE_TYPE_MACSEC = 21,
+ NM_DEVICE_TYPE_DUMMY = 22,
+ NM_DEVICE_TYPE_PPP = 23,
+ NM_DEVICE_TYPE_OVS_INTERFACE = 24,
+ NM_DEVICE_TYPE_OVS_PORT = 25,
+ NM_DEVICE_TYPE_OVS_BRIDGE = 26,
+ NM_DEVICE_TYPE_WPAN = 27,
+ NM_DEVICE_TYPE_6LOWPAN = 28,
+ NM_DEVICE_TYPE_WIREGUARD = 29,
+ NM_DEVICE_TYPE_WIFI_P2P = 30,
+ NM_DEVICE_TYPE_VRF = 31,
+ };
+ // Matches 'NMMetered' from
+ // https://developer-old.gnome.org/NetworkManager/stable/nm-dbus-types.html#NMMetered
+ enum NMMetered {
+ NM_METERED_UNKNOWN,
+ NM_METERED_YES,
+ NM_METERED_NO,
+ NM_METERED_GUESS_YES,
+ NM_METERED_GUESS_NO,
+ };
+
+ explicit QNetworkManagerInterface(QObject *parent = nullptr);
+ ~QNetworkManagerInterface();
+
+ void setBackend(QNetworkManagerNetworkInformationBackend *ourBackend);
+
+ NMState state() const;
+ NMConnectivityState connectivityState() const;
+ NMDeviceType deviceType() const;
+ NMMetered meteredState() const;
+
+ bool isValid() const { return QDBusAbstractInterface::isValid() && validDBusConnection; }
+
+private Q_SLOTS:
+ void setProperties(const QString &interfaceName, const QMap<QString, QVariant> &map,
+ const QStringList &invalidatedProperties);
+
+private:
+ Q_DISABLE_COPY_MOVE(QNetworkManagerInterface)
+
+ NMDeviceType extractDeviceType(const QDBusObjectPath &devicePath) const;
+ NMMetered extractDeviceMetered(const QDBusObjectPath &devicePath) const;
+
+ std::optional<QDBusObjectPath> primaryConnectionDevicePath() const;
+
+ QVariantMap propertyMap;
+ QNetworkManagerNetworkInformationBackend *backend = nullptr;
+ bool validDBusConnection = true;
+};
+
+class PropertiesDBusInterface : public QDBusAbstractInterface
+{
+public:
+ PropertiesDBusInterface(const QString &service, const QString &path, const QString &interface,
+ const QDBusConnection &connection, QObject *parent = nullptr)
+ : QDBusAbstractInterface(service, path, interface.toLatin1().data(), connection, parent)
+ {
+ }
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/plugins/networkinformation/scnetworkreachability/CMakeLists.txt b/src/plugins/networkinformation/scnetworkreachability/CMakeLists.txt
new file mode 100644
index 0000000000..a939ab4405
--- /dev/null
+++ b/src/plugins/networkinformation/scnetworkreachability/CMakeLists.txt
@@ -0,0 +1,14 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+qt_internal_add_plugin(QSCNetworkReachabilityNetworkInformationPlugin
+ OUTPUT_NAME qscnetworkreachability
+ CLASS_NAME QSCNetworkReachabilityNetworkInformationBackendFactory
+ PLUGIN_TYPE networkinformation
+ DEFAULT_IF APPLE
+ SOURCES
+ qscnetworkreachabilitynetworkinformationbackend.mm
+ LIBRARIES
+ Qt::NetworkPrivate
+ ${FWSystemConfiguration}
+)
diff --git a/src/plugins/networkinformation/scnetworkreachability/qscnetworkreachabilitynetworkinformationbackend.mm b/src/plugins/networkinformation/scnetworkreachability/qscnetworkreachabilitynetworkinformationbackend.mm
new file mode 100644
index 0000000000..d1f3cb41d4
--- /dev/null
+++ b/src/plugins/networkinformation/scnetworkreachability/qscnetworkreachabilitynetworkinformationbackend.mm
@@ -0,0 +1,158 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <QtNetwork/private/qnetworkinformation_p.h>
+
+#include <QtNetwork/private/qnetconmonitor_p.h>
+
+#include <QtCore/qglobal.h>
+#include <QtCore/private/qobject_p.h>
+
+QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(lcNetInfoSCR)
+Q_LOGGING_CATEGORY(lcNetInfoSCR, "qt.network.info.scnetworkreachability");
+
+static QString backendName()
+{
+ return QString::fromUtf16(QNetworkInformationBackend::PluginNames
+ [QNetworkInformationBackend::PluginNamesAppleIndex]);
+}
+
+class QSCNetworkReachabilityNetworkInformationBackend : public QNetworkInformationBackend
+{
+ Q_OBJECT
+public:
+ QSCNetworkReachabilityNetworkInformationBackend();
+ ~QSCNetworkReachabilityNetworkInformationBackend();
+
+ QString name() const override { return backendName(); }
+ QNetworkInformation::Features featuresSupported() const override
+ {
+ return featuresSupportedStatic();
+ }
+
+ static QNetworkInformation::Features featuresSupportedStatic()
+ {
+ return QNetworkInformation::Features(QNetworkInformation::Feature::Reachability
+#ifdef QT_PLATFORM_UIKIT
+ | QNetworkInformation::Feature::TransportMedium
+#endif
+ );
+ }
+
+private Q_SLOTS:
+ void reachabilityChanged(bool isOnline);
+
+#ifdef QT_PLATFORM_UIKIT
+ void isWwanChanged(bool isOnline);
+#endif
+
+private:
+ Q_DISABLE_COPY_MOVE(QSCNetworkReachabilityNetworkInformationBackend);
+
+ QNetworkConnectionMonitor ipv4Probe;
+ QNetworkConnectionMonitor ipv6Probe;
+};
+
+class QSCNetworkReachabilityNetworkInformationBackendFactory : public QNetworkInformationBackendFactory
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID QNetworkInformationBackendFactory_iid)
+ Q_INTERFACES(QNetworkInformationBackendFactory)
+public:
+ QSCNetworkReachabilityNetworkInformationBackendFactory() = default;
+ ~QSCNetworkReachabilityNetworkInformationBackendFactory() = default;
+ QString name() const override { return backendName(); }
+ QNetworkInformation::Features featuresSupported() const override
+ {
+ return QSCNetworkReachabilityNetworkInformationBackend::featuresSupportedStatic();
+ }
+
+ QNetworkInformationBackend *create(QNetworkInformation::Features requiredFeatures) const override
+ {
+ if ((requiredFeatures & featuresSupported()) != requiredFeatures)
+ return nullptr;
+ return new QSCNetworkReachabilityNetworkInformationBackend();
+ }
+
+private:
+ Q_DISABLE_COPY_MOVE(QSCNetworkReachabilityNetworkInformationBackendFactory);
+};
+
+QSCNetworkReachabilityNetworkInformationBackend::QSCNetworkReachabilityNetworkInformationBackend()
+{
+ bool isOnline = false;
+#ifdef QT_PLATFORM_UIKIT
+ bool isWwan = false;
+#endif
+ if (ipv4Probe.setTargets(QHostAddress::AnyIPv4, {})) {
+ // We manage to create SCNetworkReachabilityRef for IPv4, let's
+ // read the last known state then!
+ isOnline |= ipv4Probe.isReachable();
+#ifdef QT_PLATFORM_UIKIT
+ isWwan |= ipv4Probe.isWwan();
+#endif
+ ipv4Probe.startMonitoring();
+ }
+
+ if (ipv6Probe.setTargets(QHostAddress::AnyIPv6, {})) {
+ // We manage to create SCNetworkReachability ref for IPv6, let's
+ // read the last known state then!
+ isOnline |= ipv6Probe.isReachable();
+#ifdef QT_PLATFORM_UIKIT
+ isWwan |= ipv6Probe.isWwan();
+#endif
+ ipv6Probe.startMonitoring();
+ }
+ reachabilityChanged(isOnline);
+#ifdef QT_PLATFORM_UIKIT
+ isWwanChanged(isWwan);
+#endif
+
+ connect(&ipv4Probe, &QNetworkConnectionMonitor::reachabilityChanged, this,
+ &QSCNetworkReachabilityNetworkInformationBackend::reachabilityChanged,
+ Qt::QueuedConnection);
+ connect(&ipv6Probe, &QNetworkConnectionMonitor::reachabilityChanged, this,
+ &QSCNetworkReachabilityNetworkInformationBackend::reachabilityChanged,
+ Qt::QueuedConnection);
+
+#ifdef QT_PLATFORM_UIKIT
+ connect(&ipv4Probe, &QNetworkConnectionMonitor::isWwanChanged, this,
+ &QSCNetworkReachabilityNetworkInformationBackend::isWwanChanged,
+ Qt::QueuedConnection);
+ connect(&ipv6Probe, &QNetworkConnectionMonitor::isWwanChanged, this,
+ &QSCNetworkReachabilityNetworkInformationBackend::isWwanChanged,
+ Qt::QueuedConnection);
+#endif
+}
+
+QSCNetworkReachabilityNetworkInformationBackend::~QSCNetworkReachabilityNetworkInformationBackend()
+{
+}
+
+void QSCNetworkReachabilityNetworkInformationBackend::reachabilityChanged(bool isOnline)
+{
+ setReachability(isOnline ? QNetworkInformation::Reachability::Online
+ : QNetworkInformation::Reachability::Disconnected);
+}
+
+#ifdef QT_PLATFORM_UIKIT
+void QSCNetworkReachabilityNetworkInformationBackend::isWwanChanged(bool isWwan)
+{
+ // The reachability API from Apple only has one entry regarding transport medium: "IsWWAN"[0].
+ // This is _serviceable_ on iOS where the only other credible options are "WLAN" or
+ // "Disconnected". But on macOS you could be connected by Ethernet as well, so how would that be
+ // reported? It doesn't matter anyway since "IsWWAN" is not available on macOS.
+ // [0]: https://developer.apple.com/documentation/systemconfiguration/scnetworkreachabilityflags/kscnetworkreachabilityflagsiswwan?language=objc
+ if (reachability() == QNetworkInformation::Reachability::Disconnected) {
+ setTransportMedium(QNetworkInformation::TransportMedium::Unknown);
+ } else {
+ setTransportMedium(isWwan ? QNetworkInformation::TransportMedium::Cellular
+ : QNetworkInformation::TransportMedium::WiFi);
+ }
+}
+#endif
+
+QT_END_NAMESPACE
+
+#include "qscnetworkreachabilitynetworkinformationbackend.moc"
diff --git a/src/plugins/platforminputcontexts/CMakeLists.txt b/src/plugins/platforminputcontexts/CMakeLists.txt
index 155f5161f2..78b3ec99d9 100644
--- a/src/plugins/platforminputcontexts/CMakeLists.txt
+++ b/src/plugins/platforminputcontexts/CMakeLists.txt
@@ -1,8 +1,9 @@
-# Generated from platforminputcontexts.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
if(QT_FEATURE_xkbcommon)
add_subdirectory(compose)
endif()
-if(QT_FEATURE_xkbcommon AND TARGET Qt::DBus AND UNIX AND NOT APPLE_OSX)
+if(QT_FEATURE_xkbcommon AND TARGET Qt::DBus AND UNIX AND NOT MACOS)
add_subdirectory(ibus)
endif()
diff --git a/src/plugins/platforminputcontexts/compose/.prev_CMakeLists.txt b/src/plugins/platforminputcontexts/compose/.prev_CMakeLists.txt
deleted file mode 100644
index ff09314303..0000000000
--- a/src/plugins/platforminputcontexts/compose/.prev_CMakeLists.txt
+++ /dev/null
@@ -1,24 +0,0 @@
-# Generated from compose.pro.
-
-#####################################################################
-## QComposePlatformInputContextPlugin Plugin:
-#####################################################################
-
-qt_add_plugin(QComposePlatformInputContextPlugin
- OUTPUT_NAME composeplatforminputcontextplugin
- TYPE platforminputcontexts
- SOURCES
- qcomposeplatforminputcontext.cpp qcomposeplatforminputcontext.h
- qcomposeplatforminputcontextmain.cpp
- LIBRARIES
- XKB::XKB
- PUBLIC_LIBRARIES
- Qt::Core
- Qt::CorePrivate
- Qt::Gui
- Qt::GuiPrivate
-)
-
-#### Keys ignored in scope 1:.:.:compose.pro:<TRUE>:
-# OTHER_FILES = "$$PWD/compose.json"
-# PLUGIN_EXTENDS = "-"
diff --git a/src/plugins/platforminputcontexts/compose/CMakeLists.txt b/src/plugins/platforminputcontexts/compose/CMakeLists.txt
index fe4e3b8b80..9e71a7a07c 100644
--- a/src/plugins/platforminputcontexts/compose/CMakeLists.txt
+++ b/src/plugins/platforminputcontexts/compose/CMakeLists.txt
@@ -1,26 +1,24 @@
-# Generated from compose.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## QComposePlatformInputContextPlugin Plugin:
#####################################################################
-qt_find_package(XKB) # special case
-pkg_get_variable(PKG_X11_PREFIX x11 prefix) # special case
-qt_add_plugin(QComposePlatformInputContextPlugin
+qt_find_package(XKB)
+pkg_get_variable(PKG_X11_PREFIX x11 prefix)
+
+qt_internal_add_plugin(QComposePlatformInputContextPlugin
OUTPUT_NAME composeplatforminputcontextplugin
- TYPE platforminputcontexts
+ PLUGIN_TYPE platforminputcontexts
+ DEFAULT_IF FALSE
SOURCES
qcomposeplatforminputcontext.cpp qcomposeplatforminputcontext.h
qcomposeplatforminputcontextmain.cpp
LIBRARIES
- XKB::XKB
- PUBLIC_LIBRARIES
Qt::Core
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
+ XKB::XKB
)
-
-#### Keys ignored in scope 1:.:.:compose.pro:<TRUE>:
-# OTHER_FILES = "$$PWD/compose.json"
-# PLUGIN_EXTENDS = "-"
diff --git a/src/plugins/platforminputcontexts/compose/compose.pro b/src/plugins/platforminputcontexts/compose/compose.pro
deleted file mode 100644
index 2e2f8600c3..0000000000
--- a/src/plugins/platforminputcontexts/compose/compose.pro
+++ /dev/null
@@ -1,19 +0,0 @@
-TARGET = composeplatforminputcontextplugin
-
-QT += core-private gui-private
-
-SOURCES += $$PWD/qcomposeplatforminputcontextmain.cpp \
- $$PWD/qcomposeplatforminputcontext.cpp
-
-HEADERS += $$PWD/qcomposeplatforminputcontext.h
-
-QMAKE_USE_PRIVATE += xkbcommon
-
-include($$OUT_PWD/../../../gui/qtgui-config.pri)
-
-OTHER_FILES += $$PWD/compose.json
-
-PLUGIN_TYPE = platforminputcontexts
-PLUGIN_EXTENDS = -
-PLUGIN_CLASS_NAME = QComposePlatformInputContextPlugin
-load(qt_plugin)
diff --git a/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.cpp b/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.cpp
index 4e9828663f..3e74189076 100644
--- a/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.cpp
+++ b/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.cpp
@@ -1,44 +1,9 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 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$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qcomposeplatforminputcontext.h"
#include <QtCore/QCoreApplication>
+#include <QtCore/qvarlengtharray.h>
#include <QtGui/QKeyEvent>
#include <QtGui/QGuiApplication>
@@ -71,10 +36,16 @@ void QComposeInputContext::ensureInitialized()
}
m_initialized = true;
- const char *locale = setlocale(LC_CTYPE, "");
- if (!locale)
- locale = setlocale(LC_CTYPE, nullptr);
- qCDebug(lcXkbCompose) << "detected locale (LC_CTYPE):" << locale;
+ // Get locale from user env settings, see also
+ // https://xkbcommon.org/doc/current/group__compose.html#compose-locale
+ const char *locale = getenv("LC_ALL");
+ if (!locale || !*locale)
+ locale = getenv("LC_CTYPE");
+ if (!locale || !*locale)
+ locale = getenv("LANG");
+ if (!locale || !*locale)
+ locale = "C";
+ qCDebug(lcXkbCompose) << "detected locale:" << locale;
m_composeTable = xkb_compose_table_new_from_locale(m_XkbContext, locale, XKB_COMPOSE_COMPILE_NO_FLAGS);
if (m_composeTable)
@@ -137,8 +108,7 @@ bool QComposeInputContext::filterEvent(const QEvent *event)
case XKB_COMPOSE_NOTHING:
return false;
default:
- Q_UNREACHABLE();
- return false;
+ Q_UNREACHABLE_RETURN(false);
}
}
@@ -164,3 +134,5 @@ void QComposeInputContext::update(Qt::InputMethodQueries q)
}
QT_END_NAMESPACE
+
+#include "moc_qcomposeplatforminputcontext.cpp"
diff --git a/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.h b/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.h
index b1de1b1094..79b98de3fa 100644
--- a/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.h
+++ b/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 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$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QCOMPOSEPLATFORMINPUTCONTEXT_H
#define QCOMPOSEPLATFORMINPUTCONTEXT_H
@@ -45,6 +9,7 @@
#include <xkbcommon/xkbcommon-compose.h>
+Q_DECLARE_OPAQUE_POINTER(xkb_context *)
QT_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(lcXkbCompose)
@@ -73,7 +38,6 @@ protected:
private:
bool m_initialized = false;
- xkb_context *m_context = nullptr;
xkb_compose_table *m_composeTable = nullptr;
xkb_compose_state *m_composeState = nullptr;
QObject *m_focusObject = nullptr;
diff --git a/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontextmain.cpp b/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontextmain.cpp
index d062d4fd6a..804ced957b 100644
--- a/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontextmain.cpp
+++ b/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontextmain.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 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$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <qpa/qplatforminputcontextplugin_p.h>
@@ -45,6 +9,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
class QComposePlatformInputContextPlugin : public QPlatformInputContextPlugin
{
Q_OBJECT
@@ -58,8 +24,8 @@ QComposeInputContext *QComposePlatformInputContextPlugin::create(const QString &
{
Q_UNUSED(paramList);
- if (system.compare(system, QLatin1String("compose"), Qt::CaseInsensitive) == 0
- || system.compare(system, QLatin1String("xim"), Qt::CaseInsensitive) == 0)
+ if (system.compare(system, "compose"_L1, Qt::CaseInsensitive) == 0
+ || system.compare(system, "xim"_L1, Qt::CaseInsensitive) == 0)
return new QComposeInputContext;
return nullptr;
}
diff --git a/src/plugins/platforminputcontexts/ibus/CMakeLists.txt b/src/plugins/platforminputcontexts/ibus/CMakeLists.txt
index 1017407342..54847e86fd 100644
--- a/src/plugins/platforminputcontexts/ibus/CMakeLists.txt
+++ b/src/plugins/platforminputcontexts/ibus/CMakeLists.txt
@@ -1,12 +1,14 @@
-# Generated from ibus.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## QIbusPlatformInputContextPlugin Plugin:
#####################################################################
-qt_add_plugin(QIbusPlatformInputContextPlugin
+qt_internal_add_plugin(QIbusPlatformInputContextPlugin
OUTPUT_NAME ibusplatforminputcontextplugin
- TYPE platforminputcontexts
+ PLUGIN_TYPE platforminputcontexts
+ DEFAULT_IF FALSE
SOURCES
main.cpp
qibusinputcontextproxy.cpp qibusinputcontextproxy.h
@@ -14,14 +16,10 @@ qt_add_plugin(QIbusPlatformInputContextPlugin
qibusproxy.cpp qibusproxy.h
qibusproxyportal.cpp qibusproxyportal.h
qibustypes.cpp qibustypes.h
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Core
Qt::DBus
Qt::Gui
Qt::GuiPrivate
- Qt::XkbCommonSupportPrivate
+ XKB::XKB
)
-
-#### Keys ignored in scope 1:.:.:ibus.pro:<TRUE>:
-# OTHER_FILES = "$$PWD/ibus.json"
-# PLUGIN_EXTENDS = "-"
diff --git a/src/plugins/platforminputcontexts/ibus/ibus.pro b/src/plugins/platforminputcontexts/ibus/ibus.pro
deleted file mode 100644
index 9ba2297e38..0000000000
--- a/src/plugins/platforminputcontexts/ibus/ibus.pro
+++ /dev/null
@@ -1,22 +0,0 @@
-TARGET = ibusplatforminputcontextplugin
-
-QT += dbus gui-private xkbcommon_support-private
-SOURCES += $$PWD/qibusplatforminputcontext.cpp \
- $$PWD/qibusproxy.cpp \
- $$PWD/qibusproxyportal.cpp \
- $$PWD/qibusinputcontextproxy.cpp \
- $$PWD/qibustypes.cpp \
- $$PWD/main.cpp
-
-HEADERS += $$PWD/qibusplatforminputcontext.h \
- $$PWD/qibusproxy.h \
- $$PWD/qibusproxyportal.h \
- $$PWD/qibusinputcontextproxy.h \
- $$PWD/qibustypes.h
-
-OTHER_FILES += $$PWD/ibus.json
-
-PLUGIN_TYPE = platforminputcontexts
-PLUGIN_EXTENDS = -
-PLUGIN_CLASS_NAME = QIbusPlatformInputContextPlugin
-load(qt_plugin)
diff --git a/src/plugins/platforminputcontexts/ibus/interfaces/org.freedesktop.IBus.InputContext.xml b/src/plugins/platforminputcontexts/ibus/interfaces/org.freedesktop.IBus.InputContext.xml
index 9c67a38c57..30fa7431c3 100644
--- a/src/plugins/platforminputcontexts/ibus/interfaces/org.freedesktop.IBus.InputContext.xml
+++ b/src/plugins/platforminputcontexts/ibus/interfaces/org.freedesktop.IBus.InputContext.xml
@@ -2,6 +2,12 @@
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
<interface name="org.freedesktop.IBus.InputContext">
+ <property name="ClientCommitPreedit" type="(b)" access="readwrite">
+ <annotation name="org.qtproject.QtDBus.QtTypeName" value="QIBusPropTypeClientCommitPreedit"/>
+ </property>
+ <property name='ContentType' type='(uu)' access='readwrite'>
+ <annotation name="org.qtproject.QtDBus.QtTypeName" value="QIBusPropTypeContentType"/>
+ </property>
<method name="ProcessKeyEvent">
<arg name="keyval" direction="in" type="u"/>
<arg name="keycode" direction="in" type="u"/>
@@ -14,6 +20,12 @@
<arg name="w" direction="in" type="i"/>
<arg name="h" direction="in" type="i"/>
</method>
+ <method name='SetCursorLocationRelative'>
+ <arg name="x" direction="in" type="i"/>
+ <arg name="y" direction="in" type="i"/>
+ <arg name="w" direction="in" type="i"/>
+ <arg name="h" direction="in" type="i"/>
+ </method>
<method name="FocusIn"/>
<method name="FocusOut"/>
<method name="Reset"/>
@@ -56,6 +68,12 @@
<arg name="cursor_pos" type="u"/>
<arg name="visible" type="b"/>
</signal>
+ <signal name="UpdatePreeditTextWithMode">
+ <arg name="text" type="v"/>
+ <arg name="cursor_pos" type="u"/>
+ <arg name="visible" type="b"/>
+ <arg name="mode" type="u"/>
+ </signal>
<signal name="ShowPreeditText"/>
<signal name="HidePreeditText"/>
<signal name="UpdateAuxiliaryText">
diff --git a/src/plugins/platforminputcontexts/ibus/main.cpp b/src/plugins/platforminputcontexts/ibus/main.cpp
index 0a7da3b14c..d74be4bedf 100644
--- a/src/plugins/platforminputcontexts/ibus/main.cpp
+++ b/src/plugins/platforminputcontexts/ibus/main.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <qpa/qplatforminputcontextplugin_p.h>
#include <QtCore/QStringList>
@@ -45,6 +9,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
class QIbusPlatformInputContextPlugin : public QPlatformInputContextPlugin
{
Q_OBJECT
@@ -58,13 +24,16 @@ QIBusPlatformInputContext *QIbusPlatformInputContextPlugin::create(const QString
{
Q_UNUSED(paramList);
- if (system.compare(system, QLatin1String("ibus"), Qt::CaseInsensitive) == 0) {
+ if (system.compare(system, "ibus"_L1, Qt::CaseInsensitive) == 0) {
qDBusRegisterMetaType<QIBusAttribute>();
qDBusRegisterMetaType<QIBusAttributeList>();
qDBusRegisterMetaType<QIBusText>();
+ qDBusRegisterMetaType<QIBusPropTypeClientCommitPreedit>();
+ qDBusRegisterMetaType<QIBusPropTypeContentType>();
return new QIBusPlatformInputContext;
}
- return 0;
+
+ return nullptr;
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforminputcontexts/ibus/qibusinputcontextproxy.cpp b/src/plugins/platforminputcontexts/ibus/qibusinputcontextproxy.cpp
index 793c9dd95c..248abbc32b 100644
--- a/src/plugins/platforminputcontexts/ibus/qibusinputcontextproxy.cpp
+++ b/src/plugins/platforminputcontexts/ibus/qibusinputcontextproxy.cpp
@@ -2,7 +2,7 @@
* This file was generated by qdbusxml2cpp version 0.8
* Command line was: qdbusxml2cpp -N -p qibusinputcontextproxy -c QIBusInputContextProxy interfaces/org.freedesktop.IBus.InputContext.xml
*
- * qdbusxml2cpp is Copyright (C) 2015 The Qt Company Ltd.
+ * qdbusxml2cpp is Copyright (C) 2023 The Qt Company Ltd and other contributors.
*
* This is an auto-generated file.
* This file may have been hand-edited. Look for HAND-EDIT comments
diff --git a/src/plugins/platforminputcontexts/ibus/qibusinputcontextproxy.h b/src/plugins/platforminputcontexts/ibus/qibusinputcontextproxy.h
index 396a213aaa..82e78aa35b 100644
--- a/src/plugins/platforminputcontexts/ibus/qibusinputcontextproxy.h
+++ b/src/plugins/platforminputcontexts/ibus/qibusinputcontextproxy.h
@@ -2,14 +2,14 @@
* This file was generated by qdbusxml2cpp version 0.8
* Command line was: qdbusxml2cpp -N -p qibusinputcontextproxy -c QIBusInputContextProxy interfaces/org.freedesktop.IBus.InputContext.xml
*
- * qdbusxml2cpp is Copyright (C) 2015 The Qt Company Ltd.
+ * qdbusxml2cpp is Copyright (C) 2023 The Qt Company Ltd and other contributors.
*
* This is an auto-generated file.
* Do not edit! All changes made to it will be lost.
*/
-#ifndef QIBUSINPUTCONTEXTPROXY_H_1394889529
-#define QIBUSINPUTCONTEXTPROXY_H_1394889529
+#ifndef QIBUSINPUTCONTEXTPROXY_H
+#define QIBUSINPUTCONTEXTPROXY_H
#include <QtCore/QObject>
#include <QtCore/QByteArray>
@@ -20,6 +20,9 @@
#include <QtCore/QVariant>
#include <QtDBus/QtDBus>
+// Added for QIBusPropTypeClientCommitPreedit and QIBusPropTypeContentType
+#include "qibustypes.h"
+
/*
* Proxy class for interface org.freedesktop.IBus.InputContext
*/
@@ -35,95 +38,114 @@ public:
~QIBusInputContextProxy();
+ Q_PROPERTY(QIBusPropTypeClientCommitPreedit ClientCommitPreedit READ clientCommitPreedit WRITE setClientCommitPreedit)
+ inline QIBusPropTypeClientCommitPreedit clientCommitPreedit() const
+ { return qvariant_cast< QIBusPropTypeClientCommitPreedit >(property("ClientCommitPreedit")); }
+ inline void setClientCommitPreedit(const QIBusPropTypeClientCommitPreedit &value)
+ { setProperty("ClientCommitPreedit", QVariant::fromValue(value)); }
+
+ Q_PROPERTY(QIBusPropTypeContentType ContentType READ contentType WRITE setContentType)
+ inline QIBusPropTypeContentType contentType() const
+ { return qvariant_cast< QIBusPropTypeContentType >(property("ContentType")); }
+ inline void setContentType(const QIBusPropTypeContentType &value)
+ { setProperty("ContentType", QVariant::fromValue(value)); }
+
public Q_SLOTS: // METHODS
inline QDBusPendingReply<> Destroy()
{
QList<QVariant> argumentList;
- return asyncCallWithArgumentList(QLatin1String("Destroy"), argumentList);
+ return asyncCallWithArgumentList(QStringLiteral("Destroy"), argumentList);
}
inline QDBusPendingReply<> Disable()
{
QList<QVariant> argumentList;
- return asyncCallWithArgumentList(QLatin1String("Disable"), argumentList);
+ return asyncCallWithArgumentList(QStringLiteral("Disable"), argumentList);
}
inline QDBusPendingReply<> Enable()
{
QList<QVariant> argumentList;
- return asyncCallWithArgumentList(QLatin1String("Enable"), argumentList);
+ return asyncCallWithArgumentList(QStringLiteral("Enable"), argumentList);
}
inline QDBusPendingReply<> FocusIn()
{
QList<QVariant> argumentList;
- return asyncCallWithArgumentList(QLatin1String("FocusIn"), argumentList);
+ return asyncCallWithArgumentList(QStringLiteral("FocusIn"), argumentList);
}
inline QDBusPendingReply<> FocusOut()
{
QList<QVariant> argumentList;
- return asyncCallWithArgumentList(QLatin1String("FocusOut"), argumentList);
+ return asyncCallWithArgumentList(QStringLiteral("FocusOut"), argumentList);
}
inline QDBusPendingReply<QDBusVariant> GetEngine()
{
QList<QVariant> argumentList;
- return asyncCallWithArgumentList(QLatin1String("GetEngine"), argumentList);
+ return asyncCallWithArgumentList(QStringLiteral("GetEngine"), argumentList);
}
inline QDBusPendingReply<bool> IsEnabled()
{
QList<QVariant> argumentList;
- return asyncCallWithArgumentList(QLatin1String("IsEnabled"), argumentList);
+ return asyncCallWithArgumentList(QStringLiteral("IsEnabled"), argumentList);
}
inline QDBusPendingReply<bool> ProcessKeyEvent(uint keyval, uint keycode, uint state)
{
QList<QVariant> argumentList;
argumentList << QVariant::fromValue(keyval) << QVariant::fromValue(keycode) << QVariant::fromValue(state);
- return asyncCallWithArgumentList(QLatin1String("ProcessKeyEvent"), argumentList);
+ return asyncCallWithArgumentList(QStringLiteral("ProcessKeyEvent"), argumentList);
}
inline QDBusPendingReply<> PropertyActivate(const QString &name, int state)
{
QList<QVariant> argumentList;
argumentList << QVariant::fromValue(name) << QVariant::fromValue(state);
- return asyncCallWithArgumentList(QLatin1String("PropertyActivate"), argumentList);
+ return asyncCallWithArgumentList(QStringLiteral("PropertyActivate"), argumentList);
}
inline QDBusPendingReply<> Reset()
{
QList<QVariant> argumentList;
- return asyncCallWithArgumentList(QLatin1String("Reset"), argumentList);
+ return asyncCallWithArgumentList(QStringLiteral("Reset"), argumentList);
}
inline QDBusPendingReply<> SetCapabilities(uint caps)
{
QList<QVariant> argumentList;
argumentList << QVariant::fromValue(caps);
- return asyncCallWithArgumentList(QLatin1String("SetCapabilities"), argumentList);
+ return asyncCallWithArgumentList(QStringLiteral("SetCapabilities"), argumentList);
}
inline QDBusPendingReply<> SetCursorLocation(int x, int y, int w, int h)
{
QList<QVariant> argumentList;
argumentList << QVariant::fromValue(x) << QVariant::fromValue(y) << QVariant::fromValue(w) << QVariant::fromValue(h);
- return asyncCallWithArgumentList(QLatin1String("SetCursorLocation"), argumentList);
+ return asyncCallWithArgumentList(QStringLiteral("SetCursorLocation"), argumentList);
+ }
+
+ inline QDBusPendingReply<> SetCursorLocationRelative(int x, int y, int w, int h)
+ {
+ QList<QVariant> argumentList;
+ argumentList << QVariant::fromValue(x) << QVariant::fromValue(y) << QVariant::fromValue(w) << QVariant::fromValue(h);
+ return asyncCallWithArgumentList(QStringLiteral("SetCursorLocationRelative"), argumentList);
}
inline QDBusPendingReply<> SetEngine(const QString &name)
{
QList<QVariant> argumentList;
argumentList << QVariant::fromValue(name);
- return asyncCallWithArgumentList(QLatin1String("SetEngine"), argumentList);
+ return asyncCallWithArgumentList(QStringLiteral("SetEngine"), argumentList);
}
inline QDBusPendingReply<> SetSurroundingText(const QDBusVariant &text, uint cursor_pos, uint anchor_pos)
{
QList<QVariant> argumentList;
argumentList << QVariant::fromValue(text) << QVariant::fromValue(cursor_pos) << QVariant::fromValue(anchor_pos);
- return asyncCallWithArgumentList(QLatin1String("SetSurroundingText"), argumentList);
+ return asyncCallWithArgumentList(QStringLiteral("SetSurroundingText"), argumentList);
}
Q_SIGNALS: // SIGNALS
@@ -147,6 +169,7 @@ Q_SIGNALS: // SIGNALS
void UpdateAuxiliaryText(const QDBusVariant &text, bool visible);
void UpdateLookupTable(const QDBusVariant &table, bool visible);
void UpdatePreeditText(const QDBusVariant &text, uint cursor_pos, bool visible);
+ void UpdatePreeditTextWithMode(const QDBusVariant &text, uint cursor_pos, bool visible, uint mode);
void UpdateProperty(const QDBusVariant &prop);
};
diff --git a/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp b/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp
index 47ac54927b..00c7884cda 100644
--- a/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp
+++ b/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp
@@ -1,67 +1,37 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qibusplatforminputcontext.h"
-#include <QtDebug>
+#include <QDebug>
#include <QTextCharFormat>
#include <QGuiApplication>
+#include <QWindow>
+#include <QEvent>
+#include <QFile>
+#include <QFileInfo>
+#include <QStandardPaths>
#include <QDBusVariant>
-#include <qwindow.h>
-#include <qevent.h>
+#include <QDBusPendingReply>
+#include <QDBusReply>
+#include <QDBusServiceWatcher>
+
+#include "qibusproxy.h"
+#include "qibusproxyportal.h"
+#include "qibusinputcontextproxy.h"
+#include "qibustypes.h"
#include <qpa/qplatformcursor.h>
#include <qpa/qplatformscreen.h>
#include <qpa/qwindowsysteminterface_p.h>
-#include <QtGui/private/qguiapplication_p.h>
-
-#include <QtXkbCommonSupport/private/qxkbcommon_p.h>
+#include <private/qguiapplication_p.h>
+#include <private/qxkbcommon_p.h>
-#include "qibusproxy.h"
-#include "qibusproxyportal.h"
-#include "qibusinputcontextproxy.h"
-#include "qibustypes.h"
+#include <memory>
#include <sys/types.h>
#include <signal.h>
-#include <QtDBus>
#ifndef IBUS_RELEASE_MASK
#define IBUS_RELEASE_MASK (1 << 30)
@@ -73,30 +43,41 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
enum { debug = 0 };
class QIBusPlatformInputContextPrivate
{
+ Q_DISABLE_COPY_MOVE(QIBusPlatformInputContextPrivate)
public:
+ // This enum might be synced with IBusPreeditFocusMode
+ // in ibustypes.h of IBUS project
+ enum PreeditFocusMode {
+ PREEDIT_CLEAR = 0,
+ PREEDIT_COMMIT = 1,
+ };
+
QIBusPlatformInputContextPrivate();
~QIBusPlatformInputContextPrivate()
{
- delete context;
- delete bus;
- delete portalBus;
- delete connection;
+ // dereference QDBusConnection to actually disconnect
+ serviceWatcher.setConnection(QDBusConnection(QString()));
+ context = nullptr;
+ portalBus = nullptr;
+ bus = nullptr;
+ QDBusConnection::disconnectFromBus("QIBusProxy"_L1);
}
static QString getSocketPath();
- QDBusConnection *createConnection();
+ void createConnection();
void initBus();
void createBusProxy();
- QDBusConnection *connection;
- QIBusProxy *bus;
- QIBusProxyPortal *portalBus; // bus and portalBus are alternative.
- QIBusInputContextProxy *context;
+ std::unique_ptr<QIBusProxy> bus;
+ std::unique_ptr<QIBusProxyPortal> portalBus; // bus and portalBus are alternative.
+ std::unique_ptr<QIBusInputContextProxy> context;
QDBusServiceWatcher serviceWatcher;
bool usePortal; // return value of shouldConnectIbusPortal
@@ -106,6 +87,7 @@ public:
QList<QInputMethodEvent::Attribute> attributes;
bool needsSurroundingText;
QLocale locale;
+ PreeditFocusMode preeditFocusMode = PREEDIT_COMMIT; // for backward compatibility
};
@@ -177,8 +159,6 @@ void QIBusPlatformInputContext::invokeAction(QInputMethod::Action a, int)
void QIBusPlatformInputContext::reset()
{
- QPlatformInputContext::reset();
-
if (!d->busConnected)
return;
@@ -189,8 +169,6 @@ void QIBusPlatformInputContext::reset()
void QIBusPlatformInputContext::commit()
{
- QPlatformInputContext::commit();
-
if (!d->busConnected)
return;
@@ -201,10 +179,18 @@ void QIBusPlatformInputContext::commit()
return;
}
- if (!d->predit.isEmpty()) {
- QInputMethodEvent event;
- event.setCommitString(d->predit);
- QCoreApplication::sendEvent(input, &event);
+ if (d->preeditFocusMode == QIBusPlatformInputContextPrivate::PREEDIT_COMMIT) {
+ if (!d->predit.isEmpty()) {
+ QInputMethodEvent event;
+ event.setCommitString(d->predit);
+ QCoreApplication::sendEvent(input, &event);
+ }
+ } else {
+ if (!d->predit.isEmpty()) {
+ // Clear the existing preedit
+ QInputMethodEvent event;
+ QCoreApplication::sendEvent(input, &event);
+ }
}
d->context->Reset();
@@ -239,7 +225,6 @@ void QIBusPlatformInputContext::update(Qt::InputMethodQueries q)
d->context->SetSurroundingText(dbusText, cursorPosition, anchorPosition);
}
- QPlatformInputContext::update(q);
}
void QIBusPlatformInputContext::cursorRectChanged()
@@ -248,16 +233,37 @@ void QIBusPlatformInputContext::cursorRectChanged()
return;
QRect r = qApp->inputMethod()->cursorRectangle().toRect();
- if(!r.isValid())
+ if (!r.isValid())
return;
QWindow *inputWindow = qApp->focusWindow();
if (!inputWindow)
return;
- r.moveTopLeft(inputWindow->mapToGlobal(r.topLeft()));
+ if (!inputWindow->screen())
+ return;
+
+ if (QGuiApplication::platformName().startsWith("wayland"_L1)) {
+ auto margins = inputWindow->frameMargins();
+ r.translate(margins.left(), margins.top());
+ qreal scale = inputWindow->devicePixelRatio();
+ QRect newRect = QRect(r.x() * scale, r.y() * scale, r.width() * scale, r.height() * scale);
+ if (debug)
+ qDebug() << "microFocus" << newRect;
+ d->context->SetCursorLocationRelative(newRect.x(), newRect.y(),
+ newRect.width(), newRect.height());
+ return;
+ }
+
+ // x11/xcb
+ auto screenGeometry = inputWindow->screen()->geometry();
+ auto point = inputWindow->mapToGlobal(r.topLeft());
+ qreal scale = inputWindow->devicePixelRatio();
+ auto native = (point - screenGeometry.topLeft()) * scale + screenGeometry.topLeft();
+ QRect newRect(native, r.size() * scale);
if (debug)
- qDebug() << "microFocus" << r;
- d->context->SetCursorLocation(r.x(), r.y(), r.width(), r.height());
+ qDebug() << "microFocus" << newRect;
+ d->context->SetCursorLocation(newRect.x(), newRect.y(),
+ newRect.width(), newRect.height());
}
void QIBusPlatformInputContext::setFocusObject(QObject *object)
@@ -268,7 +274,7 @@ void QIBusPlatformInputContext::setFocusObject(QObject *object)
// It would seem natural here to call FocusOut() on the input method if we
// transition from an IME accepted focus object to one that does not accept it.
// Mysteriously however that is not sufficient to fix bug QTBUG-63066.
- if (!inputMethodAccepted())
+ if (object && !inputMethodAccepted())
return;
if (debug)
@@ -328,6 +334,15 @@ void QIBusPlatformInputContext::updatePreeditText(const QDBusVariant &text, uint
d->predit = t.text;
}
+void QIBusPlatformInputContext::updatePreeditTextWithMode(const QDBusVariant &text, uint cursorPos, bool visible, uint mode)
+{
+ updatePreeditText(text, cursorPos, visible);
+ if (mode > 0)
+ d->preeditFocusMode = QIBusPlatformInputContextPrivate::PreeditFocusMode::PREEDIT_COMMIT;
+ else
+ d->preeditFocusMode = QIBusPlatformInputContextPrivate::PreeditFocusMode::PREEDIT_CLEAR;
+}
+
void QIBusPlatformInputContext::forwardKeyEvent(uint keyval, uint keycode, uint state)
{
if (!qApp)
@@ -504,7 +519,7 @@ void QIBusPlatformInputContext::filterEventFinished(QDBusPendingCallWatcher *cal
if (!filtered) {
#ifndef QT_NO_CONTEXTMENU
if (type == QEvent::KeyPress && qtcode == Qt::Key_Menu
- && window != NULL) {
+ && window != nullptr) {
const QPoint globalPos = window->screen()->handle()->cursor()->pos();
const QPoint pos = window->mapFromGlobal(globalPos);
QWindowSystemInterfacePrivate::ContextMenuEvent contextMenuEvent(window, false, pos,
@@ -534,12 +549,12 @@ void QIBusPlatformInputContext::socketChanged(const QString &str)
m_timer.stop();
- if (d->context)
- disconnect(d->context);
- if (d->bus && d->bus->isValid())
- disconnect(d->bus);
- if (d->connection)
- d->connection->disconnectFromBus(QLatin1String("QIBusProxy"));
+ // dereference QDBusConnection to actually disconnect
+ d->serviceWatcher.setConnection(QDBusConnection(QString()));
+ d->context = nullptr;
+ d->bus = nullptr;
+ d->busConnected = false;
+ QDBusConnection::disconnectFromBus("QIBusProxy"_L1);
m_timer.start(100);
}
@@ -591,37 +606,34 @@ void QIBusPlatformInputContext::globalEngineChanged(const QString &engine_name)
void QIBusPlatformInputContext::connectToContextSignals()
{
if (d->bus && d->bus->isValid()) {
- connect(d->bus, SIGNAL(GlobalEngineChanged(QString)), this, SLOT(globalEngineChanged(QString)));
+ connect(d->bus.get(), SIGNAL(GlobalEngineChanged(QString)), this, SLOT(globalEngineChanged(QString)));
}
if (d->context) {
- connect(d->context, SIGNAL(CommitText(QDBusVariant)), SLOT(commitText(QDBusVariant)));
- connect(d->context, SIGNAL(UpdatePreeditText(QDBusVariant,uint,bool)), this, SLOT(updatePreeditText(QDBusVariant,uint,bool)));
- connect(d->context, SIGNAL(ForwardKeyEvent(uint,uint,uint)), this, SLOT(forwardKeyEvent(uint,uint,uint)));
- connect(d->context, SIGNAL(DeleteSurroundingText(int,uint)), this, SLOT(deleteSurroundingText(int,uint)));
- connect(d->context, SIGNAL(RequireSurroundingText()), this, SLOT(surroundingTextRequired()));
- connect(d->context, SIGNAL(HidePreeditText()), this, SLOT(hidePreeditText()));
- connect(d->context, SIGNAL(ShowPreeditText()), this, SLOT(showPreeditText()));
+ connect(d->context.get(), SIGNAL(CommitText(QDBusVariant)), SLOT(commitText(QDBusVariant)));
+ connect(d->context.get(), SIGNAL(UpdatePreeditText(QDBusVariant,uint,bool)), this, SLOT(updatePreeditText(QDBusVariant,uint,bool)));
+ connect(d->context.get(), SIGNAL(UpdatePreeditTextWithMode(QDBusVariant,uint,bool,uint)), this, SLOT(updatePreeditTextWithMode(QDBusVariant,uint,bool,uint)));
+ connect(d->context.get(), SIGNAL(ForwardKeyEvent(uint,uint,uint)), this, SLOT(forwardKeyEvent(uint,uint,uint)));
+ connect(d->context.get(), SIGNAL(DeleteSurroundingText(int,uint)), this, SLOT(deleteSurroundingText(int,uint)));
+ connect(d->context.get(), SIGNAL(RequireSurroundingText()), this, SLOT(surroundingTextRequired()));
+ connect(d->context.get(), SIGNAL(HidePreeditText()), this, SLOT(hidePreeditText()));
+ connect(d->context.get(), SIGNAL(ShowPreeditText()), this, SLOT(showPreeditText()));
}
}
-static inline bool checkRunningUnderFlatpak()
+static inline bool checkNeedPortalSupport()
{
- return !QStandardPaths::locate(QStandardPaths::RuntimeLocation, QLatin1String("flatpak-info")).isEmpty();
+ return QFileInfo::exists("/.flatpak-info"_L1) || qEnvironmentVariableIsSet("SNAP");
}
static bool shouldConnectIbusPortal()
{
// honor the same env as ibus-gtk
- return (checkRunningUnderFlatpak() || !qgetenv("IBUS_USE_PORTAL").isNull());
+ return (checkNeedPortalSupport() || qEnvironmentVariableIsSet("IBUS_USE_PORTAL"));
}
QIBusPlatformInputContextPrivate::QIBusPlatformInputContextPrivate()
- : connection(0),
- bus(0),
- portalBus(0),
- context(0),
- usePortal(shouldConnectIbusPortal()),
+ : usePortal(shouldConnectIbusPortal()),
valid(false),
busConnected(false),
needsSurroundingText(false)
@@ -645,42 +657,43 @@ QIBusPlatformInputContextPrivate::QIBusPlatformInputContextPrivate()
void QIBusPlatformInputContextPrivate::initBus()
{
- connection = createConnection();
+ createConnection();
busConnected = false;
createBusProxy();
}
void QIBusPlatformInputContextPrivate::createBusProxy()
{
- if (!connection || !connection->isConnected())
+ QDBusConnection connection("QIBusProxy"_L1);
+ if (!connection.isConnected())
return;
const char* ibusService = usePortal ? "org.freedesktop.portal.IBus" : "org.freedesktop.IBus";
QDBusReply<QDBusObjectPath> ic;
if (usePortal) {
- portalBus = new QIBusProxyPortal(QLatin1String(ibusService),
- QLatin1String("/org/freedesktop/IBus"),
- *connection);
+ portalBus = std::make_unique<QIBusProxyPortal>(QLatin1StringView(ibusService),
+ "/org/freedesktop/IBus"_L1,
+ connection);
if (!portalBus->isValid()) {
qWarning("QIBusPlatformInputContext: invalid portal bus.");
return;
}
- ic = portalBus->CreateInputContext(QLatin1String("QIBusInputContext"));
+ ic = portalBus->CreateInputContext("QIBusInputContext"_L1);
} else {
- bus = new QIBusProxy(QLatin1String(ibusService),
- QLatin1String("/org/freedesktop/IBus"),
- *connection);
+ bus = std::make_unique<QIBusProxy>(QLatin1StringView(ibusService),
+ "/org/freedesktop/IBus"_L1,
+ connection);
if (!bus->isValid()) {
qWarning("QIBusPlatformInputContext: invalid bus.");
return;
}
- ic = bus->CreateInputContext(QLatin1String("QIBusInputContext"));
+ ic = bus->CreateInputContext("QIBusInputContext"_L1);
}
serviceWatcher.removeWatchedService(ibusService);
- serviceWatcher.setConnection(*connection);
+ serviceWatcher.setConnection(connection);
serviceWatcher.addWatchedService(ibusService);
if (!ic.isValid()) {
@@ -688,7 +701,7 @@ void QIBusPlatformInputContextPrivate::createBusProxy()
return;
}
- context = new QIBusInputContextProxy(QLatin1String(ibusService), ic.value().path(), *connection);
+ context = std::make_unique<QIBusInputContextProxy>(QLatin1StringView(ibusService), ic.value().path(), connection);
if (!context->isValid()) {
qWarning("QIBusPlatformInputContext: invalid input context.");
@@ -705,6 +718,8 @@ void QIBusPlatformInputContextPrivate::createBusProxy()
};
context->SetCapabilities(IBUS_CAP_PREEDIT_TEXT|IBUS_CAP_FOCUS|IBUS_CAP_SURROUNDING_TEXT);
+ context->setClientCommitPreedit(QIBusPropTypeClientCommitPreedit(true));
+
if (debug)
qDebug(">>>> bus connected!");
busConnected = true;
@@ -712,36 +727,54 @@ void QIBusPlatformInputContextPrivate::createBusProxy()
QString QIBusPlatformInputContextPrivate::getSocketPath()
{
- QByteArray display(qgetenv("DISPLAY"));
- QByteArray host = "unix";
+ QByteArray display;
QByteArray displayNumber = "0";
+ bool isWayland = false;
+
+ if (qEnvironmentVariableIsSet("IBUS_ADDRESS_FILE")) {
+ QByteArray path = qgetenv("IBUS_ADDRESS_FILE");
+ return QString::fromLocal8Bit(path);
+ } else if (qEnvironmentVariableIsSet("WAYLAND_DISPLAY")) {
+ display = qgetenv("WAYLAND_DISPLAY");
+ isWayland = true;
+ } else {
+ display = qgetenv("DISPLAY");
+ }
+ QByteArray host = "unix";
+
+ if (isWayland) {
+ displayNumber = display;
+ } else {
+ int pos = display.indexOf(':');
+ if (pos > 0)
+ host = display.left(pos);
+ ++pos;
+ int pos2 = display.indexOf('.', pos);
+ if (pos2 > 0)
+ displayNumber = display.mid(pos, pos2 - pos);
+ else
+ displayNumber = display.mid(pos);
+ }
- int pos = display.indexOf(':');
- if (pos > 0)
- host = display.left(pos);
- ++pos;
- int pos2 = display.indexOf('.', pos);
- if (pos2 > 0)
- displayNumber = display.mid(pos, pos2 - pos);
- else
- displayNumber = display.mid(pos);
if (debug)
qDebug() << "host=" << host << "displayNumber" << displayNumber;
return QStandardPaths::writableLocation(QStandardPaths::ConfigLocation) +
- QLatin1String("/ibus/bus/") +
- QLatin1String(QDBusConnection::localMachineId()) +
- QLatin1Char('-') + QString::fromLocal8Bit(host) + QLatin1Char('-') + QString::fromLocal8Bit(displayNumber);
+ "/ibus/bus/"_L1 +
+ QLatin1StringView(QDBusConnection::localMachineId()) +
+ u'-' + QString::fromLocal8Bit(host) + u'-' + QString::fromLocal8Bit(displayNumber);
}
-QDBusConnection *QIBusPlatformInputContextPrivate::createConnection()
+void QIBusPlatformInputContextPrivate::createConnection()
{
- if (usePortal)
- return new QDBusConnection(QDBusConnection::connectToBus(QDBusConnection::SessionBus, QLatin1String("QIBusProxy")));
- QFile file(getSocketPath());
+ if (usePortal) {
+ QDBusConnection::connectToBus(QDBusConnection::SessionBus, "QIBusProxy"_L1);
+ return;
+ }
+ QFile file(getSocketPath());
if (!file.open(QFile::ReadOnly))
- return 0;
+ return;
QByteArray address;
int pid = -1;
@@ -760,9 +793,11 @@ QDBusConnection *QIBusPlatformInputContextPrivate::createConnection()
if (debug)
qDebug() << "IBUS_ADDRESS=" << address << "PID=" << pid;
if (address.isEmpty() || pid < 0 || kill(pid, 0) != 0)
- return 0;
+ return;
- return new QDBusConnection(QDBusConnection::connectToBus(QString::fromLatin1(address), QLatin1String("QIBusProxy")));
+ QDBusConnection::connectToBus(QString::fromLatin1(address), "QIBusProxy"_L1);
}
QT_END_NAMESPACE
+
+#include "moc_qibusplatforminputcontext.cpp"
diff --git a/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.h b/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.h
index e9c9c55f6a..ef8c0b7c8f 100644
--- a/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.h
+++ b/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QIBUSPLATFORMINPUTCONTEXT_H
#define QIBUSPLATFORMINPUTCONTEXT_H
@@ -50,6 +14,8 @@
#include <QTimer>
#include <QWindow>
+#include "qibustypes.h"
+
QT_BEGIN_NAMESPACE
class QIBusPlatformInputContextPrivate;
@@ -102,6 +68,7 @@ public:
public Q_SLOTS:
void commitText(const QDBusVariant &text);
void updatePreeditText(const QDBusVariant &text, uint cursor_pos, bool visible);
+ void updatePreeditTextWithMode(const QDBusVariant &text, uint cursor_pos, bool visible, uint mode);
void forwardKeyEvent(uint keyval, uint keycode, uint state);
void cursorRectChanged();
void deleteSurroundingText(int offset, uint n_chars);
diff --git a/src/plugins/platforminputcontexts/ibus/qibusproxy.cpp b/src/plugins/platforminputcontexts/ibus/qibusproxy.cpp
index 6b46e106ab..8f104a782d 100644
--- a/src/plugins/platforminputcontexts/ibus/qibusproxy.cpp
+++ b/src/plugins/platforminputcontexts/ibus/qibusproxy.cpp
@@ -13,6 +13,8 @@
#include "qibusproxy.h"
+#include <QDBusReply>
+
/*
* Implementation of interface class QIBusProxy
*/
@@ -96,3 +98,4 @@ void QIBusProxy::globalEngineChanged(const QString &engine_name)
emit GlobalEngineChanged(engine_name);
}
+#include "moc_qibusproxy.cpp"
diff --git a/src/plugins/platforminputcontexts/ibus/qibusproxy.h b/src/plugins/platforminputcontexts/ibus/qibusproxy.h
index c9876deebf..73aff1a3d9 100644
--- a/src/plugins/platforminputcontexts/ibus/qibusproxy.h
+++ b/src/plugins/platforminputcontexts/ibus/qibusproxy.h
@@ -11,14 +11,15 @@
#ifndef QIBUSPROXY_H_1308831142
#define QIBUSPROXY_H_1308831142
-#include <QtCore/QObject>
-#include <QtCore/QByteArray>
-#include <QtCore/QList>
-#include <QtCore/QMap>
-#include <QtCore/QString>
-#include <QtCore/QStringList>
-#include <QtCore/QVariant>
-#include <QtDBus/QtDBus>
+#include <QObject>
+#include <QByteArray>
+#include <QList>
+#include <QMap>
+#include <QString>
+#include <QStringList>
+#include <QVariant>
+#include <QDBusAbstractInterface>
+#include <QDBusPendingReply>
#include "qibustypes.h"
@@ -109,7 +110,7 @@ public Q_SLOTS: // METHODS
#endif
QIBusEngineDesc getGlobalEngine();
-private:
+private Q_SLOTS:
void globalEngineChanged(const QString &engine_name);
Q_SIGNALS: // SIGNALS
diff --git a/src/plugins/platforminputcontexts/ibus/qibusproxyportal.cpp b/src/plugins/platforminputcontexts/ibus/qibusproxyportal.cpp
index 50482e2d9a..dc5b37aa6e 100644
--- a/src/plugins/platforminputcontexts/ibus/qibusproxyportal.cpp
+++ b/src/plugins/platforminputcontexts/ibus/qibusproxyportal.cpp
@@ -2,7 +2,7 @@
* This file was generated by qdbusxml2cpp version 0.8
* Command line was: qdbusxml2cpp -N -p qibusproxyportal -c QIBusProxyPortal interfaces/org.freedesktop.IBus.Portal.xml
*
- * qdbusxml2cpp is Copyright (C) 2017 The Qt Company Ltd.
+ * qdbusxml2cpp is Copyright (C) 2023 The Qt Company Ltd and other contributors.
*
* This is an auto-generated file.
* This file may have been hand-edited. Look for HAND-EDIT comments
diff --git a/src/plugins/platforminputcontexts/ibus/qibusproxyportal.h b/src/plugins/platforminputcontexts/ibus/qibusproxyportal.h
index bdd1d9c395..450205f12a 100644
--- a/src/plugins/platforminputcontexts/ibus/qibusproxyportal.h
+++ b/src/plugins/platforminputcontexts/ibus/qibusproxyportal.h
@@ -2,7 +2,7 @@
* This file was generated by qdbusxml2cpp version 0.8
* Command line was: qdbusxml2cpp -N -p qibusproxyportal -c QIBusProxyPortal interfaces/org.freedesktop.IBus.Portal.xml
*
- * qdbusxml2cpp is Copyright (C) 2017 The Qt Company Ltd.
+ * qdbusxml2cpp is Copyright (C) 2023 The Qt Company Ltd and other contributors.
*
* This is an auto-generated file.
* Do not edit! All changes made to it will be lost.
diff --git a/src/plugins/platforminputcontexts/ibus/qibustypes.cpp b/src/plugins/platforminputcontexts/ibus/qibustypes.cpp
index 443df271a8..ab1a244b6d 100644
--- a/src/plugins/platforminputcontexts/ibus/qibustypes.cpp
+++ b/src/plugins/platforminputcontexts/ibus/qibustypes.cpp
@@ -1,44 +1,8 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qibustypes.h"
-#include <QtDBus>
+
#include <QHash>
QT_BEGIN_NAMESPACE
@@ -214,7 +178,7 @@ QList<QInputMethodEvent::Attribute> QIBusAttributeList::imAttributes() const
QHash<QPair<int, int>, QTextCharFormat> rangeAttrs;
const int numAttributes = attributes.size();
- // Merge text fomats for identical ranges into a single QTextFormat.
+ // Merge text formats for identical ranges into a single QTextFormat.
for (int i = 0; i < numAttributes; ++i) {
const QIBusAttribute &attr = attributes.at(i);
const QTextCharFormat &format = attr.format();
@@ -358,4 +322,44 @@ newest:
argument.endStructure();
}
+QIBusPropTypeClientCommitPreedit::QIBusPropTypeClientCommitPreedit(bool inClientCommitPreedit)
+ : clientCommitPreedit(inClientCommitPreedit)
+{
+}
+
+void QIBusPropTypeClientCommitPreedit::serializeTo(QDBusArgument &argument) const
+{
+ argument.beginStructure();
+ argument << clientCommitPreedit;
+ argument.endStructure();
+}
+
+void QIBusPropTypeClientCommitPreedit::deserializeFrom(const QDBusArgument &argument)
+{
+ argument.beginStructure();
+ argument >> clientCommitPreedit;
+ argument.endStructure();
+}
+
+QIBusPropTypeContentType::QIBusPropTypeContentType(unsigned int inPurpose, unsigned int inHints)
+ : purpose(inPurpose)
+ , hints(inHints)
+{
+}
+
+void QIBusPropTypeContentType::serializeTo(QDBusArgument &argument) const
+{
+ argument.beginStructure();
+ argument << purpose << hints;
+ argument.endStructure();
+}
+
+void QIBusPropTypeContentType::deserializeFrom(const QDBusArgument &argument)
+{
+ argument.beginStructure();
+ argument >> purpose;
+ argument >> hints;
+ argument.endStructure();
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/platforminputcontexts/ibus/qibustypes.h b/src/plugins/platforminputcontexts/ibus/qibustypes.h
index 217cd836fc..b697e432a0 100644
--- a/src/plugins/platforminputcontexts/ibus/qibustypes.h
+++ b/src/plugins/platforminputcontexts/ibus/qibustypes.h
@@ -1,45 +1,9 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QIBUSTYPES_H
#define QIBUSTYPES_H
-#include <qvector.h>
+#include <qlist.h>
#include <qevent.h>
#include <QDBusArgument>
#include <QTextCharFormat>
@@ -92,7 +56,7 @@ public:
quint32 start;
quint32 end;
};
-Q_DECLARE_TYPEINFO(QIBusAttribute, Q_MOVABLE_TYPE);
+Q_DECLARE_TYPEINFO(QIBusAttribute, Q_RELOCATABLE_TYPE);
class QIBusAttributeList : private QIBusSerializable
{
@@ -104,9 +68,9 @@ public:
void serializeTo(QDBusArgument &argument) const;
void deserializeFrom(const QDBusArgument &argument);
- QVector<QIBusAttribute> attributes;
+ QList<QIBusAttribute> attributes;
};
-Q_DECLARE_TYPEINFO(QIBusAttributeList, Q_MOVABLE_TYPE);
+Q_DECLARE_TYPEINFO(QIBusAttributeList, Q_RELOCATABLE_TYPE);
class QIBusText : private QIBusSerializable
{
@@ -119,7 +83,7 @@ public:
QString text;
QIBusAttributeList attributes;
};
-Q_DECLARE_TYPEINFO(QIBusText, Q_MOVABLE_TYPE);
+Q_DECLARE_TYPEINFO(QIBusText, Q_RELOCATABLE_TYPE);
class QIBusEngineDesc : private QIBusSerializable
{
@@ -147,7 +111,7 @@ public:
QString textdomain;
QString iconpropkey;
};
-Q_DECLARE_TYPEINFO(QIBusEngineDesc, Q_MOVABLE_TYPE);
+Q_DECLARE_TYPEINFO(QIBusEngineDesc, Q_RELOCATABLE_TYPE);
inline QDBusArgument &operator<<(QDBusArgument &argument, const QIBusAttribute &attribute)
{ attribute.serializeTo(argument); return argument; }
@@ -169,6 +133,44 @@ inline QDBusArgument &operator<<(QDBusArgument &argument, const QIBusEngineDesc
inline const QDBusArgument &operator>>(const QDBusArgument &argument, QIBusEngineDesc &desc)
{ desc.deserializeFrom(argument); return argument; }
+class QIBusPropTypeClientCommitPreedit
+{
+public:
+ QIBusPropTypeClientCommitPreedit() {};
+
+ QIBusPropTypeClientCommitPreedit(bool inClientCommitPreedit);
+
+ void serializeTo(QDBusArgument &argument) const;
+ void deserializeFrom(const QDBusArgument &argument);
+
+ bool clientCommitPreedit;
+};
+inline QDBusArgument &operator<<(QDBusArgument &argument, const QIBusPropTypeClientCommitPreedit &data)
+{ data.serializeTo(argument); return argument; }
+inline const QDBusArgument &operator>>(const QDBusArgument &argument, QIBusPropTypeClientCommitPreedit &data)
+{ data.deserializeFrom(argument); return argument; }
+
+class QIBusPropTypeContentType
+{
+public:
+ QIBusPropTypeContentType() {};
+
+ QIBusPropTypeContentType(unsigned int inPurpose, unsigned int inHint);
+
+ void serializeTo(QDBusArgument &argument) const;
+ void deserializeFrom(const QDBusArgument &argument);
+
+ unsigned int purpose;
+ unsigned int hints;
+};
+inline QDBusArgument &operator<<(QDBusArgument &argument, const QIBusPropTypeContentType &data)
+{ data.serializeTo(argument); return argument; }
+inline const QDBusArgument &operator>>(const QDBusArgument &argument, QIBusPropTypeContentType &data)
+{ data.deserializeFrom(argument); return argument; }
+
+Q_DECLARE_TYPEINFO(QIBusPropTypeClientCommitPreedit, Q_RELOCATABLE_TYPE);
+Q_DECLARE_TYPEINFO(QIBusPropTypeContentType, Q_RELOCATABLE_TYPE);
+
QT_END_NAMESPACE
Q_DECLARE_METATYPE(QIBusAttribute)
@@ -176,4 +178,6 @@ Q_DECLARE_METATYPE(QIBusAttributeList)
Q_DECLARE_METATYPE(QIBusText)
Q_DECLARE_METATYPE(QIBusEngineDesc)
+Q_DECLARE_METATYPE(QIBusPropTypeClientCommitPreedit)
+Q_DECLARE_METATYPE(QIBusPropTypeContentType)
#endif
diff --git a/src/plugins/platforminputcontexts/platforminputcontexts.pro b/src/plugins/platforminputcontexts/platforminputcontexts.pro
deleted file mode 100644
index 56a39a49e7..0000000000
--- a/src/plugins/platforminputcontexts/platforminputcontexts.pro
+++ /dev/null
@@ -1,11 +0,0 @@
-TEMPLATE = subdirs
-QT_FOR_CONFIG += gui-private
-
-qtConfig(xkbcommon) {
- SUBDIRS += compose
-
- qtHaveModule(dbus) {
- !macos:!win32:SUBDIRS += ibus
- }
-}
-
diff --git a/src/plugins/platforms/.prev_CMakeLists.txt b/src/plugins/platforms/.prev_CMakeLists.txt
deleted file mode 100644
index 5797b07233..0000000000
--- a/src/plugins/platforms/.prev_CMakeLists.txt
+++ /dev/null
@@ -1,57 +0,0 @@
-# Generated from platforms.pro.
-
-if(ANDROID AND NOT ANDROID_EMBEDDED)
- add_subdirectory(android)
-endif()
-if(NOT ANDROID)
- add_subdirectory(minimal)
-endif()
-if(QT_FEATURE_freetype AND NOT ANDROID)
- add_subdirectory(offscreen)
-endif()
-if(QT_FEATURE_xcb)
- add_subdirectory(xcb)
-endif()
-if(APPLE_UIKIT AND NOT APPLE_WATCHOS)
- add_subdirectory(ios)
-endif()
-if(APPLE_OSX)
- add_subdirectory(cocoa)
-endif()
-if(QT_FEATURE_direct3d9 AND WIN32 AND NOT WINRT)
- add_subdirectory(windows)
-endif()
-if(QT_FEATURE_direct3d11 AND WINRT)
- add_subdirectory(winrt)
-endif()
-if(QT_FEATURE_direct2d1_1 AND QT_FEATURE_direct3d11_1 AND QT_FEATURE_directwrite1)
- add_subdirectory(direct2d)
-endif()
-if(QNX)
- add_subdirectory(qnx)
-endif()
-if(QT_FEATURE_eglfs)
- add_subdirectory(eglfs)
- add_subdirectory(minimalegl)
-endif()
-if(QT_FEATURE_directfb)
- add_subdirectory(directfb)
-endif()
-if(QT_FEATURE_linuxfb)
- add_subdirectory(linuxfb)
-endif()
-if(QT_FEATURE_vnc AND TARGET Qt::Network)
- add_subdirectory(vnc)
-endif()
-if(FREEBSD)
- add_subdirectory(bsdfb)
-endif()
-if(HAIKU)
- add_subdirectory(haiku)
-endif()
-if(WASM)
- add_subdirectory(wasm)
-endif()
-if(QT_FEATURE_integrityfb)
- add_subdirectory(integrity)
-endif()
diff --git a/src/plugins/platforms/CMakeLists.txt b/src/plugins/platforms/CMakeLists.txt
index 57c3952e4c..69071a22c2 100644
--- a/src/plugins/platforms/CMakeLists.txt
+++ b/src/plugins/platforms/CMakeLists.txt
@@ -1,34 +1,32 @@
-# Generated from platforms.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
-if(ANDROID AND NOT ANDROID_EMBEDDED)
+if(ANDROID)
add_subdirectory(android)
endif()
-if(NOT ANDROID)
+if(NOT ANDROID AND NOT WASM)
add_subdirectory(minimal)
endif()
-if(QT_FEATURE_freetype AND NOT ANDROID)
+if(QT_FEATURE_freetype AND NOT ANDROID AND NOT WASM)
add_subdirectory(offscreen)
endif()
if(QT_FEATURE_xcb)
add_subdirectory(xcb)
endif()
-if(APPLE_UIKIT AND NOT APPLE_WATCHOS)
+if(UIKIT AND NOT WATCHOS)
add_subdirectory(ios)
endif()
-if(APPLE_OSX)
+if(MACOS)
add_subdirectory(cocoa)
endif()
-if(WIN32 AND NOT WINRT) # special case TODO fix direct3d9 test
+if(WIN32)
add_subdirectory(windows)
endif()
-if(QT_FEATURE_direct3d11 AND WINRT)
- # add_subdirectory(winrt) # special case TODO
-endif()
-if(QT_FEATURE_direct2d1_1 AND QT_FEATURE_direct3d11_1 AND QT_FEATURE_directwrite1)
- # add_subdirectory(direct2d) # special case TODO
+if(QT_FEATURE_direct2d1_1 AND QT_FEATURE_directwrite)
+ add_subdirectory(direct2d)
endif()
if(QNX)
- # add_subdirectory(qnx) # special case TODO
+ add_subdirectory(qnx)
endif()
if(QT_FEATURE_eglfs)
add_subdirectory(eglfs)
@@ -44,14 +42,17 @@ if(QT_FEATURE_vnc AND TARGET Qt::Network)
add_subdirectory(vnc)
endif()
if(FREEBSD)
- # add_subdirectory(bsdfb) # special case TODO
+ # add_subdirectory(bsdfb) # TODO: QTBUG-112768
endif()
if(HAIKU)
- # add_subdirectory(haiku) # special case TODO
+ # add_subdirectory(haiku) # TODO: QTBUG-112768
endif()
if(WASM)
- # add_subdirectory(wasm) # special case TODO
+ add_subdirectory(wasm)
endif()
if(QT_FEATURE_integrityfb)
- # add_subdirectory(integrity) # special case TODO
+ # add_subdirectory(integrity) # TODO: QTBUG-112768
+endif()
+if(QT_FEATURE_vkkhrdisplay)
+ add_subdirectory(vkkhrdisplay)
endif()
diff --git a/src/plugins/platforms/android/.prev_CMakeLists.txt b/src/plugins/platforms/android/.prev_CMakeLists.txt
deleted file mode 100644
index 7b21613fb9..0000000000
--- a/src/plugins/platforms/android/.prev_CMakeLists.txt
+++ /dev/null
@@ -1,85 +0,0 @@
-# Generated from android.pro.
-
-#####################################################################
-## QAndroidIntegrationPlugin Plugin:
-#####################################################################
-
-qt_add_plugin(QAndroidIntegrationPlugin
- OUTPUT_NAME qtforandroid
- TYPE platforms
- SOURCES
- androidcontentfileengine.cpp androidcontentfileengine.h
- androiddeadlockprotector.cpp androiddeadlockprotector.h
- androidjniaccessibility.cpp androidjniaccessibility.h
- androidjniclipboard.cpp androidjniclipboard.h
- androidjniinput.cpp androidjniinput.h
- androidjnimain.cpp androidjnimain.h
- androidjnimenu.cpp androidjnimenu.h
- androidsurfaceclient.h
- main.cpp
- qandroidassetsfileenginehandler.cpp qandroidassetsfileenginehandler.h
- qandroideventdispatcher.cpp qandroideventdispatcher.h
- qandroidinputcontext.cpp qandroidinputcontext.h
- qandroidplatformaccessibility.cpp qandroidplatformaccessibility.h
- qandroidplatformbackingstore.cpp qandroidplatformbackingstore.h
- qandroidplatformclipboard.cpp qandroidplatformclipboard.h
- qandroidplatformdialoghelpers.cpp qandroidplatformdialoghelpers.h
- qandroidplatformfiledialoghelper.cpp qandroidplatformfiledialoghelper.h
- qandroidplatformfontdatabase.cpp qandroidplatformfontdatabase.h
- qandroidplatformforeignwindow.cpp qandroidplatformforeignwindow.h
- qandroidplatformintegration.cpp qandroidplatformintegration.h
- qandroidplatformmenu.cpp qandroidplatformmenu.h
- qandroidplatformmenubar.cpp qandroidplatformmenubar.h
- qandroidplatformmenuitem.cpp qandroidplatformmenuitem.h
- qandroidplatformoffscreensurface.cpp qandroidplatformoffscreensurface.h
- qandroidplatformopenglcontext.cpp qandroidplatformopenglcontext.h
- qandroidplatformopenglwindow.cpp qandroidplatformopenglwindow.h
- qandroidplatformscreen.cpp qandroidplatformscreen.h
- qandroidplatformservices.cpp qandroidplatformservices.h
- qandroidplatformtheme.cpp qandroidplatformtheme.h
- qandroidplatformwindow.cpp qandroidplatformwindow.h
- qandroidsystemlocale.cpp qandroidsystemlocale.h
- INCLUDE_DIRECTORIES
- ${CMAKE_CURRENT_SOURCE_DIR}
- ${QT_SOURCE_TREE}/src/3rdparty/android
- PUBLIC_LIBRARIES
- Qt::AccessibilitySupportPrivate
- Qt::Core
- Qt::CorePrivate
- Qt::EglSupportPrivate
- Qt::EventDispatcherSupportPrivate
- Qt::FontDatabaseSupportPrivate
- Qt::Gui
- Qt::GuiPrivate
- android
- jnigraphics
-)
-
-#### Keys ignored in scope 1:.:.:android.pro:<TRUE>:
-# OTHER_FILES = "$$PWD/android.json"
-
-## Scopes:
-#####################################################################
-
-qt_extend_target(QAndroidIntegrationPlugin CONDITION QT_FEATURE_vulkan
- SOURCES
- qandroidplatformvulkaninstance.cpp qandroidplatformvulkaninstance.h
- qandroidplatformvulkanwindow.cpp qandroidplatformvulkanwindow.h
- PUBLIC_LIBRARIES
- Qt::VulkanSupportPrivate
-)
-
-qt_extend_target(QAndroidIntegrationPlugin CONDITION TARGET Qt::PlatformCompositorSupportPrivate
- PUBLIC_LIBRARIES
- Qt::PlatformCompositorSupportPrivate
-)
-
-qt_extend_target(QAndroidIntegrationPlugin CONDITION QT_FEATURE_android_style_assets
- SOURCES
- extract.cpp
-)
-
-qt_extend_target(QAndroidIntegrationPlugin CONDITION NOT QT_FEATURE_android_style_assets
- SOURCES
- extract-dummy.cpp
-)
diff --git a/src/plugins/platforms/android/CMakeLists.txt b/src/plugins/platforms/android/CMakeLists.txt
index 4d1f83053b..d5a275a76c 100644
--- a/src/plugins/platforms/android/CMakeLists.txt
+++ b/src/plugins/platforms/android/CMakeLists.txt
@@ -1,33 +1,33 @@
-# Generated from android.pro.
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## QAndroidIntegrationPlugin Plugin:
#####################################################################
+qt_find_package(EGL)
-qt_add_plugin(QAndroidIntegrationPlugin
+qt_internal_add_plugin(QAndroidIntegrationPlugin
OUTPUT_NAME qtforandroid
- TYPE platforms
- DEFAULT_IF ${QT_QPA_DEFAULT_PLATFORM} MATCHES android # special case
+ PLUGIN_TYPE platforms
+ DEFAULT_IF ${QT_QPA_DEFAULT_PLATFORM} MATCHES android
SOURCES
androidcontentfileengine.cpp androidcontentfileengine.h
- androiddeadlockprotector.cpp androiddeadlockprotector.h
+ androiddeadlockprotector.h
androidjniaccessibility.cpp androidjniaccessibility.h
- androidjniclipboard.cpp androidjniclipboard.h
androidjniinput.cpp androidjniinput.h
androidjnimain.cpp androidjnimain.h
androidjnimenu.cpp androidjnimenu.h
- androidsurfaceclient.h
main.cpp
qandroidassetsfileenginehandler.cpp qandroidassetsfileenginehandler.h
qandroideventdispatcher.cpp qandroideventdispatcher.h
qandroidinputcontext.cpp qandroidinputcontext.h
qandroidplatformaccessibility.cpp qandroidplatformaccessibility.h
- qandroidplatformbackingstore.cpp qandroidplatformbackingstore.h
qandroidplatformclipboard.cpp qandroidplatformclipboard.h
qandroidplatformdialoghelpers.cpp qandroidplatformdialoghelpers.h
qandroidplatformfiledialoghelper.cpp qandroidplatformfiledialoghelper.h
qandroidplatformfontdatabase.cpp qandroidplatformfontdatabase.h
qandroidplatformforeignwindow.cpp qandroidplatformforeignwindow.h
+ qandroidplatformiconengine.cpp qandroidplatformiconengine.h
qandroidplatformintegration.cpp qandroidplatformintegration.h
qandroidplatformmenu.cpp qandroidplatformmenu.h
qandroidplatformmenubar.cpp qandroidplatformmenubar.h
@@ -40,55 +40,51 @@ qt_add_plugin(QAndroidIntegrationPlugin
qandroidplatformtheme.cpp qandroidplatformtheme.h
qandroidplatformwindow.cpp qandroidplatformwindow.h
qandroidsystemlocale.cpp qandroidsystemlocale.h
+ androidwindowembedding.cpp androidwindowembedding.h
+ NO_UNITY_BUILD_SOURCES
+ # Conflicting symbols and macros with androidjnimain.cpp
+ # TODO: Unify the usage of FIND_AND_CHECK_CLASS, and similar
+ # macros. Q_JNI_FIND_AND_CHECK_CLASS in `qjnihelpers_p.h`
+ # seems to be doing most of the work already.
+ androidjnimenu.cpp
+ qandroidinputcontext.cpp
+ androidjniaccessibility.cpp
+ qandroidplatformdialoghelpers.cpp
+ # Conflicting JNI classes, and types
+ androidcontentfileengine.cpp
+ qandroidplatformintegration.cpp
INCLUDE_DIRECTORIES
${CMAKE_CURRENT_SOURCE_DIR}
- ${QT_SOURCE_TREE}/src/3rdparty/android
- PUBLIC_LIBRARIES
- Qt::AccessibilitySupportPrivate
+ ${QtBase_SOURCE_DIR}/src/3rdparty/android
+ LIBRARIES
+ EGL::EGL
Qt::Core
Qt::CorePrivate
- Qt::EglSupportPrivate
- Qt::EventDispatcherSupportPrivate
- Qt::FontDatabaseSupportPrivate
Qt::Gui
Qt::GuiPrivate
android
jnigraphics
-# special case begin
- INSTALL_DIRECTORY
- plugins/platforms
- OUTPUT_DIRECTORY
- plugins/platforms
- ARCHIVE_INSTALL_DIRECTORY
- plugins/platforms
-# special case end
+ EGL::EGL
)
-#### Keys ignored in scope 1:.:.:android.pro:<TRUE>:
-# OTHER_FILES = "$$PWD/android.json"
-
## Scopes:
#####################################################################
-qt_extend_target(QAndroidIntegrationPlugin CONDITION QT_FEATURE_vulkan
+qt_internal_extend_target(QAndroidIntegrationPlugin CONDITION QT_FEATURE_android_style_assets
SOURCES
- qandroidplatformvulkaninstance.cpp qandroidplatformvulkaninstance.h
- qandroidplatformvulkanwindow.cpp qandroidplatformvulkanwindow.h
- PUBLIC_LIBRARIES
- Qt::VulkanSupportPrivate
-)
-
-qt_extend_target(QAndroidIntegrationPlugin CONDITION TARGET Qt::PlatformCompositorSupportPrivate
- PUBLIC_LIBRARIES
- Qt::PlatformCompositorSupportPrivate
+ extract.cpp
)
-qt_extend_target(QAndroidIntegrationPlugin CONDITION QT_FEATURE_android_style_assets
+qt_internal_extend_target(QAndroidIntegrationPlugin CONDITION NOT QT_FEATURE_android_style_assets
SOURCES
- extract.cpp
+ extract-dummy.cpp
)
-qt_extend_target(QAndroidIntegrationPlugin CONDITION NOT QT_FEATURE_android_style_assets
+qt_internal_extend_target(QAndroidIntegrationPlugin CONDITION QT_FEATURE_vulkan
SOURCES
- extract-dummy.cpp
+ qandroidplatformvulkaninstance.cpp qandroidplatformvulkaninstance.h
+ qandroidplatformvulkanwindow.cpp qandroidplatformvulkanwindow.h
+ NO_UNITY_BUILD_SOURCES
+ # To avoid undefined symbols due to missing VK_USE_PLATFORM_ANDROID_KHR
+ qandroidplatformvulkaninstance.cpp qandroidplatformvulkanwindow.cpp
)
diff --git a/src/plugins/platforms/android/android.pro b/src/plugins/platforms/android/android.pro
deleted file mode 100644
index 8ea78f7cba..0000000000
--- a/src/plugins/platforms/android/android.pro
+++ /dev/null
@@ -1,94 +0,0 @@
-TARGET = qtforandroid
-
-LIBS += -ljnigraphics -landroid
-
-QT += \
- core-private gui-private \
- eventdispatcher_support-private accessibility_support-private \
- fontdatabase_support-private egl_support-private
-
-qtConfig(vulkan): QT += vulkan_support-private
-
-qtHaveModule(platformcompositor_support-private): QT += platformcompositor_support-private
-
-OTHER_FILES += $$PWD/android.json
-
-INCLUDEPATH += \
- $$PWD \
- $$QT_SOURCE_TREE/src/3rdparty/android
-
-SOURCES += $$PWD/main.cpp \
- $$PWD/androidcontentfileengine.cpp \
- $$PWD/androiddeadlockprotector.cpp \
- $$PWD/androidjnimain.cpp \
- $$PWD/androidjniaccessibility.cpp \
- $$PWD/androidjniinput.cpp \
- $$PWD/androidjnimenu.cpp \
- $$PWD/androidjniclipboard.cpp \
- $$PWD/qandroidplatformintegration.cpp \
- $$PWD/qandroidplatformservices.cpp \
- $$PWD/qandroidassetsfileenginehandler.cpp \
- $$PWD/qandroidinputcontext.cpp \
- $$PWD/qandroidplatformaccessibility.cpp \
- $$PWD/qandroidplatformfontdatabase.cpp \
- $$PWD/qandroidplatformdialoghelpers.cpp \
- $$PWD/qandroidplatformclipboard.cpp \
- $$PWD/qandroidplatformtheme.cpp \
- $$PWD/qandroidplatformmenubar.cpp \
- $$PWD/qandroidplatformmenu.cpp \
- $$PWD/qandroidplatformmenuitem.cpp \
- $$PWD/qandroidsystemlocale.cpp \
- $$PWD/qandroidplatformscreen.cpp \
- $$PWD/qandroidplatformwindow.cpp \
- $$PWD/qandroidplatformopenglwindow.cpp \
- $$PWD/qandroidplatformbackingstore.cpp \
- $$PWD/qandroidplatformopenglcontext.cpp \
- $$PWD/qandroidplatformforeignwindow.cpp \
- $$PWD/qandroideventdispatcher.cpp \
- $$PWD/qandroidplatformoffscreensurface.cpp \
- $$PWD/qandroidplatformfiledialoghelper.cpp
-
-HEADERS += $$PWD/qandroidplatformintegration.h \
- $$PWD/androidcontentfileengine.h \
- $$PWD/androiddeadlockprotector.h \
- $$PWD/androidjnimain.h \
- $$PWD/androidjniaccessibility.h \
- $$PWD/androidjniinput.h \
- $$PWD/androidjnimenu.h \
- $$PWD/androidjniclipboard.h \
- $$PWD/qandroidplatformservices.h \
- $$PWD/qandroidassetsfileenginehandler.h \
- $$PWD/qandroidinputcontext.h \
- $$PWD/qandroidplatformaccessibility.h \
- $$PWD/qandroidplatformfontdatabase.h \
- $$PWD/qandroidplatformclipboard.h \
- $$PWD/qandroidplatformdialoghelpers.h \
- $$PWD/qandroidplatformtheme.h \
- $$PWD/qandroidplatformmenubar.h \
- $$PWD/qandroidplatformmenu.h \
- $$PWD/qandroidplatformmenuitem.h \
- $$PWD/qandroidsystemlocale.h \
- $$PWD/androidsurfaceclient.h \
- $$PWD/qandroidplatformscreen.h \
- $$PWD/qandroidplatformwindow.h \
- $$PWD/qandroidplatformopenglwindow.h \
- $$PWD/qandroidplatformbackingstore.h \
- $$PWD/qandroidplatformopenglcontext.h \
- $$PWD/qandroidplatformforeignwindow.h \
- $$PWD/qandroideventdispatcher.h \
- $$PWD/qandroidplatformoffscreensurface.h \
- $$PWD/qandroidplatformfiledialoghelper.h
-
-qtConfig(android-style-assets): SOURCES += $$PWD/extract.cpp
-else: SOURCES += $$PWD/extract-dummy.cpp
-
-qtConfig(vulkan) {
- SOURCES += $$PWD/qandroidplatformvulkaninstance.cpp \
- $$PWD/qandroidplatformvulkanwindow.cpp
- HEADERS += $$PWD/qandroidplatformvulkaninstance.h \
- $$PWD/qandroidplatformvulkanwindow.h
-}
-
-PLUGIN_TYPE = platforms
-PLUGIN_CLASS_NAME = QAndroidIntegrationPlugin
-load(qt_plugin)
diff --git a/src/plugins/platforms/android/androidcontentfileengine.cpp b/src/plugins/platforms/android/androidcontentfileengine.cpp
index 1444407195..db6c601f33 100644
--- a/src/plugins/platforms/android/androidcontentfileengine.cpp
+++ b/src/plugins/platforms/android/androidcontentfileengine.cpp
@@ -1,92 +1,834 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 Volker Krause <vkrause@kde.org>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2019 Volker Krause <vkrause@kde.org>
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "androidcontentfileengine.h"
-#include <private/qjni_p.h>
-#include <private/qjnihelpers_p.h>
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qjnienvironment.h>
+#include <QtCore/qjniobject.h>
+#include <QtCore/qurl.h>
+#include <QtCore/qdatetime.h>
+#include <QtCore/qmimedatabase.h>
-#include <QDebug>
+QT_BEGIN_NAMESPACE
-AndroidContentFileEngine::AndroidContentFileEngine(const QString &fileName)
- : QFSFileEngine(fileName)
+using namespace QNativeInterface;
+using namespace Qt::StringLiterals;
+
+Q_DECLARE_JNI_CLASS(ContentResolverType, "android/content/ContentResolver");
+Q_DECLARE_JNI_CLASS(UriType, "android/net/Uri");
+Q_DECLARE_JNI_CLASS(Uri, "android/net/Uri");
+Q_DECLARE_JNI_CLASS(ParcelFileDescriptorType, "android/os/ParcelFileDescriptor");
+Q_DECLARE_JNI_CLASS(CursorType, "android/database/Cursor");
+Q_DECLARE_JNI_TYPE(StringArray, "[Ljava/lang/String;");
+
+static QJniObject &contentResolverInstance()
+{
+ static QJniObject contentResolver;
+ if (!contentResolver.isValid()) {
+ contentResolver = QJniObject(QNativeInterface::QAndroidApplication::context())
+ .callMethod<QtJniTypes::ContentResolverType>("getContentResolver");
+ }
+
+ return contentResolver;
+}
+
+AndroidContentFileEngine::AndroidContentFileEngine(const QString &filename)
+ : m_initialFile(filename),
+ m_documentFile(DocumentFile::parseFromAnyUri(filename))
{
+ setFileName(filename);
}
-bool AndroidContentFileEngine::open(QIODevice::OpenMode openMode)
+bool AndroidContentFileEngine::open(QIODevice::OpenMode openMode,
+ std::optional<QFile::Permissions> permissions)
{
+ Q_UNUSED(permissions);
QString openModeStr;
if (openMode & QFileDevice::ReadOnly) {
- openModeStr += QLatin1Char('r');
+ openModeStr += u'r';
}
if (openMode & QFileDevice::WriteOnly) {
- openModeStr += QLatin1Char('w');
+ openModeStr += u'w';
+ if (!m_documentFile->exists()) {
+ if (QUrl(m_initialFile).path().startsWith("/tree/"_L1)) {
+ const int lastSeparatorIndex = m_initialFile.lastIndexOf('/');
+ const QString fileName = m_initialFile.mid(lastSeparatorIndex + 1);
+
+ QString mimeType;
+ const auto mimeTypes = QMimeDatabase().mimeTypesForFileName(fileName);
+ if (!mimeTypes.empty())
+ mimeType = mimeTypes.first().name();
+ else
+ mimeType = "application/octet-stream";
+
+ if (m_documentFile->parent()) {
+ auto createdFile = m_documentFile->parent()->createFile(mimeType, fileName);
+ if (createdFile)
+ m_documentFile = createdFile;
+ }
+ } else {
+ qWarning() << "open(): non-existent content URI with a document type provided";
+ }
+ }
}
if (openMode & QFileDevice::Truncate) {
- openModeStr += QLatin1Char('t');
+ openModeStr += u't';
} else if (openMode & QFileDevice::Append) {
- openModeStr += QLatin1Char('a');
+ openModeStr += u'a';
}
- const auto fd = QJNIObjectPrivate::callStaticMethod<jint>("org/qtproject/qt5/android/QtNative",
- "openFdForContentUrl",
- "(Landroid/content/Context;Ljava/lang/String;Ljava/lang/String;)I",
- QtAndroidPrivate::context(),
- QJNIObjectPrivate::fromString(fileName(DefaultName)).object(),
- QJNIObjectPrivate::fromString(openModeStr).object());
+ m_pfd = contentResolverInstance().callMethod<
+ QtJniTypes::ParcelFileDescriptorType, QtJniTypes::UriType, jstring>(
+ "openFileDescriptor",
+ m_documentFile->uri().object(),
+ QJniObject::fromString(openModeStr).object<jstring>());
+
+ if (!m_pfd.isValid())
+ return false;
+
+ const auto fd = m_pfd.callMethod<jint>("getFd");
if (fd < 0) {
+ closeNativeFileDescriptor();
+ return false;
+ }
+
+ return QFSFileEngine::open(openMode, fd, QFile::DontCloseHandle);
+}
+
+bool AndroidContentFileEngine::close()
+{
+ closeNativeFileDescriptor();
+ return QFSFileEngine::close();
+}
+
+void AndroidContentFileEngine::closeNativeFileDescriptor()
+{
+ if (m_pfd.isValid()) {
+ m_pfd.callMethod<void>("close");
+ m_pfd = QJniObject();
+ }
+}
+
+qint64 AndroidContentFileEngine::size() const
+{
+ return m_documentFile->length();
+}
+
+bool AndroidContentFileEngine::remove()
+{
+ return m_documentFile->remove();
+}
+
+bool AndroidContentFileEngine::rename(const QString &newName)
+{
+ if (m_documentFile->rename(newName)) {
+ m_initialFile = m_documentFile->uri().toString();
+ return true;
+ }
+ return false;
+}
+
+bool AndroidContentFileEngine::mkdir(const QString &dirName, bool createParentDirectories,
+ std::optional<QFileDevice::Permissions> permissions) const
+{
+ Q_UNUSED(permissions)
+
+ QString tmp = dirName;
+ tmp.remove(m_initialFile);
+
+ QStringList dirParts = tmp.split(u'/');
+ dirParts.removeAll("");
+
+ if (dirParts.isEmpty())
return false;
+
+ auto createdDir = m_documentFile;
+ bool allDirsCreated = true;
+ for (const auto &dir : dirParts) {
+ // Find if the sub-dir already exists and then don't re-create it
+ bool subDirExists = false;
+ for (const DocumentFilePtr &subDir : m_documentFile->listFiles()) {
+ if (dir == subDir->name() && subDir->isDirectory()) {
+ createdDir = subDir;
+ subDirExists = true;
+ }
+ }
+
+ if (!subDirExists) {
+ createdDir = createdDir->createDirectory(dir);
+ if (!createdDir) {
+ allDirsCreated = false;
+ break;
+ }
+ }
+
+ if (!createParentDirectories)
+ break;
+ }
+
+ return allDirsCreated;
+}
+
+bool AndroidContentFileEngine::rmdir(const QString &dirName, bool recurseParentDirectories) const
+{
+ if (recurseParentDirectories)
+ qWarning() << "rmpath(): Unsupported for Content URIs";
+
+ const QString dirFileName = QUrl(dirName).fileName();
+ bool deleted = false;
+ for (const DocumentFilePtr &dir : m_documentFile->listFiles()) {
+ if (dirFileName == dir->name() && dir->isDirectory()) {
+ deleted = dir->remove();
+ break;
+ }
+ }
+
+ return deleted;
+}
+
+QByteArray AndroidContentFileEngine::id() const
+{
+ return m_documentFile->id().toUtf8();
+}
+
+QDateTime AndroidContentFileEngine::fileTime(QFile::FileTime time) const
+{
+ switch (time) {
+ case QFile::FileModificationTime:
+ return m_documentFile->lastModified();
+ break;
+ default:
+ break;
}
- return QFSFileEngine::open(openMode, fd, QFile::AutoCloseHandle);
+ return QDateTime();
+}
+
+AndroidContentFileEngine::FileFlags AndroidContentFileEngine::fileFlags(FileFlags type) const
+{
+ FileFlags flags;
+ if (!m_documentFile->exists())
+ return flags;
+
+ flags = ExistsFlag;
+ if (!m_documentFile->canRead())
+ return flags;
+
+ flags |= ReadOwnerPerm|ReadUserPerm|ReadGroupPerm|ReadOtherPerm;
+
+ if (m_documentFile->isDirectory()) {
+ flags |= DirectoryType;
+ } else {
+ flags |= FileType;
+ if (m_documentFile->canWrite())
+ flags |= WriteOwnerPerm|WriteUserPerm|WriteGroupPerm|WriteOtherPerm;
+ }
+ return type & flags;
}
+QString AndroidContentFileEngine::fileName(FileName f) const
+{
+ switch (f) {
+ case PathName:
+ case AbsolutePathName:
+ case CanonicalPathName:
+ case DefaultName:
+ case AbsoluteName:
+ case CanonicalName:
+ return m_documentFile->uri().toString();
+ case BaseName:
+ return m_documentFile->name();
+ default:
+ break;
+ }
+
+ return QString();
+}
+
+QAbstractFileEngine::IteratorUniquePtr
+AndroidContentFileEngine::beginEntryList(const QString &path, QDir::Filters filters,
+ const QStringList &filterNames)
+{
+ return std::make_unique<AndroidContentFileEngineIterator>(path, filters, filterNames);
+}
AndroidContentFileEngineHandler::AndroidContentFileEngineHandler() = default;
AndroidContentFileEngineHandler::~AndroidContentFileEngineHandler() = default;
-QAbstractFileEngine* AndroidContentFileEngineHandler::create(const QString &fileName) const
+std::unique_ptr<QAbstractFileEngine>
+AndroidContentFileEngineHandler::create(const QString &fileName) const
+{
+ if (fileName.startsWith("content"_L1))
+ return std::make_unique<AndroidContentFileEngine>(fileName);
+
+ return {};
+
+}
+
+AndroidContentFileEngineIterator::AndroidContentFileEngineIterator(
+ const QString &path, QDir::Filters filters, const QStringList &filterNames)
+ : QAbstractFileEngineIterator(path, filters, filterNames)
+{
+}
+
+AndroidContentFileEngineIterator::~AndroidContentFileEngineIterator()
+{
+}
+
+bool AndroidContentFileEngineIterator::advance()
+{
+ if (m_index == -1 && m_files.isEmpty()) {
+ const auto currentPath = path();
+ if (currentPath.isEmpty())
+ return false;
+
+ const auto iterDoc = DocumentFile::parseFromAnyUri(currentPath);
+ if (iterDoc->isDirectory())
+ for (const auto &doc : iterDoc->listFiles())
+ m_files.append(doc);
+ if (m_files.isEmpty())
+ return false;
+ m_index = 0;
+ return true;
+ }
+
+ if (m_index < m_files.size() - 1) {
+ ++m_index;
+ return true;
+ }
+
+ return false;
+}
+
+QString AndroidContentFileEngineIterator::currentFileName() const
+{
+ if (m_index < 0 || m_index > m_files.size())
+ return QString();
+ return m_files.at(m_index)->name();
+}
+
+QString AndroidContentFileEngineIterator::currentFilePath() const
+{
+ if (m_index < 0 || m_index > m_files.size())
+ return QString();
+ return m_files.at(m_index)->uri().toString();
+}
+
+// Start of Cursor
+
+class Cursor
+{
+public:
+ explicit Cursor(const QJniObject &object)
+ : m_object{object} { }
+
+ ~Cursor()
+ {
+ if (m_object.isValid())
+ m_object.callMethod<void>("close");
+ }
+
+ enum Type {
+ FIELD_TYPE_NULL = 0x00000000,
+ FIELD_TYPE_INTEGER = 0x00000001,
+ FIELD_TYPE_FLOAT = 0x00000002,
+ FIELD_TYPE_STRING = 0x00000003,
+ FIELD_TYPE_BLOB = 0x00000004
+ };
+
+ QVariant data(int columnIndex) const
+ {
+ int type = m_object.callMethod<jint>("getType", columnIndex);
+ switch (type) {
+ case FIELD_TYPE_NULL:
+ return {};
+ case FIELD_TYPE_INTEGER:
+ return QVariant::fromValue(m_object.callMethod<jlong>("getLong", columnIndex));
+ case FIELD_TYPE_FLOAT:
+ return QVariant::fromValue(m_object.callMethod<jdouble>("getDouble", columnIndex));
+ case FIELD_TYPE_STRING:
+ return QVariant::fromValue(m_object.callMethod<jstring>("getString",
+ columnIndex).toString());
+ case FIELD_TYPE_BLOB: {
+ auto blob = m_object.callMethod<jbyteArray>("getBlob", columnIndex);
+ QJniEnvironment env;
+ const auto blobArray = blob.object<jbyteArray>();
+ const int size = env->GetArrayLength(blobArray);
+ const auto byteArray = env->GetByteArrayElements(blobArray, nullptr);
+ QByteArray data{reinterpret_cast<const char *>(byteArray), size};
+ env->ReleaseByteArrayElements(blobArray, byteArray, 0);
+ return QVariant::fromValue(data);
+ }
+ }
+ return {};
+ }
+
+ static std::unique_ptr<Cursor> queryUri(const QJniObject &uri,
+ const QStringList &projection = {},
+ const QString &selection = {},
+ const QStringList &selectionArgs = {},
+ const QString &sortOrder = {})
+ {
+ auto cursor = contentResolverInstance().callMethod<QtJniTypes::CursorType>(
+ "query",
+ uri.object<QtJniTypes::UriType>(),
+ projection.isEmpty() ?
+ nullptr : fromStringList(projection).object<QtJniTypes::StringArray>(),
+ selection.isEmpty() ? nullptr : QJniObject::fromString(selection).object<jstring>(),
+ selectionArgs.isEmpty() ?
+ nullptr : fromStringList(selectionArgs).object<QtJniTypes::StringArray>(),
+ sortOrder.isEmpty() ? nullptr : QJniObject::fromString(sortOrder).object<jstring>());
+ if (!cursor.isValid())
+ return {};
+ return std::make_unique<Cursor>(cursor);
+ }
+
+ static QVariant queryColumn(const QJniObject &uri, const QString &column)
+ {
+ const auto query = queryUri(uri, {column});
+ if (!query)
+ return {};
+
+ if (query->rowCount() != 1 || query->columnCount() != 1)
+ return {};
+ query->moveToFirst();
+ return query->data(0);
+ }
+
+ bool isNull(int columnIndex) const
+ {
+ return m_object.callMethod<jboolean>("isNull", columnIndex);
+ }
+
+ int columnCount() const { return m_object.callMethod<jint>("getColumnCount"); }
+ int rowCount() const { return m_object.callMethod<jint>("getCount"); }
+ int row() const { return m_object.callMethod<jint>("getPosition"); }
+ bool isFirst() const { return m_object.callMethod<jboolean>("isFirst"); }
+ bool isLast() const { return m_object.callMethod<jboolean>("isLast"); }
+ bool moveToFirst() { return m_object.callMethod<jboolean>("moveToFirst"); }
+ bool moveToLast() { return m_object.callMethod<jboolean>("moveToLast"); }
+ bool moveToNext() { return m_object.callMethod<jboolean>("moveToNext"); }
+
+private:
+ static QJniObject fromStringList(const QStringList &list)
+ {
+ QJniEnvironment env;
+ auto array = env->NewObjectArray(list.size(), env.findClass("java/lang/String"), nullptr);
+ for (int i = 0; i < list.size(); ++i)
+ env->SetObjectArrayElement(array, i, QJniObject::fromString(list[i]).object());
+ return QJniObject::fromLocalRef(array);
+ }
+
+ QJniObject m_object;
+};
+
+// End of Cursor
+
+// Start of DocumentsContract
+
+Q_DECLARE_JNI_CLASS(DocumentsContract, "android/provider/DocumentsContract");
+
+/*!
+ *
+ * DocumentsContract Api.
+ * Check https://developer.android.com/reference/android/provider/DocumentsContract
+ * for more information.
+ *
+ * \note This does not implement all facilities of the native API.
+ *
+ */
+namespace DocumentsContract
+{
+
+namespace Document {
+const QLatin1String COLUMN_DISPLAY_NAME("_display_name");
+const QLatin1String COLUMN_DOCUMENT_ID("document_id");
+const QLatin1String COLUMN_FLAGS("flags");
+const QLatin1String COLUMN_LAST_MODIFIED("last_modified");
+const QLatin1String COLUMN_MIME_TYPE("mime_type");
+const QLatin1String COLUMN_SIZE("_size");
+
+constexpr int FLAG_DIR_SUPPORTS_CREATE = 0x00000008;
+constexpr int FLAG_SUPPORTS_DELETE = 0x00000004;
+constexpr int FLAG_SUPPORTS_MOVE = 0x00000100;
+constexpr int FLAG_SUPPORTS_RENAME = 0x00000040;
+constexpr int FLAG_SUPPORTS_WRITE = 0x00000002;
+constexpr int FLAG_VIRTUAL_DOCUMENT = 0x00000200;
+
+const QLatin1String MIME_TYPE_DIR("vnd.android.document/directory");
+} // namespace Document
+
+QString documentId(const QJniObject &uri)
+{
+ return QJniObject::callStaticMethod<jstring, QtJniTypes::UriType>(
+ QtJniTypes::Traits<QtJniTypes::DocumentsContract>::className(),
+ "getDocumentId",
+ uri.object()).toString();
+}
+
+QString treeDocumentId(const QJniObject &uri)
+{
+ return QJniObject::callStaticMethod<jstring, QtJniTypes::UriType>(
+ QtJniTypes::Traits<QtJniTypes::DocumentsContract>::className(),
+ "getTreeDocumentId",
+ uri.object()).toString();
+}
+
+QJniObject buildChildDocumentsUriUsingTree(const QJniObject &uri, const QString &parentDocumentId)
{
- if (!fileName.startsWith(QLatin1String("content"))) {
- return nullptr;
+ return QJniObject::callStaticMethod<QtJniTypes::UriType>(
+ QtJniTypes::Traits<QtJniTypes::DocumentsContract>::className(),
+ "buildChildDocumentsUriUsingTree",
+ uri.object<QtJniTypes::UriType>(),
+ QJniObject::fromString(parentDocumentId).object<jstring>());
+
+}
+
+QJniObject buildDocumentUriUsingTree(const QJniObject &treeUri, const QString &documentId)
+{
+ return QJniObject::callStaticMethod<QtJniTypes::UriType>(
+ QtJniTypes::Traits<QtJniTypes::DocumentsContract>::className(),
+ "buildDocumentUriUsingTree",
+ treeUri.object<QtJniTypes::UriType>(),
+ QJniObject::fromString(documentId).object<jstring>());
+}
+
+bool isDocumentUri(const QJniObject &uri)
+{
+ return QJniObject::callStaticMethod<jboolean>(
+ QtJniTypes::Traits<QtJniTypes::DocumentsContract>::className(),
+ "isDocumentUri",
+ QNativeInterface::QAndroidApplication::context(),
+ uri.object<QtJniTypes::UriType>());
+}
+
+bool isTreeUri(const QJniObject &uri)
+{
+ return QJniObject::callStaticMethod<jboolean>(
+ QtJniTypes::Traits<QtJniTypes::DocumentsContract>::className(),
+ "isTreeUri",
+ uri.object<QtJniTypes::UriType>());
+}
+
+QJniObject createDocument(const QJniObject &parentDocumentUri, const QString &mimeType,
+ const QString &displayName)
+{
+ return QJniObject::callStaticMethod<QtJniTypes::UriType>(
+ QtJniTypes::Traits<QtJniTypes::DocumentsContract>::className(),
+ "createDocument",
+ contentResolverInstance().object<QtJniTypes::ContentResolverType>(),
+ parentDocumentUri.object<QtJniTypes::UriType>(),
+ QJniObject::fromString(mimeType).object<jstring>(),
+ QJniObject::fromString(displayName).object<jstring>());
+}
+
+bool deleteDocument(const QJniObject &documentUri)
+{
+ const int flags = Cursor::queryColumn(documentUri, Document::COLUMN_FLAGS).toInt();
+ if (!(flags & Document::FLAG_SUPPORTS_DELETE))
+ return {};
+
+ return QJniObject::callStaticMethod<jboolean>(
+ QtJniTypes::Traits<QtJniTypes::DocumentsContract>::className(),
+ "deleteDocument",
+ contentResolverInstance().object<QtJniTypes::ContentResolverType>(),
+ documentUri.object<QtJniTypes::UriType>());
+}
+
+QJniObject moveDocument(const QJniObject &sourceDocumentUri,
+ const QJniObject &sourceParentDocumentUri,
+ const QJniObject &targetParentDocumentUri)
+{
+ const int flags = Cursor::queryColumn(sourceDocumentUri, Document::COLUMN_FLAGS).toInt();
+ if (!(flags & Document::FLAG_SUPPORTS_MOVE))
+ return {};
+
+ return QJniObject::callStaticMethod<QtJniTypes::UriType>(
+ QtJniTypes::Traits<QtJniTypes::DocumentsContract>::className(),
+ "moveDocument",
+ contentResolverInstance().object<QtJniTypes::ContentResolverType>(),
+ sourceDocumentUri.object<QtJniTypes::UriType>(),
+ sourceParentDocumentUri.object<QtJniTypes::UriType>(),
+ targetParentDocumentUri.object<QtJniTypes::UriType>());
+}
+
+QJniObject renameDocument(const QJniObject &documentUri, const QString &displayName)
+{
+ const int flags = Cursor::queryColumn(documentUri, Document::COLUMN_FLAGS).toInt();
+ if (!(flags & Document::FLAG_SUPPORTS_RENAME))
+ return {};
+
+ return QJniObject::callStaticMethod<QtJniTypes::UriType>(
+ QtJniTypes::Traits<QtJniTypes::DocumentsContract>::className(),
+ "renameDocument",
+ contentResolverInstance().object<QtJniTypes::ContentResolverType>(),
+ documentUri.object<QtJniTypes::UriType>(),
+ QJniObject::fromString(displayName).object<jstring>());
+}
+} // End DocumentsContract namespace
+
+// Start of DocumentFile
+
+using namespace DocumentsContract;
+
+namespace {
+class MakeableDocumentFile : public DocumentFile
+{
+public:
+ MakeableDocumentFile(const QJniObject &uri, const DocumentFilePtr &parent = {})
+ : DocumentFile(uri, parent)
+ {}
+};
+}
+
+DocumentFile::DocumentFile(const QJniObject &uri,
+ const DocumentFilePtr &parent)
+ : m_uri{uri}
+ , m_parent{parent}
+{}
+
+QJniObject parseUri(const QString &uri)
+{
+ QString uriToParse = uri;
+ if (uriToParse.contains(' '))
+ uriToParse.replace(' ', QUrl::toPercentEncoding(" "));
+
+ return QJniObject::callStaticMethod<QtJniTypes::UriType>(
+ QtJniTypes::Traits<QtJniTypes::Uri>::className(),
+ "parse",
+ QJniObject::fromString(uriToParse).object<jstring>());
+}
+
+DocumentFilePtr DocumentFile::parseFromAnyUri(const QString &fileName)
+{
+ const QString encodedUri = QUrl(fileName).toEncoded();
+ const QJniObject uri = parseUri(encodedUri);
+
+ if (DocumentsContract::isDocumentUri(uri) || !DocumentsContract::isTreeUri(uri))
+ return fromSingleUri(uri);
+
+ const QString documentType = "/document/"_L1;
+ const QString treeType = "/tree/"_L1;
+
+ const int treeIndex = encodedUri.indexOf(treeType);
+ const int documentIndex = encodedUri.indexOf(documentType);
+ const int index = fileName.lastIndexOf("/");
+
+ if (index <= treeIndex + treeType.size() || index <= documentIndex + documentType.size())
+ return fromTreeUri(uri);
+
+ const QString parentUrl = encodedUri.left(index);
+ DocumentFilePtr parentDocFile = fromTreeUri(parseUri(parentUrl));
+
+ const QString baseName = encodedUri.mid(index);
+ const QString fileUrl = parentUrl + QUrl::toPercentEncoding(baseName);
+
+ DocumentFilePtr docFile = std::make_shared<MakeableDocumentFile>(parseUri(fileUrl));
+ if (parentDocFile && parentDocFile->isDirectory())
+ docFile->m_parent = parentDocFile;
+
+ return docFile;
+}
+
+DocumentFilePtr DocumentFile::fromSingleUri(const QJniObject &uri)
+{
+ return std::make_shared<MakeableDocumentFile>(uri);
+}
+
+DocumentFilePtr DocumentFile::fromTreeUri(const QJniObject &treeUri)
+{
+ QString docId;
+ if (isDocumentUri(treeUri))
+ docId = documentId(treeUri);
+ else
+ docId = treeDocumentId(treeUri);
+
+ return std::make_shared<MakeableDocumentFile>(buildDocumentUriUsingTree(treeUri, docId));
+}
+
+DocumentFilePtr DocumentFile::createFile(const QString &mimeType, const QString &displayName)
+{
+ if (isDirectory()) {
+ return std::make_shared<MakeableDocumentFile>(
+ createDocument(m_uri, mimeType, displayName),
+ shared_from_this());
}
+ return {};
+}
+
+DocumentFilePtr DocumentFile::createDirectory(const QString &displayName)
+{
+ if (isDirectory()) {
+ return std::make_shared<MakeableDocumentFile>(
+ createDocument(m_uri, Document::MIME_TYPE_DIR, displayName),
+ shared_from_this());
+ }
+ return {};
+}
- return new AndroidContentFileEngine(fileName);
+const QJniObject &DocumentFile::uri() const
+{
+ return m_uri;
}
+
+const DocumentFilePtr &DocumentFile::parent() const
+{
+ return m_parent;
+}
+
+QString DocumentFile::name() const
+{
+ return Cursor::queryColumn(m_uri, Document::COLUMN_DISPLAY_NAME).toString();
+}
+
+QString DocumentFile::id() const
+{
+ return DocumentsContract::documentId(uri());
+}
+
+QString DocumentFile::mimeType() const
+{
+ return Cursor::queryColumn(m_uri, Document::COLUMN_MIME_TYPE).toString();
+}
+
+bool DocumentFile::isDirectory() const
+{
+ return mimeType() == Document::MIME_TYPE_DIR;
+}
+
+bool DocumentFile::isFile() const
+{
+ const QString type = mimeType();
+ return type != Document::MIME_TYPE_DIR && !type.isEmpty();
+}
+
+bool DocumentFile::isVirtual() const
+{
+ return isDocumentUri(m_uri) && (Cursor::queryColumn(m_uri,
+ Document::COLUMN_FLAGS).toInt() & Document::FLAG_VIRTUAL_DOCUMENT);
+}
+
+QDateTime DocumentFile::lastModified() const
+{
+ const auto timeVariant = Cursor::queryColumn(m_uri, Document::COLUMN_LAST_MODIFIED);
+ if (timeVariant.isValid())
+ return QDateTime::fromMSecsSinceEpoch(timeVariant.toLongLong());
+ return {};
+}
+
+int64_t DocumentFile::length() const
+{
+ return Cursor::queryColumn(m_uri, Document::COLUMN_SIZE).toLongLong();
+}
+
+namespace {
+constexpr int FLAG_GRANT_READ_URI_PERMISSION = 0x00000001;
+constexpr int FLAG_GRANT_WRITE_URI_PERMISSION = 0x00000002;
+}
+
+bool DocumentFile::canRead() const
+{
+ const auto context = QJniObject(QNativeInterface::QAndroidApplication::context());
+ const bool selfUriPermission = context.callMethod<jint>("checkCallingOrSelfUriPermission",
+ m_uri.object<QtJniTypes::UriType>(),
+ FLAG_GRANT_READ_URI_PERMISSION);
+ if (selfUriPermission != 0)
+ return false;
+
+ return !mimeType().isEmpty();
+}
+
+bool DocumentFile::canWrite() const
+{
+ const auto context = QJniObject(QNativeInterface::QAndroidApplication::context());
+ const bool selfUriPermission = context.callMethod<jint>("checkCallingOrSelfUriPermission",
+ m_uri.object<QtJniTypes::UriType>(),
+ FLAG_GRANT_WRITE_URI_PERMISSION);
+ if (selfUriPermission != 0)
+ return false;
+
+ const QString type = mimeType();
+ if (type.isEmpty())
+ return false;
+
+ const int flags = Cursor::queryColumn(m_uri, Document::COLUMN_FLAGS).toInt();
+ if (flags & Document::FLAG_SUPPORTS_DELETE)
+ return true;
+
+ const bool supportsWrite = (flags & Document::FLAG_SUPPORTS_WRITE);
+ const bool isDir = (type == Document::MIME_TYPE_DIR);
+ const bool dirSupportsCreate = (isDir && (flags & Document::FLAG_DIR_SUPPORTS_CREATE));
+
+ return dirSupportsCreate || supportsWrite;
+}
+
+bool DocumentFile::remove()
+{
+ return deleteDocument(m_uri);
+}
+
+bool DocumentFile::exists() const
+{
+ return !name().isEmpty();
+}
+
+std::vector<DocumentFilePtr> DocumentFile::listFiles()
+{
+ std::vector<DocumentFilePtr> res;
+ const auto childrenUri = buildChildDocumentsUriUsingTree(m_uri, documentId(m_uri));
+ const auto query = Cursor::queryUri(childrenUri, {Document::COLUMN_DOCUMENT_ID});
+ if (!query)
+ return res;
+
+ while (query->moveToNext()) {
+ const auto uri = buildDocumentUriUsingTree(m_uri, query->data(0).toString());
+ res.push_back(std::make_shared<MakeableDocumentFile>(uri, shared_from_this()));
+ }
+ return res;
+}
+
+bool DocumentFile::rename(const QString &newName)
+{
+ QJniObject uri;
+ if (newName.startsWith("content://"_L1)) {
+ auto lastSeparatorIndex = [](const QString &file) {
+ int posDecoded = file.lastIndexOf("/");
+ int posEncoded = file.lastIndexOf(QUrl::toPercentEncoding("/"));
+ return posEncoded > posDecoded ? posEncoded : posDecoded;
+ };
+
+ // first try to see if the new file is under the same tree and thus used rename only
+ const QString parent = m_uri.toString().left(lastSeparatorIndex(m_uri.toString()));
+ if (newName.contains(parent)) {
+ QString displayName = newName.mid(lastSeparatorIndex(newName));
+ if (displayName.startsWith('/'))
+ displayName.remove(0, 1);
+ else if (displayName.startsWith(QUrl::toPercentEncoding("/")))
+ displayName.remove(0, 3);
+
+ uri = renameDocument(m_uri, displayName);
+ } else {
+ // Move
+ QJniObject srcParentUri = fromTreeUri(parseUri(parent))->uri();
+ const QString destParent = newName.left(lastSeparatorIndex(newName));
+ QJniObject targetParentUri = fromTreeUri(parseUri(destParent))->uri();
+ uri = moveDocument(m_uri, srcParentUri, targetParentUri);
+ }
+ } else {
+ uri = renameDocument(m_uri, newName);
+ }
+
+ if (uri.isValid()) {
+ m_uri = uri;
+ return true;
+ }
+
+ return false;
+}
+
+QT_END_NAMESPACE
+
+// End of DocumentFile
diff --git a/src/plugins/platforms/android/androidcontentfileengine.h b/src/plugins/platforms/android/androidcontentfileengine.h
index db3def03d6..11d0cd7201 100644
--- a/src/plugins/platforms/android/androidcontentfileengine.h
+++ b/src/plugins/platforms/android/androidcontentfileengine.h
@@ -1,52 +1,44 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 Volker Krause <vkrause@kde.org>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2019 Volker Krause <vkrause@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef ANDROIDCONTENTFILEENGINE_H
#define ANDROIDCONTENTFILEENGINE_H
#include <private/qfsfileengine_p.h>
+#include <QtCore/qjniobject.h>
+#include <QtCore/qlist.h>
+
+QT_BEGIN_NAMESPACE
+
+using DocumentFilePtr = std::shared_ptr<class DocumentFile>;
+
class AndroidContentFileEngine : public QFSFileEngine
{
public:
AndroidContentFileEngine(const QString &fileName);
- bool open(QIODevice::OpenMode openMode) override;
+ bool open(QIODevice::OpenMode openMode, std::optional<QFile::Permissions> permissions) override;
+ bool close() override;
+ qint64 size() const override;
+ bool remove() override;
+ bool rename(const QString &newName) override;
+ bool mkdir(const QString &dirName, bool createParentDirectories,
+ std::optional<QFile::Permissions> permissions = std::nullopt) const override;
+ bool rmdir(const QString &dirName, bool recurseParentDirectories) const override;
+ QByteArray id() const override;
+ bool caseSensitive() const override { return true; }
+ QDateTime fileTime(QFile::FileTime time) const override;
+ FileFlags fileFlags(FileFlags type = FileInfoAll) const override;
+ QString fileName(FileName file = DefaultName) const override;
+ IteratorUniquePtr beginEntryList(const QString &path, QDir::Filters filters,
+ const QStringList &filterNames) override;
+
+private:
+ void closeNativeFileDescriptor();
+
+ QString m_initialFile;
+ QJniObject m_pfd;
+ DocumentFilePtr m_documentFile;
};
class AndroidContentFileEngineHandler : public QAbstractFileEngineHandler
@@ -54,7 +46,66 @@ class AndroidContentFileEngineHandler : public QAbstractFileEngineHandler
public:
AndroidContentFileEngineHandler();
~AndroidContentFileEngineHandler();
- QAbstractFileEngine *create(const QString &fileName) const override;
+ std::unique_ptr<QAbstractFileEngine> create(const QString &fileName) const override;
};
+class AndroidContentFileEngineIterator : public QAbstractFileEngineIterator
+{
+public:
+ AndroidContentFileEngineIterator(const QString &path, QDir::Filters filters,
+ const QStringList &filterNames);
+ ~AndroidContentFileEngineIterator();
+
+ bool advance() override;
+
+ QString currentFileName() const override;
+ QString currentFilePath() const override;
+private:
+ mutable QList<DocumentFilePtr> m_files;
+ mutable qsizetype m_index = -1;
+};
+
+/*!
+ *
+ * DocumentFile Api.
+ * Check https://developer.android.com/reference/androidx/documentfile/provider/DocumentFile
+ * for more information.
+ *
+ */
+class DocumentFile : public std::enable_shared_from_this<DocumentFile>
+{
+public:
+ static DocumentFilePtr parseFromAnyUri(const QString &filename);
+ static DocumentFilePtr fromSingleUri(const QJniObject &uri);
+ static DocumentFilePtr fromTreeUri(const QJniObject &treeUri);
+
+ DocumentFilePtr createFile(const QString &mimeType, const QString &displayName);
+ DocumentFilePtr createDirectory(const QString &displayName);
+ const QJniObject &uri() const;
+ const DocumentFilePtr &parent() const;
+ QString name() const;
+ QString id() const;
+ QString mimeType() const;
+ bool isDirectory() const;
+ bool isFile() const;
+ bool isVirtual() const;
+ QDateTime lastModified() const;
+ int64_t length() const;
+ bool canRead() const;
+ bool canWrite() const;
+ bool remove();
+ bool exists() const;
+ std::vector<DocumentFilePtr> listFiles();
+ bool rename(const QString &newName);
+
+protected:
+ DocumentFile(const QJniObject &uri, const std::shared_ptr<DocumentFile> &parent);
+
+protected:
+ QJniObject m_uri;
+ DocumentFilePtr m_parent;
+};
+
+QT_END_NAMESPACE
+
#endif // ANDROIDCONTENTFILEENGINE_H
diff --git a/src/plugins/platforms/android/androiddeadlockprotector.cpp b/src/plugins/platforms/android/androiddeadlockprotector.cpp
deleted file mode 100644
index 2bac55f160..0000000000
--- a/src/plugins/platforms/android/androiddeadlockprotector.cpp
+++ /dev/null
@@ -1,43 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 "androiddeadlockprotector.h"
-
-QAtomicInt AndroidDeadlockProtector::s_blocked(0);
-
diff --git a/src/plugins/platforms/android/androiddeadlockprotector.h b/src/plugins/platforms/android/androiddeadlockprotector.h
index 7fa5bcfcb9..22b0bed523 100644
--- a/src/plugins/platforms/android/androiddeadlockprotector.h
+++ b/src/plugins/platforms/android/androiddeadlockprotector.h
@@ -1,70 +1,28 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef ANDROID_DEADLOCKPROTECTOR_H
#define ANDROID_DEADLOCKPROTECTOR_H
-#include <QAtomicInt>
+#include <QtCore/private/qjnihelpers_p.h>
QT_BEGIN_NAMESPACE
class AndroidDeadlockProtector
{
public:
- AndroidDeadlockProtector()
- : m_acquired(0)
- {
- }
-
~AndroidDeadlockProtector() {
if (m_acquired)
- s_blocked.storeRelease(0);
+ QtAndroidPrivate::releaseAndroidDeadlockProtector();
}
bool acquire() {
- m_acquired = s_blocked.testAndSetAcquire(0, 1);
+ m_acquired = QtAndroidPrivate::acquireAndroidDeadlockProtector();
return m_acquired;
}
private:
- static QAtomicInt s_blocked;
- int m_acquired;
+ bool m_acquired = false;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/android/androidjniaccessibility.cpp b/src/plugins/platforms/android/androidjniaccessibility.cpp
index d4b7f38bf6..8f1c76ca26 100644
--- a/src/plugins/platforms/android/androidjniaccessibility.cpp
+++ b/src/plugins/platforms/android/androidjniaccessibility.cpp
@@ -1,63 +1,31 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+#include "androiddeadlockprotector.h"
#include "androidjniaccessibility.h"
#include "androidjnimain.h"
#include "qandroidplatformintegration.h"
#include "qpa/qplatformaccessibility.h"
-#include <QtAccessibilitySupport/private/qaccessiblebridgeutils_p.h>
+#include <QtGui/private/qaccessiblebridgeutils_p.h>
#include "qguiapplication.h"
#include "qwindow.h"
#include "qrect.h"
#include "QtGui/qaccessible.h"
#include <QtCore/qmath.h>
#include <QtCore/private/qjnihelpers_p.h>
-#include <QtCore/private/qjni_p.h>
+#include <QtCore/QJniObject>
#include <QtGui/private/qhighdpiscaling_p.h>
-#include "qdebug.h"
+#include <QtCore/QObject>
+#include <QtCore/qpointer.h>
+#include <QtCore/qvarlengtharray.h>
static const char m_qtTag[] = "Qt A11Y";
-static const char m_classErrorMsg[] = "Can't find class \"%s\"";
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
namespace QtAndroidAccessibility
{
static jmethodID m_addActionMethodID = 0;
@@ -65,32 +33,77 @@ namespace QtAndroidAccessibility
static jmethodID m_setCheckedMethodID = 0;
static jmethodID m_setClickableMethodID = 0;
static jmethodID m_setContentDescriptionMethodID = 0;
+ static jmethodID m_setEditableMethodID = 0;
static jmethodID m_setEnabledMethodID = 0;
static jmethodID m_setFocusableMethodID = 0;
static jmethodID m_setFocusedMethodID = 0;
+ static jmethodID m_setHeadingMethodID = 0;
static jmethodID m_setScrollableMethodID = 0;
static jmethodID m_setTextSelectionMethodID = 0;
static jmethodID m_setVisibleToUserMethodID = 0;
+ static bool m_accessibilityActivated = false;
+
+ // This object is needed to schedule the execution of the code that
+ // deals with accessibility instances to the Qt main thread.
+ // Because of that almost every method here is split into two parts.
+ // The _helper part is executed in the context of m_accessibilityContext
+ // on the main thread. The other part is executed in Java thread.
+ Q_CONSTINIT static QPointer<QObject> m_accessibilityContext = {};
+
+ // This method is called from the Qt main thread, and normally a
+ // QGuiApplication instance will be used as a parent.
+ void createAccessibilityContextObject(QObject *parent)
+ {
+ if (m_accessibilityContext)
+ m_accessibilityContext->deleteLater();
+ m_accessibilityContext = new QObject(parent);
+ }
+
+ template <typename Func, typename Ret>
+ void runInObjectContext(QObject *context, Func &&func, Ret *retVal)
+ {
+ AndroidDeadlockProtector protector;
+ if (!protector.acquire()) {
+ __android_log_print(ANDROID_LOG_WARN, m_qtTag,
+ "Could not run accessibility call in object context, accessing "
+ "main thread could lead to deadlock");
+ return;
+ }
+
+ if (!QtAndroid::blockEventLoopsWhenSuspended()
+ || QGuiApplication::applicationState() != Qt::ApplicationSuspended) {
+ QMetaObject::invokeMethod(context, func, Qt::BlockingQueuedConnection, retVal);
+ } else {
+ __android_log_print(ANDROID_LOG_WARN, m_qtTag,
+ "Could not run accessibility call in object context, event loop suspended.");
+ }
+ }
+
void initialize()
{
- QJNIObjectPrivate::callStaticMethod<void>(QtAndroid::applicationClass(),
- "initializeAccessibility");
+ QtAndroid::qtActivityDelegate().callMethod<void>("initializeAccessibility");
+ }
+
+ bool isActive()
+ {
+ return m_accessibilityActivated;
}
static void setActive(JNIEnv */*env*/, jobject /*thiz*/, jboolean active)
{
QMutexLocker lock(QtAndroid::platformInterfaceMutex());
QAndroidPlatformIntegration *platformIntegration = QtAndroid::androidPlatformIntegration();
+ m_accessibilityActivated = active;
if (platformIntegration)
platformIntegration->accessibility()->setActive(active);
else
- __android_log_print(ANDROID_LOG_WARN, m_qtTag, "Could not activate platform accessibility.");
+ __android_log_print(ANDROID_LOG_WARN, m_qtTag, "Could not (yet) activate platform accessibility.");
}
QAccessibleInterface *interfaceFromId(jint objectId)
{
- QAccessibleInterface *iface = 0;
+ QAccessibleInterface *iface = nullptr;
if (objectId == -1) {
QWindow *win = qApp->focusWindow();
if (win)
@@ -101,7 +114,38 @@ namespace QtAndroidAccessibility
return iface;
}
- static jintArray childIdListForAccessibleObject(JNIEnv *env, jobject /*thiz*/, jint objectId)
+ void notifyLocationChange(uint accessibilityObjectId)
+ {
+ QtAndroid::notifyAccessibilityLocationChange(accessibilityObjectId);
+ }
+
+ static int parentId_helper(int objectId); // forward declaration
+
+ void notifyObjectHide(uint accessibilityObjectId)
+ {
+ const auto parentObjectId = parentId_helper(accessibilityObjectId);
+ QtAndroid::notifyObjectHide(accessibilityObjectId, parentObjectId);
+ }
+
+ void notifyObjectFocus(uint accessibilityObjectId)
+ {
+ QtAndroid::notifyObjectFocus(accessibilityObjectId);
+ }
+
+ static jstring jvalueForAccessibleObject(int objectId); // forward declaration
+
+ void notifyValueChanged(uint accessibilityObjectId)
+ {
+ jstring value = jvalueForAccessibleObject(accessibilityObjectId);
+ QtAndroid::notifyValueChanged(accessibilityObjectId, value);
+ }
+
+ void notifyScrolledEvent(uint accessiblityObjectId)
+ {
+ QtAndroid::notifyScrolledEvent(accessiblityObjectId);
+ }
+
+ static QVarLengthArray<int, 8> childIdListForAccessibleObject_helper(int objectId)
{
QAccessibleInterface *iface = interfaceFromId(objectId);
if (iface && iface->isValid()) {
@@ -113,6 +157,18 @@ namespace QtAndroidAccessibility
if (child && child->isValid())
ifaceIdArray.append(QAccessible::uniqueId(child));
}
+ return ifaceIdArray;
+ }
+ return {};
+ }
+
+ static jintArray childIdListForAccessibleObject(JNIEnv *env, jobject /*thiz*/, jint objectId)
+ {
+ if (m_accessibilityContext) {
+ QVarLengthArray<jint, 8> ifaceIdArray;
+ runInObjectContext(m_accessibilityContext, [objectId]() {
+ return childIdListForAccessibleObject_helper(objectId);
+ }, &ifaceIdArray);
jintArray jArray = env->NewIntArray(jsize(ifaceIdArray.count()));
env->SetIntArrayRegion(jArray, 0, ifaceIdArray.count(), ifaceIdArray.data());
return jArray;
@@ -121,7 +177,7 @@ namespace QtAndroidAccessibility
return env->NewIntArray(jsize(0));
}
- static jint parentId(JNIEnv */*env*/, jobject /*thiz*/, jint objectId)
+ static int parentId_helper(int objectId)
{
QAccessibleInterface *iface = interfaceFromId(objectId);
if (iface && iface->isValid()) {
@@ -135,28 +191,54 @@ namespace QtAndroidAccessibility
return -1;
}
- static jobject screenRect(JNIEnv *env, jobject /*thiz*/, jint objectId)
+ static jint parentId(JNIEnv */*env*/, jobject /*thiz*/, jint objectId)
+ {
+ jint result = -1;
+ if (m_accessibilityContext) {
+ runInObjectContext(m_accessibilityContext, [objectId]() {
+ return parentId_helper(objectId);
+ }, &result);
+ }
+ return result;
+ }
+
+ static QRect screenRect_helper(int objectId, bool clip = true)
{
QRect rect;
QAccessibleInterface *iface = interfaceFromId(objectId);
if (iface && iface->isValid()) {
rect = QHighDpi::toNativePixels(iface->rect(), iface->window());
}
+ // If the widget is not fully in-bound in its parent then we have to clip the rectangle to draw
+ if (clip && iface && iface->parent() && iface->parent()->isValid()) {
+ const auto parentRect = QHighDpi::toNativePixels(iface->parent()->rect(), iface->parent()->window());
+ rect = rect.intersected(parentRect);
+ }
+ return rect;
+ }
+ static jobject screenRect(JNIEnv *env, jobject /*thiz*/, jint objectId)
+ {
+ QRect rect;
+ if (m_accessibilityContext) {
+ runInObjectContext(m_accessibilityContext, [objectId]() {
+ return screenRect_helper(objectId);
+ }, &rect);
+ }
jclass rectClass = env->FindClass("android/graphics/Rect");
jmethodID ctor = env->GetMethodID(rectClass, "<init>", "(IIII)V");
jobject jrect = env->NewObject(rectClass, ctor, rect.left(), rect.top(), rect.right(), rect.bottom());
return jrect;
}
- static jint hitTest(JNIEnv */*env*/, jobject /*thiz*/, jfloat x, jfloat y)
+ static int hitTest_helper(float x, float y)
{
QAccessibleInterface *root = interfaceFromId(-1);
if (root && root->isValid()) {
QPoint pos = QHighDpi::fromNativePixels(QPoint(int(x), int(y)), root->window());
QAccessibleInterface *child = root->childAt(pos.x(), pos.y());
- QAccessibleInterface *lastChild = 0;
+ QAccessibleInterface *lastChild = nullptr;
while (child && (child != lastChild)) {
lastChild = child;
child = child->childAt(pos.x(), pos.y());
@@ -167,127 +249,305 @@ namespace QtAndroidAccessibility
return -1;
}
- static jboolean clickAction(JNIEnv */*env*/, jobject /*thiz*/, jint objectId)
+ static jint hitTest(JNIEnv */*env*/, jobject /*thiz*/, jfloat x, jfloat y)
{
-// qDebug() << "A11Y: CLICK: " << objectId;
- QAccessibleInterface *iface = interfaceFromId(objectId);
- if (iface && iface->isValid() && iface->actionInterface()) {
- if (iface->actionInterface()->actionNames().contains(QAccessibleActionInterface::pressAction()))
- iface->actionInterface()->doAction(QAccessibleActionInterface::pressAction());
- else
- iface->actionInterface()->doAction(QAccessibleActionInterface::toggleAction());
+ jint result = -1;
+ if (m_accessibilityContext) {
+ runInObjectContext(m_accessibilityContext, [x, y]() {
+ return hitTest_helper(x, y);
+ }, &result);
}
- return false;
+ return result;
}
- static jboolean scrollForward(JNIEnv */*env*/, jobject /*thiz*/, jint objectId)
+ static void invokeActionOnInterfaceInMainThread(QAccessibleActionInterface* actionInterface,
+ const QString& action)
+ {
+ // Queue the action and return back to Java thread, so that we do not
+ // block it for too long
+ QMetaObject::invokeMethod(qApp, [actionInterface, action]() {
+ actionInterface->doAction(action);
+ }, Qt::QueuedConnection);
+ }
+
+ static bool clickAction_helper(int objectId)
{
QAccessibleInterface *iface = interfaceFromId(objectId);
- if (iface && iface->isValid())
- return QAccessibleBridgeUtils::performEffectiveAction(iface, QAccessibleActionInterface::increaseAction());
- return false;
+ if (!iface || !iface->isValid() || !iface->actionInterface())
+ return false;
+
+ const auto& actionNames = iface->actionInterface()->actionNames();
+
+ if (actionNames.contains(QAccessibleActionInterface::pressAction())) {
+ invokeActionOnInterfaceInMainThread(iface->actionInterface(),
+ QAccessibleActionInterface::pressAction());
+ } else if (actionNames.contains(QAccessibleActionInterface::toggleAction())) {
+ invokeActionOnInterfaceInMainThread(iface->actionInterface(),
+ QAccessibleActionInterface::toggleAction());
+ } else {
+ return false;
+ }
+ return true;
}
- static jboolean scrollBackward(JNIEnv */*env*/, jobject /*thiz*/, jint objectId)
+ static jboolean clickAction(JNIEnv */*env*/, jobject /*thiz*/, jint objectId)
+ {
+ bool result = false;
+ if (m_accessibilityContext) {
+ runInObjectContext(m_accessibilityContext, [objectId]() {
+ return clickAction_helper(objectId);
+ }, &result);
+ }
+ return result;
+ }
+
+ static bool scroll_helper(int objectId, const QString &actionName)
{
QAccessibleInterface *iface = interfaceFromId(objectId);
if (iface && iface->isValid())
- return QAccessibleBridgeUtils::performEffectiveAction(iface, QAccessibleActionInterface::decreaseAction());
+ return QAccessibleBridgeUtils::performEffectiveAction(iface, actionName);
return false;
}
+ static jboolean scrollForward(JNIEnv */*env*/, jobject /*thiz*/, jint objectId)
+ {
+ bool result = false;
-#define FIND_AND_CHECK_CLASS(CLASS_NAME) \
-clazz = env->FindClass(CLASS_NAME); \
-if (!clazz) { \
- __android_log_print(ANDROID_LOG_FATAL, m_qtTag, m_classErrorMsg, CLASS_NAME); \
- return JNI_FALSE; \
-}
+ const auto& ids = childIdListForAccessibleObject_helper(objectId);
+ if (ids.isEmpty())
+ return false;
- //__android_log_print(ANDROID_LOG_FATAL, m_qtTag, m_methodErrorMsg, METHOD_NAME, METHOD_SIGNATURE);
+ const int firstChildId = ids.first();
+ const QRect oldPosition = screenRect_helper(firstChildId, false);
+ if (m_accessibilityContext) {
+ runInObjectContext(m_accessibilityContext, [objectId]() {
+ return scroll_helper(objectId, QAccessibleActionInterface::increaseAction());
+ }, &result);
+ }
+ // Don't check for position change if the call was not successful
+ return result && oldPosition != screenRect_helper(firstChildId, false);
+ }
+
+ static jboolean scrollBackward(JNIEnv */*env*/, jobject /*thiz*/, jint objectId)
+ {
+ bool result = false;
+
+ const auto& ids = childIdListForAccessibleObject_helper(objectId);
+ if (ids.isEmpty())
+ return false;
+
+ const int firstChildId = ids.first();
+ const QRect oldPosition = screenRect_helper(firstChildId, false);
+
+ if (m_accessibilityContext) {
+ runInObjectContext(m_accessibilityContext, [objectId]() {
+ return scroll_helper(objectId, QAccessibleActionInterface::decreaseAction());
+ }, &result);
+ }
+
+ // Don't check for position change if the call was not successful
+ return result && oldPosition != screenRect_helper(firstChildId, false);
+ }
- static jstring descriptionForAccessibleObject_helper(JNIEnv *env, QAccessibleInterface *iface)
+ static QString textFromValue(QAccessibleInterface *iface)
+ {
+ QString valueStr;
+ QAccessibleValueInterface *valueIface = iface->valueInterface();
+ if (valueIface) {
+ const QVariant valueVar = valueIface->currentValue();
+ const auto type = valueVar.typeId();
+ if (type == QMetaType::Double || type == QMetaType::Float) {
+ // QVariant's toString() formats floating-point values with
+ // FloatingPointShortest, which is not an accessible
+ // representation; nor, in many cases, is it suitable to the UI
+ // element whose value we're looking at. So roll our own
+ // A11Y-friendly conversion to string.
+ const double val = valueVar.toDouble();
+ // Try to use minimumStepSize() to determine precision
+ bool stepIsValid = false;
+ const double step = qAbs(valueIface->minimumStepSize().toDouble(&stepIsValid));
+ if (!stepIsValid || qFuzzyIsNull(step)) {
+ // Ignore step, use default precision
+ valueStr = qFuzzyIsNull(val) ? u"0"_s : QString::number(val, 'f');
+ } else {
+ const int precision = [](double s) {
+ int count = 0;
+ while (s < 1. && !qFuzzyCompare(s, 1.)) {
+ ++count;
+ s *= 10;
+ }
+ // If s is now 1.25, we want to show some more digits,
+ // but don't want to get silly with a step like 1./7;
+ // so only include a few extra digits.
+ const int stop = count + 3;
+ const auto fractional = [](double v) {
+ double whole = 0.0;
+ std::modf(v + 0.5, &whole);
+ return qAbs(v - whole);
+ };
+ s = fractional(s);
+ while (count < stop && !qFuzzyIsNull(s)) {
+ ++count;
+ s = fractional(s * 10);
+ }
+ return count;
+ }(step);
+ valueStr = qFuzzyIsNull(val / step) ? u"0"_s
+ : QString::number(val, 'f', precision);
+ }
+ } else {
+ valueStr = valueVar.toString();
+ }
+ }
+ return valueStr;
+ }
+
+ static jstring jvalueForAccessibleObject(int objectId)
+ {
+ QAccessibleInterface *iface = interfaceFromId(objectId);
+ const QString value = textFromValue(iface);
+ QJniEnvironment env;
+ jstring jstr = env->NewString((jchar*)value.constData(), (jsize)value.size());
+ if (env.checkAndClearExceptions())
+ __android_log_print(ANDROID_LOG_WARN, m_qtTag, "Failed to create jstring");
+ return jstr;
+ }
+
+ static QString descriptionForInterface(QAccessibleInterface *iface)
{
QString desc;
if (iface && iface->isValid()) {
+ bool hasValue = false;
desc = iface->text(QAccessible::Name);
if (desc.isEmpty())
desc = iface->text(QAccessible::Description);
if (desc.isEmpty()) {
desc = iface->text(QAccessible::Value);
- if (desc.isEmpty()) {
- if (QAccessibleValueInterface *valueIface = iface->valueInterface()) {
- desc= valueIface->currentValue().toString();
- }
+ hasValue = !desc.isEmpty();
+ }
+ if (!hasValue && iface->valueInterface()) {
+ const QString valueStr = textFromValue(iface);
+ if (!valueStr.isEmpty()) {
+ if (!desc.isEmpty())
+ desc.append(QChar(QChar::Space));
+ desc.append(valueStr);
}
}
}
- return env->NewString((jchar*) desc.constData(), (jsize) desc.size());
+ return desc;
}
- static jstring descriptionForAccessibleObject(JNIEnv *env, jobject /*thiz*/, jint objectId)
+ static QString descriptionForAccessibleObject_helper(int objectId)
{
QAccessibleInterface *iface = interfaceFromId(objectId);
- return descriptionForAccessibleObject_helper(env, iface);
+ return descriptionForInterface(iface);
}
- static bool populateNode(JNIEnv *env, jobject /*thiz*/, jint objectId, jobject node)
+ static jstring descriptionForAccessibleObject(JNIEnv *env, jobject /*thiz*/, jint objectId)
+ {
+ QString desc;
+ if (m_accessibilityContext) {
+ runInObjectContext(m_accessibilityContext, [objectId]() {
+ return descriptionForAccessibleObject_helper(objectId);
+ }, &desc);
+ }
+ return env->NewString((jchar*) desc.constData(), (jsize) desc.size());
+ }
+
+
+ struct NodeInfo
{
+ bool valid = false;
+ QAccessible::State state;
+ QAccessible::Role role;
+ QStringList actions;
+ QString description;
+ bool hasTextSelection = false;
+ int selectionStart = 0;
+ int selectionEnd = 0;
+ };
+
+ static NodeInfo populateNode_helper(int objectId)
+ {
+ NodeInfo info;
QAccessibleInterface *iface = interfaceFromId(objectId);
- if (!iface || !iface->isValid()) {
+ if (iface && iface->isValid()) {
+ info.valid = true;
+ info.state = iface->state();
+ info.role = iface->role();
+ info.actions = QAccessibleBridgeUtils::effectiveActionNames(iface);
+ info.description = descriptionForInterface(iface);
+ QAccessibleTextInterface *textIface = iface->textInterface();
+ if (textIface && (textIface->selectionCount() > 0)) {
+ info.hasTextSelection = true;
+ textIface->selection(0, &info.selectionStart, &info.selectionEnd);
+ }
+ }
+ return info;
+ }
+
+ static jboolean populateNode(JNIEnv *env, jobject /*thiz*/, jint objectId, jobject node)
+ {
+ NodeInfo info;
+ if (m_accessibilityContext) {
+ runInObjectContext(m_accessibilityContext, [objectId]() {
+ return populateNode_helper(objectId);
+ }, &info);
+ }
+ if (!info.valid) {
__android_log_print(ANDROID_LOG_WARN, m_qtTag, "Accessibility: populateNode for Invalid ID");
return false;
}
- QAccessible::State state = iface->state();
- const QStringList actions = QAccessibleBridgeUtils::effectiveActionNames(iface);
- const bool hasClickableAction = actions.contains(QAccessibleActionInterface::pressAction())
- || actions.contains(QAccessibleActionInterface::toggleAction());
- const bool hasIncreaseAction = actions.contains(QAccessibleActionInterface::increaseAction());
- const bool hasDecreaseAction = actions.contains(QAccessibleActionInterface::decreaseAction());
- // try to fill in the text property, this is what the screen reader reads
- jstring jdesc = descriptionForAccessibleObject_helper(env, iface);
-
- if (QAccessibleTextInterface *textIface = iface->textInterface()) {
- if (m_setTextSelectionMethodID && textIface->selectionCount() > 0) {
- int startSelection;
- int endSelection;
- textIface->selection(0, &startSelection, &endSelection);
- env->CallVoidMethod(node, m_setTextSelectionMethodID, startSelection, endSelection);
- }
+ const bool hasClickableAction =
+ info.actions.contains(QAccessibleActionInterface::pressAction()) ||
+ info.actions.contains(QAccessibleActionInterface::toggleAction());
+ const bool hasIncreaseAction =
+ info.actions.contains(QAccessibleActionInterface::increaseAction());
+ const bool hasDecreaseAction =
+ info.actions.contains(QAccessibleActionInterface::decreaseAction());
+
+ if (info.hasTextSelection && m_setTextSelectionMethodID) {
+ env->CallVoidMethod(node, m_setTextSelectionMethodID, info.selectionStart,
+ info.selectionEnd);
}
- env->CallVoidMethod(node, m_setEnabledMethodID, !state.disabled);
- env->CallVoidMethod(node, m_setCheckableMethodID, (bool)state.checkable);
- env->CallVoidMethod(node, m_setCheckedMethodID, (bool)state.checked);
- env->CallVoidMethod(node, m_setFocusableMethodID, (bool)state.focusable);
- env->CallVoidMethod(node, m_setFocusedMethodID, (bool)state.focused);
- env->CallVoidMethod(node, m_setVisibleToUserMethodID, !state.invisible);
+ env->CallVoidMethod(node, m_setCheckableMethodID, (bool)info.state.checkable);
+ env->CallVoidMethod(node, m_setCheckedMethodID, (bool)info.state.checked);
+ env->CallVoidMethod(node, m_setEditableMethodID, info.state.editable);
+ env->CallVoidMethod(node, m_setEnabledMethodID, !info.state.disabled);
+ env->CallVoidMethod(node, m_setFocusableMethodID, (bool)info.state.focusable);
+ env->CallVoidMethod(node, m_setFocusedMethodID, (bool)info.state.focused);
+ if (m_setHeadingMethodID)
+ env->CallVoidMethod(node, m_setHeadingMethodID, info.role == QAccessible::Heading);
+ env->CallVoidMethod(node, m_setVisibleToUserMethodID, !info.state.invisible);
env->CallVoidMethod(node, m_setScrollableMethodID, hasIncreaseAction || hasDecreaseAction);
- env->CallVoidMethod(node, m_setClickableMethodID, hasClickableAction);
+ env->CallVoidMethod(node, m_setClickableMethodID, hasClickableAction || info.role == QAccessible::Link);
// Add ACTION_CLICK
if (hasClickableAction)
- env->CallVoidMethod(node, m_addActionMethodID, (int)16); // ACTION_CLICK defined in AccessibilityNodeInfo
+ env->CallVoidMethod(node, m_addActionMethodID, (int)0x00000010); // ACTION_CLICK defined in AccessibilityNodeInfo
// Add ACTION_SCROLL_FORWARD
if (hasIncreaseAction)
- env->CallVoidMethod(node, m_addActionMethodID, (int)4096); // ACTION_SCROLL_FORWARD defined in AccessibilityNodeInfo
+ env->CallVoidMethod(node, m_addActionMethodID, (int)0x00001000); // ACTION_SCROLL_FORWARD defined in AccessibilityNodeInfo
// Add ACTION_SCROLL_BACKWARD
if (hasDecreaseAction)
- env->CallVoidMethod(node, m_addActionMethodID, (int)8192); // ACTION_SCROLL_BACKWARD defined in AccessibilityNodeInfo
-
+ env->CallVoidMethod(node, m_addActionMethodID, (int)0x00002000); // ACTION_SCROLL_BACKWARD defined in AccessibilityNodeInfo
+ // try to fill in the text property, this is what the screen reader reads
+ jstring jdesc = env->NewString((jchar*)info.description.constData(),
+ (jsize)info.description.size());
//CALL_METHOD(node, "setText", "(Ljava/lang/CharSequence;)V", jdesc)
env->CallVoidMethod(node, m_setContentDescriptionMethodID, jdesc);
return true;
}
- static JNINativeMethod methods[] = {
+ static const JNINativeMethod methods[] = {
{"setActive","(Z)V",(void*)setActive},
{"childIdListForAccessibleObject", "(I)[I", (jintArray)childIdListForAccessibleObject},
{"parentId", "(I)I", (void*)parentId},
@@ -307,13 +567,10 @@ if (!clazz) { \
return false; \
}
- bool registerNatives(JNIEnv *env)
+ bool registerNatives(QJniEnvironment &env)
{
- jclass clazz;
- FIND_AND_CHECK_CLASS("org/qtproject/qt5/android/accessibility/QtNativeAccessibility");
- jclass appClass = static_cast<jclass>(env->NewGlobalRef(clazz));
-
- if (env->RegisterNatives(appClass, methods, sizeof(methods) / sizeof(methods[0])) < 0) {
+ if (!env.registerNativeMethods("org/qtproject/qt/android/QtNativeAccessibility",
+ methods, sizeof(methods) / sizeof(methods[0]))) {
__android_log_print(ANDROID_LOG_FATAL,"Qt A11y", "RegisterNatives failed");
return false;
}
@@ -324,9 +581,13 @@ if (!clazz) { \
GET_AND_CHECK_STATIC_METHOD(m_setCheckedMethodID, nodeInfoClass, "setChecked", "(Z)V");
GET_AND_CHECK_STATIC_METHOD(m_setClickableMethodID, nodeInfoClass, "setClickable", "(Z)V");
GET_AND_CHECK_STATIC_METHOD(m_setContentDescriptionMethodID, nodeInfoClass, "setContentDescription", "(Ljava/lang/CharSequence;)V");
+ GET_AND_CHECK_STATIC_METHOD(m_setEditableMethodID, nodeInfoClass, "setEditable", "(Z)V");
GET_AND_CHECK_STATIC_METHOD(m_setEnabledMethodID, nodeInfoClass, "setEnabled", "(Z)V");
GET_AND_CHECK_STATIC_METHOD(m_setFocusableMethodID, nodeInfoClass, "setFocusable", "(Z)V");
GET_AND_CHECK_STATIC_METHOD(m_setFocusedMethodID, nodeInfoClass, "setFocused", "(Z)V");
+ if (QtAndroidPrivate::androidSdkVersion() >= 28) {
+ GET_AND_CHECK_STATIC_METHOD(m_setHeadingMethodID, nodeInfoClass, "setHeading", "(Z)V");
+ }
GET_AND_CHECK_STATIC_METHOD(m_setScrollableMethodID, nodeInfoClass, "setScrollable", "(Z)V");
GET_AND_CHECK_STATIC_METHOD(m_setVisibleToUserMethodID, nodeInfoClass, "setVisibleToUser", "(Z)V");
GET_AND_CHECK_STATIC_METHOD(m_setTextSelectionMethodID, nodeInfoClass, "setTextSelection", "(II)V");
diff --git a/src/plugins/platforms/android/androidjniaccessibility.h b/src/plugins/platforms/android/androidjniaccessibility.h
index f393ce0b08..d967dde3ff 100644
--- a/src/plugins/platforms/android/androidjniaccessibility.h
+++ b/src/plugins/platforms/android/androidjniaccessibility.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef ANDROIDJNIACCESSIBILITY_H
#define ANDROIDJNIACCESSIBILITY_H
@@ -44,10 +8,20 @@
QT_BEGIN_NAMESPACE
+class QObject;
+class QJniEnvironment;
+
namespace QtAndroidAccessibility
{
void initialize();
- bool registerNatives(JNIEnv *env);
+ bool isActive();
+ bool registerNatives(QJniEnvironment &env);
+ void notifyLocationChange(uint accessibilityObjectId);
+ void notifyObjectHide(uint accessibilityObjectId);
+ void notifyObjectFocus(uint accessibilityObjectId);
+ void notifyValueChanged(uint accessibilityObjectId);
+ void notifyScrolledEvent(uint accessibilityObjectId);
+ void createAccessibilityContextObject(QObject *parent);
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/android/androidjniclipboard.cpp b/src/plugins/platforms/android/androidjniclipboard.cpp
deleted file mode 100644
index 671d0b56d0..0000000000
--- a/src/plugins/platforms/android/androidjniclipboard.cpp
+++ /dev/null
@@ -1,128 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
-** 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 "androidjniclipboard.h"
-#include <QtCore/QUrl>
-#include <QtCore/private/qjni_p.h>
-
-QT_BEGIN_NAMESPACE
-
-using namespace QtAndroid;
-namespace QtAndroidClipboard
-{
- QAndroidPlatformClipboard *m_manager = nullptr;
-
- static JNINativeMethod methods[] = {
- {"onClipboardDataChanged", "()V", (void *)onClipboardDataChanged}
- };
-
- void setClipboardManager(QAndroidPlatformClipboard *manager)
- {
- m_manager = manager;
- QJNIObjectPrivate::callStaticMethod<void>(applicationClass(), "registerClipboardManager");
- jclass appClass = QtAndroid::applicationClass();
- QJNIEnvironmentPrivate env;
- if (env->RegisterNatives(appClass, methods, sizeof(methods) / sizeof(methods[0])) < 0) {
- __android_log_print(ANDROID_LOG_FATAL,"Qt", "RegisterNatives failed");
- return;
- }
- }
- void setClipboardMimeData(QMimeData *data)
- {
- QJNIObjectPrivate::callStaticMethod<void>(applicationClass(), "clearClipData");
- if (data->hasText()) {
- QJNIObjectPrivate::callStaticMethod<void>(applicationClass(),
- "setClipboardText", "(Ljava/lang/String;)V",
- QJNIObjectPrivate::fromString(data->text()).object());
- }
- if (data->hasHtml()) {
- QJNIObjectPrivate::callStaticMethod<void>(applicationClass(),
- "setClipboardHtml",
- "(Ljava/lang/String;Ljava/lang/String;)V",
- QJNIObjectPrivate::fromString(data->text()).object(),
- QJNIObjectPrivate::fromString(data->html()).object());
- }
- if (data->hasUrls()) {
- QList<QUrl> urls = data->urls();
- for (const auto &u : qAsConst(urls)) {
- QJNIObjectPrivate::callStaticMethod<void>(applicationClass(), "setClipboardUri",
- "(Ljava/lang/String;)V",
- QJNIObjectPrivate::fromString(u.toEncoded()).object());
- }
- }
- }
-
- QMimeData *getClipboardMimeData()
- {
- QMimeData *data = new QMimeData;
- if (QJNIObjectPrivate::callStaticMethod<jboolean>(applicationClass(), "hasClipboardText")) {
- data->setText(QJNIObjectPrivate::callStaticObjectMethod(applicationClass(),
- "getClipboardText",
- "()Ljava/lang/String;").toString());
- }
- if (QJNIObjectPrivate::callStaticMethod<jboolean>(applicationClass(), "hasClipboardHtml")) {
- data->setHtml(QJNIObjectPrivate::callStaticObjectMethod(applicationClass(),
- "getClipboardHtml",
- "()Ljava/lang/String;").toString());
- }
- if (QJNIObjectPrivate::callStaticMethod<jboolean>(applicationClass(), "hasClipboardUri")) {
- QJNIObjectPrivate uris = QJNIObjectPrivate::callStaticObjectMethod(applicationClass(),
- "getClipboardUris",
- "()[Ljava/lang/String;");
- if (uris.isValid()) {
- QList<QUrl> urls;
- QJNIEnvironmentPrivate env;
- jobjectArray juris = static_cast<jobjectArray>(uris.object());
- const jint nUris = env->GetArrayLength(juris);
- urls.reserve(static_cast<int>(nUris));
- for (int i = 0; i < nUris; ++i)
- urls << QUrl(QJNIObjectPrivate(env->GetObjectArrayElement(juris, i)).toString());
- data->setUrls(urls);
- }
- }
- return data;
- }
-
- void onClipboardDataChanged(JNIEnv */*env*/, jobject /*thiz*/)
- {
- m_manager->emitChanged(QClipboard::Clipboard);
- }
-}
-
-QT_END_NAMESPACE
diff --git a/src/plugins/platforms/android/androidjniclipboard.h b/src/plugins/platforms/android/androidjniclipboard.h
deleted file mode 100644
index e83e6b555c..0000000000
--- a/src/plugins/platforms/android/androidjniclipboard.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
-** 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 ANDROIDJNICLIPBOARD_H
-#define ANDROIDJNICLIPBOARD_H
-
-#include <QString>
-#include "qandroidplatformclipboard.h"
-#include "androidjnimain.h"
-
-QT_BEGIN_NAMESPACE
-
-class QAndroidPlatformClipboard;
-namespace QtAndroidClipboard
-{
- // Clipboard support
- void setClipboardManager(QAndroidPlatformClipboard *manager);
- void setClipboardMimeData(QMimeData *data);
- QMimeData *getClipboardMimeData();
- void onClipboardDataChanged(JNIEnv */*env*/, jobject /*thiz*/);
- // Clipboard support
-}
-
-QT_END_NAMESPACE
-
-#endif // ANDROIDJNICLIPBOARD_H
diff --git a/src/plugins/platforms/android/androidjniinput.cpp b/src/plugins/platforms/android/androidjniinput.cpp
index 56885f2e23..00e6b7ca51 100644
--- a/src/plugins/platforms/android/androidjniinput.cpp
+++ b/src/plugins/platforms/android/androidjniinput.cpp
@@ -1,42 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
-** Copyright (C) 2016 Olivier Goffart <ogoffart@woboq.com>
-** Contact: http://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$
-**
-****************************************************************************/
+// Copyright (C) 2023 The Qt Company Ltd.
+// Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+// Copyright (C) 2016 Olivier Goffart <ogoffart@woboq.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtGui/qtguiglobal.h>
@@ -44,78 +9,135 @@
#include "androidjnimain.h"
#include "qandroidplatformintegration.h"
+#include <qpa/qplatformwindow.h>
#include <qpa/qwindowsysteminterface.h>
#include <QTouchEvent>
#include <QPointer>
#include <QGuiApplication>
-#include <QDebug>
#include <QtMath>
QT_BEGIN_NAMESPACE
+Q_LOGGING_CATEGORY(lcQpaInputMethods, "qt.qpa.input.methods");
+
using namespace QtAndroid;
+Q_DECLARE_JNI_CLASS(QtLayout, "org/qtproject/qt/android/QtLayout")
+
namespace QtAndroidInput
{
static bool m_ignoreMouseEvents = false;
- static bool m_softwareKeyboardVisible = false;
static QRect m_softwareKeyboardRect;
static QList<QWindowSystemInterface::TouchPoint> m_touchPoints;
static QPointer<QWindow> m_mouseGrabber;
+ GenericMotionEventListener::~GenericMotionEventListener() {}
+ namespace {
+ struct GenericMotionEventListeners {
+ QMutex mutex;
+ QList<QtAndroidInput::GenericMotionEventListener *> listeners;
+ };
+ }
+ Q_GLOBAL_STATIC(GenericMotionEventListeners, g_genericMotionEventListeners)
+
+ static jboolean dispatchGenericMotionEvent(JNIEnv *, jclass, jobject event)
+ {
+ jboolean ret = JNI_FALSE;
+ QMutexLocker locker(&g_genericMotionEventListeners()->mutex);
+ for (auto *listener : std::as_const(g_genericMotionEventListeners()->listeners))
+ ret |= listener->handleGenericMotionEvent(event);
+ return ret;
+ }
+
+ KeyEventListener::~KeyEventListener() {}
+ namespace {
+ struct KeyEventListeners {
+ QMutex mutex;
+ QList<QtAndroidInput::KeyEventListener *> listeners;
+ };
+ }
+ Q_GLOBAL_STATIC(KeyEventListeners, g_keyEventListeners)
+
+ static jboolean dispatchKeyEvent(JNIEnv *, jclass, jobject event)
+ {
+ jboolean ret = JNI_FALSE;
+ QMutexLocker locker(&g_keyEventListeners()->mutex);
+ for (auto *listener : std::as_const(g_keyEventListeners()->listeners))
+ ret |= listener->handleKeyEvent(event);
+ return ret;
+ }
+
+ void registerGenericMotionEventListener(QtAndroidInput::GenericMotionEventListener *listener)
+ {
+ QMutexLocker locker(&g_genericMotionEventListeners()->mutex);
+ g_genericMotionEventListeners()->listeners.push_back(listener);
+ }
+
+ void unregisterGenericMotionEventListener(QtAndroidInput::GenericMotionEventListener *listener)
+ {
+ QMutexLocker locker(&g_genericMotionEventListeners()->mutex);
+ g_genericMotionEventListeners()->listeners.removeOne(listener);
+ }
+
+ void registerKeyEventListener(QtAndroidInput::KeyEventListener *listener)
+ {
+ QMutexLocker locker(&g_keyEventListeners()->mutex);
+ g_keyEventListeners()->listeners.push_back(listener);
+ }
+
+ void unregisterKeyEventListener(QtAndroidInput::KeyEventListener *listener)
+ {
+ QMutexLocker locker(&g_keyEventListeners()->mutex);
+ g_keyEventListeners()->listeners.removeOne(listener);
+ }
+
+ QJniObject qtLayout()
+ {
+ return qtActivityDelegate().callMethod<QtJniTypes::QtLayout>("getQtLayout");
+ }
+
void updateSelection(int selStart, int selEnd, int candidatesStart, int candidatesEnd)
{
-#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
- qDebug() << ">>> UPDATESELECTION" << selStart << selEnd << candidatesStart << candidatesEnd;
-#endif
- QJNIObjectPrivate::callStaticMethod<void>(applicationClass(),
- "updateSelection",
- "(IIII)V",
- selStart,
- selEnd,
- candidatesStart,
- candidatesEnd);
+ qCDebug(lcQpaInputMethods) << ">>> UPDATESELECTION" << selStart << selEnd << candidatesStart << candidatesEnd;
+ qtInputDelegate().callMethod<void>("updateSelection",
+ selStart,
+ selEnd,
+ candidatesStart,
+ candidatesEnd);
}
void showSoftwareKeyboard(int left, int top, int width, int height, int inputHints, int enterKeyType)
{
- QJNIObjectPrivate::callStaticMethod<void>(applicationClass(),
- "showSoftwareKeyboard",
- "(IIIIII)V",
- left,
- top,
- width,
- height,
- inputHints,
- enterKeyType
- );
-#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
- qDebug() << "@@@ SHOWSOFTWAREKEYBOARD" << left << top << width << height << inputHints << enterKeyType;
-#endif
+ qtInputDelegate().callMethod<void>("showSoftwareKeyboard",
+ QtAndroidPrivate::activity(),
+ qtLayout().object<QtJniTypes::QtLayout>(),
+ left,
+ top,
+ width,
+ height,
+ inputHints,
+ enterKeyType);
+ qCDebug(lcQpaInputMethods) << "@@@ SHOWSOFTWAREKEYBOARD" << left << top << width << height << inputHints << enterKeyType;
}
void resetSoftwareKeyboard()
{
- QJNIObjectPrivate::callStaticMethod<void>(applicationClass(), "resetSoftwareKeyboard");
-#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
- qDebug("@@@ RESETSOFTWAREKEYBOARD");
-#endif
+ qtInputDelegate().callMethod<void>("resetSoftwareKeyboard");
+ qCDebug(lcQpaInputMethods) << "@@@ RESETSOFTWAREKEYBOARD";
}
void hideSoftwareKeyboard()
{
- QJNIObjectPrivate::callStaticMethod<void>(applicationClass(), "hideSoftwareKeyboard");
-#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
- qDebug("@@@ HIDESOFTWAREKEYBOARD");
-#endif
+ qtInputDelegate().callMethod<void>("hideSoftwareKeyboard");
+ qCDebug(lcQpaInputMethods) << "@@@ HIDESOFTWAREKEYBOARD";
}
bool isSoftwareKeyboardVisible()
{
- return m_softwareKeyboardVisible;
+ return qtInputDelegate().callMethod<jboolean>("isSoftwareKeyboardVisible");
}
QRect softwareKeyboardRect()
@@ -123,104 +145,114 @@ namespace QtAndroidInput
return m_softwareKeyboardRect;
}
+ int getSelectHandleWidth()
+ {
+ return qtInputDelegate().callMethod<jint>("getSelectHandleWidth");
+ }
+
void updateHandles(int mode, QPoint editMenuPos, uint32_t editButtons, QPoint cursor, QPoint anchor, bool rtl)
{
- QJNIObjectPrivate::callStaticMethod<void>(applicationClass(), "updateHandles", "(IIIIIIIIZ)V",
- mode, editMenuPos.x(), editMenuPos.y(), editButtons,
- cursor.x(), cursor.y(),
- anchor.x(), anchor.y(), rtl);
+ qtInputDelegate().callMethod<void>("updateHandles",
+ QtAndroidPrivate::activity(),
+ qtLayout().object<QtJniTypes::QtLayout>(),
+ mode, editMenuPos.x(), editMenuPos.y(), editButtons,
+ cursor.x(), cursor.y(),
+ anchor.x(), anchor.y(), rtl);
}
- static void mouseDown(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint x, jint y)
+ static void mouseDown(JNIEnv */*env*/, jobject /*thiz*/, jint winId, jint x, jint y)
{
if (m_ignoreMouseEvents)
return;
- QPoint globalPos(x,y);
- QWindow *tlw = topLevelWindowAt(globalPos);
- m_mouseGrabber = tlw;
- QPoint localPos = tlw ? (globalPos - tlw->position()) : globalPos;
- QWindowSystemInterface::handleMouseEvent(tlw,
- localPos,
- globalPos,
- Qt::MouseButtons(Qt::LeftButton));
+ const QPoint globalPos(x,y);
+ QWindow *window = windowFromId(winId);
+ m_mouseGrabber = window;
+ const QPoint localPos = window && window->handle() ?
+ window->handle()->mapFromGlobal(globalPos) : globalPos;
+ QWindowSystemInterface::handleMouseEvent(window, localPos, globalPos,
+ Qt::MouseButtons(Qt::LeftButton),
+ Qt::LeftButton, QEvent::MouseButtonPress);
}
- static void mouseUp(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint x, jint y)
+ static void mouseUp(JNIEnv */*env*/, jobject /*thiz*/, jint winId, jint x, jint y)
{
- QPoint globalPos(x,y);
- QWindow *tlw = m_mouseGrabber.data();
- if (!tlw)
- tlw = topLevelWindowAt(globalPos);
- QPoint localPos = tlw ? (globalPos -tlw->position()) : globalPos;
- QWindowSystemInterface::handleMouseEvent(tlw, localPos, globalPos
- , Qt::MouseButtons(Qt::NoButton));
+ const QPoint globalPos(x,y);
+ QWindow *window = m_mouseGrabber.data();
+ if (!window)
+ window = windowFromId(winId);
+
+ const QPoint localPos = window && window->handle() ?
+ window->handle()->mapFromGlobal(globalPos) : globalPos;
+ QWindowSystemInterface::handleMouseEvent(window, localPos, globalPos,
+ Qt::MouseButtons(Qt::NoButton),
+ Qt::LeftButton, QEvent::MouseButtonRelease);
m_ignoreMouseEvents = false;
- m_mouseGrabber = 0;
+ m_mouseGrabber.clear();
}
- static void mouseMove(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint x, jint y)
+ static void mouseMove(JNIEnv */*env*/, jobject /*thiz*/, jint winId, jint x, jint y)
{
if (m_ignoreMouseEvents)
return;
- QPoint globalPos(x,y);
- QWindow *tlw = m_mouseGrabber.data();
- if (!tlw)
- tlw = topLevelWindowAt(globalPos);
- QPoint localPos = tlw ? (globalPos-tlw->position()) : globalPos;
- QWindowSystemInterface::handleMouseEvent(tlw,
- localPos,
- globalPos,
- Qt::MouseButtons(m_mouseGrabber ? Qt::LeftButton : Qt::NoButton));
+ const QPoint globalPos(x,y);
+ QWindow *window = m_mouseGrabber.data();
+ if (!window)
+ window = windowFromId(winId);
+ const QPoint localPos = window && window->handle() ?
+ window->handle()->mapFromGlobal(globalPos) : globalPos;
+ QWindowSystemInterface::handleMouseEvent(window, localPos, globalPos,
+ Qt::MouseButtons(m_mouseGrabber ? Qt::LeftButton : Qt::NoButton),
+ Qt::NoButton, QEvent::MouseMove);
}
- static void mouseWheel(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint x, jint y, jfloat hdelta, jfloat vdelta)
+ static void mouseWheel(JNIEnv */*env*/, jobject /*thiz*/, jint winId, jint x, jint y, jfloat hdelta, jfloat vdelta)
{
if (m_ignoreMouseEvents)
return;
- QPoint globalPos(x,y);
- QWindow *tlw = m_mouseGrabber.data();
- if (!tlw)
- tlw = topLevelWindowAt(globalPos);
- QPoint localPos = tlw ? (globalPos-tlw->position()) : globalPos;
- QPoint angleDelta(hdelta * 120, vdelta * 120);
+ const QPoint globalPos(x,y);
+ QWindow *window = m_mouseGrabber.data();
+ if (!window)
+ window = windowFromId(winId);
+ const QPoint localPos = window && window->handle() ?
+ window->handle()->mapFromGlobal(globalPos) : globalPos;
+ const QPoint angleDelta(hdelta * 120, vdelta * 120);
- QWindowSystemInterface::handleWheelEvent(tlw,
+ QWindowSystemInterface::handleWheelEvent(window,
localPos,
globalPos,
QPoint(),
angleDelta);
}
- static void longPress(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint x, jint y)
+ static void longPress(JNIEnv */*env*/, jobject /*thiz*/, jint winId, jint x, jint y)
{
QAndroidInputContext *inputContext = QAndroidInputContext::androidInputContext();
if (inputContext && qGuiApp)
QMetaObject::invokeMethod(inputContext, "longPress", Q_ARG(int, x), Q_ARG(int, y));
//### TODO: add proper API for Qt 5.2
- static bool rightMouseFromLongPress = qEnvironmentVariableIntValue("QT_NECESSITAS_COMPATIBILITY_LONG_PRESS");
+ static bool rightMouseFromLongPress = qEnvironmentVariableIntValue("QT_ANDROID_ENABLE_RIGHT_MOUSE_FROM_LONG_PRESS");
if (!rightMouseFromLongPress)
return;
m_ignoreMouseEvents = true;
- QPoint globalPos(x,y);
- QWindow *tlw = topLevelWindowAt(globalPos);
- QPoint localPos = tlw ? (globalPos-tlw->position()) : globalPos;
-
- // Release left button
- QWindowSystemInterface::handleMouseEvent(tlw,
- localPos,
- globalPos,
- Qt::MouseButtons(Qt::NoButton));
-
- // Press right button
- QWindowSystemInterface::handleMouseEvent(tlw,
- localPos,
- globalPos,
- Qt::MouseButtons(Qt::RightButton));
+ const QPoint globalPos(x,y);
+ QWindow *window = windowFromId(winId);
+ const QPoint localPos = window && window->handle() ?
+ window->handle()->mapFromGlobal(globalPos) : globalPos;
+
+ // Click right button if no other button is already pressed.
+ if (!m_mouseGrabber) {
+ QWindowSystemInterface::handleMouseEvent(window, localPos, globalPos,
+ Qt::MouseButtons(Qt::RightButton), Qt::RightButton,
+ QEvent::MouseButtonPress);
+ QWindowSystemInterface::handleMouseEvent(window, localPos, globalPos,
+ Qt::MouseButtons(Qt::NoButton), Qt::RightButton,
+ QEvent::MouseButtonRelease);
+ }
}
static void touchBegin(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/)
@@ -231,69 +263,97 @@ namespace QtAndroidInput
static void touchAdd(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint id, jint action, jboolean /*primary*/, jint x, jint y,
jfloat major, jfloat minor, jfloat rotation, jfloat pressure)
{
- Qt::TouchPointState state = Qt::TouchPointStationary;
+ QEventPoint::State state = QEventPoint::State::Stationary;
switch (action) {
case 0:
- state = Qt::TouchPointPressed;
+ state = QEventPoint::State::Pressed;
break;
case 1:
- state = Qt::TouchPointMoved;
+ state = QEventPoint::State::Updated;
break;
case 2:
- state = Qt::TouchPointStationary;
+ state = QEventPoint::State::Stationary;
break;
case 3:
- state = Qt::TouchPointReleased;
+ state = QEventPoint::State::Released;
break;
}
- const int dw = desktopWidthPixels();
- const int dh = desktopHeightPixels();
+ const int dw = availableWidthPixels();
+ const int dh = availableHeightPixels();
QWindowSystemInterface::TouchPoint touchPoint;
touchPoint.id = id;
touchPoint.pressure = pressure;
touchPoint.rotation = qRadiansToDegrees(rotation);
touchPoint.normalPosition = QPointF(double(x / dw), double(y / dh));
touchPoint.state = state;
- touchPoint.area = QRectF(x - double(minor),
- y - double(major),
- double(minor * 2),
- double(major * 2));
+ touchPoint.area = QRectF(x - double(minor * 0.5f),
+ y - double(major * 0.5f),
+ double(minor),
+ double(major));
m_touchPoints.push_back(touchPoint);
-
- if (state == Qt::TouchPointPressed) {
+ if (state == QEventPoint::State::Pressed) {
QAndroidInputContext *inputContext = QAndroidInputContext::androidInputContext();
if (inputContext && qGuiApp)
QMetaObject::invokeMethod(inputContext, "touchDown", Q_ARG(int, x), Q_ARG(int, y));
}
}
- static void touchEnd(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint /*action*/)
+ static QPointingDevice *getTouchDevice()
+ {
+ QAndroidPlatformIntegration *platformIntegration = QtAndroid::androidPlatformIntegration();
+ if (!platformIntegration)
+ return nullptr;
+
+ QPointingDevice *touchDevice = platformIntegration->touchDevice();
+ if (!touchDevice) {
+ touchDevice = new QPointingDevice("Android touchscreen", 1,
+ QInputDevice::DeviceType::TouchScreen,
+ QPointingDevice::PointerType::Finger,
+ QPointingDevice::Capability::Position
+ | QPointingDevice::Capability::Area
+ | QPointingDevice::Capability::Pressure
+ | QPointingDevice::Capability::NormalizedPosition,
+ 10, 0);
+ QWindowSystemInterface::registerInputDevice(touchDevice);
+ platformIntegration->setTouchDevice(touchDevice);
+ }
+
+ return touchDevice;
+ }
+
+ static void touchEnd(JNIEnv * /*env*/, jobject /*thiz*/, jint winId, jint /*action*/)
{
if (m_touchPoints.isEmpty())
return;
QMutexLocker lock(QtAndroid::platformInterfaceMutex());
- QAndroidPlatformIntegration *platformIntegration = QtAndroid::androidPlatformIntegration();
- if (!platformIntegration)
+ const QPointingDevice *touchDevice = getTouchDevice();
+ if (!touchDevice)
return;
- QTouchDevice *touchDevice = platformIntegration->touchDevice();
- if (touchDevice == 0) {
- touchDevice = new QTouchDevice;
- touchDevice->setType(QTouchDevice::TouchScreen);
- touchDevice->setCapabilities(QTouchDevice::Position
- | QTouchDevice::Area
- | QTouchDevice::Pressure
- | QTouchDevice::NormalizedPosition);
- QWindowSystemInterface::registerTouchDevice(touchDevice);
- platformIntegration->setTouchDevice(touchDevice);
- }
-
- QWindow *window = QtAndroid::topLevelWindowAt(m_touchPoints.at(0).area.center().toPoint());
+ QWindow *window = QtAndroid::windowFromId(winId);
+ if (!window)
+ return;
QWindowSystemInterface::handleTouchEvent(window, touchDevice, m_touchPoints);
}
+ static void touchCancel(JNIEnv * /*env*/, jobject /*thiz*/, jint winId)
+ {
+ if (m_touchPoints.isEmpty())
+ return;
+
+ QMutexLocker lock(QtAndroid::platformInterfaceMutex());
+ const QPointingDevice *touchDevice = getTouchDevice();
+ if (!touchDevice)
+ return;
+
+ QWindow *window = QtAndroid::windowFromId(winId);
+ if (!window)
+ return;
+ QWindowSystemInterface::handleTouchCancelEvent(window, touchDevice);
+ }
+
static bool isTabletEventSupported(JNIEnv */*env*/, jobject /*thiz*/)
{
#if QT_CONFIG(tabletevent)
@@ -303,14 +363,14 @@ namespace QtAndroidInput
#endif // QT_CONFIG(tabletevent)
}
- static void tabletEvent(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint deviceId, jlong time, jint action,
+ static void tabletEvent(JNIEnv */*env*/, jobject /*thiz*/, jint winId, jint deviceId, jlong time, jint action,
jint pointerType, jint buttonState, jfloat x, jfloat y, jfloat pressure)
{
#if QT_CONFIG(tabletevent)
- QPointF globalPosF(x, y);
- QPoint globalPos((int)x, (int)y);
- QWindow *tlw = topLevelWindowAt(globalPos);
- QPointF localPos = tlw ? (globalPosF - tlw->position()) : globalPosF;
+ const QPointF globalPosF(x, y);
+ QWindow *window = windowFromId(winId);
+ const QPointF localPos = window && window->handle() ?
+ window->handle()->mapFromGlobalF(globalPosF) : globalPosF;
// Galaxy Note with plain Android:
// 0 1 0 stylus press
@@ -330,6 +390,7 @@ namespace QtAndroidInput
Qt::MouseButtons buttons = Qt::NoButton;
switch (action) {
case 1: // ACTION_UP
+ case 6: // ACTION_POINTER_UP, happens if stylus is not the primary pointer
case 212: // stylus release while side-button held on Galaxy Note 4
buttons = Qt::NoButton;
break;
@@ -341,33 +402,31 @@ namespace QtAndroidInput
break;
}
-#ifdef QT_DEBUG_ANDROID_STYLUS
- qDebug() << action << pointerType << buttonState << '@' << x << y << "pressure" << pressure << ": buttons" << buttons;
-#endif
+ qCDebug(lcQpaInputMethods) << action << pointerType << buttonState << '@' << x << y << "pressure" << pressure << ": buttons" << buttons;
- QWindowSystemInterface::handleTabletEvent(tlw, ulong(time),
- localPos, globalPosF, QTabletEvent::Stylus, pointerType,
+ QWindowSystemInterface::handleTabletEvent(window, ulong(time),
+ localPos, globalPosF, int(QInputDevice::DeviceType::Stylus), pointerType,
buttons, pressure, 0, 0, 0., 0., 0, deviceId, Qt::NoModifier);
#endif // QT_CONFIG(tabletevent)
}
- static int mapAndroidKey(int key)
+ static QKeyCombination mapAndroidKey(int key)
{
// 0--9 0x00000007 -- 0x00000010
if (key >= 0x00000007 && key <= 0x00000010)
- return Qt::Key_0 + key - 0x00000007;
+ return QKeyCombination::fromCombined(Qt::Key_0 + key - 0x00000007);
// A--Z 0x0000001d -- 0x00000036
if (key >= 0x0000001d && key <= 0x00000036)
- return Qt::Key_A + key - 0x0000001d;
+ return QKeyCombination::fromCombined(Qt::Key_A + key - 0x0000001d);
// F1--F12 0x00000083 -- 0x0000008e
if (key >= 0x00000083 && key <= 0x0000008e)
- return Qt::Key_F1 + key - 0x00000083;
+ return QKeyCombination::fromCombined(Qt::Key_F1 + key - 0x00000083);
// NUMPAD_0--NUMPAD_9 0x00000090 -- 0x00000099
if (key >= 0x00000090 && key <= 0x00000099)
- return Qt::KeypadModifier + Qt::Key_0 + key - 0x00000090;
+ return QKeyCombination::fromCombined(Qt::KeypadModifier | Qt::Key_0 + key - 0x00000090);
// BUTTON_1--KEYCODE_BUTTON_16 0x000000bc -- 0x000000cb
@@ -501,7 +560,7 @@ namespace QtAndroidInput
return Qt::Key_Alt;
case 0x0000004f: // KEYCODE_HEADSETHOOK
- return 0;
+ return QKeyCombination::fromCombined(0);
case 0x00000050: // KEYCODE_FOCUS
return Qt::Key_CameraFocus;
@@ -513,13 +572,13 @@ namespace QtAndroidInput
return Qt::Key_Menu;
case 0x00000053: // KEYCODE_NOTIFICATION
- return 0;
+ return QKeyCombination::fromCombined(0);
case 0x00000054: // KEYCODE_SEARCH
return Qt::Key_Search;
case 0x00000055: // KEYCODE_MEDIA_PLAY_PAUSE
- return Qt::Key_MediaPlay;
+ return Qt::Key_MediaTogglePlayPause;
case 0x00000056: // KEYCODE_MEDIA_STOP
return Qt::Key_MediaStop;
@@ -546,7 +605,7 @@ namespace QtAndroidInput
return Qt::Key_PageDown;
case 0x0000005e: // KEYCODE_PICTSYMBOLS
- return 0;
+ return QKeyCombination::fromCombined(0);
case 0x00000060: // KEYCODE_BUTTON_A
case 0x00000061: // KEYCODE_BUTTON_B
@@ -563,7 +622,7 @@ namespace QtAndroidInput
case 0x0000006c: // KEYCODE_BUTTON_START
case 0x0000006d: // KEYCODE_BUTTON_SELECT
case 0x0000006e: // KEYCODE_BUTTON_MODE
- return 0;
+ return QKeyCombination::fromCombined(0);
case 0x0000006f: // KEYCODE_ESCAPE
return Qt::Key_Escape;
@@ -586,7 +645,7 @@ namespace QtAndroidInput
return Qt::Key_Meta;
case 0x00000077: // KEYCODE_FUNCTION
- return 0;
+ return QKeyCombination::fromCombined(0);
case 0x00000078: // KEYCODE_SYSRQ
return Qt::Key_Print;
@@ -627,28 +686,28 @@ namespace QtAndroidInput
// NUMPAD_0--NUMPAD_9 0x00000090 -- 0x00000099
case 0x0000009a: // KEYCODE_NUMPAD_DIVIDE
- return Qt::KeypadModifier + Qt::Key_Slash;
+ return Qt::KeypadModifier | Qt::Key_Slash;
case 0x0000009b: // KEYCODE_NUMPAD_MULTIPLY
- return Qt::KeypadModifier + Qt::Key_Asterisk;
+ return Qt::KeypadModifier | Qt::Key_Asterisk;
case 0x0000009c: // KEYCODE_NUMPAD_SUBTRACT
- return Qt::KeypadModifier + Qt::Key_Minus;
+ return Qt::KeypadModifier | Qt::Key_Minus;
case 0x0000009d: // KEYCODE_NUMPAD_ADD
- return Qt::KeypadModifier + Qt::Key_Plus;
+ return Qt::KeypadModifier | Qt::Key_Plus;
case 0x0000009e: // KEYCODE_NUMPAD_DOT
- return Qt::KeypadModifier + Qt::Key_Period;
+ return Qt::KeypadModifier | Qt::Key_Period;
case 0x0000009f: // KEYCODE_NUMPAD_COMMA
- return Qt::KeypadModifier + Qt::Key_Comma;
+ return Qt::KeypadModifier | Qt::Key_Comma;
case 0x000000a0: // KEYCODE_NUMPAD_ENTER
return Qt::Key_Enter;
case 0x000000a1: // KEYCODE_NUMPAD_EQUALS
- return Qt::KeypadModifier + Qt::Key_Equal;
+ return Qt::KeypadModifier | Qt::Key_Equal;
case 0x000000a2: // KEYCODE_NUMPAD_LEFT_PAREN
return Qt::Key_ParenLeft;
@@ -676,13 +735,13 @@ namespace QtAndroidInput
case 0x000000aa: // KEYCODE_TV
case 0x000000ab: // KEYCODE_WINDOW
- return 0;
+ return QKeyCombination::fromCombined(0);
case 0x000000ac: // KEYCODE_GUIDE
return Qt::Key_Guide;
case 0x000000ad: // KEYCODE_DVR
- return 0;
+ return QKeyCombination::fromCombined(0);
case 0x000000ae: // KEYCODE_BOOKMARK
return Qt::Key_AddFavorite;
@@ -699,7 +758,7 @@ namespace QtAndroidInput
case 0x000000b4: // KEYCODE_STB_INPUT
case 0x000000b5: // KEYCODE_AVR_POWER
case 0x000000b6: // KEYCODE_AVR_INPUT
- return 0;
+ return QKeyCombination::fromCombined(0);
case 0x000000b7: // KEYCODE_PROG_RED
return Qt::Key_Red;
@@ -721,7 +780,7 @@ namespace QtAndroidInput
case 0x000000cd: // KEYCODE_MANNER_MODE do we need such a thing?
case 0x000000ce: // KEYCODE_3D_MODE
case 0x000000cf: // KEYCODE_CONTACTS
- return 0;
+ return QKeyCombination::fromCombined(0);
case 0x000000d0: // KEYCODE_CALENDAR
return Qt::Key_Calendar;
@@ -747,7 +806,7 @@ namespace QtAndroidInput
default:
qWarning() << "Unhandled key code " << key << '!';
- return 0;
+ return QKeyCombination::fromCombined(0);
}
}
@@ -780,7 +839,7 @@ namespace QtAndroidInput
{
QWindowSystemInterface::handleKeyEvent(0,
QEvent::KeyPress,
- mapAndroidKey(key),
+ mapAndroidKey(key).toCombined(),
mapAndroidModifiers(modifier),
toString(unicode),
autoRepeat);
@@ -790,7 +849,7 @@ namespace QtAndroidInput
{
QWindowSystemInterface::handleKeyEvent(0,
QEvent::KeyRelease,
- mapAndroidKey(key),
+ mapAndroidKey(key).toCombined(),
mapAndroidModifiers(modifier),
toString(unicode),
autoRepeat);
@@ -798,7 +857,6 @@ namespace QtAndroidInput
static void keyboardVisibilityChanged(JNIEnv */*env*/, jobject /*thiz*/, jboolean visibility)
{
- m_softwareKeyboardVisible = visibility;
if (!visibility)
m_softwareKeyboardRect = QRect();
@@ -810,9 +868,7 @@ namespace QtAndroidInput
QMetaObject::invokeMethod(inputContext, "hideSelectionHandles", Qt::QueuedConnection);
}
}
-#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
- qDebug() << "@@@ KEYBOARDVISIBILITYCHANGED" << inputContext;
-#endif
+ qCDebug(lcQpaInputMethods) << "@@@ KEYBOARDVISIBILITYCHANGED" << inputContext;
}
static void keyboardGeometryChanged(JNIEnv */*env*/, jobject /*thiz*/, jint x, jint y, jint w, jint h)
@@ -825,16 +881,12 @@ namespace QtAndroidInput
if (inputContext && qGuiApp)
inputContext->emitKeyboardRectChanged();
-#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
- qDebug() << "@@@ KEYBOARDRECTCHANGED" << m_softwareKeyboardRect;
-#endif
+ qCDebug(lcQpaInputMethods) << "@@@ KEYBOARDRECTCHANGED" << m_softwareKeyboardRect;
}
static void handleLocationChanged(JNIEnv */*env*/, jobject /*thiz*/, int id, int x, int y)
{
-#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
- qDebug() << "@@@ handleLocationChanged" << id << x << y;
-#endif
+ qCDebug(lcQpaInputMethods) << "@@@ handleLocationChanged" << id << x << y;
QAndroidInputContext *inputContext = QAndroidInputContext::androidInputContext();
if (inputContext && qGuiApp)
QMetaObject::invokeMethod(inputContext, "handleLocationChanged", Qt::BlockingQueuedConnection,
@@ -842,10 +894,12 @@ namespace QtAndroidInput
}
- static JNINativeMethod methods[] = {
+
+ static const JNINativeMethod methods[] = {
{"touchBegin","(I)V",(void*)touchBegin},
{"touchAdd","(IIIZIIFFFF)V",(void*)touchAdd},
{"touchEnd","(II)V",(void*)touchEnd},
+ {"touchCancel", "(I)V", (void *)touchCancel},
{"mouseDown", "(III)V", (void *)mouseDown},
{"mouseUp", "(III)V", (void *)mouseUp},
{"mouseMove", "(III)V", (void *)mouseMove},
@@ -857,14 +911,15 @@ namespace QtAndroidInput
{"keyUp", "(IIIZ)V", (void *)keyUp},
{"keyboardVisibilityChanged", "(Z)V", (void *)keyboardVisibilityChanged},
{"keyboardGeometryChanged", "(IIII)V", (void *)keyboardGeometryChanged},
- {"handleLocationChanged", "(III)V", (void *)handleLocationChanged}
+ {"handleLocationChanged", "(III)V", (void *)handleLocationChanged},
+ {"dispatchGenericMotionEvent", "(Landroid/view/MotionEvent;)Z", reinterpret_cast<void *>(dispatchGenericMotionEvent)},
+ {"dispatchKeyEvent", "(Landroid/view/KeyEvent;)Z", reinterpret_cast<void *>(dispatchKeyEvent)},
};
- bool registerNatives(JNIEnv *env)
+ bool registerNatives(QJniEnvironment &env)
{
- jclass appClass = QtAndroid::applicationClass();
-
- if (env->RegisterNatives(appClass, methods, sizeof(methods) / sizeof(methods[0])) < 0) {
+ if (!env.registerNativeMethods(QtJniTypes::Traits<QtJniTypes::QtInputDelegate>::className(),
+ methods, sizeof(methods) / sizeof(methods[0]))) {
__android_log_print(ANDROID_LOG_FATAL,"Qt", "RegisterNatives failed");
return false;
}
diff --git a/src/plugins/platforms/android/androidjniinput.h b/src/plugins/platforms/android/androidjniinput.h
index cc3070c4aa..28a2665bf6 100644
--- a/src/plugins/platforms/android/androidjniinput.h
+++ b/src/plugins/platforms/android/androidjniinput.h
@@ -1,51 +1,20 @@
-/****************************************************************************
-**
-** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef ANDROIDJNIINPUT_H
#define ANDROIDJNIINPUT_H
#include <jni.h>
#include <QtCore/qglobal.h>
+#include <QtCore/QLoggingCategory>
#include <QtCore/QRect>
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(lcQpaInputMethods);
+
+class QJniEnvironment;
+
namespace QtAndroidInput
{
// Software keyboard support
@@ -58,9 +27,31 @@ namespace QtAndroidInput
// Software keyboard support
// cursor/selection handles
- void updateHandles(int handleCount, QPoint editMenuPos = QPoint(), uint32_t editButtons = 0, QPoint cursor = QPoint(), QPoint anchor = QPoint(), bool rtl = false);
-
- bool registerNatives(JNIEnv *env);
+ void updateHandles(int handleCount, QPoint editMenuPos = QPoint(), uint32_t editButtons = 0,
+ QPoint cursor = QPoint(), QPoint anchor = QPoint(), bool rtl = false);
+ int getSelectHandleWidth();
+
+ class GenericMotionEventListener
+ {
+ public:
+ virtual ~GenericMotionEventListener();
+ virtual bool handleGenericMotionEvent(jobject event) = 0;
+ };
+
+ class KeyEventListener
+ {
+ public:
+ virtual ~KeyEventListener();
+ virtual bool handleKeyEvent(jobject event) = 0;
+ };
+
+ void registerGenericMotionEventListener(GenericMotionEventListener *listener);
+ void unregisterGenericMotionEventListener(GenericMotionEventListener *listener);
+
+ void registerKeyEventListener(KeyEventListener *listener);
+ void unregisterKeyEventListener(KeyEventListener *listener);
+
+ bool registerNatives(QJniEnvironment &env);
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/android/androidjnimain.cpp b/src/plugins/platforms/android/androidjnimain.cpp
index 1c7800358f..206bbd03d6 100644
--- a/src/plugins/platforms/android/androidjnimain.cpp
+++ b/src/plugins/platforms/android/androidjnimain.cpp
@@ -1,74 +1,46 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 BogDan Vatra <bogdan@kde.org>
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2014 BogDan Vatra <bogdan@kde.org>
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <dlfcn.h>
#include <pthread.h>
-#include <semaphore.h>
#include <qplugin.h>
-#include <qdebug.h>
+#include <semaphore.h>
-#include "androidjnimain.h"
+#include "androidcontentfileengine.h"
+#include "androiddeadlockprotector.h"
#include "androidjniaccessibility.h"
#include "androidjniinput.h"
-#include "androidjniclipboard.h"
+#include "androidjnimain.h"
#include "androidjnimenu.h"
-#include "androidcontentfileengine.h"
-#include "androiddeadlockprotector.h"
+#include "androidwindowembedding.h"
+#include "qandroidassetsfileenginehandler.h"
+#include "qandroideventdispatcher.h"
#include "qandroidplatformdialoghelpers.h"
#include "qandroidplatformintegration.h"
-#include "qandroidassetsfileenginehandler.h"
+#include "qandroidplatformclipboard.h"
+#include "qandroidplatformwindow.h"
-#include <android/bitmap.h>
-#include <android/asset_manager_jni.h>
-#include "qandroideventdispatcher.h"
#include <android/api-level.h>
+#include <android/asset_manager_jni.h>
+#include <android/bitmap.h>
+#include <QtCore/private/qjnihelpers_p.h>
+#include <QtCore/qbasicatomic.h>
+#include <QtCore/qjnienvironment.h>
+#include <QtCore/qjniobject.h>
+#include <QtCore/qprocess.h>
#include <QtCore/qresource.h>
+#include <QtCore/qscopeguard.h>
#include <QtCore/qthread.h>
-#include <QtCore/private/qjnihelpers_p.h>
-#include <QtCore/private/qjni_p.h>
#include <QtGui/private/qguiapplication_p.h>
#include <QtGui/private/qhighdpiscaling_p.h>
#include <qpa/qwindowsysteminterface.h>
+
+using namespace Qt::StringLiterals;
+
QT_BEGIN_NAMESPACE
static JavaVM *m_javaVM = nullptr;
@@ -78,11 +50,12 @@ static jmethodID m_loadClassMethodID = nullptr;
static AAssetManager *m_assetManager = nullptr;
static jobject m_assets = nullptr;
static jobject m_resourcesObj = nullptr;
-static jobject m_activityObject = nullptr;
-static jmethodID m_createSurfaceMethodID = nullptr;
-static jobject m_serviceObject = nullptr;
-static jmethodID m_setSurfaceGeometryMethodID = nullptr;
-static jmethodID m_destroySurfaceMethodID = nullptr;
+
+static jclass m_qtActivityClass = nullptr;
+static jclass m_qtServiceClass = nullptr;
+
+static QtJniTypes::QtActivityDelegateBase m_activityDelegate = nullptr;
+static QtJniTypes::QtInputDelegate m_inputDelegate = nullptr;
static int m_pendingApplicationState = -1;
static QBasicMutex m_platformMutex;
@@ -92,8 +65,6 @@ static jmethodID m_createBitmapMethodID = nullptr;
static jobject m_ARGB_8888_BitmapConfigValue = nullptr;
static jobject m_RGB_565_BitmapConfigValue = nullptr;
-static bool m_statusBarShowing = true;
-
static jclass m_bitmapDrawableClass = nullptr;
static jmethodID m_bitmapDrawableConstructorMethodID = nullptr;
@@ -103,16 +74,11 @@ static void *m_mainLibraryHnd = nullptr;
static QList<QByteArray> m_applicationParams;
static sem_t m_exitSemaphore, m_terminateSemaphore;
-QHash<int, AndroidSurfaceClient *> m_surfaces;
-
-static QBasicMutex m_surfacesMutex;
-static int m_surfaceId = 1;
-
static QAndroidPlatformIntegration *m_androidPlatformIntegration = nullptr;
-static int m_desktopWidthPixels = 0;
-static int m_desktopHeightPixels = 0;
+static int m_availableWidthPixels = 0;
+static int m_availableHeightPixels = 0;
static double m_scaledDensity = 0;
static double m_density = 1.0;
@@ -125,6 +91,10 @@ static const char m_qtTag[] = "Qt";
static const char m_classErrorMsg[] = "Can't find class \"%s\"";
static const char m_methodErrorMsg[] = "Can't find method \"%s%s\"";
+Q_CONSTINIT static QBasicAtomicInt startQtAndroidPluginCalled = Q_BASIC_ATOMIC_INITIALIZER(0);
+
+Q_DECLARE_JNI_CLASS(QtEmbeddedDelegateFactory, "org/qtproject/qt/android/QtEmbeddedDelegateFactory")
+
namespace QtAndroid
{
QBasicMutex *platformInterfaceMutex()
@@ -135,10 +105,16 @@ namespace QtAndroid
void setAndroidPlatformIntegration(QAndroidPlatformIntegration *androidPlatformIntegration)
{
m_androidPlatformIntegration = androidPlatformIntegration;
+ QtAndroid::notifyNativePluginIntegrationReady((bool)m_androidPlatformIntegration);
// flush the pending state if necessary.
- if (m_androidPlatformIntegration && (m_pendingApplicationState != -1))
+ if (m_androidPlatformIntegration && (m_pendingApplicationState != -1)) {
+ if (m_pendingApplicationState == Qt::ApplicationActive)
+ QtAndroidPrivate::handleResume();
+ else if (m_pendingApplicationState == Qt::ApplicationInactive)
+ QtAndroidPrivate::handlePause();
QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationState(m_pendingApplicationState));
+ }
m_pendingApplicationState = -1;
}
@@ -155,14 +131,29 @@ namespace QtAndroid
: 0;
}
- int desktopWidthPixels()
+ QWindow *windowFromId(int windowId)
{
- return m_desktopWidthPixels;
+ if (!qGuiApp)
+ return nullptr;
+
+ for (QWindow *w : qGuiApp->allWindows()) {
+ if (!w->handle())
+ continue;
+ QAndroidPlatformWindow *window = static_cast<QAndroidPlatformWindow *>(w->handle());
+ if (window->nativeViewId() == windowId)
+ return w;
+ }
+ return nullptr;
}
- int desktopHeightPixels()
+ int availableWidthPixels()
{
- return m_desktopHeightPixels;
+ return m_availableWidthPixels;
+ }
+
+ int availableHeightPixels()
+ {
+ return m_availableHeightPixels;
}
double scaledDensity()
@@ -190,32 +181,90 @@ namespace QtAndroid
return m_applicationClass;
}
- jobject activity()
+ // TODO move calls from here to where they logically belong
+ void setSystemUiVisibility(SystemUiVisibility uiVisibility)
{
- return m_activityObject;
+ qtActivityDelegate().callMethod<void>("setSystemUiVisibility", jint(uiVisibility));
}
- jobject service()
+ // FIXME: avoid direct access to QtActivityDelegate
+ QtJniTypes::QtActivityDelegateBase qtActivityDelegate()
{
- return m_serviceObject;
+ using namespace QtJniTypes;
+ if (!m_activityDelegate.isValid()) {
+ if (isQtApplication()) {
+ auto context = QtAndroidPrivate::activity();
+ m_activityDelegate = context.callMethod<QtActivityDelegateBase>("getActivityDelegate");
+ } else {
+ m_activityDelegate = QJniObject::callStaticMethod<QtActivityDelegateBase>(
+ Traits<QtEmbeddedDelegateFactory>::className(),
+ "getActivityDelegate",
+ QtAndroidPrivate::activity());
+ }
+ }
+
+ return m_activityDelegate;
}
- void showStatusBar()
+ QtJniTypes::QtInputDelegate qtInputDelegate()
{
- if (m_statusBarShowing)
- return;
+ if (!m_inputDelegate.isValid()) {
+ m_inputDelegate = qtActivityDelegate().callMethod<QtJniTypes::QtInputDelegate>(
+ "getInputDelegate");
+ }
- QJNIObjectPrivate::callStaticMethod<void>(m_applicationClass, "setFullScreen", "(Z)V", false);
- m_statusBarShowing = true;
+ return m_inputDelegate;
}
- void hideStatusBar()
+ bool isQtApplication()
{
- if (!m_statusBarShowing)
- return;
+ // Returns true if the app is a Qt app, i.e. Qt controls the whole app and
+ // the Activity/Service is created by Qt. Returns false if instead Qt is
+ // embedded into a native Android app, where the Activity/Service is created
+ // by the user, outside of Qt, and Qt content is added as a view.
+ JNIEnv *env = QJniEnvironment::getJniEnv();
+ auto activity = QtAndroidPrivate::activity();
+ if (activity.isValid())
+ return env->IsInstanceOf(activity.object(), m_qtActivityClass);
+ auto service = QtAndroidPrivate::service();
+ if (service.isValid())
+ return env->IsInstanceOf(QtAndroidPrivate::service().object(), m_qtServiceClass);
+ // return true as default as Qt application is our default use case.
+ // famous last words: we should not end up here
+ return true;
+ }
+
+ void notifyAccessibilityLocationChange(uint accessibilityObjectId)
+ {
+ qtActivityDelegate().callMethod<void>("notifyLocationChange", accessibilityObjectId);
+ }
+
+ void notifyObjectHide(uint accessibilityObjectId, uint parentObjectId)
+ {
+ qtActivityDelegate().callMethod<void>("notifyObjectHide",
+ accessibilityObjectId, parentObjectId);
+ }
+
+ void notifyObjectFocus(uint accessibilityObjectId)
+ {
+ qtActivityDelegate().callMethod<void>("notifyObjectFocus", accessibilityObjectId);
+ }
- QJNIObjectPrivate::callStaticMethod<void>(m_applicationClass, "setFullScreen", "(Z)V", true);
- m_statusBarShowing = false;
+ void notifyValueChanged(uint accessibilityObjectId, jstring value)
+ {
+ qtActivityDelegate().callMethod<void>("notifyValueChanged", accessibilityObjectId, value);
+ }
+
+ void notifyScrolledEvent(uint accessibilityObjectId)
+ {
+ qtActivityDelegate().callMethod<void>("notifyScrolledEvent", accessibilityObjectId);
+ }
+
+ void notifyNativePluginIntegrationReady(bool ready)
+ {
+ QJniObject::callStaticMethod<void>(m_applicationClass,
+ "notifyNativePluginIntegrationReady",
+ ready);
}
jobject createBitmap(QImage img, JNIEnv *env)
@@ -224,7 +273,7 @@ namespace QtAndroid
return 0;
if (img.format() != QImage::Format_RGBA8888 && img.format() != QImage::Format_RGB16)
- img = img.convertToFormat(QImage::Format_RGBA8888);
+ img = std::move(img).convertToFormat(QImage::Format_RGBA8888);
jobject bitmap = env->CallStaticObjectMethod(m_bitmapClass,
m_createBitmapMethodID,
@@ -306,133 +355,19 @@ namespace QtAndroid
QString deviceName()
{
- QString manufacturer = QJNIObjectPrivate::getStaticObjectField("android/os/Build", "MANUFACTURER", "Ljava/lang/String;").toString();
- QString model = QJNIObjectPrivate::getStaticObjectField("android/os/Build", "MODEL", "Ljava/lang/String;").toString();
-
- return manufacturer + QLatin1Char(' ') + model;
- }
+ QString manufacturer = QJniObject::getStaticObjectField("android/os/Build", "MANUFACTURER", "Ljava/lang/String;").toString();
+ QString model = QJniObject::getStaticObjectField("android/os/Build", "MODEL", "Ljava/lang/String;").toString();
- int createSurface(AndroidSurfaceClient *client, const QRect &geometry, bool onTop, int imageDepth)
- {
- QJNIEnvironmentPrivate env;
- if (!env)
- return -1;
-
- m_surfacesMutex.lock();
- int surfaceId = m_surfaceId++;
- m_surfaces[surfaceId] = client;
- m_surfacesMutex.unlock();
-
- jint x = 0, y = 0, w = -1, h = -1;
- if (!geometry.isNull()) {
- x = geometry.x();
- y = geometry.y();
- w = std::max(geometry.width(), 1);
- h = std::max(geometry.height(), 1);
- }
- env->CallStaticVoidMethod(m_applicationClass,
- m_createSurfaceMethodID,
- surfaceId,
- jboolean(onTop),
- x, y, w, h,
- imageDepth);
- return surfaceId;
- }
-
- int insertNativeView(jobject view, const QRect &geometry)
- {
- m_surfacesMutex.lock();
- const int surfaceId = m_surfaceId++;
- m_surfaces[surfaceId] = nullptr; // dummy
- m_surfacesMutex.unlock();
-
- jint x = 0, y = 0, w = -1, h = -1;
- if (!geometry.isNull())
- geometry.getRect(&x, &y, &w, &h);
-
- QJNIObjectPrivate::callStaticMethod<void>(m_applicationClass,
- "insertNativeView",
- "(ILandroid/view/View;IIII)V",
- surfaceId,
- view,
- x,
- y,
- qMax(w, 1),
- qMax(h, 1));
-
- return surfaceId;
+ return manufacturer + u' ' + model;
}
void setViewVisibility(jobject view, bool visible)
{
- QJNIObjectPrivate::callStaticMethod<void>(m_applicationClass,
- "setViewVisibility",
- "(Landroid/view/View;Z)V",
- view,
- visible);
- }
-
- void setSurfaceGeometry(int surfaceId, const QRect &geometry)
- {
- if (surfaceId == -1)
- return;
-
- QJNIEnvironmentPrivate env;
- if (!env)
- return;
- jint x = 0, y = 0, w = -1, h = -1;
- if (!geometry.isNull()) {
- x = geometry.x();
- y = geometry.y();
- w = geometry.width();
- h = geometry.height();
- }
- env->CallStaticVoidMethod(m_applicationClass,
- m_setSurfaceGeometryMethodID,
- surfaceId,
- x, y, w, h);
- }
-
-
- void destroySurface(int surfaceId)
- {
- if (surfaceId == -1)
- return;
-
- {
- QMutexLocker lock(&m_surfacesMutex);
- const auto &it = m_surfaces.find(surfaceId);
- if (it != m_surfaces.end())
- m_surfaces.erase(it);
- }
-
- QJNIEnvironmentPrivate env;
- if (env)
- env->CallStaticVoidMethod(m_applicationClass,
- m_destroySurfaceMethodID,
- surfaceId);
- }
-
- void bringChildToFront(int surfaceId)
- {
- if (surfaceId == -1)
- return;
-
- QJNIObjectPrivate::callStaticMethod<void>(m_applicationClass,
- "bringChildToFront",
- "(I)V",
- surfaceId);
- }
-
- void bringChildToBack(int surfaceId)
- {
- if (surfaceId == -1)
- return;
-
- QJNIObjectPrivate::callStaticMethod<void>(m_applicationClass,
- "bringChildToBack",
- "(I)V",
- surfaceId);
+ QJniObject::callStaticMethod<void>(m_applicationClass,
+ "setViewVisibility",
+ "(Landroid/view/View;Z)V",
+ view,
+ visible);
}
bool blockEventLoopsWhenSuspended()
@@ -448,28 +383,19 @@ namespace QtAndroid
} // namespace QtAndroid
-static jboolean startQtAndroidPlugin(JNIEnv *env, jobject /*object*/, jstring paramsString, jstring environmentString)
+static jboolean startQtAndroidPlugin(JNIEnv *env, jobject /*object*/, jstring paramsString)
{
+ Q_UNUSED(env)
+
m_androidPlatformIntegration = nullptr;
m_androidAssetsFileEngineHandler = new AndroidAssetsFileEngineHandler();
m_androidContentFileEngineHandler = new AndroidContentFileEngineHandler();
m_mainLibraryHnd = nullptr;
- { // Set env. vars
- const char *nativeString = env->GetStringUTFChars(environmentString, 0);
- const QList<QByteArray> envVars = QByteArray(nativeString).split('\t');
- env->ReleaseStringUTFChars(environmentString, nativeString);
- for (const QByteArray &envVar : envVars) {
- int pos = envVar.indexOf('=');
- if (pos != -1 && ::setenv(envVar.left(pos), envVar.mid(pos + 1), 1) != 0)
- qWarning() << "Can't set environment" << envVar;
- }
- }
- const char *nativeString = env->GetStringUTFChars(paramsString, 0);
- QByteArray string = nativeString;
- env->ReleaseStringUTFChars(paramsString, nativeString);
+ const QStringList argsList = QProcess::splitCommand(QJniObject(paramsString).toString());
- m_applicationParams=string.split('\t');
+ for (const QString &arg : argsList)
+ m_applicationParams.append(arg.toUtf8());
// Go home
QDir::setCurrent(QDir::homePath());
@@ -509,11 +435,11 @@ static void waitForServiceSetup(JNIEnv *env, jclass /*clazz*/)
Q_UNUSED(env);
// The service must wait until the QCoreApplication starts otherwise onBind will be
// called too early
- if (m_serviceObject)
+ if (QtAndroidPrivate::service().isValid())
QtAndroidPrivate::waitForServiceSetup();
}
-static jboolean startQtApplication(JNIEnv */*env*/, jclass /*clazz*/)
+static void startQtApplication(JNIEnv */*env*/, jclass /*clazz*/)
{
{
JNIEnv* env = nullptr;
@@ -521,20 +447,27 @@ static jboolean startQtApplication(JNIEnv */*env*/, jclass /*clazz*/)
args.version = JNI_VERSION_1_6;
args.name = "QtMainThread";
args.group = NULL;
- JavaVM *vm = QtAndroidPrivate::javaVM();
- if (vm != 0)
+ JavaVM *vm = QJniEnvironment::javaVM();
+ if (vm)
vm->AttachCurrentThread(&env, &args);
}
+ // Register type for invokeMethod() calls.
+ qRegisterMetaType<Qt::ScreenOrientation>("Qt::ScreenOrientation");
+
// Register resources if they are available
if (QFile{QStringLiteral("assets:/android_rcc_bundle.rcc")}.exists())
QResource::registerResource(QStringLiteral("assets:/android_rcc_bundle.rcc"));
- QVarLengthArray<const char *> params(m_applicationParams.size());
- for (int i = 0; i < m_applicationParams.size(); i++)
- params[i] = static_cast<const char *>(m_applicationParams[i].constData());
+ const int argc = m_applicationParams.size();
+ QVarLengthArray<char *> argv(argc + 1);
+ for (int i = 0; i < argc; i++)
+ argv[i] = m_applicationParams[i].data();
+ argv[argc] = nullptr;
- int ret = m_main(m_applicationParams.length(), const_cast<char **>(params.data()));
+ startQtAndroidPluginCalled.fetchAndAddRelease(1);
+ const int ret = m_main(argc, argv.data());
+ qInfo() << "main() returned" << ret;
if (m_mainLibraryHnd) {
int res = dlclose(m_mainLibraryHnd);
@@ -542,17 +475,16 @@ static jboolean startQtApplication(JNIEnv */*env*/, jclass /*clazz*/)
qWarning() << "dlclose failed:" << dlerror();
}
- if (m_applicationClass) {
- qWarning("exit app 0");
- QJNIObjectPrivate::callStaticMethod<void>(m_applicationClass, "quitApp", "()V");
- }
+ if (m_applicationClass)
+ QJniObject::callStaticMethod<void>(m_applicationClass, "quitApp", "()V");
sem_post(&m_terminateSemaphore);
sem_wait(&m_exitSemaphore);
sem_destroy(&m_exitSemaphore);
// We must call exit() to ensure that all global objects will be destructed
- exit(ret);
+ if (!qEnvironmentVariableIsSet("QT_ANDROID_NO_EXIT_CALL"))
+ exit(ret);
}
static void quitQtCoreApplication(JNIEnv *env, jclass /*clazz*/)
@@ -580,17 +512,15 @@ static void terminateQt(JNIEnv *env, jclass /*clazz*/)
QAndroidEventDispatcherStopper::instance()->goingToStop(false);
}
- sem_wait(&m_terminateSemaphore);
+ if (startQtAndroidPluginCalled.loadAcquire())
+ sem_wait(&m_terminateSemaphore);
+
sem_destroy(&m_terminateSemaphore);
env->DeleteGlobalRef(m_applicationClass);
env->DeleteGlobalRef(m_classLoaderObject);
if (m_resourcesObj)
env->DeleteGlobalRef(m_resourcesObj);
- if (m_activityObject)
- env->DeleteGlobalRef(m_activityObject);
- if (m_serviceObject)
- env->DeleteGlobalRef(m_serviceObject);
if (m_bitmapClass)
env->DeleteGlobalRef(m_bitmapClass);
if (m_ARGB_8888_BitmapConfigValue)
@@ -601,56 +531,49 @@ static void terminateQt(JNIEnv *env, jclass /*clazz*/)
env->DeleteGlobalRef(m_bitmapDrawableClass);
if (m_assets)
env->DeleteGlobalRef(m_assets);
+ if (m_qtActivityClass)
+ env->DeleteGlobalRef(m_qtActivityClass);
+ if (m_qtServiceClass)
+ env->DeleteGlobalRef(m_qtServiceClass);
m_androidPlatformIntegration = nullptr;
delete m_androidAssetsFileEngineHandler;
m_androidAssetsFileEngineHandler = nullptr;
sem_post(&m_exitSemaphore);
}
-static void setSurface(JNIEnv *env, jobject /*thiz*/, jint id, jobject jSurface, jint w, jint h)
-{
- QMutexLocker lock(&m_surfacesMutex);
- const auto &it = m_surfaces.find(id);
- if (it == m_surfaces.end())
- return;
-
- auto surfaceClient = it.value();
- if (surfaceClient)
- surfaceClient->surfaceChanged(env, jSurface, w, h);
-}
-
-static void setDisplayMetrics(JNIEnv */*env*/, jclass /*clazz*/,
- jint widthPixels, jint heightPixels,
- jint desktopWidthPixels, jint desktopHeightPixels,
- jdouble xdpi, jdouble ydpi,
- jdouble scaledDensity, jdouble density)
+static void setDisplayMetrics(JNIEnv * /*env*/, jclass /*clazz*/, jint screenWidthPixels,
+ jint screenHeightPixels, jint availableLeftPixels,
+ jint availableTopPixels, jint availableWidthPixels,
+ jint availableHeightPixels, jdouble xdpi, jdouble ydpi,
+ jdouble scaledDensity, jdouble density, jfloat refreshRate)
{
- // Android does not give us the correct screen size for immersive mode, but
- // the surface does have the right size
-
- widthPixels = qMax(widthPixels, desktopWidthPixels);
- heightPixels = qMax(heightPixels, desktopHeightPixels);
+ Q_UNUSED(availableLeftPixels)
+ Q_UNUSED(availableTopPixels)
- m_desktopWidthPixels = desktopWidthPixels;
- m_desktopHeightPixels = desktopHeightPixels;
+ m_availableWidthPixels = availableWidthPixels;
+ m_availableHeightPixels = availableHeightPixels;
m_scaledDensity = scaledDensity;
m_density = density;
+ const QSize screenSize(screenWidthPixels, screenHeightPixels);
+ // available geometry always starts from top left
+ const QRect availableGeometry(0, 0, availableWidthPixels, availableHeightPixels);
+ const QSize physicalSize(qRound(double(screenWidthPixels) / xdpi * 25.4),
+ qRound(double(screenHeightPixels) / ydpi * 25.4));
+
QMutexLocker lock(&m_platformMutex);
if (!m_androidPlatformIntegration) {
- QAndroidPlatformIntegration::setDefaultDisplayMetrics(desktopWidthPixels,
- desktopHeightPixels,
- qRound(double(widthPixels) / xdpi * 25.4),
- qRound(double(heightPixels) / ydpi * 25.4),
- widthPixels,
- heightPixels);
+ QAndroidPlatformIntegration::setDefaultDisplayMetrics(
+ availableGeometry.left(), availableGeometry.top(), availableGeometry.width(),
+ availableGeometry.height(), physicalSize.width(), physicalSize.height(),
+ screenSize.width(), screenSize.height());
} else {
- m_androidPlatformIntegration->setDisplayMetrics(qRound(double(widthPixels) / xdpi * 25.4),
- qRound(double(heightPixels) / ydpi * 25.4));
- m_androidPlatformIntegration->setScreenSize(widthPixels, heightPixels);
- m_androidPlatformIntegration->setDesktopSize(desktopWidthPixels, desktopHeightPixels);
+ m_androidPlatformIntegration->setScreenSizeParameters(physicalSize, screenSize,
+ availableGeometry);
+ m_androidPlatformIntegration->setRefreshRate(refreshRate);
}
}
+Q_DECLARE_JNI_NATIVE_METHOD(setDisplayMetrics)
static void updateWindow(JNIEnv */*env*/, jobject /*thiz*/)
{
@@ -670,10 +593,6 @@ static void updateWindow(JNIEnv */*env*/, jobject /*thiz*/)
QWindowSystemInterface::handleExposeEvent(w, QRegion(QRect(QPoint(), w->geometry().size())));
}
}
-
- QAndroidPlatformScreen *screen = static_cast<QAndroidPlatformScreen *>(m_androidPlatformIntegration->screen());
- if (screen->rasterSurfaces())
- QMetaObject::invokeMethod(screen, "setDirty", Qt::QueuedConnection, Q_ARG(QRect,screen->geometry()));
}
static void updateApplicationState(JNIEnv */*env*/, jobject /*thiz*/, jint state)
@@ -743,11 +662,51 @@ static void handleOrientationChanged(JNIEnv */*env*/, jobject /*thiz*/, jint new
QAndroidPlatformIntegration::setScreenOrientation(screenOrientation, native);
QMutexLocker lock(&m_platformMutex);
if (m_androidPlatformIntegration) {
- QPlatformScreen *screen = m_androidPlatformIntegration->screen();
- QWindowSystemInterface::handleScreenOrientationChange(screen->screen(),
- screenOrientation);
+ QAndroidPlatformScreen *screen = m_androidPlatformIntegration->screen();
+ // Use invokeMethod to keep the certain order of the "geometry change"
+ // and "orientation change" event handling.
+ if (screen) {
+ QMetaObject::invokeMethod(screen, "setOrientation", Qt::AutoConnection,
+ Q_ARG(Qt::ScreenOrientation, screenOrientation));
+ }
}
}
+Q_DECLARE_JNI_NATIVE_METHOD(handleOrientationChanged)
+
+static void handleRefreshRateChanged(JNIEnv */*env*/, jclass /*cls*/, jfloat refreshRate)
+{
+ if (m_androidPlatformIntegration)
+ m_androidPlatformIntegration->setRefreshRate(refreshRate);
+}
+Q_DECLARE_JNI_NATIVE_METHOD(handleRefreshRateChanged)
+
+static void handleScreenAdded(JNIEnv */*env*/, jclass /*cls*/, jint displayId)
+{
+ if (m_androidPlatformIntegration)
+ m_androidPlatformIntegration->handleScreenAdded(displayId);
+}
+Q_DECLARE_JNI_NATIVE_METHOD(handleScreenAdded)
+
+static void handleScreenChanged(JNIEnv */*env*/, jclass /*cls*/, jint displayId)
+{
+ if (m_androidPlatformIntegration)
+ m_androidPlatformIntegration->handleScreenChanged(displayId);
+}
+Q_DECLARE_JNI_NATIVE_METHOD(handleScreenChanged)
+
+static void handleScreenRemoved(JNIEnv */*env*/, jclass /*cls*/, jint displayId)
+{
+ if (m_androidPlatformIntegration)
+ m_androidPlatformIntegration->handleScreenRemoved(displayId);
+}
+Q_DECLARE_JNI_NATIVE_METHOD(handleScreenRemoved)
+
+static void handleUiDarkModeChanged(JNIEnv */*env*/, jobject /*thiz*/, jint newUiMode)
+{
+ QAndroidPlatformIntegration::setColorScheme(
+ (newUiMode == 1 ) ? Qt::ColorScheme::Dark : Qt::ColorScheme::Light);
+}
+Q_DECLARE_JNI_NATIVE_METHOD(handleUiDarkModeChanged)
static void onActivityResult(JNIEnv */*env*/, jclass /*cls*/,
jint requestCode,
@@ -768,117 +727,137 @@ static jobject onBind(JNIEnv */*env*/, jclass /*cls*/, jobject intent)
}
static JNINativeMethod methods[] = {
- {"startQtAndroidPlugin", "(Ljava/lang/String;Ljava/lang/String;)Z", (void *)startQtAndroidPlugin},
- {"startQtApplication", "()V", (void *)startQtApplication},
- {"quitQtAndroidPlugin", "()V", (void *)quitQtAndroidPlugin},
- {"quitQtCoreApplication", "()V", (void *)quitQtCoreApplication},
- {"terminateQt", "()V", (void *)terminateQt},
- {"waitForServiceSetup", "()V", (void *)waitForServiceSetup},
- {"setDisplayMetrics", "(IIIIDDDD)V", (void *)setDisplayMetrics},
- {"setSurface", "(ILjava/lang/Object;II)V", (void *)setSurface},
- {"updateWindow", "()V", (void *)updateWindow},
- {"updateApplicationState", "(I)V", (void *)updateApplicationState},
- {"handleOrientationChanged", "(II)V", (void *)handleOrientationChanged},
- {"onActivityResult", "(IILandroid/content/Intent;)V", (void *)onActivityResult},
- {"onNewIntent", "(Landroid/content/Intent;)V", (void *)onNewIntent},
- {"onBind", "(Landroid/content/Intent;)Landroid/os/IBinder;", (void *)onBind}
+ { "startQtAndroidPlugin", "(Ljava/lang/String;)Z", (void *)startQtAndroidPlugin },
+ { "startQtApplication", "()V", (void *)startQtApplication },
+ { "quitQtAndroidPlugin", "()V", (void *)quitQtAndroidPlugin },
+ { "quitQtCoreApplication", "()V", (void *)quitQtCoreApplication },
+ { "terminateQt", "()V", (void *)terminateQt },
+ { "waitForServiceSetup", "()V", (void *)waitForServiceSetup },
+ { "updateWindow", "()V", (void *)updateWindow },
+ { "updateApplicationState", "(I)V", (void *)updateApplicationState },
+ { "onActivityResult", "(IILandroid/content/Intent;)V", (void *)onActivityResult },
+ { "onNewIntent", "(Landroid/content/Intent;)V", (void *)onNewIntent },
+ { "onBind", "(Landroid/content/Intent;)Landroid/os/IBinder;", (void *)onBind }
};
#define FIND_AND_CHECK_CLASS(CLASS_NAME) \
clazz = env->FindClass(CLASS_NAME); \
if (!clazz) { \
__android_log_print(ANDROID_LOG_FATAL, m_qtTag, m_classErrorMsg, CLASS_NAME); \
- return JNI_FALSE; \
+ return false; \
}
#define GET_AND_CHECK_METHOD(VAR, CLASS, METHOD_NAME, METHOD_SIGNATURE) \
VAR = env->GetMethodID(CLASS, METHOD_NAME, METHOD_SIGNATURE); \
if (!VAR) { \
__android_log_print(ANDROID_LOG_FATAL, m_qtTag, m_methodErrorMsg, METHOD_NAME, METHOD_SIGNATURE); \
- return JNI_FALSE; \
+ return false; \
}
#define GET_AND_CHECK_STATIC_METHOD(VAR, CLASS, METHOD_NAME, METHOD_SIGNATURE) \
VAR = env->GetStaticMethodID(CLASS, METHOD_NAME, METHOD_SIGNATURE); \
if (!VAR) { \
__android_log_print(ANDROID_LOG_FATAL, m_qtTag, m_methodErrorMsg, METHOD_NAME, METHOD_SIGNATURE); \
- return JNI_FALSE; \
+ return false; \
}
#define GET_AND_CHECK_FIELD(VAR, CLASS, FIELD_NAME, FIELD_SIGNATURE) \
VAR = env->GetFieldID(CLASS, FIELD_NAME, FIELD_SIGNATURE); \
if (!VAR) { \
__android_log_print(ANDROID_LOG_FATAL, m_qtTag, m_methodErrorMsg, FIELD_NAME, FIELD_SIGNATURE); \
- return JNI_FALSE; \
+ return false; \
}
#define GET_AND_CHECK_STATIC_FIELD(VAR, CLASS, FIELD_NAME, FIELD_SIGNATURE) \
VAR = env->GetStaticFieldID(CLASS, FIELD_NAME, FIELD_SIGNATURE); \
if (!VAR) { \
__android_log_print(ANDROID_LOG_FATAL, m_qtTag, m_methodErrorMsg, FIELD_NAME, FIELD_SIGNATURE); \
- return JNI_FALSE; \
+ return false; \
}
-static int registerNatives(JNIEnv *env)
+Q_DECLARE_JNI_CLASS(QtDisplayManager, "org/qtproject/qt/android/QtDisplayManager")
+
+static bool registerNatives(QJniEnvironment &env)
{
jclass clazz;
- FIND_AND_CHECK_CLASS("org/qtproject/qt5/android/QtNative");
+ FIND_AND_CHECK_CLASS("org/qtproject/qt/android/QtNative");
m_applicationClass = static_cast<jclass>(env->NewGlobalRef(clazz));
- if (env->RegisterNatives(m_applicationClass, methods, sizeof(methods) / sizeof(methods[0])) < 0) {
+ if (!env.registerNativeMethods(m_applicationClass,
+ methods, sizeof(methods) / sizeof(methods[0]))) {
__android_log_print(ANDROID_LOG_FATAL,"Qt", "RegisterNatives failed");
- return JNI_FALSE;
+ return false;
}
- GET_AND_CHECK_STATIC_METHOD(m_createSurfaceMethodID, m_applicationClass, "createSurface", "(IZIIIII)V");
- GET_AND_CHECK_STATIC_METHOD(m_setSurfaceGeometryMethodID, m_applicationClass, "setSurfaceGeometry", "(IIIII)V");
- GET_AND_CHECK_STATIC_METHOD(m_destroySurfaceMethodID, m_applicationClass, "destroySurface", "(I)V");
+ bool success = env.registerNativeMethods(
+ QtJniTypes::Traits<QtJniTypes::QtDisplayManager>::className(),
+ {
+ Q_JNI_NATIVE_METHOD(setDisplayMetrics),
+ Q_JNI_NATIVE_METHOD(handleOrientationChanged),
+ Q_JNI_NATIVE_METHOD(handleRefreshRateChanged),
+ Q_JNI_NATIVE_METHOD(handleScreenAdded),
+ Q_JNI_NATIVE_METHOD(handleScreenChanged),
+ Q_JNI_NATIVE_METHOD(handleScreenRemoved),
+ Q_JNI_NATIVE_METHOD(handleUiDarkModeChanged)
+ });
+
+ if (!success) {
+ qCritical() << "QtDisplayManager: registerNativeMethods() failed";
+ return JNI_FALSE;
+ }
jmethodID methodID;
GET_AND_CHECK_STATIC_METHOD(methodID, m_applicationClass, "activity", "()Landroid/app/Activity;");
- jobject activityObject = env->CallStaticObjectMethod(m_applicationClass, methodID);
- GET_AND_CHECK_STATIC_METHOD(methodID, m_applicationClass, "service", "()Landroid/app/Service;");
- jobject serviceObject = env->CallStaticObjectMethod(m_applicationClass, methodID);
+ jobject contextObject = env->CallStaticObjectMethod(m_applicationClass, methodID);
+ if (!contextObject) {
+ GET_AND_CHECK_STATIC_METHOD(methodID, m_applicationClass, "service", "()Landroid/app/Service;");
+ contextObject = env->CallStaticObjectMethod(m_applicationClass, methodID);
+ }
+
+ if (!contextObject) {
+ __android_log_print(ANDROID_LOG_FATAL,"Qt", "Failed to get Activity or Service object");
+ return false;
+ }
+ const auto releaseContextObject = qScopeGuard([&env, contextObject]{
+ env->DeleteLocalRef(contextObject);
+ });
+
GET_AND_CHECK_STATIC_METHOD(methodID, m_applicationClass, "classLoader", "()Ljava/lang/ClassLoader;");
m_classLoaderObject = env->NewGlobalRef(env->CallStaticObjectMethod(m_applicationClass, methodID));
clazz = env->GetObjectClass(m_classLoaderObject);
GET_AND_CHECK_METHOD(m_loadClassMethodID, clazz, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
- if (serviceObject)
- m_serviceObject = env->NewGlobalRef(serviceObject);
-
- if (activityObject)
- m_activityObject = env->NewGlobalRef(activityObject);
-
- jobject object = activityObject ? activityObject : serviceObject;
- if (object) {
- FIND_AND_CHECK_CLASS("android/content/ContextWrapper");
- GET_AND_CHECK_METHOD(methodID, clazz, "getAssets", "()Landroid/content/res/AssetManager;");
- m_assets = env->NewGlobalRef(env->CallObjectMethod(object, methodID));
- m_assetManager = AAssetManager_fromJava(env, m_assets);
-
- GET_AND_CHECK_METHOD(methodID, clazz, "getResources", "()Landroid/content/res/Resources;");
- m_resourcesObj = env->NewGlobalRef(env->CallObjectMethod(object, methodID));
-
- FIND_AND_CHECK_CLASS("android/graphics/Bitmap");
- m_bitmapClass = static_cast<jclass>(env->NewGlobalRef(clazz));
- GET_AND_CHECK_STATIC_METHOD(m_createBitmapMethodID, m_bitmapClass
- , "createBitmap", "(IILandroid/graphics/Bitmap$Config;)Landroid/graphics/Bitmap;");
- FIND_AND_CHECK_CLASS("android/graphics/Bitmap$Config");
- jfieldID fieldId;
- GET_AND_CHECK_STATIC_FIELD(fieldId, clazz, "ARGB_8888", "Landroid/graphics/Bitmap$Config;");
- m_ARGB_8888_BitmapConfigValue = env->NewGlobalRef(env->GetStaticObjectField(clazz, fieldId));
- GET_AND_CHECK_STATIC_FIELD(fieldId, clazz, "RGB_565", "Landroid/graphics/Bitmap$Config;");
- m_RGB_565_BitmapConfigValue = env->NewGlobalRef(env->GetStaticObjectField(clazz, fieldId));
-
- FIND_AND_CHECK_CLASS("android/graphics/drawable/BitmapDrawable");
- m_bitmapDrawableClass = static_cast<jclass>(env->NewGlobalRef(clazz));
- GET_AND_CHECK_METHOD(m_bitmapDrawableConstructorMethodID,
- m_bitmapDrawableClass,
- "<init>",
- "(Landroid/content/res/Resources;Landroid/graphics/Bitmap;)V");
- }
-
- return JNI_TRUE;
+
+ FIND_AND_CHECK_CLASS("android/content/ContextWrapper");
+ GET_AND_CHECK_METHOD(methodID, clazz, "getAssets", "()Landroid/content/res/AssetManager;");
+ m_assets = env->NewGlobalRef(env->CallObjectMethod(contextObject, methodID));
+ m_assetManager = AAssetManager_fromJava(env.jniEnv(), m_assets);
+
+ GET_AND_CHECK_METHOD(methodID, clazz, "getResources", "()Landroid/content/res/Resources;");
+ m_resourcesObj = env->NewGlobalRef(env->CallObjectMethod(contextObject, methodID));
+
+ FIND_AND_CHECK_CLASS("android/graphics/Bitmap");
+ m_bitmapClass = static_cast<jclass>(env->NewGlobalRef(clazz));
+ GET_AND_CHECK_STATIC_METHOD(m_createBitmapMethodID, m_bitmapClass,
+ "createBitmap", "(IILandroid/graphics/Bitmap$Config;)Landroid/graphics/Bitmap;");
+ FIND_AND_CHECK_CLASS("android/graphics/Bitmap$Config");
+ jfieldID fieldId;
+ GET_AND_CHECK_STATIC_FIELD(fieldId, clazz, "ARGB_8888", "Landroid/graphics/Bitmap$Config;");
+ m_ARGB_8888_BitmapConfigValue = env->NewGlobalRef(env->GetStaticObjectField(clazz, fieldId));
+ GET_AND_CHECK_STATIC_FIELD(fieldId, clazz, "RGB_565", "Landroid/graphics/Bitmap$Config;");
+ m_RGB_565_BitmapConfigValue = env->NewGlobalRef(env->GetStaticObjectField(clazz, fieldId));
+
+ FIND_AND_CHECK_CLASS("android/graphics/drawable/BitmapDrawable");
+ m_bitmapDrawableClass = static_cast<jclass>(env->NewGlobalRef(clazz));
+ GET_AND_CHECK_METHOD(m_bitmapDrawableConstructorMethodID,
+ m_bitmapDrawableClass,
+ "<init>", "(Landroid/content/res/Resources;Landroid/graphics/Bitmap;)V");
+
+ FIND_AND_CHECK_CLASS("org/qtproject/qt/android/QtActivityBase");
+ m_qtActivityClass = static_cast<jclass>(env->NewGlobalRef(clazz));
+ FIND_AND_CHECK_CLASS("org/qtproject/qt/android/QtServiceBase");
+ m_qtServiceClass = static_cast<jclass>(env->NewGlobalRef(clazz));
+
+ return true;
}
QT_END_NAMESPACE
@@ -891,36 +870,29 @@ Q_DECL_EXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void */*reserved*/)
initialized = true;
QT_USE_NAMESPACE
- typedef union {
- JNIEnv *nativeEnvironment;
- void *venv;
- } UnionJNIEnvToVoid;
-
- UnionJNIEnvToVoid uenv;
- uenv.venv = nullptr;
- m_javaVM = nullptr;
-
- if (vm->GetEnv(&uenv.venv, JNI_VERSION_1_6) != JNI_OK) {
- __android_log_print(ANDROID_LOG_FATAL, "Qt", "GetEnv failed");
+ m_javaVM = vm;
+ QJniEnvironment env;
+ if (!env.isValid()) {
+ m_javaVM = nullptr;
+ __android_log_print(ANDROID_LOG_FATAL, "Qt", "Failed to initialize the JNI Environment");
return -1;
}
- JNIEnv *env = uenv.nativeEnvironment;
if (!registerNatives(env)
|| !QtAndroidInput::registerNatives(env)
|| !QtAndroidMenu::registerNatives(env)
|| !QtAndroidAccessibility::registerNatives(env)
- || !QtAndroidDialogHelpers::registerNatives(env)) {
+ || !QtAndroidDialogHelpers::registerNatives(env)
+ || !QAndroidPlatformClipboard::registerNatives(env)
+ || !QAndroidPlatformWindow::registerNatives(env)
+ || !QtAndroidWindowEmbedding::registerNatives(env)) {
__android_log_print(ANDROID_LOG_FATAL, "Qt", "registerNatives failed");
return -1;
}
QWindowSystemInterfacePrivate::TabletEvent::setPlatformSynthesizesMouse(false);
- m_javaVM = vm;
// attach qt main thread data to this thread
- QObject threadSetter;
- if (threadSetter.thread())
- threadSetter.thread()->setObjectName("QtMainLoopThread");
+ QThread::currentThread()->setObjectName("QtMainLoopThread");
__android_log_print(ANDROID_LOG_INFO, "Qt", "qt started");
return JNI_VERSION_1_6;
}
diff --git a/src/plugins/platforms/android/androidjnimain.h b/src/plugins/platforms/android/androidjnimain.h
index 17ae30a1be..57a71a8650 100644
--- a/src/plugins/platforms/android/androidjnimain.h
+++ b/src/plugins/platforms/android/androidjnimain.h
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 BogDan Vatra <bogdan@kde.org>
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2014 BogDan Vatra <bogdan@kde.org>
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef ANDROID_APP_H
#define ANDROID_APP_H
@@ -47,6 +11,8 @@
#include <android/asset_manager.h>
#include <QImage>
+#include <private/qjnihelpers_p.h>
+#include <QtCore/QJniObject>
QT_BEGIN_NAMESPACE
@@ -57,43 +23,52 @@ class QAndroidPlatformIntegration;
class QWidget;
class QString;
class QWindow;
-class AndroidSurfaceClient;
+class QAndroidPlatformWindow;
class QBasicMutex;
+Q_DECLARE_JNI_CLASS(QtActivityDelegateBase, "org/qtproject/qt/android/QtActivityDelegateBase")
+Q_DECLARE_JNI_CLASS(QtInputDelegate, "org/qtproject/qt/android/QtInputDelegate")
+
namespace QtAndroid
{
QBasicMutex *platformInterfaceMutex();
QAndroidPlatformIntegration *androidPlatformIntegration();
void setAndroidPlatformIntegration(QAndroidPlatformIntegration *androidPlatformIntegration);
void setQtThread(QThread *thread);
-
-
- int createSurface(AndroidSurfaceClient * client, const QRect &geometry, bool onTop, int imageDepth);
- int insertNativeView(jobject view, const QRect &geometry);
void setViewVisibility(jobject view, bool visible);
- void setSurfaceGeometry(int surfaceId, const QRect &geometry);
- void destroySurface(int surfaceId);
- void bringChildToFront(int surfaceId);
- void bringChildToBack(int surfaceId);
QWindow *topLevelWindowAt(const QPoint &globalPos);
- int desktopWidthPixels();
- int desktopHeightPixels();
+ QWindow *windowFromId(int windowId);
+ int availableWidthPixels();
+ int availableHeightPixels();
double scaledDensity();
double pixelDensity();
JavaVM *javaVM();
jobject assets();
AAssetManager *assetManager();
jclass applicationClass();
- jobject activity();
- jobject service();
- void showStatusBar();
- void hideStatusBar();
+ QtJniTypes::QtActivityDelegateBase qtActivityDelegate();
+ QtJniTypes::QtInputDelegate qtInputDelegate();
- jobject createBitmap(QImage img, JNIEnv *env = 0);
+ // Keep synchronized with flags in ActivityDelegate.java
+ enum SystemUiVisibility {
+ SYSTEM_UI_VISIBILITY_NORMAL = 0,
+ SYSTEM_UI_VISIBILITY_FULLSCREEN = 1,
+ SYSTEM_UI_VISIBILITY_TRANSLUCENT = 2
+ };
+ void setSystemUiVisibility(SystemUiVisibility uiVisibility);
+
+ jobject createBitmap(QImage img, JNIEnv *env = nullptr);
jobject createBitmap(int width, int height, QImage::Format format, JNIEnv *env);
- jobject createBitmapDrawable(jobject bitmap, JNIEnv *env = 0);
+ jobject createBitmapDrawable(jobject bitmap, JNIEnv *env = nullptr);
+
+ void notifyAccessibilityLocationChange(uint accessibilityObjectId);
+ void notifyObjectHide(uint accessibilityObjectId, uint parentObjectId);
+ void notifyObjectFocus(uint accessibilityObjectId);
+ void notifyValueChanged(uint accessibilityObjectId, jstring value);
+ void notifyScrolledEvent(uint accessibilityObjectId);
+ void notifyNativePluginIntegrationReady(bool ready);
const char *classErrorMsgFmt();
const char *methodErrorMsgFmt();
@@ -101,6 +76,8 @@ namespace QtAndroid
QString deviceName();
bool blockEventLoopsWhenSuspended();
+
+ bool isQtApplication();
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/android/androidjnimenu.cpp b/src/plugins/platforms/android/androidjnimenu.cpp
index de2fdaa0e2..8bf37d1af2 100644
--- a/src/plugins/platforms/android/androidjnimenu.cpp
+++ b/src/plugins/platforms/android/androidjnimenu.cpp
@@ -1,46 +1,10 @@
-/****************************************************************************
-**
-** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#include "androidjnimenu.h"
#include "androidjnimain.h"
-#include "qandroidplatformmenubar.h"
+#include "androidjnimenu.h"
#include "qandroidplatformmenu.h"
+#include "qandroidplatformmenubar.h"
#include "qandroidplatformmenuitem.h"
#include <QMutex>
@@ -50,7 +14,7 @@
#include <QSet>
#include <QWindow>
#include <QtCore/private/qjnihelpers_p.h>
-#include <QtCore/private/qjni_p.h>
+#include <QtCore/QJniObject>
QT_BEGIN_NAMESPACE
@@ -59,15 +23,13 @@ using namespace QtAndroid;
namespace QtAndroidMenu
{
static QList<QAndroidPlatformMenu *> pendingContextMenus;
- static QAndroidPlatformMenu *visibleMenu = 0;
- static QRecursiveMutex visibleMenuMutex;
+ static QAndroidPlatformMenu *visibleMenu = nullptr;
+ Q_CONSTINIT static QRecursiveMutex visibleMenuMutex;
static QSet<QAndroidPlatformMenuBar *> menuBars;
- static QAndroidPlatformMenuBar *visibleMenuBar = 0;
- static QWindow *activeTopLevelWindow = 0;
- static QRecursiveMutex menuBarMutex;
-
- static jmethodID openContextMenuMethodID = 0;
+ static QAndroidPlatformMenuBar *visibleMenuBar = nullptr;
+ static QWindow *activeTopLevelWindow = nullptr;
+ Q_CONSTINIT static QRecursiveMutex menuBarMutex;
static jmethodID clearMenuMethodID = 0;
static jmethodID addMenuItemMethodID = 0;
@@ -82,35 +44,38 @@ namespace QtAndroidMenu
void resetMenuBar()
{
- QJNIObjectPrivate::callStaticMethod<void>(applicationClass(), "resetOptionsMenu");
+ qtActivityDelegate().callMethod<void>("resetOptionsMenu");
}
void openOptionsMenu()
{
- QJNIObjectPrivate::callStaticMethod<void>(applicationClass(), "openOptionsMenu");
+ qtActivityDelegate().callMethod<void>("openOptionsMenu");
}
- void showContextMenu(QAndroidPlatformMenu *menu, const QRect &anchorRect, JNIEnv *env)
+ void showContextMenu(QAndroidPlatformMenu *menu, const QRect &anchorRect)
{
QMutexLocker lock(&visibleMenuMutex);
if (visibleMenu)
pendingContextMenus.append(visibleMenu);
visibleMenu = menu;
menu->aboutToShow();
- env->CallStaticVoidMethod(applicationClass(), openContextMenuMethodID, anchorRect.x(), anchorRect.y(), anchorRect.width(), anchorRect.height());
+ qtActivityDelegate().callMethod<void>("openContextMenu",
+ anchorRect.x(), anchorRect.y(),
+ anchorRect.width(), anchorRect.height());
}
void hideContextMenu(QAndroidPlatformMenu *menu)
{
QMutexLocker lock(&visibleMenuMutex);
if (visibleMenu == menu) {
- QJNIObjectPrivate::callStaticMethod<void>(applicationClass(), "closeContextMenu");
+ qtActivityDelegate().callMethod<void>("closeContextMenu");
pendingContextMenus.clear();
} else {
pendingContextMenus.removeOne(menu);
}
}
+ // FIXME
void syncMenu(QAndroidPlatformMenu */*menu*/)
{
// QMutexLocker lock(&visibleMenuMutex);
@@ -152,7 +117,7 @@ namespace QtAndroidMenu
visibleMenuBar = 0;
activeTopLevelWindow = window;
- for (QAndroidPlatformMenuBar *menuBar : qAsConst(menuBars)) {
+ for (QAndroidPlatformMenuBar *menuBar : std::as_const(menuBars)) {
if (menuBar->parentWindow() == window) {
visibleMenuBar = menuBar;
resetMenuBar();
@@ -180,12 +145,12 @@ namespace QtAndroidMenu
static QString removeAmpersandEscapes(QString s)
{
- int i = 0;
+ qsizetype i = 0;
while (i < s.size()) {
++i;
- if (s.at(i-1) != QLatin1Char('&'))
+ if (s.at(i - 1) != u'&')
continue;
- if (i < s.size() && s.at(i) == QLatin1Char('&'))
+ if (i < s.size() && s.at(i) == u'&')
++i;
s.remove(i-1,1);
}
@@ -246,8 +211,10 @@ namespace QtAndroidMenu
return order;
}
- static jboolean onPrepareOptionsMenu(JNIEnv *env, jobject /*thiz*/, jobject menu)
+ static jboolean onPrepareOptionsMenu(JNIEnv *env, jobject thiz, jobject menu)
{
+ Q_UNUSED(thiz)
+
env->CallVoidMethod(menu, clearMenuMethodID);
QMutexLocker lock(&menuBarMutex);
if (!visibleMenuBar)
@@ -284,8 +251,11 @@ namespace QtAndroidMenu
return order ? JNI_TRUE : JNI_FALSE;
}
- static jboolean onOptionsItemSelected(JNIEnv *env, jobject /*thiz*/, jint menuId, jboolean checked)
+ static jboolean onOptionsItemSelected(JNIEnv *env, jobject thiz, jint menuId, jboolean checked)
{
+ Q_UNUSED(env)
+ Q_UNUSED(thiz)
+
QMutexLocker lock(&menuBarMutex);
if (!visibleMenuBar)
return JNI_FALSE;
@@ -295,7 +265,7 @@ namespace QtAndroidMenu
QAndroidPlatformMenuItem *item = static_cast<QAndroidPlatformMenuItem *>(menus.front()->menuItemForId(menuId));
if (item) {
if (item->menu()) {
- showContextMenu(item->menu(), QRect(), env);
+ showContextMenu(item->menu(), QRect());
} else {
if (item->isCheckable())
item->setChecked(checked);
@@ -305,18 +275,23 @@ namespace QtAndroidMenu
} else {
QAndroidPlatformMenu *menu = static_cast<QAndroidPlatformMenu *>(visibleMenuBar->menuForId(menuId));
if (menu)
- showContextMenu(menu, QRect(), env);
+ showContextMenu(menu, QRect());
}
return JNI_TRUE;
}
- static void onOptionsMenuClosed(JNIEnv */*env*/, jobject /*thiz*/, jobject /*menu*/)
+ static void onOptionsMenuClosed(JNIEnv *env, jobject thiz, jobject menu)
{
+ Q_UNUSED(env)
+ Q_UNUSED(thiz)
+ Q_UNUSED(menu)
}
- static void onCreateContextMenu(JNIEnv *env, jobject /*thiz*/, jobject menu)
+ static void onCreateContextMenu(JNIEnv *env, jobject thiz, jobject menu)
{
+ Q_UNUSED(thiz)
+
env->CallVoidMethod(menu, clearMenuMethodID);
QMutexLocker lock(&visibleMenuMutex);
if (!visibleMenu)
@@ -330,8 +305,9 @@ namespace QtAndroidMenu
addAllMenuItemsToMenu(env, menu, visibleMenu);
}
- static void fillContextMenu(JNIEnv *env, jobject /*thiz*/, jobject menu)
+ static void fillContextMenu(JNIEnv *env, jobject thiz, jobject menu)
{
+ Q_UNUSED(thiz)
env->CallVoidMethod(menu, clearMenuMethodID);
QMutexLocker lock(&visibleMenuMutex);
if (!visibleMenu)
@@ -340,20 +316,23 @@ namespace QtAndroidMenu
addAllMenuItemsToMenu(env, menu, visibleMenu);
}
- static jboolean onContextItemSelected(JNIEnv *env, jobject /*thiz*/, jint menuId, jboolean checked)
+ static jboolean onContextItemSelected(JNIEnv *env, jobject thiz, jint menuId, jboolean checked)
{
+ Q_UNUSED(env)
+ Q_UNUSED(thiz)
+
QMutexLocker lock(&visibleMenuMutex);
QAndroidPlatformMenuItem * item = static_cast<QAndroidPlatformMenuItem *>(visibleMenu->menuItemForId(menuId));
if (item) {
if (item->menu()) {
- showContextMenu(item->menu(), QRect(), env);
+ showContextMenu(item->menu(), QRect());
} else {
if (item->isCheckable())
item->setChecked(checked);
item->activated();
visibleMenu->aboutToHide();
visibleMenu = 0;
- for (QAndroidPlatformMenu *menu : qAsConst(pendingContextMenus)) {
+ for (QAndroidPlatformMenu *menu : std::as_const(pendingContextMenus)) {
if (menu->isVisible())
menu->aboutToHide();
}
@@ -363,8 +342,12 @@ namespace QtAndroidMenu
return JNI_TRUE;
}
- static void onContextMenuClosed(JNIEnv *env, jobject /*thiz*/, jobject /*menu*/)
+ static void onContextMenuClosed(JNIEnv *env, jobject thiz, jobject menu)
{
+ Q_UNUSED(env)
+ Q_UNUSED(thiz)
+ Q_UNUSED(menu)
+
QMutexLocker lock(&visibleMenuMutex);
if (!visibleMenu)
return;
@@ -372,7 +355,7 @@ namespace QtAndroidMenu
visibleMenu->aboutToHide();
visibleMenu = 0;
if (!pendingContextMenus.empty())
- showContextMenu(pendingContextMenus.takeLast(), QRect(), env);
+ showContextMenu(pendingContextMenus.takeLast(), QRect());
}
static JNINativeMethod methods[] = {
@@ -413,17 +396,15 @@ namespace QtAndroidMenu
return false; \
}
- bool registerNatives(JNIEnv *env)
+ bool registerNatives(QJniEnvironment &env)
{
jclass appClass = applicationClass();
- if (env->RegisterNatives(appClass, methods, sizeof(methods) / sizeof(methods[0])) < 0) {
+ if (!env.registerNativeMethods(appClass, methods, sizeof(methods) / sizeof(methods[0]))) {
__android_log_print(ANDROID_LOG_FATAL,"Qt", "RegisterNatives failed");
return false;
}
- GET_AND_CHECK_STATIC_METHOD(openContextMenuMethodID, appClass, "openContextMenu", "(IIII)V");
-
jclass clazz;
FIND_AND_CHECK_CLASS("android/view/Menu");
GET_AND_CHECK_METHOD(clearMenuMethodID, clazz, "clear", "()V");
diff --git a/src/plugins/platforms/android/androidjnimenu.h b/src/plugins/platforms/android/androidjnimenu.h
index 9569d18978..e10ad930d9 100644
--- a/src/plugins/platforms/android/androidjnimenu.h
+++ b/src/plugins/platforms/android/androidjnimenu.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef ANDROIDJNIMENU_H
#define ANDROIDJNIMENU_H
@@ -51,12 +15,13 @@ class QAndroidPlatformMenuItem;
class QWindow;
class QRect;
class QPoint;
+class QJniEnvironment;
namespace QtAndroidMenu
{
// Menu support
void openOptionsMenu();
- void showContextMenu(QAndroidPlatformMenu *menu, const QRect &anchorRect, JNIEnv *env);
+ void showContextMenu(QAndroidPlatformMenu *menu, const QRect &anchorRect);
void hideContextMenu(QAndroidPlatformMenu *menu);
void syncMenu(QAndroidPlatformMenu *menu);
void androidPlatformMenuDestroyed(QAndroidPlatformMenu *menu);
@@ -67,7 +32,7 @@ namespace QtAndroidMenu
void removeMenuBar(QAndroidPlatformMenuBar *menuBar);
// Menu support
- bool registerNatives(JNIEnv *env);
+ bool registerNatives(QJniEnvironment &env);
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/android/androidsurfaceclient.h b/src/plugins/platforms/android/androidsurfaceclient.h
deleted file mode 100644
index f06106f0b7..0000000000
--- a/src/plugins/platforms/android/androidsurfaceclient.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 BogDan Vatra <bogdan@kde.org>
-** 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 ANDROIDSURFACECLIENT_H
-#define ANDROIDSURFACECLIENT_H
-#include <QMutex>
-#include <jni.h>
-
-QT_BEGIN_NAMESPACE
-
-class AndroidSurfaceClient
-{
-public:
- virtual void surfaceChanged(JNIEnv *jniEnv, jobject surface, int w, int h) = 0;
- void lockSurface() { m_surfaceMutex.lock(); }
- void unlockSurface() { m_surfaceMutex.unlock(); }
-
-protected:
- QMutex m_surfaceMutex;
-};
-
-QT_END_NAMESPACE
-
-#endif // ANDROIDSURFACECLIENT_H
diff --git a/src/plugins/platforms/android/androidwindowembedding.cpp b/src/plugins/platforms/android/androidwindowembedding.cpp
new file mode 100644
index 0000000000..230776f571
--- /dev/null
+++ b/src/plugins/platforms/android/androidwindowembedding.cpp
@@ -0,0 +1,75 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "androidwindowembedding.h"
+
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qjnienvironment.h>
+#include <QtCore/qjniobject.h>
+#include <QtCore/qjnitypes.h>
+#include <QtGui/qwindow.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_JNI_CLASS(QtView, "org/qtproject/qt/android/QtView");
+Q_DECLARE_JNI_CLASS(QtEmbeddedDelegate, "org/qtproject/qt/android/QtEmbeddedDelegate");
+
+namespace QtAndroidWindowEmbedding {
+ void createRootWindow(JNIEnv *, jclass, QtJniTypes::View rootView,
+ jint x, jint y, jint width, jint height)
+ {
+ // QWindow should be constructed on the Qt thread rather than directly in the caller thread
+ // To avoid hitting checkReceiverThread assert in QCoreApplication::doNotify
+ QMetaObject::invokeMethod(qApp, [rootView, x, y, width, height] {
+ QWindow *parentWindow = QWindow::fromWinId(reinterpret_cast<WId>(rootView.object()));
+ parentWindow->setGeometry(x, y, width, height);
+ rootView.callMethod<void>("createWindow", reinterpret_cast<jlong>(parentWindow));
+ });
+ }
+
+ void deleteWindow(JNIEnv *, jclass, jlong windowRef)
+ {
+ QWindow *window = reinterpret_cast<QWindow*>(windowRef);
+ window->deleteLater();
+ }
+
+ void setWindowVisible(JNIEnv *, jclass, jlong windowRef, jboolean visible)
+ {
+ QMetaObject::invokeMethod(qApp, [windowRef, visible] {
+ QWindow *window = reinterpret_cast<QWindow*>(windowRef);
+ if (visible) {
+ window->showNormal();
+ if (!window->parent()->isVisible())
+ window->parent()->showNormal();
+ } else {
+ window->hide();
+ }
+ });
+ }
+
+ void resizeWindow(JNIEnv *, jclass, jlong windowRef, jint x, jint y, jint width, jint height)
+ {
+ QMetaObject::invokeMethod(qApp, [windowRef, x, y, width, height] {
+ QWindow *window = reinterpret_cast<QWindow*>(windowRef);
+ QWindow *parent = window->parent();
+ if (parent)
+ parent->setGeometry(x, y, width, height);
+ window->setGeometry(0, 0, width, height);
+ });
+ }
+
+ bool registerNatives(QJniEnvironment& env) {
+ using namespace QtJniTypes;
+ bool success = env.registerNativeMethods(Traits<QtEmbeddedDelegate>::className(),
+ {Q_JNI_NATIVE_SCOPED_METHOD(createRootWindow, QtAndroidWindowEmbedding),
+ Q_JNI_NATIVE_SCOPED_METHOD(deleteWindow, QtAndroidWindowEmbedding)});
+
+ success &= env.registerNativeMethods(Traits<QtView>::className(),
+ {Q_JNI_NATIVE_SCOPED_METHOD(setWindowVisible, QtAndroidWindowEmbedding),
+ Q_JNI_NATIVE_SCOPED_METHOD(resizeWindow, QtAndroidWindowEmbedding)});
+ return success;
+
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/android/androidwindowembedding.h b/src/plugins/platforms/android/androidwindowembedding.h
new file mode 100644
index 0000000000..b7b0e1205f
--- /dev/null
+++ b/src/plugins/platforms/android/androidwindowembedding.h
@@ -0,0 +1,41 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QTANDROIDWINDOWEMBEDDING_H
+#define QTANDROIDWINDOWEMBEDDING_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/qjnienvironment.h>
+#include <QtCore/qjnitypes.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_JNI_CLASS(View, "android/view/View");
+
+namespace QtAndroidWindowEmbedding
+{
+ bool registerNatives(QJniEnvironment& env);
+ void createRootWindow(JNIEnv *, jclass, QtJniTypes::View rootView,
+ jint x, jint y,jint width, jint height);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(createRootWindow)
+ void deleteWindow(JNIEnv *, jclass, jlong window);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(deleteWindow)
+ void setWindowVisible(JNIEnv *, jclass, jlong window, jboolean visible);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(setWindowVisible)
+ void resizeWindow(JNIEnv *, jclass, jlong windowRef, jint x, jint y, jint width, jint height);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(resizeWindow)
+};
+
+QT_END_NAMESPACE
+
+#endif // QTANDROIDWINDOWEMBEDDING_H
diff --git a/src/plugins/platforms/android/extract-dummy.cpp b/src/plugins/platforms/android/extract-dummy.cpp
index fdce8ec64c..a8b27bb0d8 100644
--- a/src/plugins/platforms/android/extract-dummy.cpp
+++ b/src/plugins/platforms/android/extract-dummy.cpp
@@ -1,51 +1,11 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <jni.h>
#include <extract.h>
-extern "C" JNIEXPORT jintArray JNICALL Java_org_qtproject_qt5_android_ExtractStyle_extractNativeChunkInfo20(JNIEnv *, jobject, long)
-{
- return 0;
-}
-
-extern "C" JNIEXPORT jintArray JNICALL Java_org_qtproject_qt5_android_ExtractStyle_extractChunkInfo20(JNIEnv *, jobject, jbyteArray)
+extern "C" JNIEXPORT jintArray JNICALL
+Java_org_qtproject_qt_android_ExtractStyle_extractNativeChunkInfo20(JNIEnv *, jobject, long)
{
return 0;
}
diff --git a/src/plugins/platforms/android/extract.cpp b/src/plugins/platforms/android/extract.cpp
index acffa353f1..d81d70d18d 100644
--- a/src/plugins/platforms/android/extract.cpp
+++ b/src/plugins/platforms/android/extract.cpp
@@ -1,48 +1,15 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 BogDan Vatra <bogdan@kde.org>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// Copyright (C) 2014 BogDan Vatra <bogdan@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#include <jni.h>
+#include <QtCore/QJniEnvironment>
+
+#include <alloca.h>
#include <android/log.h>
#include <extract.h>
-#include <alloca.h>
+#include <jni.h>
#include <stdlib.h>
#define LOG_TAG "extractSyleInfo"
@@ -91,7 +58,8 @@ Res_png_9patch* Res_png_9patch::deserialize(const void* inData)
return (Res_png_9patch*) inData;
}
-extern "C" JNIEXPORT jintArray JNICALL Java_org_qtproject_qt5_android_ExtractStyle_extractNativeChunkInfo20(JNIEnv * env, jobject, long addr)
+extern "C" JNIEXPORT jintArray JNICALL
+Java_org_qtproject_qt_android_ExtractStyle_extractNativeChunkInfo20(JNIEnv *env, jobject, long addr)
{
Res_png_9patch20* chunk = reinterpret_cast<Res_png_9patch20*>(addr);
Res_png_9patch20::deserialize(chunk);
@@ -123,20 +91,6 @@ extern "C" JNIEXPORT jintArray JNICALL Java_org_qtproject_qt5_android_ExtractSty
return result;
}
-extern "C" JNIEXPORT jintArray JNICALL Java_org_qtproject_qt5_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 (!env->ExceptionCheck())
- return Java_org_qtproject_qt5_android_ExtractStyle_extractNativeChunkInfo20(env, obj, long(storage));
- else
- env->ExceptionClear();
- return 0;
-}
-
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/main.cpp b/src/plugins/platforms/android/main.cpp
index 4841d0425c..0e749f55a5 100644
--- a/src/plugins/platforms/android/main.cpp
+++ b/src/plugins/platforms/android/main.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 BogDan Vatra <bogdan@kde.org>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2019 BogDan Vatra <bogdan@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <qpa/qplatformintegrationplugin.h>
@@ -43,6 +7,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
class QAndroidIntegrationPlugin : public QPlatformIntegrationPlugin
{
Q_OBJECT
@@ -54,7 +20,7 @@ public:
QPlatformIntegration *QAndroidIntegrationPlugin::create(const QString& system, const QStringList& paramList)
{
- if (!system.compare(QLatin1String("android"), Qt::CaseInsensitive))
+ if (!system.compare("android"_L1, Qt::CaseInsensitive))
return new QAndroidPlatformIntegration(paramList);
return nullptr;
diff --git a/src/plugins/platforms/android/qandroidassetsfileenginehandler.cpp b/src/plugins/platforms/android/qandroidassetsfileenginehandler.cpp
index ca16efe34f..4ea6536cef 100644
--- a/src/plugins/platforms/android/qandroidassetsfileenginehandler.cpp
+++ b/src/plugins/platforms/android/qandroidassetsfileenginehandler.cpp
@@ -1,71 +1,39 @@
-/****************************************************************************
-**
-** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#include "qandroidassetsfileenginehandler.h"
#include "androidjnimain.h"
+#include "qandroidassetsfileenginehandler.h"
+
#include <optional>
#include <QCoreApplication>
-#include <QVector>
-#include <QtCore/private/qjni_p.h>
+#include <QList>
+#include <QtCore/QJniEnvironment>
+#include <QtCore/QJniObject>
QT_BEGIN_NAMESPACE
-static const QLatin1String assetsPrefix("assets:");
+using namespace Qt::StringLiterals;
+
+static const auto assetsPrefix = "assets:"_L1;
const static int prefixSize = 7;
static inline QString cleanedAssetPath(QString file)
{
if (file.startsWith(assetsPrefix))
file.remove(0, prefixSize);
- file.replace(QLatin1String("//"), QLatin1String("/"));
- if (file.startsWith(QLatin1Char('/')))
+ file.replace("//"_L1, "/"_L1);
+ if (file.startsWith(u'/'))
file.remove(0, 1);
- if (file.endsWith(QLatin1Char('/')))
+ if (file.endsWith(u'/'))
file.chop(1);
return file;
}
static inline QString prefixedPath(QString path)
{
- path = assetsPrefix + QLatin1Char('/') + path;
- path.replace(QLatin1String("//"), QLatin1String("/"));
+ path = assetsPrefix + u'/' + path;
+ path.replace("//"_L1, "/"_L1);
return path;
}
@@ -79,16 +47,17 @@ struct AssetItem {
AssetItem (const QString &rawName)
: name(rawName)
{
- if (name.endsWith(QLatin1Char('/'))) {
+ if (name.endsWith(u'/')) {
type = Type::Folder;
name.chop(1);
}
}
Type type = Type::File;
QString name;
+ qint64 size = -1;
};
-using AssetItemList = QVector<AssetItem>;
+using AssetItemList = QList<AssetItem>;
class FolderIterator : public AssetItemList
{
@@ -112,7 +81,7 @@ public:
{
if (filePath.isEmpty())
return AssetItem::Type::Folder;
- const QStringList paths = filePath.split(QLatin1Char('/'));
+ const QStringList paths = filePath.split(u'/');
QString fullPath;
AssetItem::Type res = AssetItem::Type::Invalid;
for (const auto &path: paths) {
@@ -123,7 +92,7 @@ public:
if (it == folder->end() || it->name != path)
return AssetItem::Type::Invalid;
if (!fullPath.isEmpty())
- fullPath.append(QLatin1Char('/'));
+ fullPath.append(u'/');
fullPath += path;
res = it->type;
}
@@ -139,23 +108,25 @@ public:
FolderIterator(const QString &path)
: m_path(path)
{
- QJNIObjectPrivate files = QJNIObjectPrivate::callStaticObjectMethod(QtAndroid::applicationClass(),
+ // Note that empty dirs in the assets dir before the build are not going to be
+ // included in the final apk, so no empty folders should expected to be listed.
+ QJniObject files = QJniObject::callStaticObjectMethod(QtAndroid::applicationClass(),
"listAssetContent",
"(Landroid/content/res/AssetManager;Ljava/lang/String;)[Ljava/lang/String;",
- QtAndroid::assets(), QJNIObjectPrivate::fromString(path).object());
+ QtAndroid::assets(), QJniObject::fromString(path).object());
if (files.isValid()) {
- QJNIEnvironmentPrivate env;
- jobjectArray jFiles = static_cast<jobjectArray>(files.object());
+ QJniEnvironment env;
+ jobjectArray jFiles = files.object<jobjectArray>();
const jint nFiles = env->GetArrayLength(jFiles);
for (int i = 0; i < nFiles; ++i) {
- AssetItem item{QJNIObjectPrivate::fromLocalRef(env->GetObjectArrayElement(jFiles, i)).toString()};
+ AssetItem item{QJniObject::fromLocalRef(env->GetObjectArrayElement(jFiles, i)).toString()};
insert(std::upper_bound(begin(), end(), item, [](const auto &a, const auto &b){
return a.name < b.name;
}), item);
}
}
- m_path = assetsPrefix + QLatin1Char('/') + m_path + QLatin1Char('/');
- m_path.replace(QLatin1String("//"), QLatin1String("/"));
+ m_path = assetsPrefix + u'/' + m_path + u'/';
+ m_path.replace("//"_L1, "/"_L1);
}
QString currentFileName() const
@@ -171,17 +142,13 @@ public:
return m_path + at(m_index).name;
}
- bool hasNext() const
- {
- return !empty() && m_index + 1 < size();
- }
-
- std::optional<std::pair<QString, AssetItem>> next()
+ bool advance()
{
- if (!hasNext())
- return {};
- ++m_index;
- return std::pair<QString, AssetItem>(currentFileName(), at(m_index));
+ if (!empty() && m_index + 1 < size()) {
+ ++m_index;
+ return true;
+ }
+ return false;
}
private:
@@ -192,7 +159,7 @@ private:
};
QCache<QString, QSharedPointer<FolderIterator>> FolderIterator::m_assetsCache(std::max(50, qEnvironmentVariableIntValue("QT_ANDROID_MAX_ASSETS_CACHE_SIZE")));
-QMutex FolderIterator::m_assetsCacheMutex;
+Q_CONSTINIT QMutex FolderIterator::m_assetsCacheMutex;
class AndroidAbstractFileEngineIterator: public QAbstractFileEngineIterator
{
@@ -200,11 +167,9 @@ public:
AndroidAbstractFileEngineIterator(QDir::Filters filters,
const QStringList &nameFilters,
const QString &path)
- : QAbstractFileEngineIterator(filters, nameFilters)
+ : QAbstractFileEngineIterator(path, filters, nameFilters)
{
- m_stack.push_back(FolderIterator::fromCache(cleanedAssetPath(path), true));
- if (m_stack.last()->empty())
- m_stack.pop_back();
+ m_currentIterator = FolderIterator::fromCache(cleanedAssetPath(path), true);
}
QFileInfo currentFileInfo() const override
@@ -219,45 +184,20 @@ public:
return m_currentIterator->currentFileName();
}
- virtual QString currentFilePath() const
+ QString currentFilePath() const override
{
if (!m_currentIterator)
return {};
return m_currentIterator->currentFilePath();
}
- bool hasNext() const override
- {
- if (m_stack.empty())
- return false;
- if (!m_stack.last()->hasNext()) {
- m_stack.pop_back();
- return hasNext();
- }
- return true;
- }
-
- QString next() override
+ bool advance() override
{
- if (m_stack.empty()) {
- m_currentIterator.reset();
- return {};
- }
- m_currentIterator = m_stack.last();
- auto res = m_currentIterator->next();
- if (!res)
- return {};
- if (res->second.type == AssetItem::Type::Folder) {
- m_stack.push_back(FolderIterator::fromCache(cleanedAssetPath(currentFilePath()), true));
- if (m_stack.last()->empty())
- m_stack.pop_back();
- }
- return res->first;
+ return m_currentIterator ? m_currentIterator->advance() : false;
}
private:
- mutable QSharedPointer<FolderIterator> m_currentIterator;
- mutable QVector<QSharedPointer<FolderIterator>> m_stack;
+ QSharedPointer<FolderIterator> m_currentIterator;
};
class AndroidAbstractFileEngine: public QAbstractFileEngine
@@ -274,9 +214,11 @@ public:
close();
}
- bool open(QIODevice::OpenMode openMode) override
+ bool open(QIODevice::OpenMode openMode, std::optional<QFile::Permissions> permissions) override
{
- if (m_isFolder || (openMode & QIODevice::WriteOnly))
+ Q_UNUSED(permissions);
+
+ if (!m_assetInfo || m_assetInfo->type != AssetItem::Type::File || (openMode & QIODevice::WriteOnly))
return false;
close();
m_assetFile = AAssetManager_open(m_assetManager, m_fileName.toUtf8(), AASSET_MODE_BUFFER);
@@ -290,14 +232,13 @@ public:
m_assetFile = 0;
return true;
}
- m_isFolder = false;
return false;
}
qint64 size() const override
{
- if (m_assetFile)
- return AAsset_getLength(m_assetFile);
+ if (m_assetInfo)
+ return m_assetInfo->size;
return -1;
}
@@ -322,49 +263,41 @@ public:
return -1;
}
- bool isSequential() const override
- {
- return false;
- }
-
bool caseSensitive() const override
{
return true;
}
- bool isRelativePath() const override
- {
- return false;
- }
-
FileFlags fileFlags(FileFlags type = FileInfoAll) const override
{
FileFlags commonFlags(ReadOwnerPerm|ReadUserPerm|ReadGroupPerm|ReadOtherPerm|ExistsFlag);
FileFlags flags;
- if (m_assetFile)
- flags = FileType | commonFlags;
- else if (m_isFolder)
- flags = DirectoryType | commonFlags;
+ if (m_assetInfo) {
+ if (m_assetInfo->type == AssetItem::Type::File)
+ flags = FileType | commonFlags;
+ else if (m_assetInfo->type == AssetItem::Type::Folder)
+ flags = DirectoryType | commonFlags;
+ }
return type & flags;
}
QString fileName(FileName file = DefaultName) const override
{
- int pos;
+ qsizetype pos;
switch (file) {
case DefaultName:
case AbsoluteName:
case CanonicalName:
return prefixedPath(m_fileName);
case BaseName:
- if ((pos = m_fileName.lastIndexOf(QChar(QLatin1Char('/')))) != -1)
- return prefixedPath(m_fileName.mid(pos));
+ if ((pos = m_fileName.lastIndexOf(u'/')) != -1)
+ return m_fileName.mid(pos + 1);
else
- return prefixedPath(m_fileName);
+ return m_fileName;
case PathName:
case AbsolutePathName:
case CanonicalPathName:
- if ((pos = m_fileName.lastIndexOf(QChar(QLatin1Char('/')))) != -1)
+ if ((pos = m_fileName.lastIndexOf(u'/')) != -1)
return prefixedPath(m_fileName.left(pos));
else
return prefixedPath(m_fileName);
@@ -379,22 +312,51 @@ public:
return;
close();
m_fileName = cleanedAssetPath(file);
- switch (FolderIterator::fileType(m_fileName)) {
- case AssetItem::Type::File:
- open(QIODevice::ReadOnly);
- break;
- case AssetItem::Type::Folder:
- m_isFolder = true;
- break;
- case AssetItem::Type::Invalid:
- break;
+
+ {
+ QMutexLocker lock(&m_assetsInfoCacheMutex);
+ QSharedPointer<AssetItem> *assetInfoPtr = m_assetsInfoCache.object(m_fileName);
+ if (assetInfoPtr) {
+ m_assetInfo = *assetInfoPtr;
+ return;
+ }
}
+
+ QSharedPointer<AssetItem> *newAssetInfoPtr = new QSharedPointer<AssetItem>(new AssetItem);
+
+ m_assetInfo = *newAssetInfoPtr;
+ m_assetInfo->name = m_fileName;
+ m_assetInfo->type = AssetItem::Type::Invalid;
+
+ m_assetFile = AAssetManager_open(m_assetManager, m_fileName.toUtf8(), AASSET_MODE_BUFFER);
+
+ if (m_assetFile) {
+ m_assetInfo->type = AssetItem::Type::File;
+ m_assetInfo->size = AAsset_getLength(m_assetFile);
+ } else {
+ auto *assetDir = AAssetManager_openDir(m_assetManager, m_fileName.toUtf8());
+ if (assetDir) {
+ if (AAssetDir_getNextFileName(assetDir)
+ || (!FolderIterator::fromCache(m_fileName, false)->empty())) {
+ // If AAssetDir_getNextFileName is not valid, it still can be a directory that
+ // contains only other directories (no files). FolderIterator will not be called
+ // on the directory containing files so it should not be too time consuming now.
+ m_assetInfo->type = AssetItem::Type::Folder;
+ }
+ AAssetDir_close(assetDir);
+ }
+ }
+
+ QMutexLocker lock(&m_assetsInfoCacheMutex);
+ m_assetsInfoCache.insert(m_fileName, newAssetInfoPtr);
}
- Iterator *beginEntryList(QDir::Filters filters, const QStringList &filterNames) override
+ IteratorUniquePtr
+ beginEntryList(const QString &, QDir::Filters filters, const QStringList &filterNames) override
{
- if (m_isFolder)
- return new AndroidAbstractFileEngineIterator(filters, filterNames, m_fileName);
+ // AndroidAbstractFileEngineIterator use `m_fileName` as the path
+ if (m_assetInfo && m_assetInfo->type == AssetItem::Type::Folder)
+ return std::make_unique<AndroidAbstractFileEngineIterator>(filters, filterNames, m_fileName);
return nullptr;
}
@@ -402,31 +364,37 @@ private:
AAsset *m_assetFile = nullptr;
AAssetManager *m_assetManager = nullptr;
// initialize with a name that can't be used as a file name
- QString m_fileName = QLatin1String(".");
- bool m_isFolder = false;
+ QString m_fileName = "."_L1;
+ QSharedPointer<AssetItem> m_assetInfo;
+
+ static QCache<QString, QSharedPointer<AssetItem>> m_assetsInfoCache;
+ static QMutex m_assetsInfoCacheMutex;
};
+QCache<QString, QSharedPointer<AssetItem>> AndroidAbstractFileEngine::m_assetsInfoCache(std::max(200, qEnvironmentVariableIntValue("QT_ANDROID_MAX_FILEINFO_ASSETS_CACHE_SIZE")));
+Q_CONSTINIT QMutex AndroidAbstractFileEngine::m_assetsInfoCacheMutex;
AndroidAssetsFileEngineHandler::AndroidAssetsFileEngineHandler()
{
m_assetManager = QtAndroid::assetManager();
}
-QAbstractFileEngine * AndroidAssetsFileEngineHandler::create(const QString &fileName) const
+std::unique_ptr<QAbstractFileEngine>
+AndroidAssetsFileEngineHandler::create(const QString &fileName) const
{
if (fileName.isEmpty())
- return nullptr;
+ return {};
if (!fileName.startsWith(assetsPrefix))
- return nullptr;
+ return {};
QString path = fileName.mid(prefixSize);
- path.replace(QLatin1String("//"), QLatin1String("/"));
- if (path.startsWith(QLatin1Char('/')))
+ path.replace("//"_L1, "/"_L1);
+ if (path.startsWith(u'/'))
path.remove(0, 1);
- if (path.endsWith(QLatin1Char('/')))
+ if (path.endsWith(u'/'))
path.chop(1);
- return new AndroidAbstractFileEngine(m_assetManager, path);
+ return std::make_unique<AndroidAbstractFileEngine>(m_assetManager, path);
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/android/qandroidassetsfileenginehandler.h b/src/plugins/platforms/android/qandroidassetsfileenginehandler.h
index 51cc5b07a8..8e5f87a51a 100644
--- a/src/plugins/platforms/android/qandroidassetsfileenginehandler.h
+++ b/src/plugins/platforms/android/qandroidassetsfileenginehandler.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QANDROIDASSETSFILEENGINEHANDLER_H
#define QANDROIDASSETSFILEENGINEHANDLER_H
@@ -53,7 +17,7 @@ class AndroidAssetsFileEngineHandler: public QAbstractFileEngineHandler
{
public:
AndroidAssetsFileEngineHandler();
- QAbstractFileEngine *create(const QString &fileName) const override;
+ std::unique_ptr<QAbstractFileEngine> create(const QString &fileName) const override;
private:
AAssetManager *m_assetManager;
diff --git a/src/plugins/platforms/android/qandroideventdispatcher.cpp b/src/plugins/platforms/android/qandroideventdispatcher.cpp
index 3a1fb7a6de..8d1a085844 100644
--- a/src/plugins/platforms/android/qandroideventdispatcher.cpp
+++ b/src/plugins/platforms/android/qandroideventdispatcher.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 BogDan Vatra <bogdan@kde.org>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2014 BogDan Vatra <bogdan@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qandroideventdispatcher.h"
#include "androidjnimain.h"
@@ -101,7 +65,7 @@ bool QAndroidEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags
QAndroidEventDispatcherStopper *QAndroidEventDispatcherStopper::instance()
{
- static QAndroidEventDispatcherStopper androidEventDispatcherStopper;
+ Q_CONSTINIT static QAndroidEventDispatcherStopper androidEventDispatcherStopper;
return &androidEventDispatcherStopper;
}
@@ -111,7 +75,7 @@ void QAndroidEventDispatcherStopper::startAll()
if (!m_started.testAndSetOrdered(0, 1))
return;
- for (QAndroidEventDispatcher *d : qAsConst(m_dispatchers))
+ for (QAndroidEventDispatcher *d : std::as_const(m_dispatchers))
d->start();
}
@@ -121,7 +85,7 @@ void QAndroidEventDispatcherStopper::stopAll()
if (!m_started.testAndSetOrdered(1, 0))
return;
- for (QAndroidEventDispatcher *d : qAsConst(m_dispatchers))
+ for (QAndroidEventDispatcher *d : std::as_const(m_dispatchers))
d->stop();
}
@@ -140,6 +104,6 @@ void QAndroidEventDispatcherStopper::removeEventDispatcher(QAndroidEventDispatch
void QAndroidEventDispatcherStopper::goingToStop(bool stop)
{
QMutexLocker lock(&m_mutex);
- for (QAndroidEventDispatcher *d : qAsConst(m_dispatchers))
+ for (QAndroidEventDispatcher *d : std::as_const(m_dispatchers))
d->goingToStop(stop);
}
diff --git a/src/plugins/platforms/android/qandroideventdispatcher.h b/src/plugins/platforms/android/qandroideventdispatcher.h
index 4fdd7af7a5..a086b705b1 100644
--- a/src/plugins/platforms/android/qandroideventdispatcher.h
+++ b/src/plugins/platforms/android/qandroideventdispatcher.h
@@ -1,54 +1,18 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 BogDan Vatra <bogdan@kde.org>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2014 BogDan Vatra <bogdan@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QANDROIDEVENTDISPATCHER_H
#define QANDROIDEVENTDISPATCHER_H
#include <QtCore/QMutex>
#include <QtCore/QSemaphore>
-#include <QtEventDispatcherSupport/private/qunixeventdispatcher_qpa_p.h>
+#include <QtGui/private/qunixeventdispatcher_qpa_p.h>
class QAndroidEventDispatcher : public QUnixEventDispatcherQPA
{
Q_OBJECT
public:
- explicit QAndroidEventDispatcher(QObject *parent = 0);
+ explicit QAndroidEventDispatcher(QObject *parent = nullptr);
~QAndroidEventDispatcher();
void start();
void stop();
@@ -78,7 +42,7 @@ public:
private:
QMutex m_mutex;
QAtomicInt m_started = 1;
- QVector<QAndroidEventDispatcher *> m_dispatchers;
+ QList<QAndroidEventDispatcher *> m_dispatchers;
};
diff --git a/src/plugins/platforms/android/qandroidinputcontext.cpp b/src/plugins/platforms/android/qandroidinputcontext.cpp
index e78c317863..62212ff63d 100644
--- a/src/plugins/platforms/android/qandroidinputcontext.cpp
+++ b/src/plugins/platforms/android/qandroidinputcontext.cpp
@@ -1,66 +1,29 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
-** Copyright (C) 2016 Olivier Goffart <ogoffart@woboq.com>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+// Copyright (C) 2016 Olivier Goffart <ogoffart@woboq.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <android/log.h>
-#include "qandroidinputcontext.h"
-#include "androidjnimain.h"
+#include "androiddeadlockprotector.h"
#include "androidjniinput.h"
+#include "androidjnimain.h"
#include "qandroideventdispatcher.h"
-#include "androiddeadlockprotector.h"
+#include "qandroidinputcontext.h"
#include "qandroidplatformintegration.h"
-#include <QDebug>
+#include "private/qhighdpiscaling_p.h"
+
+#include <QTextBoundaryFinder>
+#include <QTextCharFormat>
+#include <QtCore/QJniEnvironment>
+#include <QtCore/QJniObject>
#include <qevent.h>
#include <qguiapplication.h>
+#include <qinputmethod.h>
#include <qsharedpointer.h>
#include <qthread.h>
-#include <qinputmethod.h>
#include <qwindow.h>
-#include <QtCore/private/qjni_p.h>
-#include <private/qhighdpiscaling_p.h>
-
-#include <QTextCharFormat>
-#include <QTextBoundaryFinder>
-
-#include <QDebug>
+#include <qpa/qplatformwindow.h>
QT_BEGIN_NAMESPACE
@@ -91,9 +54,10 @@ private:
} // namespace anonymous
-static QAndroidInputContext *m_androidInputContext = 0;
-static char const *const QtNativeInputConnectionClassName = "org/qtproject/qt5/android/QtNativeInputConnection";
-static char const *const QtExtractedTextClassName = "org/qtproject/qt5/android/QtExtractedText";
+static QAndroidInputContext *m_androidInputContext = nullptr;
+static char const *const QtNativeInputConnectionClassName = "org/qtproject/qt/android/QtNativeInputConnection";
+static char const *const QtExtractedTextClassName = "org/qtproject/qt/android/QtExtractedText";
+static int m_selectHandleWidth = 0;
static jclass m_extractedTextClass = 0;
static jmethodID m_classConstructorMethodID = 0;
static jfieldID m_partialEndOffsetFieldID = 0;
@@ -116,9 +80,7 @@ static jboolean beginBatchEdit(JNIEnv */*env*/, jobject /*thiz*/)
if (!m_androidInputContext)
return JNI_FALSE;
-#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
- qDebug("@@@ BEGINBATCH");
-#endif
+ qCDebug(lcQpaInputMethods) << "@@@ BEGINBATCH";
jboolean res = JNI_FALSE;
runOnQtThread([&res]{res = m_androidInputContext->beginBatchEdit();});
return res;
@@ -129,9 +91,7 @@ static jboolean endBatchEdit(JNIEnv */*env*/, jobject /*thiz*/)
if (!m_androidInputContext)
return JNI_FALSE;
-#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
- qDebug("@@@ ENDBATCH");
-#endif
+ qCDebug(lcQpaInputMethods) << "@@@ ENDBATCH";
jboolean res = JNI_FALSE;
runOnQtThread([&res]{res = m_androidInputContext->endBatchEdit();});
@@ -149,9 +109,7 @@ static jboolean commitText(JNIEnv *env, jobject /*thiz*/, jstring text, jint new
QString str(reinterpret_cast<const QChar *>(jstr), env->GetStringLength(text));
env->ReleaseStringChars(text, jstr);
-#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
- qDebug() << "@@@ COMMIT" << str << newCursorPosition;
-#endif
+ qCDebug(lcQpaInputMethods) << "@@@ COMMIT" << str << newCursorPosition;
jboolean res = JNI_FALSE;
runOnQtThread([&]{res = m_androidInputContext->commitText(str, newCursorPosition);});
return res;
@@ -162,9 +120,7 @@ static jboolean deleteSurroundingText(JNIEnv */*env*/, jobject /*thiz*/, jint le
if (!m_androidInputContext)
return JNI_FALSE;
-#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
- qDebug() << "@@@ DELETE" << leftLength << rightLength;
-#endif
+ qCDebug(lcQpaInputMethods) << "@@@ DELETE" << leftLength << rightLength;
jboolean res = JNI_FALSE;
runOnQtThread([&]{res = m_androidInputContext->deleteSurroundingText(leftLength, rightLength);});
return res;
@@ -175,9 +131,7 @@ static jboolean finishComposingText(JNIEnv */*env*/, jobject /*thiz*/)
if (!m_androidInputContext)
return JNI_FALSE;
-#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
- qDebug("@@@ FINISH");
-#endif
+ qCDebug(lcQpaInputMethods) << "@@@ FINISH";
jboolean res = JNI_FALSE;
runOnQtThread([&]{res = m_androidInputContext->finishComposingText();});
return res;
@@ -201,9 +155,7 @@ static jobject getExtractedText(JNIEnv *env, jobject /*thiz*/, int hintMaxChars,
QAndroidInputContext::ExtractedText extractedText;
runOnQtThread([&]{extractedText = m_androidInputContext->getExtractedText(hintMaxChars, hintMaxLines, flags);});
-#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
- qDebug() << "@@@ GETEX" << hintMaxChars << hintMaxLines << QString::fromLatin1("0x") + QString::number(flags,16) << extractedText.text << "partOff:" << extractedText.partialStartOffset << extractedText.partialEndOffset << "sel:" << extractedText.selectionStart << extractedText.selectionEnd << "offset:" << extractedText.startOffset;
-#endif
+ qCDebug(lcQpaInputMethods) << "@@@ GETEX" << hintMaxChars << hintMaxLines << QString::fromLatin1("0x") + QString::number(flags,16) << extractedText.text << "partOff:" << extractedText.partialStartOffset << extractedText.partialEndOffset << "sel:" << extractedText.selectionStart << extractedText.selectionEnd << "offset:" << extractedText.startOffset;
jobject object = env->NewObject(m_extractedTextClass, m_classConstructorMethodID);
env->SetIntField(object, m_partialStartOffsetFieldID, extractedText.partialStartOffset);
@@ -226,9 +178,7 @@ static jstring getSelectedText(JNIEnv *env, jobject /*thiz*/, jint flags)
QString text;
runOnQtThread([&]{text = m_androidInputContext->getSelectedText(flags);});
-#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
- qDebug() << "@@@ GETSEL" << text;
-#endif
+ qCDebug(lcQpaInputMethods) << "@@@ GETSEL" << text;
if (text.isEmpty())
return 0;
return env->NewString(reinterpret_cast<const jchar *>(text.constData()), jsize(text.length()));
@@ -241,9 +191,7 @@ static jstring getTextAfterCursor(JNIEnv *env, jobject /*thiz*/, jint length, ji
QString text;
runOnQtThread([&]{text = m_androidInputContext->getTextAfterCursor(length, flags);});
-#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
- qDebug() << "@@@ GETA" << length << text;
-#endif
+ qCDebug(lcQpaInputMethods) << "@@@ GETA" << length << text;
return env->NewString(reinterpret_cast<const jchar *>(text.constData()), jsize(text.length()));
}
@@ -254,9 +202,7 @@ static jstring getTextBeforeCursor(JNIEnv *env, jobject /*thiz*/, jint length, j
QString text;
runOnQtThread([&]{text = m_androidInputContext->getTextBeforeCursor(length, flags);});
-#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
- qDebug() << "@@@ GETB" << length << text;
-#endif
+ qCDebug(lcQpaInputMethods) << "@@@ GETB" << length << text;
return env->NewString(reinterpret_cast<const jchar *>(text.constData()), jsize(text.length()));
}
@@ -270,9 +216,7 @@ static jboolean setComposingText(JNIEnv *env, jobject /*thiz*/, jstring text, ji
QString str(reinterpret_cast<const QChar *>(jstr), env->GetStringLength(text));
env->ReleaseStringChars(text, jstr);
-#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
- qDebug() << "@@@ SET" << str << newCursorPosition;
-#endif
+ qCDebug(lcQpaInputMethods) << "@@@ SET" << str << newCursorPosition;
jboolean res = JNI_FALSE;
runOnQtThread([&]{res = m_androidInputContext->setComposingText(str, newCursorPosition);});
return res;
@@ -283,9 +227,7 @@ static jboolean setComposingRegion(JNIEnv */*env*/, jobject /*thiz*/, jint start
if (!m_androidInputContext)
return JNI_FALSE;
-#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
- qDebug() << "@@@ SETR" << start << end;
-#endif
+ qCDebug(lcQpaInputMethods) << "@@@ SETR" << start << end;
jboolean res = JNI_FALSE;
runOnQtThread([&]{res = m_androidInputContext->setComposingRegion(start, end);});
return res;
@@ -297,9 +239,7 @@ static jboolean setSelection(JNIEnv */*env*/, jobject /*thiz*/, jint start, jint
if (!m_androidInputContext)
return JNI_FALSE;
-#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
- qDebug() << "@@@ SETSEL" << start << end;
-#endif
+ qCDebug(lcQpaInputMethods) << "@@@ SETSEL" << start << end;
jboolean res = JNI_FALSE;
runOnQtThread([&]{res = m_androidInputContext->setSelection(start, end);});
return res;
@@ -311,9 +251,7 @@ static jboolean selectAll(JNIEnv */*env*/, jobject /*thiz*/)
if (!m_androidInputContext)
return JNI_FALSE;
-#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
- qDebug("@@@ SELALL");
-#endif
+ qCDebug(lcQpaInputMethods) << "@@@ SELALL";
jboolean res = JNI_FALSE;
runOnQtThread([&]{res = m_androidInputContext->selectAll();});
return res;
@@ -324,9 +262,7 @@ static jboolean cut(JNIEnv */*env*/, jobject /*thiz*/)
if (!m_androidInputContext)
return JNI_FALSE;
-#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
- qDebug("@@@");
-#endif
+ qCDebug(lcQpaInputMethods) << "@@@";
jboolean res = JNI_FALSE;
runOnQtThread([&]{res = m_androidInputContext->cut();});
return res;
@@ -337,9 +273,7 @@ static jboolean copy(JNIEnv */*env*/, jobject /*thiz*/)
if (!m_androidInputContext)
return JNI_FALSE;
-#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
- qDebug("@@@");
-#endif
+ qCDebug(lcQpaInputMethods) << "@@@";
jboolean res = JNI_FALSE;
runOnQtThread([&]{res = m_androidInputContext->copy();});
return res;
@@ -350,9 +284,7 @@ static jboolean copyURL(JNIEnv */*env*/, jobject /*thiz*/)
if (!m_androidInputContext)
return JNI_FALSE;
-#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
- qDebug("@@@");
-#endif
+ qCDebug(lcQpaInputMethods) << "@@@";
jboolean res = JNI_FALSE;
runOnQtThread([&]{res = m_androidInputContext->copyURL();});
return res;
@@ -363,9 +295,7 @@ static jboolean paste(JNIEnv */*env*/, jobject /*thiz*/)
if (!m_androidInputContext)
return JNI_FALSE;
-#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
- qDebug("@@@ PASTE");
-#endif
+ qCDebug(lcQpaInputMethods) << "@@@ PASTE";
jboolean res = JNI_FALSE;
runOnQtThread([&]{res = m_androidInputContext->paste();});
return res;
@@ -376,14 +306,24 @@ static jboolean updateCursorPosition(JNIEnv */*env*/, jobject /*thiz*/)
if (!m_androidInputContext)
return JNI_FALSE;
-#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
- qDebug("@@@ UPDATECURSORPOS");
-#endif
+ qCDebug(lcQpaInputMethods) << "@@@ UPDATECURSORPOS";
runOnQtThread([&]{m_androidInputContext->updateCursorPosition();});
return true;
}
+static void reportFullscreenMode(JNIEnv */*env*/, jobject /*thiz*/, jboolean enabled)
+{
+ if (!m_androidInputContext)
+ return;
+
+ runOnQtThread([&]{m_androidInputContext->reportFullscreenMode(enabled);});
+}
+
+static jboolean fullscreenMode(JNIEnv */*env*/, jobject /*thiz*/)
+{
+ return m_androidInputContext ? m_androidInputContext->fullscreenMode() : false;
+}
static JNINativeMethod methods[] = {
{"beginBatchEdit", "()Z", (void *)beginBatchEdit},
@@ -392,7 +332,7 @@ static JNINativeMethod methods[] = {
{"deleteSurroundingText", "(II)Z", (void *)deleteSurroundingText},
{"finishComposingText", "()Z", (void *)finishComposingText},
{"getCursorCapsMode", "(I)I", (void *)getCursorCapsMode},
- {"getExtractedText", "(III)Lorg/qtproject/qt5/android/QtExtractedText;", (void *)getExtractedText},
+ {"getExtractedText", "(III)Lorg/qtproject/qt/android/QtExtractedText;", (void *)getExtractedText},
{"getSelectedText", "(I)Ljava/lang/String;", (void *)getSelectedText},
{"getTextAfterCursor", "(II)Ljava/lang/String;", (void *)getTextAfterCursor},
{"getTextBeforeCursor", "(II)Ljava/lang/String;", (void *)getTextBeforeCursor},
@@ -404,26 +344,16 @@ static JNINativeMethod methods[] = {
{"copy", "()Z", (void *)copy},
{"copyURL", "()Z", (void *)copyURL},
{"paste", "()Z", (void *)paste},
- {"updateCursorPosition", "()Z", (void *)updateCursorPosition}
+ {"updateCursorPosition", "()Z", (void *)updateCursorPosition},
+ {"reportFullscreenMode", "(Z)V", (void *)reportFullscreenMode},
+ {"fullscreenMode", "()Z", (void *)fullscreenMode}
};
-static QRect inputItemRectangle()
-{
- QRectF itemRect = qGuiApp->inputMethod()->inputItemRectangle();
- QRect rect = qGuiApp->inputMethod()->inputItemTransform().mapRect(itemRect).toRect();
- QWindow *window = qGuiApp->focusWindow();
- if (window)
- rect = QRect(window->mapToGlobal(rect.topLeft()), rect.size());
- double pixelDensity = window
- ? QHighDpiScaling::factor(window)
- : QHighDpiScaling::factor(QtAndroid::androidPlatformIntegration()->screen());
- if (pixelDensity != 1.0) {
- rect.setRect(rect.x() * pixelDensity,
- rect.y() * pixelDensity,
- rect.width() * pixelDensity,
- rect.height() * pixelDensity);
- }
- return rect;
+static QRect screenInputItemRectangle()
+{
+ QRect windowRect = QPlatformInputContext::inputItemRectangle().toRect();
+ QPlatformWindow *window = qGuiApp->focusWindow()->handle();
+ return QRect(window->mapToGlobal(windowRect.topLeft()), windowRect.size());
}
QAndroidInputContext::QAndroidInputContext()
@@ -433,8 +363,10 @@ QAndroidInputContext::QAndroidInputContext()
, m_handleMode(Hidden)
, m_batchEditNestingLevel(0)
, m_focusObject(0)
+ , m_fullScreenMode(false)
{
- jclass clazz = QJNIEnvironmentPrivate::findClass(QtNativeInputConnectionClassName);
+ QJniEnvironment env;
+ jclass clazz = env.findClass(QtNativeInputConnectionClassName);
if (Q_UNLIKELY(!clazz)) {
qCritical() << "Native registration unable to find class '"
<< QtNativeInputConnectionClassName
@@ -442,7 +374,6 @@ QAndroidInputContext::QAndroidInputContext()
return;
}
- QJNIEnvironmentPrivate env;
if (Q_UNLIKELY(env->RegisterNatives(clazz, methods, sizeof(methods) / sizeof(methods[0])) < 0)) {
qCritical() << "RegisterNatives failed for '"
<< QtNativeInputConnectionClassName
@@ -450,7 +381,7 @@ QAndroidInputContext::QAndroidInputContext()
return;
}
- clazz = QJNIEnvironmentPrivate::findClass(QtExtractedTextClassName);
+ clazz = env.findClass(QtExtractedTextClassName);
if (Q_UNLIKELY(!clazz)) {
qCritical() << "Native registration unable to find class '"
<< QtExtractedTextClassName
@@ -615,62 +546,109 @@ void QAndroidInputContext::updateCursorPosition()
}
}
+bool QAndroidInputContext::isImhNoTextHandlesSet()
+{
+ QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
+ if (query.isNull())
+ return false;
+ return query->value(Qt::ImHints).toUInt() & Qt::ImhNoTextHandles;
+}
+
void QAndroidInputContext::updateSelectionHandles()
{
+ if (m_fullScreenMode) {
+ QtAndroidInput::updateHandles(Hidden);
+ return;
+ }
static bool noHandles = qEnvironmentVariableIntValue("QT_QPA_NO_TEXT_HANDLES");
- if (noHandles)
+ if (noHandles || !m_focusObject)
return;
- auto im = qGuiApp->inputMethod();
- if (!m_focusObject || ((m_handleMode & 0xff) == Hidden)) {
- // Hide the handles
+ if (isImhNoTextHandlesSet()) {
QtAndroidInput::updateHandles(Hidden);
return;
}
- QWindow *window = qGuiApp->focusWindow();
- double pixelDensity = window
- ? QHighDpiScaling::factor(window)
- : QHighDpiScaling::factor(QtAndroid::androidPlatformIntegration()->screen());
- QInputMethodQueryEvent query(Qt::ImCursorPosition | Qt::ImAnchorPosition | Qt::ImEnabled | Qt::ImCurrentSelection | Qt::ImHints | Qt::ImSurroundingText);
+ auto im = qGuiApp->inputMethod();
+
+ QInputMethodQueryEvent query(Qt::ImCursorPosition | Qt::ImAnchorPosition | Qt::ImEnabled
+ | Qt::ImCurrentSelection | Qt::ImHints | Qt::ImSurroundingText
+ | Qt::ImReadOnly);
QCoreApplication::sendEvent(m_focusObject, &query);
int cpos = query.value(Qt::ImCursorPosition).toInt();
int anchor = query.value(Qt::ImAnchorPosition).toInt();
+ const QVariant readOnlyVariant = query.value(Qt::ImReadOnly);
+ bool readOnly = readOnlyVariant.toBool();
+ QPlatformWindow *qPlatformWindow = qGuiApp->focusWindow()->handle();
+
+ if (!readOnly && ((m_handleMode & 0xff) == Hidden)) {
+ QtAndroidInput::updateHandles(Hidden);
+ return;
+ }
+
+ if ( cpos == anchor && (!readOnlyVariant.isValid() || readOnly)) {
+ QtAndroidInput::updateHandles(Hidden);
+ return;
+ }
if (cpos == anchor || im->anchorRectangle().isNull()) {
- if (!query.value(Qt::ImEnabled).toBool()) {
- QtAndroidInput::updateHandles(Hidden);
- return;
+ auto curRect = cursorRectangle();
+ QPoint cursorPointGlobal = qPlatformWindow->mapToGlobal(
+ QPoint(curRect.x() + (curRect.width() / 2), curRect.y() + curRect.height()));
+ QPoint cursorPoint(curRect.center().x(), curRect.bottom());
+ int x = curRect.x();
+ int y = curRect.y();
+
+ // Use x and y for the editMenuPoint from the cursorPointGlobal when the cursor is in the Dialog
+ if (cursorPointGlobal != cursorPoint) {
+ x = cursorPointGlobal.x();
+ y = cursorPointGlobal.y();
}
- auto curRect = im->cursorRectangle();
- QPoint cursorPoint(curRect.center().x(), curRect.bottom());
- QPoint editMenuPoint(curRect.x(), curRect.y());
+ QPoint editMenuPoint(x, y);
m_handleMode &= ShowEditPopup;
m_handleMode |= ShowCursor;
- uint32_t buttons = EditContext::PasteButton;
+ uint32_t buttons = readOnly ? 0 : EditContext::PasteButton;
if (!query.value(Qt::ImSurroundingText).toString().isEmpty())
buttons |= EditContext::SelectAllButton;
- QtAndroidInput::updateHandles(m_handleMode, editMenuPoint * pixelDensity, buttons, cursorPoint * pixelDensity);
- // The VK is hidden, reset the timer
- if (m_hideCursorHandleTimer.isActive())
- m_hideCursorHandleTimer.start();
+ QtAndroidInput::updateHandles(m_handleMode, editMenuPoint, buttons, cursorPointGlobal);
+ m_hideCursorHandleTimer.start();
+
return;
}
m_handleMode = ShowSelection | ShowEditPopup ;
- auto leftRect = im->cursorRectangle();
- auto rightRect = im->anchorRectangle();
+ auto leftRect = cursorRectangle();
+ auto rightRect = anchorRectangle();
if (cpos > anchor)
std::swap(leftRect, rightRect);
-
- QPoint leftPoint(leftRect.bottomLeft().toPoint() * pixelDensity);
- QPoint righPoint(rightRect.bottomRight().toPoint() * pixelDensity);
- QPoint editPoint(leftRect.united(rightRect).topLeft().toPoint() * pixelDensity);
- QtAndroidInput::updateHandles(m_handleMode, editPoint, EditContext::AllButtons, leftPoint, righPoint,
- query.value(Qt::ImCurrentSelection).toString().isRightToLeft());
- m_hideCursorHandleTimer.stop();
+ //Move the left or right select handle to the center from the screen edge
+ //the select handle is close to or over the screen edge. Otherwise, the
+ //select handle might go out of the screen and it would be impossible to drag.
+ QPoint leftPoint(qPlatformWindow->mapToGlobal(leftRect.bottomLeft().toPoint()));
+ QPoint rightPoint(qPlatformWindow->mapToGlobal(rightRect.bottomRight().toPoint()));
+
+ QAndroidPlatformIntegration *platformIntegration = QtAndroid::androidPlatformIntegration();
+ if (platformIntegration) {
+ if (m_selectHandleWidth == 0)
+ m_selectHandleWidth = QtAndroidInput::getSelectHandleWidth() / 2;
+
+ int rightSideOfScreen = platformIntegration->screen()->availableGeometry().right();
+ if (leftPoint.x() < m_selectHandleWidth)
+ leftPoint.setX(m_selectHandleWidth);
+
+ if (rightPoint.x() > rightSideOfScreen - m_selectHandleWidth)
+ rightPoint.setX(rightSideOfScreen - m_selectHandleWidth);
+
+ QPoint editPoint(qPlatformWindow->mapToGlobal(leftRect.united(rightRect).topLeft().toPoint()));
+ uint32_t buttons = readOnly ? EditContext::CopyButton | EditContext::SelectAllButton
+ : EditContext::AllButtons;
+
+ QtAndroidInput::updateHandles(m_handleMode, editPoint, buttons, leftPoint, rightPoint,
+ query.value(Qt::ImCurrentSelection).toString().isRightToLeft());
+ m_hideCursorHandleTimer.stop();
+ }
}
/*
@@ -684,23 +662,16 @@ void QAndroidInputContext::handleLocationChanged(int handleId, int x, int y)
qWarning() << "QAndroidInputContext::handleLocationChanged returned";
return;
}
+ QPoint point(x, y);
- auto im = qGuiApp->inputMethod();
- auto leftRect = im->cursorRectangle();
// The handle is down of the cursor, but we want the position in the middle.
- QWindow *window = qGuiApp->focusWindow();
- double pixelDensity = window
- ? QHighDpiScaling::factor(window)
- : QHighDpiScaling::factor(QtAndroid::androidPlatformIntegration()->screen());
- QPointF point(x / pixelDensity, y / pixelDensity);
- point.setY(point.y() - leftRect.width() / 2);
-
QInputMethodQueryEvent query(Qt::ImCursorPosition | Qt::ImAnchorPosition
| Qt::ImAbsolutePosition | Qt::ImCurrentSelection);
QCoreApplication::sendEvent(m_focusObject, &query);
int cpos = query.value(Qt::ImCursorPosition).toInt();
int anchor = query.value(Qt::ImAnchorPosition).toInt();
- auto rightRect = im->anchorRectangle();
+ auto leftRect = cursorRectangle();
+ auto rightRect = anchorRectangle();
if (cpos > anchor)
std::swap(leftRect, rightRect);
@@ -711,10 +682,24 @@ void QAndroidInputContext::handleLocationChanged(int handleId, int x, int y)
point.setY(leftRect.center().y());
}
- const QPointF pointLocal = im->inputItemTransform().inverted().map(point);
bool ok;
- const int handlePos =
- QInputMethod::queryFocusObject(Qt::ImCursorPosition, pointLocal).toInt(&ok);
+ auto object = m_focusObject->parent();
+ int dialogMoveX = 0;
+ while (object) {
+ if (QString::compare(object->metaObject()->className(),
+ "QDialog", Qt::CaseInsensitive) == 0) {
+ dialogMoveX += object->property("x").toInt();
+ }
+ object = object->parent();
+ };
+
+ auto position =
+ QPointF(QHighDpi::fromNativePixels(point, QGuiApplication::focusWindow()));
+ const QPointF fixedPosition = QPointF(position.x() - dialogMoveX, position.y());
+ const QInputMethod *im = QGuiApplication::inputMethod();
+ const QTransform mapToLocal = im->inputItemTransform().inverted();
+ const int handlePos = im->queryFocusObject(Qt::ImCursorPosition, mapToLocal.map(fixedPosition)).toInt(&ok);
+
if (!ok)
return;
@@ -788,31 +773,30 @@ void QAndroidInputContext::handleLocationChanged(int handleId, int x, int y)
void QAndroidInputContext::touchDown(int x, int y)
{
- if (m_focusObject && inputItemRectangle().contains(x, y)) {
+ if (m_focusObject && screenInputItemRectangle().contains(x, y)) {
// If the user touch the input rectangle, we can show the cursor handle
m_handleMode = ShowCursor;
// The VK will appear in a moment, stop the timer
m_hideCursorHandleTimer.stop();
if (focusObjectIsComposing()) {
- const double pixelDensity =
- QGuiApplication::focusWindow()
- ? QHighDpiScaling::factor(QGuiApplication::focusWindow())
- : QHighDpiScaling::factor(QtAndroid::androidPlatformIntegration()->screen());
-
- const QPointF touchPointLocal =
- QGuiApplication::inputMethod()->inputItemTransform().inverted().map(
- QPointF(x / pixelDensity, y / pixelDensity));
-
const int curBlockPos = getBlockPosition(
focusObjectInputMethodQuery(Qt::ImCursorPosition | Qt::ImAbsolutePosition));
const int touchPosition = curBlockPos
- + QInputMethod::queryFocusObject(Qt::ImCursorPosition, touchPointLocal).toInt();
+ + queryFocusObject(Qt::ImCursorPosition, QPointF(x, y)).toInt();
if (touchPosition != m_composingCursor)
focusObjectStopComposing();
}
- updateSelectionHandles();
+ // Check if cursor is visible in focused window before updating handles
+ QPlatformWindow *window = qGuiApp->focusWindow()->handle();
+ const QRectF curRect = cursorRectangle();
+ const QPoint cursorGlobalPoint = window->mapToGlobal(QPoint(curRect.x(), curRect.y()));
+ const QRect windowRect = QPlatformInputContext::inputItemClipRectangle().toRect();
+ const QRect windowGlobalRect = QRect(window->mapToGlobal(windowRect.topLeft()), windowRect.size());
+
+ if (windowGlobalRect.contains(cursorGlobalPoint.x(), cursorGlobalPoint.y()))
+ updateSelectionHandles();
}
}
@@ -822,16 +806,11 @@ void QAndroidInputContext::longPress(int x, int y)
if (noHandles)
return;
- if (m_focusObject && inputItemRectangle().contains(x, y)) {
+ if (m_focusObject && screenInputItemRectangle().contains(x, y)) {
BatchEditLock batchEditLock(this);
focusObjectStopComposing();
-
- const double pixelDensity =
- QGuiApplication::focusWindow()
- ? QHighDpiScaling::factor(QGuiApplication::focusWindow())
- : QHighDpiScaling::factor(QtAndroid::androidPlatformIntegration()->screen());
- const QPointF touchPoint(x / pixelDensity, y / pixelDensity);
+ const QPointF touchPoint(x, y);
setSelectionOnFocusObject(touchPoint, touchPoint);
QInputMethodQueryEvent query(Qt::ImCursorPosition | Qt::ImAnchorPosition | Qt::ImTextBeforeCursor | Qt::ImTextAfterCursor);
@@ -897,8 +876,8 @@ void QAndroidInputContext::update(Qt::InputMethodQueries queries)
void QAndroidInputContext::invokeAction(QInputMethod::Action action, int cursorPosition)
{
#warning TODO Handle at least QInputMethod::ContextMenu action
- Q_UNUSED(action)
- Q_UNUSED(cursorPosition)
+ Q_UNUSED(action);
+ Q_UNUSED(cursorPosition);
//### click should be passed to the IM, but in the meantime it's better to ignore it than to do something wrong
// if (action == QInputMethod::Click)
// commit();
@@ -924,13 +903,18 @@ void QAndroidInputContext::showInputPanel()
if (query.isNull())
return;
+ if (!qGuiApp->focusWindow()->handle())
+ return; // not a real window, probably VR/XR
+
disconnect(m_updateCursorPosConnection);
+ m_updateCursorPosConnection = {};
+
if (qGuiApp->focusObject()->metaObject()->indexOfSignal("cursorPositionChanged(int,int)") >= 0) // QLineEdit breaks the pattern
m_updateCursorPosConnection = connect(qGuiApp->focusObject(), SIGNAL(cursorPositionChanged(int,int)), this, SLOT(updateCursorPosition()));
- else
+ else if (qGuiApp->focusObject()->metaObject()->indexOfSignal("cursorPositionChanged()") >= 0)
m_updateCursorPosConnection = connect(qGuiApp->focusObject(), SIGNAL(cursorPositionChanged()), this, SLOT(updateCursorPosition()));
- QRect rect = inputItemRectangle();
+ QRect rect = screenInputItemRectangle();
QtAndroidInput::showSoftwareKeyboard(rect.left(), rect.top(), rect.width(), rect.height(),
query->value(Qt::ImHints).toUInt(),
query->value(Qt::ImEnterKeyType).toUInt());
@@ -983,7 +967,6 @@ void QAndroidInputContext::setFocusObject(QObject *object)
m_focusObject = object;
reset();
}
- QPlatformInputContext::setFocusObject(object);
updateSelectionHandles();
}
@@ -1037,7 +1020,7 @@ jboolean QAndroidInputContext::deleteSurroundingText(jint leftLength, jint right
absolutely not what Android's native EditText does. It deletes leftLength characters before
min(selection start, composing region start) and rightLength characters after max(selection
end, composing region end). There are no known keyboards that depend on this behavior, but
- it is better to be consistent with EditText behavior, because there definetly should be no
+ it is better to be consistent with EditText behavior, because there definitely should be no
keyboards that depend on documented behavior.
*/
const int leftEnd =
@@ -1140,6 +1123,25 @@ jboolean QAndroidInputContext::finishComposingText()
return JNI_TRUE;
}
+void QAndroidInputContext::reportFullscreenMode(jboolean enabled)
+{
+ m_fullScreenMode = enabled;
+ BatchEditLock batchEditLock(this);
+ if (!focusObjectStopComposing())
+ return;
+
+ if (enabled)
+ m_handleMode = Hidden;
+
+ updateSelectionHandles();
+}
+
+// Called in calling thread's context
+jboolean QAndroidInputContext::fullscreenMode()
+{
+ return m_fullScreenMode;
+}
+
bool QAndroidInputContext::focusObjectIsComposing() const
{
return m_composingCursor != -1;
@@ -1151,7 +1153,7 @@ void QAndroidInputContext::focusObjectStartComposing()
return;
// Composing strings containing newline characters are rare and may cause problems
- if (m_composingText.contains(QLatin1Char('\n')))
+ if (m_composingText.contains(u'\n'))
return;
QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
@@ -1173,7 +1175,7 @@ void QAndroidInputContext::focusObjectStartComposing()
QInputMethodEvent event(m_composingText, {
{ QInputMethodEvent::Cursor, absoluteCursorPos - m_composingTextStart, 1 },
- { QInputMethodEvent::TextFormat, 0, m_composingText.length(), underlined }
+ { QInputMethodEvent::TextFormat, 0, int(m_composingText.length()), underlined }
});
event.setCommitString({}, m_composingTextStart - absoluteCursorPos, m_composingText.length());
@@ -1195,13 +1197,21 @@ bool QAndroidInputContext::focusObjectStopComposing()
m_composingCursor = -1;
- // Moving Qt's cursor to where the preedit cursor used to be
- QList<QInputMethodEvent::Attribute> attributes;
- attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Selection, localCursorPos, 0));
-
- QInputMethodEvent event(QString(), attributes);
- event.setCommitString(m_composingText);
- sendInputMethodEvent(&event);
+ {
+ // commit the composing test
+ QList<QInputMethodEvent::Attribute> attributes;
+ QInputMethodEvent event(QString(), attributes);
+ event.setCommitString(m_composingText);
+ sendInputMethodEvent(&event);
+ }
+ {
+ // Moving Qt's cursor to where the preedit cursor used to be
+ QList<QInputMethodEvent::Attribute> attributes;
+ attributes.append(
+ QInputMethodEvent::Attribute(QInputMethodEvent::Selection, localCursorPos, 0));
+ QInputMethodEvent event(QString(), attributes);
+ sendInputMethodEvent(&event);
+ }
return true;
}
@@ -1224,9 +1234,9 @@ jint QAndroidInputContext::getCursorCapsMode(jint /*reqModes*/)
QString surroundingText = query->value(Qt::ImSurroundingText).toString();
surroundingText.truncate(localPos);
if (focusObjectIsComposing())
- surroundingText += m_composingText.leftRef(m_composingCursor - m_composingTextStart);
+ surroundingText += QStringView{m_composingText}.left(m_composingCursor - m_composingTextStart);
// Add a character to see if it is at the end of the sentence or not
- QTextBoundaryFinder finder(QTextBoundaryFinder::Sentence, surroundingText + QLatin1Char('A'));
+ QTextBoundaryFinder finder(QTextBoundaryFinder::Sentence, surroundingText + u'A');
finder.setPosition(surroundingText.length());
if (finder.isAtBoundary())
atWordBoundary = finder.isAtBoundary();
@@ -1330,7 +1340,7 @@ QString QAndroidInputContext::getTextAfterCursor(jint length, jint /*flags*/)
if (focusObjectIsComposing()) {
// Controls do not report preedit text, so we have to add it
const int cursorPosInsidePreedit = m_composingCursor - m_composingTextStart;
- text = m_composingText.midRef(cursorPosInsidePreedit) + text;
+ text = QStringView{m_composingText}.mid(cursorPosInsidePreedit) + text;
} else {
// We must not return selected text if there is any
QSharedPointer<QInputMethodQueryEvent> query =
@@ -1370,7 +1380,7 @@ QString QAndroidInputContext::getTextBeforeCursor(jint length, jint /*flags*/)
if (focusObjectIsComposing()) {
// Controls do not report preedit text, so we have to add it
const int cursorPosInsidePreedit = m_composingCursor - m_composingTextStart;
- text += m_composingText.leftRef(cursorPosInsidePreedit);
+ text += QStringView{m_composingText}.left(cursorPosInsidePreedit);
} else {
// We must not return selected text if there is any
QSharedPointer<QInputMethodQueryEvent> query =
@@ -1409,16 +1419,25 @@ jboolean QAndroidInputContext::setComposingText(const QString &text, jint newCur
const int absoluteCursorPos = getAbsoluteCursorPosition(query);
int absoluteAnchorPos = getBlockPosition(query) + query->value(Qt::ImAnchorPosition).toInt();
+ auto setCursorPosition = [=]() {
+ const int cursorPos = query->value(Qt::ImCursorPosition).toInt();
+ QInputMethodEvent event({}, { { QInputMethodEvent::Selection, cursorPos, 0 } });
+ QGuiApplication::sendEvent(m_focusObject, &event);
+ };
+
// If we have composing region and selection (and therefore focusObjectIsComposing() == false),
// we must clear selection so that we won't delete it when we will be replacing composing text
if (!m_composingText.isEmpty() && absoluteCursorPos != absoluteAnchorPos) {
- const int cursorPos = query->value(Qt::ImCursorPosition).toInt();
- QInputMethodEvent event({}, { { QInputMethodEvent::Selection, cursorPos, 0 } });
- QGuiApplication::sendEvent(m_focusObject, &event);
-
+ setCursorPosition();
absoluteAnchorPos = absoluteCursorPos;
}
+ // The value of Qt::ImCursorPosition is not updated at the start
+ // when the first character is added, so we must update it (QTBUG-85090)
+ if (absoluteCursorPos == 0 && text.length() == 1 && getTextAfterCursor(1,1).length() >= 0) {
+ setCursorPosition();
+ }
+
// If we had no composing region, pretend that we had a zero-length composing region at current
// cursor position to simplify code. Also account for that we must delete selected text if there
// (still) is any.
@@ -1437,20 +1456,19 @@ jboolean QAndroidInputContext::setComposingText(const QString &text, jint newCur
const bool focusObjectWasComposing = focusObjectIsComposing();
// Same checks as in focusObjectStartComposing()
- if (!m_composingText.isEmpty() && !m_composingText.contains(QLatin1Char('\n'))
+ if (!m_composingText.isEmpty() && !m_composingText.contains(u'\n')
&& newAbsoluteCursorPos >= m_composingTextStart
&& newAbsoluteCursorPos <= m_composingTextStart + m_composingText.length())
m_composingCursor = newAbsoluteCursorPos;
else
m_composingCursor = -1;
- QInputMethodEvent event;
if (focusObjectIsComposing()) {
QTextCharFormat underlined;
underlined.setFontUnderline(true);
- event = QInputMethodEvent(m_composingText, {
- { QInputMethodEvent::TextFormat, 0, m_composingText.length(), underlined },
+ QInputMethodEvent event(m_composingText, {
+ { QInputMethodEvent::TextFormat, 0, int(m_composingText.length()), underlined },
{ QInputMethodEvent::Cursor, m_composingCursor - m_composingTextStart, 1 }
});
@@ -1458,8 +1476,12 @@ jboolean QAndroidInputContext::setComposingText(const QString &text, jint newCur
event.setCommitString({}, m_composingTextStart - effectiveAbsoluteCursorPos,
oldComposingTextLen);
}
+ if (m_composingText.isEmpty())
+ clear();
+
+ QGuiApplication::sendEvent(m_focusObject, &event);
} else {
- event = QInputMethodEvent({}, {});
+ QInputMethodEvent event({}, {});
if (focusObjectWasComposing) {
event.setCommitString(m_composingText);
@@ -1468,12 +1490,11 @@ jboolean QAndroidInputContext::setComposingText(const QString &text, jint newCur
m_composingTextStart - effectiveAbsoluteCursorPos,
oldComposingTextLen);
}
- }
-
- if (m_composingText.isEmpty())
- clear();
+ if (m_composingText.isEmpty())
+ clear();
- QGuiApplication::sendEvent(m_focusObject, &event);
+ QGuiApplication::sendEvent(m_focusObject, &event);
+ }
if (!focusObjectIsComposing() && newCursorPosition != 1) {
// Move cursor using a separate event because if we have inserted or deleted a newline
@@ -1482,7 +1503,7 @@ jboolean QAndroidInputContext::setComposingText(const QString &text, jint newCur
const int newBlockPos = getBlockPosition(
focusObjectInputMethodQuery(Qt::ImCursorPosition | Qt::ImAbsolutePosition));
- event = QInputMethodEvent({}, {
+ QInputMethodEvent event({}, {
{ QInputMethodEvent::Selection, newAbsoluteCursorPos - newBlockPos, 0 }
});
@@ -1529,7 +1550,7 @@ jboolean QAndroidInputContext::setComposingRegion(jint start, jint end)
const int additionalSuffixLen = after.length() - (text.length() - cursorPos);
if (additionalSuffixLen > 0)
- text += after.rightRef(additionalSuffixLen);
+ text += QStringView{after}.right(additionalSuffixLen);
}
if (start < textOffset) {
@@ -1543,9 +1564,7 @@ jboolean QAndroidInputContext::setComposingRegion(jint start, jint end)
}
if (start < textOffset || end - textOffset > text.length()) {
-#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
- qWarning("setComposingRegion: failed to retrieve text from composing region");
-#endif
+ qCDebug(lcQpaInputMethods) << "Warning: setComposingRegion: failed to retrieve text from composing region";
return JNI_TRUE;
}
@@ -1655,9 +1674,9 @@ jboolean QAndroidInputContext::paste()
void QAndroidInputContext::sendShortcut(const QKeySequence &sequence)
{
for (int i = 0; i < sequence.count(); ++i) {
- const int keys = sequence[i];
- Qt::Key key = Qt::Key(keys & ~Qt::KeyboardModifierMask);
- Qt::KeyboardModifiers mod = Qt::KeyboardModifiers(keys & Qt::KeyboardModifierMask);
+ const QKeyCombination keys = sequence[i];
+ Qt::Key key = Qt::Key(keys.toCombined() & ~Qt::KeyboardModifierMask);
+ Qt::KeyboardModifiers mod = Qt::KeyboardModifiers(keys.toCombined() & Qt::KeyboardModifierMask);
QKeyEvent pressEvent(QEvent::KeyPress, key, mod);
QKeyEvent releaseEvent(QEvent::KeyRelease, key, mod);
diff --git a/src/plugins/platforms/android/qandroidinputcontext.h b/src/plugins/platforms/android/qandroidinputcontext.h
index e9bfb98e66..038286c4b8 100644
--- a/src/plugins/platforms/android/qandroidinputcontext.h
+++ b/src/plugins/platforms/android/qandroidinputcontext.h
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
-** Copyright (C) 2016 Olivier Goffart <ogoffart@woboq.com>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+// Copyright (C) 2016 Olivier Goffart <ogoffart@woboq.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef ANDROIDINPUTCONTEXT_H
#define ANDROIDINPUTCONTEXT_H
@@ -45,6 +9,8 @@
#include <functional>
#include <jni.h>
#include <qevent.h>
+
+#include <QtCore/qpointer.h>
#include <QTimer>
QT_BEGIN_NAMESPACE
@@ -134,6 +100,8 @@ public:
jboolean copy();
jboolean copyURL();
jboolean paste();
+ void reportFullscreenMode(jboolean enabled);
+ jboolean fullscreenMode();
public slots:
void safeCall(const std::function<void()> &func, Qt::ConnectionType conType = Qt::BlockingQueuedConnection);
@@ -149,6 +117,7 @@ private slots:
void showInputPanelLater(Qt::ApplicationState);
private:
+ bool isImhNoTextHandlesSet();
void sendInputMethodEvent(QInputMethodEvent *event);
QSharedPointer<QInputMethodQueryEvent> focusObjectInputMethodQuery(Qt::InputMethodQueries queries = Qt::ImQueryAll);
bool focusObjectIsComposing() const;
@@ -163,8 +132,9 @@ private:
QMetaObject::Connection m_updateCursorPosConnection;
HandleModes m_handleMode;
int m_batchEditNestingLevel;
- QObject *m_focusObject;
+ QPointer<QObject> m_focusObject;
QTimer m_hideCursorHandleTimer;
+ bool m_fullScreenMode;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QAndroidInputContext::HandleModes)
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/android/qandroidplatformaccessibility.cpp b/src/plugins/platforms/android/qandroidplatformaccessibility.cpp
index fdff9c3eba..61fc21a6bc 100644
--- a/src/plugins/platforms/android/qandroidplatformaccessibility.cpp
+++ b/src/plugins/platforms/android/qandroidplatformaccessibility.cpp
@@ -1,48 +1,11 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qandroidplatformaccessibility.h"
#include "androidjniaccessibility.h"
QT_BEGIN_NAMESPACE
-
QAndroidPlatformAccessibility::QAndroidPlatformAccessibility()
{
QtAndroidAccessibility::initialize();
@@ -51,9 +14,33 @@ QAndroidPlatformAccessibility::QAndroidPlatformAccessibility()
QAndroidPlatformAccessibility::~QAndroidPlatformAccessibility()
{}
-void QAndroidPlatformAccessibility::notifyAccessibilityUpdate(QAccessibleEvent */*event*/)
+void QAndroidPlatformAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event)
+{
+ if (!isActive() || event == nullptr || !event->accessibleInterface())
+ return;
+
+ // We do not need implementation of all events, as current statues are polled
+ // by QtAccessibilityDelegate.java on every accessibility interaction.
+ // Currently we only send notification about the element's position change,
+ // so that the element can be moved on the screen if it's focused.
+
+ if (event->type() == QAccessible::LocationChanged) {
+ QtAndroidAccessibility::notifyLocationChange(event->uniqueId());
+ } else if (event->type() == QAccessible::ObjectHide) {
+ QtAndroidAccessibility::notifyObjectHide(event->uniqueId());
+ } else if (event->type() == QAccessible::Focus) {
+ QtAndroidAccessibility::notifyObjectFocus(event->uniqueId());
+ } else if (event->type() == QAccessible::ValueChanged) {
+ QtAndroidAccessibility::notifyValueChanged(event->uniqueId());
+ } else if (event->type() == QAccessible::ScrollingEnd) {
+ QtAndroidAccessibility::notifyScrolledEvent(event->uniqueId());
+ }
+}
+
+void QAndroidPlatformAccessibility::setRootObject(QObject *obj)
{
- // FIXME send events
+ QPlatformAccessibility::setRootObject(obj);
+ QtAndroidAccessibility::createAccessibilityContextObject(obj);
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/android/qandroidplatformaccessibility.h b/src/plugins/platforms/android/qandroidplatformaccessibility.h
index 8216c05fa6..9fcc45397a 100644
--- a/src/plugins/platforms/android/qandroidplatformaccessibility.h
+++ b/src/plugins/platforms/android/qandroidplatformaccessibility.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QANDROIDPLATFORMACCESSIBILITY_H
@@ -52,6 +16,7 @@ public:
~QAndroidPlatformAccessibility();
void notifyAccessibilityUpdate(QAccessibleEvent *event) override;
+ void setRootObject(QObject *obj) override;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/android/qandroidplatformbackingstore.cpp b/src/plugins/platforms/android/qandroidplatformbackingstore.cpp
deleted file mode 100644
index 61d4969c41..0000000000
--- a/src/plugins/platforms/android/qandroidplatformbackingstore.cpp
+++ /dev/null
@@ -1,88 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 BogDan Vatra <bogdan@kde.org>
-** Copyright (C) 2016 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 "qandroidplatformbackingstore.h"
-#include "qandroidplatformscreen.h"
-#include "qandroidplatformwindow.h"
-#include <qpa/qplatformscreen.h>
-
-QT_BEGIN_NAMESPACE
-
-QAndroidPlatformBackingStore::QAndroidPlatformBackingStore(QWindow *window)
- : QPlatformBackingStore(window)
-{
- if (window->handle())
- setBackingStore(window);
-}
-
-QPaintDevice *QAndroidPlatformBackingStore::paintDevice()
-{
- return &m_image;
-}
-
-void QAndroidPlatformBackingStore::flush(QWindow *window, const QRegion &region, const QPoint &offset)
-{
- Q_UNUSED(offset);
-
- if (!m_backingStoreSet)
- setBackingStore(window);
-
- (static_cast<QAndroidPlatformWindow *>(window->handle()))->repaint(region);
-}
-
-void QAndroidPlatformBackingStore::resize(const QSize &size, const QRegion &staticContents)
-{
- Q_UNUSED(staticContents);
-
- if (m_image.size() != size)
- m_image = QImage(size, window()->screen()->handle()->format());
-}
-
-void QAndroidPlatformBackingStore::setBackingStore(QWindow *window)
-{
- if (window->surfaceType() == QSurface::RasterSurface || window->surfaceType() == QSurface::RasterGLSurface) {
- (static_cast<QAndroidPlatformWindow *>(window->handle()))->setBackingStore(this);
- m_backingStoreSet = true;
- } else {
- qWarning("QAndroidPlatformBackingStore does not support OpenGL-only windows.");
- }
-}
-
-QT_END_NAMESPACE
diff --git a/src/plugins/platforms/android/qandroidplatformbackingstore.h b/src/plugins/platforms/android/qandroidplatformbackingstore.h
deleted file mode 100644
index a3a65aa30e..0000000000
--- a/src/plugins/platforms/android/qandroidplatformbackingstore.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 BogDan Vatra <bogdan@kde.org>
-** Copyright (C) 2016 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 QANDROIDPLATFORMBACKINGSTORE_H
-#define QANDROIDPLATFORMBACKINGSTORE_H
-
-#include <qpa/qplatformbackingstore.h>
-#include <qpa/qwindowsysteminterface.h>
-
-QT_BEGIN_NAMESPACE
-
-class QAndroidPlatformBackingStore : public QPlatformBackingStore
-{
-public:
- explicit QAndroidPlatformBackingStore(QWindow *window);
- QPaintDevice *paintDevice() override;
- void flush(QWindow *window, const QRegion &region, const QPoint &offset) override;
- void resize(const QSize &size, const QRegion &staticContents) override;
- QImage toImage() const override { return m_image; }
- void setBackingStore(QWindow *window);
-protected:
- QImage m_image;
- bool m_backingStoreSet = false;
-};
-
-QT_END_NAMESPACE
-
-#endif // QANDROIDPLATFORMBACKINGSTORE_H
diff --git a/src/plugins/platforms/android/qandroidplatformclipboard.cpp b/src/plugins/platforms/android/qandroidplatformclipboard.cpp
index 17dfe27d12..e5ed33b9b0 100644
--- a/src/plugins/platforms/android/qandroidplatformclipboard.cpp
+++ b/src/plugins/platforms/android/qandroidplatformclipboard.cpp
@@ -1,66 +1,102 @@
-/****************************************************************************
-**
-** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2023 The Qt Company Ltd.
+// Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qandroidplatformclipboard.h"
-#include "androidjniclipboard.h"
+
+#include <QtCore/QUrl>
+#include <QtCore/QJniEnvironment>
+#include <QtCore/QJniObject>
+#include <QtCore/private/qjnihelpers_p.h>
+
#ifndef QT_NO_CLIPBOARD
+using namespace QtJniTypes;
+
QT_BEGIN_NAMESPACE
+void QAndroidPlatformClipboard::onClipboardDataChanged(JNIEnv *env, jobject obj, jlong nativePointer)
+{
+ Q_UNUSED(env)
+ Q_UNUSED(obj)
+
+ auto *clipboardManager = reinterpret_cast<QAndroidPlatformClipboard *>(nativePointer);
+ if (clipboardManager)
+ clipboardManager->emitChanged(QClipboard::Clipboard);
+}
+
QAndroidPlatformClipboard::QAndroidPlatformClipboard()
{
- QtAndroidClipboard::setClipboardManager(this);
+ m_clipboardManager = QtClipboardManager::construct(QtAndroidPrivate::context(),
+ reinterpret_cast<jlong>(this));
+}
+
+QAndroidPlatformClipboard::~QAndroidPlatformClipboard()
+{
+ if (data)
+ delete data;
+}
+
+QMimeData *QAndroidPlatformClipboard::getClipboardMimeData()
+{
+ QMimeData *data = new QMimeData;
+ if (m_clipboardManager.callMethod<jboolean>("hasClipboardText")) {
+ data->setText(m_clipboardManager.callMethod<QString>("getClipboardText"));
+ }
+ if (m_clipboardManager.callMethod<jboolean>("hasClipboardHtml")) {
+ data->setHtml(m_clipboardManager.callMethod<QString>("getClipboardHtml"));
+ }
+ if (m_clipboardManager.callMethod<jboolean>("hasClipboardUri")) {
+ auto uris = m_clipboardManager.callMethod<QString[]>("getClipboardUris");
+ if (uris.isValid()) {
+ QList<QUrl> urls;
+ for (const QString &uri : uris)
+ urls << QUrl(uri);
+ data->setUrls(urls);
+ }
+ }
+ return data;
}
QMimeData *QAndroidPlatformClipboard::mimeData(QClipboard::Mode mode)
{
Q_UNUSED(mode);
Q_ASSERT(supportsMode(mode));
- QMimeData *data = QtAndroidClipboard::getClipboardMimeData();
- data->setParent(this);
+ if (data)
+ data->deleteLater();
+ data = getClipboardMimeData();
return data;
}
+void QAndroidPlatformClipboard::clearClipboardData()
+{
+ m_clipboardManager.callMethod<void>("clearClipData");
+}
+
+void QAndroidPlatformClipboard::setClipboardMimeData(QMimeData *data)
+{
+ clearClipboardData();
+ auto context = QtAndroidPrivate::context();
+ if (data->hasUrls()) {
+ QList<QUrl> urls = data->urls();
+ for (const auto &u : std::as_const(urls))
+ m_clipboardManager.callMethod<void>("setClipboardUri", context, u.toEncoded());
+ } else if (data->hasHtml()) { // html can contain text
+ m_clipboardManager.callMethod<void>("setClipboardHtml",
+ context, data->text(), data->html());
+ } else if (data->hasText()) { // hasText must be the last (the order matter here)
+ m_clipboardManager.callMethod<void>("setClipboardText", context, data->text());
+ }
+}
+
void QAndroidPlatformClipboard::setMimeData(QMimeData *data, QClipboard::Mode mode)
{
+ if (!data) {
+ clearClipboardData();
+ return;
+ }
if (data && supportsMode(mode))
- QtAndroidClipboard::setClipboardMimeData(data);
+ setClipboardMimeData(data);
if (data != 0)
data->deleteLater();
}
@@ -70,6 +106,18 @@ bool QAndroidPlatformClipboard::supportsMode(QClipboard::Mode mode) const
return QClipboard::Clipboard == mode;
}
+bool QAndroidPlatformClipboard::registerNatives(QJniEnvironment &env)
+{
+ bool success = env.registerNativeMethods(Traits<QtClipboardManager>::className(),
+ { Q_JNI_NATIVE_SCOPED_METHOD(onClipboardDataChanged, QAndroidPlatformClipboard) });
+ if (!success) {
+ qCritical() << "QtClipboardManager: registerNativeMethods() failed";
+ return false;
+ }
+
+ return true;
+}
+
QT_END_NAMESPACE
#endif // QT_NO_CLIPBOARD
diff --git a/src/plugins/platforms/android/qandroidplatformclipboard.h b/src/plugins/platforms/android/qandroidplatformclipboard.h
index 3ed9d323f8..ab5c527f88 100644
--- a/src/plugins/platforms/android/qandroidplatformclipboard.h
+++ b/src/plugins/platforms/android/qandroidplatformclipboard.h
@@ -1,59 +1,41 @@
-/****************************************************************************
-**
-** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2023 The Qt Company Ltd.
+// Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QANDROIDPLATFORMCLIPBOARD_H
#define QANDROIDPLATFORMCLIPBOARD_H
#include <qpa/qplatformclipboard.h>
#include <QMimeData>
+#include <QtCore/qjnitypes.h>
#ifndef QT_NO_CLIPBOARD
+
QT_BEGIN_NAMESPACE
-class QAndroidPlatformClipboard : public QObject, public QPlatformClipboard
+Q_DECLARE_JNI_CLASS(QtClipboardManager, "org/qtproject/qt/android/QtClipboardManager");
+
+class QAndroidPlatformClipboard : public QPlatformClipboard
{
public:
QAndroidPlatformClipboard();
-
+ ~QAndroidPlatformClipboard();
QMimeData *mimeData(QClipboard::Mode mode = QClipboard::Clipboard) override;
void setMimeData(QMimeData *data, QClipboard::Mode mode = QClipboard::Clipboard) override;
bool supportsMode(QClipboard::Mode mode) const override;
+
+ static bool registerNatives(QJniEnvironment &env);
+
+private:
+ QMimeData *getClipboardMimeData();
+ void setClipboardMimeData(QMimeData *data);
+ void clearClipboardData();
+
+ static void onClipboardDataChanged(JNIEnv *env, jobject obj, jlong nativePointer);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(onClipboardDataChanged)
+
+ QMimeData *data = nullptr;
+ QtJniTypes::QtClipboardManager m_clipboardManager = nullptr;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/android/qandroidplatformdialoghelpers.cpp b/src/plugins/platforms/android/qandroidplatformdialoghelpers.cpp
index 9218afa7f5..2b9a1194d2 100644
--- a/src/plugins/platforms/android/qandroidplatformdialoghelpers.cpp
+++ b/src/plugins/platforms/android/qandroidplatformdialoghelpers.cpp
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Copyright (C) 2013 BogDan Vatra <bogdan@kde.org>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2022 The Qt Company Ltd.
+// Copyright (C) 2013 BogDan Vatra <bogdan@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qandroidplatformdialoghelpers.h"
#include "androidjnimain.h"
@@ -48,16 +12,20 @@
QT_BEGIN_NAMESPACE
-namespace QtAndroidDialogHelpers {
-static jclass g_messageDialogHelperClass = 0;
+using namespace Qt::StringLiterals;
-static const char QtMessageHandlerHelperClassName[] = "org/qtproject/qt5/android/QtMessageDialogHelper";
+namespace QtAndroidDialogHelpers {
+static jclass g_messageDialogHelperClass = nullptr;
QAndroidPlatformMessageDialogHelper::QAndroidPlatformMessageDialogHelper()
- :m_buttonId(-1)
- ,m_javaMessageDialog(g_messageDialogHelperClass, "(Landroid/app/Activity;)V", QtAndroid::activity())
- ,m_shown(false)
+ : m_javaMessageDialog(g_messageDialogHelperClass, "(Landroid/app/Activity;)V",
+ QtAndroidPrivate::activity().object())
+{
+}
+
+QAndroidPlatformMessageDialogHelper::~QAndroidPlatformMessageDialogHelper()
{
+ hide();
}
void QAndroidPlatformMessageDialogHelper::exec()
@@ -71,42 +39,53 @@ static QString htmlText(QString text)
{
if (Qt::mightBeRichText(text))
return text;
- text.remove(QLatin1Char('\r'));
- return text.toHtmlEscaped().replace(QLatin1Char('\n'), QLatin1String("<br />"));
+ text.remove(u'\r');
+ return text.toHtmlEscaped().replace(u'\n', "<br />"_L1);
}
-bool QAndroidPlatformMessageDialogHelper::show(Qt::WindowFlags windowFlags
- , Qt::WindowModality windowModality
- , QWindow *parent)
+bool QAndroidPlatformMessageDialogHelper::show(Qt::WindowFlags windowFlags,
+ Qt::WindowModality windowModality,
+ QWindow *parent)
{
- Q_UNUSED(windowFlags)
- Q_UNUSED(windowModality)
- Q_UNUSED(parent)
+ Q_UNUSED(windowFlags);
+ Q_UNUSED(windowModality);
+ Q_UNUSED(parent);
QSharedPointer<QMessageDialogOptions> opt = options();
if (!opt.data())
return false;
- m_javaMessageDialog.callMethod<void>("setIcon", "(I)V", opt->icon());
+ if (!opt->checkBoxLabel().isNull())
+ return false; // Can't support
+
+ m_javaMessageDialog.callMethod<void>("setStandardIcon", "(I)V", opt->standardIcon());
QString str = htmlText(opt->windowTitle());
- if (!str.isEmpty())
- m_javaMessageDialog.callMethod<void>("setTile", "(Ljava/lang/String;)V", QJNIObjectPrivate::fromString(str).object());
+ if (!str.isEmpty()) {
+ m_javaMessageDialog.callMethod<void>("setTile", "(Ljava/lang/String;)V",
+ QJniObject::fromString(str).object());
+ }
str = htmlText(opt->text());
- if (!str.isEmpty())
- m_javaMessageDialog.callMethod<void>("setText", "(Ljava/lang/String;)V", QJNIObjectPrivate::fromString(str).object());
+ if (!str.isEmpty()) {
+ m_javaMessageDialog.callMethod<void>("setText", "(Ljava/lang/String;)V",
+ QJniObject::fromString(str).object());
+ }
str = htmlText(opt->informativeText());
- if (!str.isEmpty())
- m_javaMessageDialog.callMethod<void>("setInformativeText", "(Ljava/lang/String;)V", QJNIObjectPrivate::fromString(str).object());
+ if (!str.isEmpty()) {
+ m_javaMessageDialog.callMethod<void>("setInformativeText", "(Ljava/lang/String;)V",
+ QJniObject::fromString(str).object());
+ }
str = htmlText(opt->detailedText());
- if (!str.isEmpty())
- m_javaMessageDialog.callMethod<void>("setDetailedText", "(Ljava/lang/String;)V", QJNIObjectPrivate::fromString(str).object());
+ if (!str.isEmpty()) {
+ m_javaMessageDialog.callMethod<void>("setDetailedText", "(Ljava/lang/String;)V",
+ QJniObject::fromString(str).object());
+ }
- const int * currentLayout = buttonLayout(Qt::Horizontal, AndroidLayout);
+ const int *currentLayout = buttonLayout(Qt::Horizontal, AndroidLayout);
while (*currentLayout != QPlatformDialogHelper::EOL) {
- int role = (*currentLayout & ~QPlatformDialogHelper::Reverse);
+ const int role = (*currentLayout & ~QPlatformDialogHelper::Reverse);
addButtons(opt, static_cast<ButtonRole>(role));
++currentLayout;
}
@@ -116,14 +95,15 @@ bool QAndroidPlatformMessageDialogHelper::show(Qt::WindowFlags windowFlags
return true;
}
-void QAndroidPlatformMessageDialogHelper::addButtons(QSharedPointer<QMessageDialogOptions> opt, ButtonRole role)
+void QAndroidPlatformMessageDialogHelper::addButtons(QSharedPointer<QMessageDialogOptions> opt,
+ ButtonRole role)
{
for (const QMessageDialogOptions::CustomButton &b : opt->customButtons()) {
if (b.role == role) {
QString label = b.label;
label.remove(QChar('&'));
m_javaMessageDialog.callMethod<void>("addButton", "(ILjava/lang/String;)V", b.id,
- QJNIObjectPrivate::fromString(label).object());
+ QJniObject::fromString(label).object());
}
}
@@ -131,7 +111,8 @@ void QAndroidPlatformMessageDialogHelper::addButtons(QSharedPointer<QMessageDial
StandardButton b = static_cast<StandardButton>(i);
if (buttonRole(b) == role && (opt->standardButtons() & i)) {
const QString text = QGuiApplicationPrivate::platformTheme()->standardButtonText(b);
- m_javaMessageDialog.callMethod<void>("addButton", "(ILjava/lang/String;)V", i, QJNIObjectPrivate::fromString(text).object());
+ m_javaMessageDialog.callMethod<void>("addButton", "(ILjava/lang/String;)V", i,
+ QJniObject::fromString(text).object());
}
}
}
@@ -144,17 +125,17 @@ void QAndroidPlatformMessageDialogHelper::hide()
void QAndroidPlatformMessageDialogHelper::dialogResult(int buttonID)
{
- m_buttonId = buttonID;
if (m_loop.isRunning())
m_loop.exit();
- if (m_buttonId < 0) {
+ if (buttonID < 0) {
emit reject();
return;
}
- QPlatformDialogHelper::StandardButton standardButton = static_cast<QPlatformDialogHelper::StandardButton>(buttonID);
- QPlatformDialogHelper::ButtonRole role = QPlatformDialogHelper::buttonRole(standardButton);
+ const StandardButton standardButton = static_cast<StandardButton>(buttonID);
+ ButtonRole role = QPlatformDialogHelper::buttonRole(standardButton);
if (buttonID > QPlatformDialogHelper::LastButton) {
+ // In case of a custom button
const QMessageDialogOptions::CustomButton *custom = options()->customButton(buttonID);
Q_ASSERT(custom);
role = custom->role;
@@ -169,7 +150,7 @@ static void dialogResult(JNIEnv * /*env*/, jobject /*thiz*/, jlong handler, int
QMetaObject::invokeMethod(object, "dialogResult", Qt::QueuedConnection, Q_ARG(int, buttonID));
}
-static JNINativeMethod methods[] = {
+static const JNINativeMethod methods[] = {
{"dialogResult", "(JI)V", (void *)dialogResult}
};
@@ -181,19 +162,19 @@ static JNINativeMethod methods[] = {
return false; \
}
-bool registerNatives(JNIEnv *env)
+bool registerNatives(QJniEnvironment &env)
{
- jclass clazz = QJNIEnvironmentPrivate::findClass(QtMessageHandlerHelperClassName, env);
+ const char QtMessageHandlerHelperClassName[] = "org/qtproject/qt/android/QtMessageDialogHelper";
+ jclass clazz = env.findClass(QtMessageHandlerHelperClassName);
if (!clazz) {
__android_log_print(ANDROID_LOG_FATAL, QtAndroid::qtTagText(), QtAndroid::classErrorMsgFmt()
, QtMessageHandlerHelperClassName);
return false;
}
g_messageDialogHelperClass = static_cast<jclass>(env->NewGlobalRef(clazz));
- FIND_AND_CHECK_CLASS("org/qtproject/qt5/android/QtNativeDialogHelper");
- jclass appClass = static_cast<jclass>(env->NewGlobalRef(clazz));
- if (env->RegisterNatives(appClass, methods, sizeof(methods) / sizeof(methods[0])) < 0) {
+ if (!env.registerNativeMethods("org/qtproject/qt/android/QtNativeDialogHelper",
+ methods, sizeof(methods) / sizeof(methods[0]))) {
__android_log_print(ANDROID_LOG_FATAL, "Qt", "RegisterNatives failed");
return false;
}
diff --git a/src/plugins/platforms/android/qandroidplatformdialoghelpers.h b/src/plugins/platforms/android/qandroidplatformdialoghelpers.h
index 694b4c7580..86f1cf77e7 100644
--- a/src/plugins/platforms/android/qandroidplatformdialoghelpers.h
+++ b/src/plugins/platforms/android/qandroidplatformdialoghelpers.h
@@ -1,51 +1,20 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 BogDan Vatra <bogdan@kde.org>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2013 BogDan Vatra <bogdan@kde.org>
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QANDROIDPLATFORMDIALOGHELPERS_H
#define QANDROIDPLATFORMDIALOGHELPERS_H
+
#include <jni.h>
-#include <qpa/qplatformdialoghelper.h>
+
#include <QEventLoop>
-#include <private/qjni_p.h>
+#include <QtCore/QJniObject>
+#include <qpa/qplatformdialoghelper.h>
QT_BEGIN_NAMESPACE
+class QJniEnvironment;
+
namespace QtAndroidDialogHelpers {
class QAndroidPlatformMessageDialogHelper: public QPlatformMessageDialogHelper
@@ -53,9 +22,10 @@ class QAndroidPlatformMessageDialogHelper: public QPlatformMessageDialogHelper
Q_OBJECT
public:
QAndroidPlatformMessageDialogHelper();
+ ~QAndroidPlatformMessageDialogHelper();
+
void exec() override;
- bool show(Qt::WindowFlags windowFlags,
- Qt::WindowModality windowModality,
+ bool show(Qt::WindowFlags windowFlags, Qt::WindowModality windowModality,
QWindow *parent) override;
void hide() override;
@@ -66,14 +36,13 @@ private:
void addButtons(QSharedPointer<QMessageDialogOptions> opt, ButtonRole role);
private:
- int m_buttonId;
+ bool m_shown = false;
QEventLoop m_loop;
- QJNIObjectPrivate m_javaMessageDialog;
- bool m_shown;
+ QJniObject m_javaMessageDialog;
};
-bool registerNatives(JNIEnv *env);
+bool registerNatives(QJniEnvironment &env);
}
diff --git a/src/plugins/platforms/android/qandroidplatformfiledialoghelper.cpp b/src/plugins/platforms/android/qandroidplatformfiledialoghelper.cpp
index fb979ab6cc..d8a5c58d2c 100644
--- a/src/plugins/platforms/android/qandroidplatformfiledialoghelper.cpp
+++ b/src/plugins/platforms/android/qandroidplatformfiledialoghelper.cpp
@@ -1,58 +1,31 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 Klaralvdalens Datakonsult AB (KDAB)
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2019 Klaralvdalens Datakonsult AB (KDAB)
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qandroidplatformfiledialoghelper.h"
#include <androidjnimain.h>
-#include <private/qjni_p.h>
-#include <jni.h>
+#include <QtCore/QJniObject>
+
+#include <QMimeDatabase>
+#include <QMimeType>
+#include <QRegularExpression>
+#include <QUrl>
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
namespace QtAndroidFileDialogHelper {
#define RESULT_OK -1
#define REQUEST_CODE 1305 // Arbitrary
+const char JniIntentClass[] = "android/content/Intent";
+
QAndroidPlatformFileDialogHelper::QAndroidPlatformFileDialogHelper()
- : QPlatformFileDialogHelper()
- , m_selectedFile()
+ : QPlatformFileDialogHelper(),
+ m_activity(QtAndroidPrivate::activity())
{
}
@@ -61,92 +34,218 @@ bool QAndroidPlatformFileDialogHelper::handleActivityResult(jint requestCode, ji
if (requestCode != REQUEST_CODE)
return false;
- if (resultCode == RESULT_OK) {
- const QJNIObjectPrivate intent = QJNIObjectPrivate::fromLocalRef(data);
- const QJNIObjectPrivate uri = intent.callObjectMethod("getData", "()Landroid/net/Uri;");
- const QString uriStr = uri.callObjectMethod("toString", "()Ljava/lang/String;").toString();
- m_selectedFile = QUrl(uriStr);
- Q_EMIT fileSelected(m_selectedFile);
- Q_EMIT accept();
- } else {
+ if (resultCode != RESULT_OK) {
Q_EMIT reject();
+ return true;
+ }
+
+ const QJniObject intent = QJniObject::fromLocalRef(data);
+
+ const QJniObject uri = intent.callObjectMethod("getData", "()Landroid/net/Uri;");
+ if (uri.isValid()) {
+ takePersistableUriPermission(uri);
+ m_selectedFile.append(QUrl(uri.toString()));
+ Q_EMIT fileSelected(m_selectedFile.constFirst());
+ Q_EMIT currentChanged(m_selectedFile.constFirst());
+ Q_EMIT accept();
+
+ return true;
+ }
+
+ const QJniObject uriClipData =
+ intent.callObjectMethod("getClipData", "()Landroid/content/ClipData;");
+ if (uriClipData.isValid()) {
+ const int size = uriClipData.callMethod<jint>("getItemCount");
+ for (int i = 0; i < size; ++i) {
+ QJniObject item = uriClipData.callObjectMethod(
+ "getItemAt", "(I)Landroid/content/ClipData$Item;", i);
+
+ QJniObject itemUri = item.callObjectMethod("getUri", "()Landroid/net/Uri;");
+ takePersistableUriPermission(itemUri);
+ m_selectedFile.append(itemUri.toString());
+ }
+ Q_EMIT filesSelected(m_selectedFile);
+ Q_EMIT currentChanged(m_selectedFile.constFirst());
+ Q_EMIT accept();
}
return true;
}
-bool QAndroidPlatformFileDialogHelper::show(Qt::WindowFlags windowFlags, Qt::WindowModality windowModality, QWindow *parent)
+void QAndroidPlatformFileDialogHelper::takePersistableUriPermission(const QJniObject &uri)
{
- Q_UNUSED(windowFlags)
- Q_UNUSED(windowModality)
- Q_UNUSED(parent)
-
- if (options()->fileMode() != QFileDialogOptions::FileMode::ExistingFile)
- return false;
+ int modeFlags = QJniObject::getStaticField<jint>(
+ JniIntentClass, "FLAG_GRANT_READ_URI_PERMISSION");
- QtAndroidPrivate::registerActivityResultListener(this);
-
- const QJNIObjectPrivate ACTION_OPEN_DOCUMENT = QJNIObjectPrivate::getStaticObjectField("android/content/Intent", "ACTION_OPEN_DOCUMENT", "Ljava/lang/String;");
- QJNIObjectPrivate intent("android/content/Intent", "(Ljava/lang/String;)V", ACTION_OPEN_DOCUMENT.object());
- const QJNIObjectPrivate CATEGORY_OPENABLE = QJNIObjectPrivate::getStaticObjectField("android/content/Intent", "CATEGORY_OPENABLE", "Ljava/lang/String;");
- intent.callObjectMethod("addCategory", "(Ljava/lang/String;)Landroid/content/Intent;", CATEGORY_OPENABLE.object());
- intent.callObjectMethod("setType", "(Ljava/lang/String;)Landroid/content/Intent;", QJNIObjectPrivate::fromString(QStringLiteral("*/*")).object());
+ if (options()->acceptMode() == QFileDialogOptions::AcceptSave) {
+ modeFlags |= QJniObject::getStaticField<jint>(
+ JniIntentClass, "FLAG_GRANT_WRITE_URI_PERMISSION");
+ }
- const QJNIObjectPrivate activity(QtAndroid::activity());
- activity.callMethod<void>("startActivityForResult", "(Landroid/content/Intent;I)V", intent.object(), REQUEST_CODE);
+ QJniObject contentResolver = m_activity.callObjectMethod(
+ "getContentResolver", "()Landroid/content/ContentResolver;");
+ contentResolver.callMethod<void>("takePersistableUriPermission", "(Landroid/net/Uri;I)V",
+ uri.object(), modeFlags);
+}
- return true;
+void QAndroidPlatformFileDialogHelper::setInitialFileName(const QString &title)
+{
+ const QJniObject extraTitle = QJniObject::getStaticObjectField(
+ JniIntentClass, "EXTRA_TITLE", "Ljava/lang/String;");
+ m_intent.callObjectMethod("putExtra",
+ "(Ljava/lang/String;Ljava/lang/String;)Landroid/content/Intent;",
+ extraTitle.object(), QJniObject::fromString(title).object());
}
-void QAndroidPlatformFileDialogHelper::exec()
+void QAndroidPlatformFileDialogHelper::setInitialDirectoryUri(const QString &directory)
{
- m_eventLoop.exec(QEventLoop::DialogExec);
+ if (directory.isEmpty())
+ return;
+
+ if (QNativeInterface::QAndroidApplication::sdkVersion() < 26)
+ return;
+
+ const auto extraInitialUri = QJniObject::getStaticObjectField(
+ "android/provider/DocumentsContract", "EXTRA_INITIAL_URI", "Ljava/lang/String;");
+ m_intent.callObjectMethod("putExtra",
+ "(Ljava/lang/String;Ljava/lang/String;)Landroid/content/Intent;",
+ extraInitialUri.object(),
+ QJniObject::fromString(directory).object());
}
-void QAndroidPlatformFileDialogHelper::hide()
+void QAndroidPlatformFileDialogHelper::setOpenableCategory()
{
- if (m_eventLoop.isRunning())
- m_eventLoop.exit();
- QtAndroidPrivate::unregisterActivityResultListener(this);
+ const QJniObject CATEGORY_OPENABLE = QJniObject::getStaticObjectField(
+ JniIntentClass, "CATEGORY_OPENABLE", "Ljava/lang/String;");
+ m_intent.callObjectMethod("addCategory", "(Ljava/lang/String;)Landroid/content/Intent;",
+ CATEGORY_OPENABLE.object());
}
-QString QAndroidPlatformFileDialogHelper::selectedNameFilter() const
+void QAndroidPlatformFileDialogHelper::setAllowMultipleSelections(bool allowMultiple)
{
- return QString();
+ const QJniObject allowMultipleSelections = QJniObject::getStaticObjectField(
+ JniIntentClass, "EXTRA_ALLOW_MULTIPLE", "Ljava/lang/String;");
+ m_intent.callObjectMethod("putExtra", "(Ljava/lang/String;Z)Landroid/content/Intent;",
+ allowMultipleSelections.object(), allowMultiple);
}
-void QAndroidPlatformFileDialogHelper::selectNameFilter(const QString &filter)
+QStringList nameFilterExtensions(const QString nameFilters)
{
- Q_UNUSED(filter)
+ QStringList ret;
+#if QT_CONFIG(regularexpression)
+ QRegularExpression re("(\\*\\.[a-z .]+)");
+ QRegularExpressionMatchIterator i = re.globalMatch(nameFilters);
+ while (i.hasNext())
+ ret << i.next().captured(1).trimmed();
+#endif // QT_CONFIG(regularexpression)
+ ret.removeAll("*");
+ return ret;
}
-void QAndroidPlatformFileDialogHelper::setFilter()
+void QAndroidPlatformFileDialogHelper::setMimeTypes()
{
+ QStringList mimeTypes = options()->mimeTypeFilters();
+ const QStringList nameFilters = options()->nameFilters();
+
+ if (!nameFilters.isEmpty()) {
+ QMimeDatabase db;
+ for (auto filter : nameFilters) {
+ if (!filter.isEmpty()) {
+ for (const QString &filter : nameFilterExtensions(filter))
+ mimeTypes.append(db.mimeTypeForFile(filter, QMimeDatabase::MatchExtension).name());
+ }
+ }
+ }
+
+ const QString initialType = mimeTypes.size() == 1 ? mimeTypes.at(0) : "*/*"_L1;
+ m_intent.callObjectMethod("setType", "(Ljava/lang/String;)Landroid/content/Intent;",
+ QJniObject::fromString(initialType).object());
+
+ if (!mimeTypes.isEmpty()) {
+ const QJniObject extraMimeType = QJniObject::getStaticObjectField(
+ JniIntentClass, "EXTRA_MIME_TYPES", "Ljava/lang/String;");
+
+ const QJniObject mimeTypesArray = QJniObject::callStaticObjectMethod(
+ "org/qtproject/qt/android/QtNative",
+ "getStringArray",
+ "(Ljava/lang/String;)[Ljava/lang/String;",
+ QJniObject::fromString(mimeTypes.join(",")).object());
+
+ m_intent.callObjectMethod(
+ "putExtra", "(Ljava/lang/String;[Ljava/lang/String;)Landroid/content/Intent;",
+ extraMimeType.object(), mimeTypesArray.object());
+ }
}
-QList<QUrl> QAndroidPlatformFileDialogHelper::selectedFiles() const
+QJniObject QAndroidPlatformFileDialogHelper::getFileDialogIntent(const QString &intentType)
{
- return {m_selectedFile};
+ const QJniObject ACTION_OPEN_DOCUMENT = QJniObject::getStaticObjectField(
+ JniIntentClass, intentType.toLatin1(), "Ljava/lang/String;");
+ return QJniObject(JniIntentClass, "(Ljava/lang/String;)V",
+ ACTION_OPEN_DOCUMENT.object());
}
-void QAndroidPlatformFileDialogHelper::selectFile(const QUrl &file)
+bool QAndroidPlatformFileDialogHelper::show(Qt::WindowFlags windowFlags, Qt::WindowModality windowModality, QWindow *parent)
{
- Q_UNUSED(file)
+ Q_UNUSED(windowFlags);
+ Q_UNUSED(windowModality);
+ Q_UNUSED(parent);
+
+ bool isDirDialog = false;
+
+ m_selectedFile.clear();
+
+ if (options()->acceptMode() == QFileDialogOptions::AcceptSave) {
+ m_intent = getFileDialogIntent("ACTION_CREATE_DOCUMENT");
+ const QList<QUrl> selectedFiles = options()->initiallySelectedFiles();
+ if (selectedFiles.size() > 0)
+ setInitialFileName(selectedFiles.first().fileName());
+ } else if (options()->acceptMode() == QFileDialogOptions::AcceptOpen) {
+ switch (options()->fileMode()) {
+ case QFileDialogOptions::FileMode::DirectoryOnly:
+ case QFileDialogOptions::FileMode::Directory:
+ m_intent = getFileDialogIntent("ACTION_OPEN_DOCUMENT_TREE");
+ isDirDialog = true;
+ break;
+ case QFileDialogOptions::FileMode::ExistingFiles:
+ m_intent = getFileDialogIntent("ACTION_OPEN_DOCUMENT");
+ setAllowMultipleSelections(true);
+ break;
+ case QFileDialogOptions::FileMode::AnyFile:
+ case QFileDialogOptions::FileMode::ExistingFile:
+ m_intent = getFileDialogIntent("ACTION_OPEN_DOCUMENT");
+ break;
+ }
+ }
+
+ if (!isDirDialog) {
+ setOpenableCategory();
+ setMimeTypes();
+ }
+
+ setInitialDirectoryUri(m_directory.toString());
+
+ QtAndroidPrivate::registerActivityResultListener(this);
+ m_activity.callMethod<void>("startActivityForResult", "(Landroid/content/Intent;I)V",
+ m_intent.object(), REQUEST_CODE);
+ return true;
}
-QUrl QAndroidPlatformFileDialogHelper::directory() const
+void QAndroidPlatformFileDialogHelper::hide()
{
- return QUrl();
+ if (m_eventLoop.isRunning())
+ m_eventLoop.exit();
+ QtAndroidPrivate::unregisterActivityResultListener(this);
}
void QAndroidPlatformFileDialogHelper::setDirectory(const QUrl &directory)
{
- Q_UNUSED(directory)
+ m_directory = directory;
}
-bool QAndroidPlatformFileDialogHelper::defaultNameFilterDisables() const
+void QAndroidPlatformFileDialogHelper::exec()
{
- return false;
+ m_eventLoop.exec(QEventLoop::DialogExec);
}
}
diff --git a/src/plugins/platforms/android/qandroidplatformfiledialoghelper.h b/src/plugins/platforms/android/qandroidplatformfiledialoghelper.h
index 5cd26af7c9..156eda9142 100644
--- a/src/plugins/platforms/android/qandroidplatformfiledialoghelper.h
+++ b/src/plugins/platforms/android/qandroidplatformfiledialoghelper.h
@@ -1,49 +1,16 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 Klaralvdalens Datakonsult AB (KDAB)
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2019 Klaralvdalens Datakonsult AB (KDAB)
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QANDROIDPLATFORMFILEDIALOGHELPER_H
#define QANDROIDPLATFORMFILEDIALOGHELPER_H
#include <jni.h>
+
#include <QEventLoop>
-#include <qpa/qplatformdialoghelper.h>
+#include <QtCore/QJniObject>
#include <QtCore/private/qjnihelpers_p.h>
+#include <qpa/qplatformdialoghelper.h>
QT_BEGIN_NAMESPACE
@@ -55,26 +22,35 @@ class QAndroidPlatformFileDialogHelper: public QPlatformFileDialogHelper, public
public:
QAndroidPlatformFileDialogHelper();
- void exec() override;
- bool show(Qt::WindowFlags windowFlags,
- Qt::WindowModality windowModality,
- QWindow *parent) override;
+ void exec() override;
+ bool show(Qt::WindowFlags windowFlags, Qt::WindowModality windowModality, QWindow *parent) override;
void hide() override;
- QString selectedNameFilter() const override;
- void selectNameFilter(const QString &filter) override;
- void setFilter() override;
- QList<QUrl> selectedFiles() const override;
- void selectFile(const QUrl &file) override;
- QUrl directory() const override;
+ QString selectedNameFilter() const override { return QString(); }
+ void selectNameFilter(const QString &) override {}
+ void setFilter() override {}
+ QList<QUrl> selectedFiles() const override { return m_selectedFile; }
+ void selectFile(const QUrl &) override {}
+ QUrl directory() const override { return m_directory; }
void setDirectory(const QUrl &directory) override;
- bool defaultNameFilterDisables() const override;
+ bool defaultNameFilterDisables() const override { return false; }
bool handleActivityResult(jint requestCode, jint resultCode, jobject data) override;
private:
+ QJniObject getFileDialogIntent(const QString &intentType);
+ void takePersistableUriPermission(const QJniObject &uri);
+ void setInitialFileName(const QString &title);
+ void setInitialDirectoryUri(const QString &directory);
+ void setOpenableCategory();
+ void setAllowMultipleSelections(bool allowMultiple);
+ void setMimeTypes();
+
QEventLoop m_eventLoop;
- QUrl m_selectedFile;
+ QList<QUrl> m_selectedFile;
+ QUrl m_directory;
+ QJniObject m_intent;
+ const QJniObject m_activity;
};
}
diff --git a/src/plugins/platforms/android/qandroidplatformfontdatabase.cpp b/src/plugins/platforms/android/qandroidplatformfontdatabase.cpp
index 2fdf269566..82a10dac07 100644
--- a/src/plugins/platforms/android/qandroidplatformfontdatabase.cpp
+++ b/src/plugins/platforms/android/qandroidplatformfontdatabase.cpp
@@ -1,51 +1,23 @@
-/****************************************************************************
-**
-** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QDir>
+#include <QLocale>
#include "qandroidplatformfontdatabase.h"
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
QString QAndroidPlatformFontDatabase::fontDir() const
{
- return QLatin1String("/system/fonts");
+ return "/system/fonts"_L1;
+}
+
+QFont QAndroidPlatformFontDatabase::defaultFont() const
+{
+ return QFont("Roboto"_L1);
}
void QAndroidPlatformFontDatabase::populateFontDatabase()
@@ -59,9 +31,9 @@ void QAndroidPlatformFontDatabase::populateFontDatabase()
}
QStringList nameFilters;
- nameFilters << QLatin1String("*.ttf")
- << QLatin1String("*.otf")
- << QLatin1String("*.ttc");
+ nameFilters << "*.ttf"_L1
+ << "*.otf"_L1
+ << "*.ttc"_L1;
const auto entries = dir.entryInfoList(nameFilters, QDir::Files);
for (const QFileInfo &fi : entries) {
@@ -76,12 +48,44 @@ QStringList QAndroidPlatformFontDatabase::fallbacksForFamily(const QString &fami
QChar::Script script) const
{
QStringList result;
+
+ // Prepend CJK fonts by the locale.
+ QLocale locale = QLocale::system();
+ switch (locale.language()) {
+ case QLocale::Chinese: {
+ switch (locale.territory()) {
+ case QLocale::China:
+ case QLocale::Singapore:
+ result.append(QStringLiteral("Noto Sans Mono CJK SC"));
+ break;
+ case QLocale::Taiwan:
+ case QLocale::HongKong:
+ case QLocale::Macao:
+ result.append(QStringLiteral("Noto Sans Mono CJK TC"));
+ break;
+ default:
+ // no modifications.
+ break;
+ }
+ break;
+ }
+ case QLocale::Japanese:
+ result.append(QStringLiteral("Noto Sans Mono CJK JP"));
+ break;
+ case QLocale::Korean:
+ result.append(QStringLiteral("Noto Sans Mono CJK KR"));
+ break;
+ default:
+ // no modifications.
+ break;
+ }
+
if (styleHint == QFont::Monospace || styleHint == QFont::Courier)
- result.append(QString(qgetenv("QT_ANDROID_FONTS_MONOSPACE")).split(QLatin1Char(';')));
+ result.append(QString(qgetenv("QT_ANDROID_FONTS_MONOSPACE")).split(u';'));
else if (styleHint == QFont::Serif)
- result.append(QString(qgetenv("QT_ANDROID_FONTS_SERIF")).split(QLatin1Char(';')));
+ result.append(QString(qgetenv("QT_ANDROID_FONTS_SERIF")).split(u';'));
else
- result.append(QString(qgetenv("QT_ANDROID_FONTS")).split(QLatin1Char(';')));
+ result.append(QString(qgetenv("QT_ANDROID_FONTS")).split(u';'));
result.append(QFreeTypeFontDatabase::fallbacksForFamily(family, style, styleHint, script));
return result;
diff --git a/src/plugins/platforms/android/qandroidplatformfontdatabase.h b/src/plugins/platforms/android/qandroidplatformfontdatabase.h
index 166a590698..23561e2214 100644
--- a/src/plugins/platforms/android/qandroidplatformfontdatabase.h
+++ b/src/plugins/platforms/android/qandroidplatformfontdatabase.h
@@ -1,46 +1,10 @@
-/****************************************************************************
-**
-** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QANDROIDPLATFORMFONTDATABASE_H
#define QANDROIDPLATFORMFONTDATABASE_H
-#include <QtFontDatabaseSupport/private/qfreetypefontdatabase_p.h>
+#include <QtGui/private/qfreetypefontdatabase_p.h>
QT_BEGIN_NAMESPACE
@@ -49,6 +13,7 @@ class QAndroidPlatformFontDatabase: public QFreeTypeFontDatabase
public:
QString fontDir() const override;
void populateFontDatabase() override;
+ QFont defaultFont() const override;
QStringList fallbacksForFamily(const QString &family,
QFont::Style style,
QFont::StyleHint styleHint,
diff --git a/src/plugins/platforms/android/qandroidplatformforeignwindow.cpp b/src/plugins/platforms/android/qandroidplatformforeignwindow.cpp
index 1c920c0af9..e84a481a2b 100644
--- a/src/plugins/platforms/android/qandroidplatformforeignwindow.cpp
+++ b/src/plugins/platforms/android/qandroidplatformforeignwindow.cpp
@@ -1,125 +1,106 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qandroidplatformforeignwindow.h"
#include "androidjnimain.h"
#include <QtCore/qvariant.h>
#include <qpa/qwindowsysteminterface.h>
#include <QtCore/private/qjnihelpers_p.h>
+#include <QtCore/qjnitypes.h>
QT_BEGIN_NAMESPACE
QAndroidPlatformForeignWindow::QAndroidPlatformForeignWindow(QWindow *window, WId nativeHandle)
- : QAndroidPlatformWindow(window),
- m_surfaceId(-1)
+ : QAndroidPlatformWindow(window), m_view(nullptr), m_nativeViewInserted(false)
{
m_view = reinterpret_cast<jobject>(nativeHandle);
- if (m_view.isValid())
- QtAndroid::setViewVisibility(m_view.object(), false);
-}
+ if (isEmbeddingContainer()) {
+ m_nativeViewId = m_view.callMethod<jint>("getId");
+ return;
+ }
-QAndroidPlatformForeignWindow::~QAndroidPlatformForeignWindow()
-{
if (m_view.isValid())
QtAndroid::setViewVisibility(m_view.object(), false);
- if (m_surfaceId != -1)
- QtAndroid::destroySurface(m_surfaceId);
}
-void QAndroidPlatformForeignWindow::lower()
+QAndroidPlatformForeignWindow::~QAndroidPlatformForeignWindow()
{
- if (m_surfaceId == -1)
+ if (isEmbeddingContainer())
return;
- QAndroidPlatformWindow::lower();
- QtAndroid::bringChildToBack(m_surfaceId);
-}
+ if (m_view.isValid())
+ QtAndroid::setViewVisibility(m_view.object(), false);
-void QAndroidPlatformForeignWindow::raise()
-{
- if (m_surfaceId == -1)
- return;
+ m_nativeQtWindow.callMethod<void>("removeNativeView");
- QAndroidPlatformWindow::raise();
- QtAndroid::bringChildToFront(m_surfaceId);
}
void QAndroidPlatformForeignWindow::setGeometry(const QRect &rect)
{
QAndroidPlatformWindow::setGeometry(rect);
- if (m_surfaceId != -1)
- QtAndroid::setSurfaceGeometry(m_surfaceId, rect);
+ if (isEmbeddingContainer())
+ return;
+
+ if (m_nativeViewInserted)
+ setNativeGeometry(rect);
}
void QAndroidPlatformForeignWindow::setVisible(bool visible)
{
+ if (isEmbeddingContainer()) {
+ QAndroidPlatformWindow::setVisible(visible);
+ return;
+ }
+
if (!m_view.isValid())
return;
QtAndroid::setViewVisibility(m_view.object(), visible);
- QAndroidPlatformWindow::setVisible(visible);
- if (!visible && m_surfaceId != -1) {
- QtAndroid::destroySurface(m_surfaceId);
- m_surfaceId = -1;
- } else if (m_surfaceId == -1) {
- m_surfaceId = QtAndroid::insertNativeView(m_view.object(), geometry());
+ if (!visible && m_nativeViewInserted) {
+ m_nativeQtWindow.callMethod<void>("removeNativeView");
+ m_nativeViewInserted = false;
+ } else if (!m_nativeViewInserted) {
+ addViewToWindow();
}
}
void QAndroidPlatformForeignWindow::applicationStateChanged(Qt::ApplicationState state)
{
- if (state <= Qt::ApplicationHidden
- && m_surfaceId != -1) {
- QtAndroid::destroySurface(m_surfaceId);
- m_surfaceId = -1;
- } else if (m_view.isValid() && m_surfaceId == -1){
- m_surfaceId = QtAndroid::insertNativeView(m_view.object(), geometry());
+ if (!isEmbeddingContainer()) {
+ if (state <= Qt::ApplicationHidden
+ && m_nativeViewInserted) {
+ m_nativeQtWindow.callMethod<void>("removeNativeView");
+ m_nativeViewInserted = false;
+ } else if (m_view.isValid() && !m_nativeViewInserted){
+ addViewToWindow();
+ }
}
QAndroidPlatformWindow::applicationStateChanged(state);
}
-void QAndroidPlatformForeignWindow::setParent(const QPlatformWindow *window)
+WId QAndroidPlatformForeignWindow::winId() const
{
- Q_UNUSED(window);
+ if (isEmbeddingContainer() && m_view.isValid())
+ return reinterpret_cast<WId>(m_view.object());
+ if (m_nativeQtWindow.isValid())
+ return reinterpret_cast<WId>(m_nativeQtWindow.object());
+ return 0L;
+}
+
+void QAndroidPlatformForeignWindow::addViewToWindow()
+{
+ if (isEmbeddingContainer())
+ return;
+
+ jint x = 0, y = 0, w = -1, h = -1;
+ if (!geometry().isNull())
+ geometry().getRect(&x, &y, &w, &h);
+
+ m_nativeQtWindow.callMethod<void>("setNativeView", m_view, x, y, qMax(w, 1), qMax(h, 1));
+ m_nativeViewInserted = true;
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/android/qandroidplatformforeignwindow.h b/src/plugins/platforms/android/qandroidplatformforeignwindow.h
index af1eee5499..503524cced 100644
--- a/src/plugins/platforms/android/qandroidplatformforeignwindow.h
+++ b/src/plugins/platforms/android/qandroidplatformforeignwindow.h
@@ -1,67 +1,34 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QANDROIDPLATFORMFOREIGNWINDOW_H
#define QANDROIDPLATFORMFOREIGNWINDOW_H
-#include "androidsurfaceclient.h"
#include "qandroidplatformwindow.h"
-#include <QtCore/private/qjni_p.h>
+
+#include <QtCore/QJniObject>
QT_BEGIN_NAMESPACE
+Q_DECLARE_JNI_CLASS(View, "android/view/View")
+
class QAndroidPlatformForeignWindow : public QAndroidPlatformWindow
{
public:
explicit QAndroidPlatformForeignWindow(QWindow *window, WId nativeHandle);
~QAndroidPlatformForeignWindow();
- void lower() override;
- void raise() override;
void setGeometry(const QRect &rect) override;
void setVisible(bool visible) override;
void applicationStateChanged(Qt::ApplicationState state) override;
- void setParent(const QPlatformWindow *window) override;
bool isForeignWindow() const override { return true; }
+ WId winId() const override;
+
private:
- int m_surfaceId;
- QJNIObjectPrivate m_view;
+ void addViewToWindow();
+
+ QtJniTypes::View m_view;
+ bool m_nativeViewInserted;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/android/qandroidplatformiconengine.cpp b/src/plugins/platforms/android/qandroidplatformiconengine.cpp
new file mode 100644
index 0000000000..faa63dcca1
--- /dev/null
+++ b/src/plugins/platforms/android/qandroidplatformiconengine.cpp
@@ -0,0 +1,616 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qandroidplatformiconengine.h"
+#include "androidjnimain.h"
+
+#include <QtCore/qdebug.h>
+#include <QtCore/qjniarray.h>
+#include <QtCore/qjniobject.h>
+#include <QtCore/qloggingcategory.h>
+#include <QtCore/qfile.h>
+#include <QtCore/qset.h>
+
+#include <QtGui/qfontdatabase.h>
+#include <QtGui/qpainter.h>
+#include <QtGui/qpalette.h>
+
+QT_BEGIN_NAMESPACE
+
+using namespace Qt::StringLiterals;
+Q_LOGGING_CATEGORY(lcIconEngineFontDownload, "qt.qpa.iconengine.fontdownload")
+
+// the primary types to work with the FontRequest API
+Q_DECLARE_JNI_CLASS(FontRequest, "androidx/core/provider/FontRequest")
+Q_DECLARE_JNI_CLASS(FontsContractCompat, "androidx/core/provider/FontsContractCompat")
+Q_DECLARE_JNI_CLASS(FontFamilyResult, "androidx/core/provider/FontsContractCompat$FontFamilyResult")
+Q_DECLARE_JNI_CLASS(FontInfo, "androidx/core/provider/FontsContractCompat$FontInfo")
+
+// various utility types
+Q_DECLARE_JNI_CLASS(List, "java/util/List"); // List is just an Interface
+Q_DECLARE_JNI_CLASS(ArrayList, "java/util/ArrayList");
+Q_DECLARE_JNI_CLASS(HashSet, "java/util/HashSet");
+Q_DECLARE_JNI_CLASS(Uri, "android/net/Uri")
+Q_DECLARE_JNI_CLASS(CancellationSignal, "android/os/CancellationSignal")
+Q_DECLARE_JNI_CLASS(ParcelFileDescriptor, "android/os/ParcelFileDescriptor")
+Q_DECLARE_JNI_CLASS(ContentResolver, "android/content/ContentResolver")
+Q_DECLARE_JNI_CLASS(PackageManager, "android/content/pm/PackageManager")
+Q_DECLARE_JNI_CLASS(ProviderInfo, "android/content/pm/ProviderInfo")
+Q_DECLARE_JNI_CLASS(PackageInfo, "android/content/pm/PackageInfo")
+Q_DECLARE_JNI_CLASS(Signature, "android/content/pm/Signature")
+
+namespace FontProvider {
+
+static QString fetchFont(const QString &query)
+{
+ using namespace QtJniTypes;
+
+ static QMap<QString, QString> triedFonts;
+ const auto it = triedFonts.find(query);
+ if (it != triedFonts.constEnd())
+ return it.value();
+
+ QString fontFamily;
+ triedFonts[query] = fontFamily; // mark as tried
+
+ QStringList loadedFamilies;
+ if (QFile file(query); file.open(QIODevice::ReadOnly)) {
+ qCDebug(lcIconEngineFontDownload) << "Loading font from resource" << query;
+ const QByteArray fontData = file.readAll();
+ int fontId = QFontDatabase::addApplicationFontFromData(fontData);
+ loadedFamilies << QFontDatabase::applicationFontFamilies(fontId);
+ } else if (!query.startsWith(u":/"_s)) {
+ const QString package = u"com.google.android.gms"_s;
+ const QString authority = u"com.google.android.gms.fonts"_s;
+
+ // First we access the content provider to get the signatures of the authority for the package
+ const auto context = QtAndroidPrivate::context();
+
+ auto packageManager = context.callMethod<PackageManager>("getPackageManager");
+ if (!packageManager.isValid()) {
+ qCWarning(lcIconEngineFontDownload, "Failed to instantiate PackageManager");
+ return fontFamily;
+ }
+ const int signaturesField = PackageManager::getStaticField<int>("GET_SIGNATURES");
+ auto providerInfo = packageManager.callMethod<ProviderInfo>("resolveContentProvider",
+ authority, 0);
+ if (!providerInfo.isValid()) {
+ qCWarning(lcIconEngineFontDownload, "Failed to resolve content provider");
+ return fontFamily;
+ }
+ const QString packageName = providerInfo.getField<QString>("packageName");
+ if (packageName != package) {
+ qCWarning(lcIconEngineFontDownload, "Mismatched provider package - expected '%s', got '%s'",
+ package.toUtf8().constData(), packageName.toUtf8().constData());
+ return fontFamily;
+ }
+ auto packageInfo = packageManager.callMethod<PackageInfo>("getPackageInfo",
+ package, signaturesField);
+ if (!packageInfo.isValid()) {
+ qCWarning(lcIconEngineFontDownload, "Failed to get package info with signature field %d",
+ signaturesField);
+ return fontFamily;
+ }
+ const auto signatures = packageInfo.getField<Signature[]>("signatures");
+ if (!signatures.isValid()) {
+ qCWarning(lcIconEngineFontDownload, "Failed to get signature array from package info");
+ return fontFamily;
+ }
+
+ // FontRequest wants a list of sets for the certificates
+ ArrayList outerList;
+ HashSet innerSet;
+ Q_ASSERT(outerList.isValid() && innerSet.isValid());
+
+ for (const auto &signature : signatures) {
+ const QJniArray<jbyte> byteArray = signature.callMethod<jbyte[]>("toByteArray");
+
+ // add takes an Object, not an Array
+ if (!innerSet.callMethod<jboolean>("add", byteArray.object<jobject>()))
+ qCWarning(lcIconEngineFontDownload, "Failed to add signature to set");
+ }
+ // Add the set to the list
+ if (!outerList.callMethod<jboolean>("add", innerSet.object()))
+ qCWarning(lcIconEngineFontDownload, "Failed to add set to certificate list");
+
+ // FontRequest constructor wants a List interface, not an ArrayList
+ FontRequest fontRequest(authority, package, query, outerList.object<List>());
+ if (!fontRequest.isValid()) {
+ qCWarning(lcIconEngineFontDownload, "Failed to create font request for '%s'",
+ query.toUtf8().constData());
+ return fontFamily;
+ }
+
+ // Call FontsContractCompat::fetchFonts with the FontRequest object
+ auto fontFamilyResult = FontsContractCompat::callStaticMethod<FontFamilyResult>(
+ "fetchFonts",
+ context,
+ CancellationSignal(nullptr),
+ fontRequest);
+ if (!fontFamilyResult.isValid()) {
+ qCWarning(lcIconEngineFontDownload, "Failed to fetch fonts for query '%s'",
+ query.toUtf8().constData());
+ return fontFamily;
+ }
+
+ enum class StatusCode {
+ OK = 0,
+ UNEXPECTED_DATA_PROVIDED = 1,
+ WRONG_CERTIFICATES = 2,
+ };
+
+ const StatusCode statusCode = fontFamilyResult.callMethod<StatusCode>("getStatusCode");
+ switch (statusCode) {
+ case StatusCode::OK:
+ break;
+ case StatusCode::UNEXPECTED_DATA_PROVIDED:
+ qCWarning(lcIconEngineFontDownload, "Provider returned unexpected data for query '%s'",
+ query.toUtf8().constData());
+ return fontFamily;
+ case StatusCode::WRONG_CERTIFICATES:
+ qCWarning(lcIconEngineFontDownload, "Wrong Certificates provided in query '%s'",
+ query.toUtf8().constData());
+ return fontFamily;
+ }
+
+ const auto fontInfos = fontFamilyResult.callMethod<FontInfo[]>("getFonts");
+ if (!fontInfos.isValid()) {
+ qCWarning(lcIconEngineFontDownload, "FontFamilyResult::getFonts returned null object for '%s'",
+ query.toUtf8().constData());
+ return fontFamily;
+ }
+
+ auto contentResolver = context.callMethod<ContentResolver>("getContentResolver");
+
+ for (QJniObject fontInfo : fontInfos) {
+ if (!fontInfo.isValid()) {
+ qCDebug(lcIconEngineFontDownload, "Received null-fontInfo object, skipping");
+ continue;
+ }
+ enum class ResultCode {
+ OK = 0,
+ FONT_NOT_FOUND = 1,
+ FONT_UNAVAILABLE = 2,
+ MALFORMED_QUERY = 3,
+ };
+ const ResultCode resultCode = fontInfo.callMethod<ResultCode>("getResultCode");
+ switch (resultCode) {
+ case ResultCode::OK:
+ break;
+ case ResultCode::FONT_NOT_FOUND:
+ qCWarning(lcIconEngineFontDownload, "Font '%s' could not be found",
+ query.toUtf8().constData());
+ return fontFamily;
+ case ResultCode::FONT_UNAVAILABLE:
+ qCWarning(lcIconEngineFontDownload, "Font '%s' is unavailable at",
+ query.toUtf8().constData());
+ return fontFamily;
+ case ResultCode::MALFORMED_QUERY:
+ qCWarning(lcIconEngineFontDownload, "Query string '%s' is malformed",
+ query.toUtf8().constData());
+ return fontFamily;
+ }
+ auto fontUri = fontInfo.callMethod<Uri>("getUri");
+ // in this case the Font URI is always a content scheme file, made
+ // so the app requesting it has permissions to open
+ auto fileDescriptor = contentResolver.callMethod<ParcelFileDescriptor>("openFileDescriptor",
+ fontUri, u"r"_s);
+ if (!fileDescriptor.isValid()) {
+ qCWarning(lcIconEngineFontDownload, "Font file '%s' not accessible",
+ fontUri.toString().toUtf8().constData());
+ continue;
+ }
+
+ int fd = fileDescriptor.callMethod<int>("detachFd");
+ QFile file;
+ file.open(fd, QFile::OpenModeFlag::ReadOnly, QFile::FileHandleFlag::AutoCloseHandle);
+ const QByteArray fontData = file.readAll();
+ qCDebug(lcIconEngineFontDownload) << "Font file read:" << fontData.size() << "bytes";
+ int fontId = QFontDatabase::addApplicationFontFromData(fontData);
+ loadedFamilies << QFontDatabase::applicationFontFamilies(fontId);
+ }
+ }
+
+ qCDebug(lcIconEngineFontDownload) << "Query '" << query << "' added families" << loadedFamilies;
+ if (!loadedFamilies.isEmpty())
+ fontFamily = loadedFamilies.first();
+ triedFonts[query] = fontFamily;
+ return fontFamily;
+}
+}
+
+QString QAndroidPlatformIconEngine::glyphs() const
+{
+ if (!QFontInfo(m_iconFont).exactMatch())
+ return {};
+
+ static constexpr std::pair<QLatin1StringView, QStringView> glyphMap[] = {
+ {"address-book-new"_L1, u"\ue0e0"},
+ {"application-exit"_L1, u"\ue5cd"},
+ {"appointment-new"_L1, u"\ue878"},
+ {"call-start"_L1, u"\ue0b0"},
+ {"call-stop"_L1, u"\ue0b1"},
+ {"contact-new"_L1, u"\uf22e"},
+ {"document-new"_L1, u"\ue89c"},
+ {"document-open"_L1, u"\ue2c8"},
+ {"document-open-recent"_L1, u"\ue4a7"},
+ {"document-page-setup"_L1, u"\uf88c"},
+ {"document-print"_L1, u"\ue8ad"},
+ {"document-print-preview"_L1, u"\uefb2"},
+ {"document-properties"_L1, u"\uf775"},
+ {"document-revert"_L1, u"\ue929"},
+ {"document-save"_L1, u"\ue161"},
+ {"document-save-as"_L1, u"\ueb60"},
+ {"document-send"_L1, u"\uf09b"},
+ {"edit-clear"_L1, u"\ue872"},
+ {"edit-copy"_L1, u"\ue14d"},
+ {"edit-cut"_L1, u"\ue14e"},
+ {"edit-delete"_L1, u"\ue14a"},
+ {"edit-find"_L1, u"\ue8b6"},
+ {"edit-find-replace"_L1, u"\ue881"},
+ {"edit-paste"_L1, u"\ue14f"},
+ {"edit-redo"_L1, u"\ue15a"},
+ {"edit-select-all"_L1, u"\ue162"},
+ {"edit-undo"_L1, u"\ue166"},
+ {"folder-new"_L1, u"\ue2cc"},
+ {"format-indent-less"_L1, u"\ue23d"},
+ {"format-indent-more"_L1, u"\ue23e"},
+ {"format-justify-center"_L1, u"\ue234"},
+ {"format-justify-fill"_L1, u"\ue235"},
+ {"format-justify-left"_L1, u"\ue236"},
+ {"format-justify-right"_L1, u"\ue237"},
+ {"format-text-direction-ltr"_L1, u"\ue247"},
+ {"format-text-direction-rtl"_L1, u"\ue248"},
+ {"format-text-bold"_L1, u"\ue238"},
+ {"format-text-italic"_L1, u"\ue23f"},
+ {"format-text-underline"_L1, u"\ue249"},
+ {"format-text-strikethrough"_L1, u"\ue246"},
+ {"go-bottom"_L1,u"\ue258"},
+ {"go-down"_L1,u"\uf1e3"},
+ {"go-first"_L1, u"\ue5dc"},
+ {"go-home"_L1, u"\ue88a"},
+ {"go-jump"_L1, u"\uf719"},
+ {"go-last"_L1, u"\ue5dd"},
+ {"go-next"_L1, u"\ue5c8"},
+ {"go-previous"_L1, u"\ue5c4"},
+ {"go-top"_L1, u"\ue25a"},
+ {"go-up"_L1, u"\uf1e0"},
+ {"help-about"_L1, u"\ue88e"},
+ {"help-contents"_L1, u"\ue8de"},
+ {"help-faq"_L1, u"\uf04c"},
+ {"insert-image"_L1, u"\ue43e"},
+ {"insert-link"_L1, u"\ue178"},
+ //{"insert-object"_L1, u"\u"},
+ {"insert-text"_L1, u"\uf827"},
+ {"list-add"_L1, u"\ue145"},
+ {"list-remove"_L1, u"\ue15b"},
+ {"mail-forward"_L1, u"\ue154"},
+ {"mail-mark-important"_L1, u"\ue937"},
+ //{"mail-mark-junk"_L1, u"\u"},
+ //{"mail-mark-notjunk"_L1, u"\u"},
+ {"mail-mark-read"_L1, u"\uf18c"},
+ {"mail-mark-unread"_L1, u"\ue9bc"},
+ {"mail-message-new"_L1, u"\ue3c9"},
+ {"mail-reply-all"_L1, u"\ue15f"},
+ {"mail-reply-sender"_L1, u"\ue15e"},
+ {"mail-send"_L1, u"\ue163"},
+ //{"mail-send-receive"_L1, u"\u"},
+ {"media-eject"_L1, u"\ue8fb"},
+ {"media-playback-pause"_L1, u"\ue034"},
+ {"media-playback-start"_L1, u"\ue037"},
+ {"media-playback-stop"_L1, u"\ue047"},
+ {"media-record"_L1, u"\uf679"},
+ {"media-seek-backward"_L1, u"\ue020"},
+ {"media-seek-forward"_L1, u"\ue01f"},
+ {"media-skip-backward"_L1, u"\ue045"},
+ {"media-skip-forward"_L1, u"\ue044"},
+ //{"object-flip-horizontal"_L1, u"\u"},
+ //{"object-flip-vertical"_L1, u"\u"},
+ {"object-rotate-left"_L1, u"\ue419"},
+ {"object-rotate-right"_L1, u"\ue41a"},
+ {"process-stop"_L1, u"\ue5c9"},
+ {"system-lock-screen"_L1, u"\ue897"},
+ {"system-log-out"_L1, u"\ue9ba"},
+ //{"system-run"_L1, u"\u"},
+ {"system-search"_L1, u"\uef70"},
+ {"system-reboot"_L1, u"\uf053"},
+ {"system-shutdown"_L1, u"\ue8ac"},
+ {"tools-check-spelling"_L1, u"\ue8ce"},
+ {"view-fullscreen"_L1, u"\ue5d0"},
+ {"view-refresh"_L1, u"\ue5d5"},
+ {"view-restore"_L1, u"\uf1cf"},
+ {"view-sort-ascending"_L1, u"\ue25a"},
+ {"view-sort-descending"_L1, u"\ue258"},
+ {"window-close"_L1, u"\ue5cd"},
+ {"window-new"_L1, u"\uf710"},
+ {"zoom-fit-best"_L1, u"\uea10"},
+ {"zoom-in"_L1, u"\ue8ff"},
+ {"zoom-original"_L1, u"\ue5d1"},
+ {"zoom-out"_L1, u"\ue900"},
+ {"process-working"_L1, u"\uef64"},
+ {"accessories-calculator"_L1, u"\uea5f"},
+ {"accessories-character-map"_L1, u"\uf8a3"},
+ {"accessories-dictionary"_L1, u"\uf539"},
+ {"accessories-text-editor"_L1, u"\ue262"},
+ {"help-browser"_L1, u"\ue887"},
+ {"multimedia-volume-control"_L1, u"\ue050"},
+ {"preferences-desktop-accessibility"_L1, u"\uf05d"},
+ {"preferences-desktop-font"_L1, u"\ue165"},
+ {"preferences-desktop-keyboard"_L1, u"\ue312"},
+ //{"preferences-desktop-locale"_L1, u"\u"},
+ {"preferences-desktop-multimedia"_L1, u"\uea75"},
+ //{"preferences-desktop-screensaver"_L1, u"\u"},
+ {"preferences-desktop-theme"_L1, u"\uf560"},
+ {"preferences-desktop-wallpaper"_L1, u"\ue1bc"},
+ {"system-file-manager"_L1, u"\ue2c7"},
+ {"system-software-install"_L1, u"\ueb71"},
+ {"system-software-update"_L1, u"\ue8d7"},
+ {"utilities-system-monitor"_L1, u"\uef5b"},
+ {"utilities-terminal"_L1, u"\ueb8e"},
+ //{"applications-accessories"_L1, u"\u"},
+ {"applications-development"_L1, u"\ue720"},
+ {"applications-engineering"_L1, u"\uea3d"},
+ {"applications-games"_L1, u"\uf135"},
+ //{"applications-graphics"_L1, u"\u"},
+ {"applications-internet"_L1, u"\ue80b"},
+ {"applications-multimedia"_L1, u"\uf06a"},
+ //{"applications-office"_L1, u"\u"},
+ //{"applications-other"_L1, u"\u"},
+ {"applications-science"_L1, u"\uea4b"},
+ //{"applications-system"_L1, u"\u"},
+ //{"applications-utilities"_L1, u"\u"},
+ {"preferences-desktop"_L1, u"\ueb97"},
+ //{"preferences-desktop-peripherals"_L1, u"\u"},
+ {"preferences-desktop-personal"_L1, u"\uf835"},
+ //{"preferences-other"_L1, u"\u"},
+ {"preferences-system"_L1, u"\ue8b8"},
+ {"preferences-system-network"_L1, u"\ue894"},
+ {"system-help"_L1, u"\ue887"},
+ //{"audio-card"_L1, u"\u"},
+ {"audio-input-microphone"_L1, u"\ue029"},
+ {"battery"_L1, u"\ue1a4"},
+ {"camera-photo"_L1, u"\ue412"},
+ {"camera-video"_L1, u"\ue04b"},
+ {"camera-web"_L1, u"\uf7a6"},
+ {"computer"_L1, u"\ue30a"},
+ {"drive-harddisk"_L1, u"\uf80e"},
+ {"drive-optical"_L1, u"\ue019"}, // same as media-optical
+ //{"drive-removable-media"_L1, u"\u"},
+ {"input-gaming"_L1, u"\uf5ee"},
+ {"input-keyboard"_L1, u"\ue312"},
+ {"input-mouse"_L1, u"\ue323"},
+ //{"input-tablet"_L1, u"\u"},
+ //{"media-flash"_L1, u"\u"},
+ //{"media-floppy"_L1, u"\u"},
+ {"media-optical"_L1, u"\ue019"},
+ //{"media-tape"_L1, u"\u"},
+ //{"modem"_L1, u"\u"},
+ //{"multimedia-player"_L1, u"\u"},
+ //{"network-wired"_L1, u"\u"},
+ {"network-wireless"_L1, u"\ue63e"},
+ //{"pda"_L1, u"\u"},
+ {"phone"_L1, u"\ue32c"},
+ {"printer"_L1, u"\ue8ad"},
+ {"scanner"_L1, u"\ue329"},
+ {"video-display"_L1, u"\uf06a"},
+ //{"emblem-default"_L1, u"\u"},
+ {"emblem-documents"_L1, u"\ue873"},
+ {"emblem-downloads"_L1, u"\uf090"},
+ {"emblem-favorite"_L1, u"\uf090"},
+ {"emblem-important"_L1, u"\ue645"},
+ {"emblem-mail"_L1, u"\ue158"},
+ {"emblem-photos"_L1, u"\ue413"},
+ //{"emblem-readonly"_L1, u"\u"},
+ {"emblem-shared"_L1, u"\ue413"},
+ //{"emblem-symbolic-link"_L1, u"\u"},
+ //{"emblem-synchronized"_L1, u"\u"},
+ {"emblem-system"_L1, u"\ue8b8"},
+ //{"emblem-unreadable"_L1, u"\u"},
+ {"folder"_L1, u"\ue2c7"},
+ //{"folder-remote"_L1, u"\u"},
+ {"network-server"_L1, u"\ue875"},
+ {"network-workgroup"_L1, u"\ue1a0"},
+ {"start-here"_L1, u"\ue089"},
+ {"user-bookmarks"_L1, u"\ue98b"},
+ {"user-desktop"_L1, u"\ue30a"},
+ {"user-home"_L1, u"\ue88a"},
+ {"user-trash"_L1, u"\ue872"},
+ {"appointment-missed"_L1, u"\ue615"},
+ {"appointment-soon"_L1, u"\uf540"},
+ {"audio-volume-high"_L1, u"\ue050"},
+ {"audio-volume-low"_L1, u"\ue04d"},
+ //{"audio-volume-medium"_L1, u"\u"},
+ {"audio-volume-muted"_L1, u"\ue04e"},
+ {"battery-caution"_L1, u"\ue19c"},
+ {"battery-low"_L1, u"\uf147"},
+ {"dialog-error"_L1, u"\ue000"},
+ {"dialog-information"_L1, u"\ue88e"},
+ {"dialog-password"_L1, u"\uf042"},
+ {"dialog-question"_L1, u"\ueb8b"},
+ {"dialog-warning"_L1, u"\ue002"},
+ {"folder-drag-accept"_L1, u"\ue9a3"},
+ {"folder-open"_L1, u"\ue2c8"},
+ {"folder-visiting"_L1, u"\ue8a7"},
+ {"image-loading"_L1, u"\ue41a"},
+ {"image-missing"_L1, u"\ue3ad"},
+ {"mail-attachment"_L1, u"\ue2bc"},
+ {"mail-unread"_L1, u"\uf18a"},
+ {"mail-read"_L1, u"\uf18c"},
+ //{"mail-replied"_L1, u"\u"},
+ //{"mail-signed"_L1, u"\u"},
+ //{"mail-signed-verified"_L1, u"\u"},
+ {"media-playlist-repeat"_L1, u"\ue040"},
+ {"media-playlist-shuffle"_L1, u"\ue043"},
+ {"network-error"_L1, u"\uead9"},
+ {"network-idle"_L1, u"\ue51f"},
+ {"network-offline"_L1, u"\uf239"},
+ {"network-receive"_L1, u"\ue2c0"},
+ {"network-transmit"_L1, u"\ue2c3"},
+ {"network-transmit-receive"_L1, u"\uea18"},
+ {"printer-error"_L1, u"\uf7a0"},
+ {"printer-printing"_L1, u"\uf7a1"},
+ {"security-high"_L1, u"\ue32a"},
+ {"security-medium"_L1, u"\ue9e0"},
+ {"security-low"_L1, u"\uf012"},
+ {"software-update-available"_L1, u"\ue923"},
+ {"software-update-urgent"_L1, u"\uf05a"},
+ {"sync-error"_L1, u"\ue629"},
+ {"sync-synchronizing"_L1, u"\ue627"},
+ //{"task-due"_L1, u"\u"},
+ //{"task-past-due"_L1, u"\u"},
+ {"user-available"_L1, u"\uf565"},
+ {"user-away"_L1, u"\ue510"},
+ //{"user-idle"_L1, u"\u"},
+ {"user-offline"_L1, u"\uf7b3"},
+ {"user-trash-full"_L1, u"\ue872"}, //delete
+ //{"user-trash-full"_L1, u"\ue92b"}, //delete_forever
+ {"weather-clear"_L1, u"\uf157"},
+ {"weather-clear-night"_L1, u"\uf159"},
+ {"weather-few-clouds"_L1, u"\uf172"},
+ {"weather-few-clouds-night"_L1, u"\uf174"},
+ {"weather-fog"_L1, u"\ue818"},
+ //{"weather-overcast"_L1, u"\u"},
+ {"weather-severe-alert"_L1, u"\ue002"}, //warning
+ //{"weather-severe-alert"_L1, u"\uebd3"},//severe_cold
+ {"weather-showers"_L1, u"\uf176"},
+ //{"weather-showers-scattered"_L1, u"\u"},
+ {"weather-snow"_L1, u"\ue80f"}, //snowing
+ //{"weather-snow"_L1, u"\ue2cd"}, //weather_snowy
+ //{"weather-snow"_L1, u"\ue810"},//cloudy_snowing
+ {"weather-storm"_L1, u"\uf070"},
+ };
+
+ const auto it = std::find_if(std::begin(glyphMap), std::end(glyphMap), [this](const auto &c){
+ return c.first == m_iconName;
+ });
+ return it != std::end(glyphMap) ? it->second.toString()
+ : (m_iconName.length() == 1 ? m_iconName : QString());
+}
+
+QAndroidPlatformIconEngine::QAndroidPlatformIconEngine(const QString &iconName)
+ : m_iconName(iconName)
+ , m_glyphs(glyphs())
+{
+ QString fontFamily;
+ // The MaterialIcons-*.ttf and MaterialSymbols* font files are available from
+ // https://github.com/google/material-design-icons/tree/master. If one of them is
+ // packaged as a resource with the application, then we use it. We prioritize
+ // a variable font.
+ const QStringList fontCandidates = {
+ "MaterialSymbolsOutlined[FILL,GRAD,opsz,wght].ttf",
+ "MaterialSymbolsRounded[FILL,GRAD,opsz,wght].ttf",
+ "MaterialSymbolsSharp[FILL,GRAD,opsz,wght].ttf",
+ "MaterialIcons-Regular.ttf",
+ "MaterialIconsOutlined-Regular.otf",
+ "MaterialIconsRound-Regular.otf",
+ "MaterialIconsSharp-Regular.otf",
+ "MaterialIconsTwoTone-Regular.otf",
+ };
+ for (const auto &fontCandidate : fontCandidates) {
+ fontFamily = FontProvider::fetchFont(u":/qt-project.org/icons/%1"_s.arg(fontCandidate));
+ if (!fontFamily.isEmpty())
+ break;
+ }
+
+ // Otherwise we try to download the Outlined version of Material Symbols
+ const QString key = qEnvironmentVariable("QT_GOOGLE_FONTS_KEY");
+ if (fontFamily.isEmpty() && !key.isEmpty())
+ fontFamily = FontProvider::fetchFont(u"key=%1&name=Material+Symbols+Outlined"_s.arg(key));
+
+ // last resort - use any Material Icons
+ if (fontFamily.isEmpty())
+ fontFamily = u"Material Icons"_s;
+ m_iconFont = QFont(fontFamily);
+}
+
+QAndroidPlatformIconEngine::~QAndroidPlatformIconEngine()
+{}
+
+QIconEngine *QAndroidPlatformIconEngine::clone() const
+{
+ return new QAndroidPlatformIconEngine(m_iconName);
+}
+
+QString QAndroidPlatformIconEngine::key() const
+{
+ return u"QAndroidPlatformIconEngine"_s;
+}
+
+QString QAndroidPlatformIconEngine::iconName()
+{
+ return m_iconName;
+}
+
+bool QAndroidPlatformIconEngine::isNull()
+{
+ if (m_glyphs.isEmpty())
+ return true;
+ const QChar c0 = m_glyphs.at(0);
+ const QFontMetrics fontMetrics(m_iconFont);
+ if (c0.category() == QChar::Other_Surrogate && m_glyphs.size() > 1)
+ return !fontMetrics.inFontUcs4(QChar::surrogateToUcs4(c0, m_glyphs.at(1)));
+ return !fontMetrics.inFont(c0);
+}
+
+QList<QSize> QAndroidPlatformIconEngine::availableSizes(QIcon::Mode, QIcon::State)
+{
+ return {{16, 16}, {24, 24}, {48, 48}, {128, 128}};
+}
+
+QSize QAndroidPlatformIconEngine::actualSize(const QSize &size, QIcon::Mode mode, QIcon::State state)
+{
+ return QIconEngine::actualSize(size, mode, state);
+}
+
+QPixmap QAndroidPlatformIconEngine::pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state)
+{
+ return scaledPixmap(size, mode, state, 1.0);
+}
+
+QPixmap QAndroidPlatformIconEngine::scaledPixmap(const QSize &size, QIcon::Mode mode, QIcon::State state, qreal scale)
+{
+ const quint64 cacheKey = calculateCacheKey(mode, state);
+ if (cacheKey != m_cacheKey || m_pixmap.size() != size || m_pixmap.devicePixelRatio() != scale) {
+ m_pixmap = QPixmap(size * scale);
+ m_pixmap.fill(Qt::transparent);
+ m_pixmap.setDevicePixelRatio(scale);
+
+ QPainter painter(&m_pixmap);
+ paint(&painter, QRect(QPoint(), size), mode, state);
+
+ m_cacheKey = cacheKey;
+ }
+
+ return m_pixmap;
+}
+
+void QAndroidPlatformIconEngine::paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state)
+{
+ Q_UNUSED(state);
+
+ painter->save();
+ QFont renderFont(m_iconFont);
+ renderFont.setPixelSize(rect.height());
+ painter->setFont(renderFont);
+
+ QPalette palette;
+ switch (mode) {
+ case QIcon::Active:
+ painter->setPen(palette.color(QPalette::Active, QPalette::Text));
+ break;
+ case QIcon::Normal:
+ painter->setPen(palette.color(QPalette::Active, QPalette::Text));
+ break;
+ case QIcon::Disabled:
+ painter->setPen(palette.color(QPalette::Disabled, QPalette::Text));
+ break;
+ case QIcon::Selected:
+ painter->setPen(palette.color(QPalette::Active, QPalette::HighlightedText));
+ break;
+ }
+
+ painter->drawText(rect, Qt::AlignCenter, m_glyphs);
+ painter->restore();
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/android/qandroidplatformiconengine.h b/src/plugins/platforms/android/qandroidplatformiconengine.h
new file mode 100644
index 0000000000..cac54481d9
--- /dev/null
+++ b/src/plugins/platforms/android/qandroidplatformiconengine.h
@@ -0,0 +1,44 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QANDROIDPLATFORMICONENGINE_H
+#define QANDROIDPLATFORMICONENGINE_H
+
+#include <QtGui/qiconengine.h>
+#include <QtGui/qfont.h>
+
+QT_BEGIN_NAMESPACE
+
+class QAndroidPlatformIconEngine : public QIconEngine
+{
+public:
+ QAndroidPlatformIconEngine(const QString &iconName);
+ ~QAndroidPlatformIconEngine();
+ QIconEngine *clone() const override;
+ QString key() const override;
+ QString iconName() override;
+ bool isNull() override;
+
+ QList<QSize> availableSizes(QIcon::Mode, QIcon::State) override;
+ QSize actualSize(const QSize &size, QIcon::Mode mode, QIcon::State state) override;
+ QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) override;
+ QPixmap scaledPixmap(const QSize &size, QIcon::Mode mode, QIcon::State state, qreal scale) override;
+ void paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state) override;
+
+private:
+ static constexpr quint64 calculateCacheKey(QIcon::Mode mode, QIcon::State state)
+ {
+ return (quint64(mode) << 32) | state;
+ }
+ QString glyphs() const;
+
+ const QString m_iconName;
+ QFont m_iconFont;
+ const QString m_glyphs;
+ mutable QPixmap m_pixmap;
+ mutable quint64 m_cacheKey = {};
+};
+
+QT_END_NAMESPACE
+
+#endif // QANDROIDPLATFORMICONENGINE_H
diff --git a/src/plugins/platforms/android/qandroidplatformintegration.cpp b/src/plugins/platforms/android/qandroidplatformintegration.cpp
index 592b78d936..038fe5172a 100644
--- a/src/plugins/platforms/android/qandroidplatformintegration.cpp
+++ b/src/plugins/platforms/android/qandroidplatformintegration.cpp
@@ -1,76 +1,39 @@
-/****************************************************************************
-**
-** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qandroidplatformintegration.h"
-#include <QtCore/private/qjni_p.h>
-#include <QtGui/private/qguiapplication_p.h>
-#include <QGuiApplication>
-#include <QOpenGLContext>
-#if QT_CONFIG(opengl)
-#include <QtPlatformCompositorSupport/qpa/qplatformbackingstoreopenglsupport.h>
-#endif
-#include <QThread>
-#include <QOffscreenSurface>
-
-#include <QtEglSupport/private/qeglpbuffer_p.h>
-#include <qpa/qwindowsysteminterface.h>
-#include <qpa/qplatformwindow.h>
-#include <qpa/qplatformoffscreensurface.h>
-
+#include "androidjniaccessibility.h"
#include "androidjnimain.h"
#include "qabstracteventdispatcher.h"
#include "qandroideventdispatcher.h"
-#include "qandroidplatformbackingstore.h"
#include "qandroidplatformaccessibility.h"
#include "qandroidplatformclipboard.h"
-#include "qandroidplatformforeignwindow.h"
#include "qandroidplatformfontdatabase.h"
+#include "qandroidplatformforeignwindow.h"
+#include "qandroidplatformoffscreensurface.h"
#include "qandroidplatformopenglcontext.h"
#include "qandroidplatformopenglwindow.h"
#include "qandroidplatformscreen.h"
#include "qandroidplatformservices.h"
#include "qandroidplatformtheme.h"
#include "qandroidsystemlocale.h"
-#include "qandroidplatformoffscreensurface.h"
-#include <QtPlatformHeaders/QEGLNativeContext>
+#include <QGuiApplication>
+#include <QOffscreenSurface>
+#include <QOpenGLContext>
+#include <QThread>
+#include <QtCore/QJniObject>
+#include <QtGui/private/qeglpbuffer_p.h>
+#include <QtGui/private/qguiapplication_p.h>
+#include <QtGui/private/qoffscreensurface_p.h>
+#include <QtGui/private/qrhibackingstore_p.h>
+#include <qpa/qplatformoffscreensurface.h>
+#include <qpa/qplatformwindow.h>
+#include <qpa/qwindowsysteminterface.h>
+
+#include <jni.h>
#if QT_CONFIG(vulkan)
#include "qandroidplatformvulkanwindow.h"
@@ -81,26 +44,48 @@
QT_BEGIN_NAMESPACE
-int QAndroidPlatformIntegration::m_defaultGeometryWidth = 320;
-int QAndroidPlatformIntegration::m_defaultGeometryHeight = 455;
-int QAndroidPlatformIntegration::m_defaultScreenWidth = 320;
-int QAndroidPlatformIntegration::m_defaultScreenHeight = 455;
-int QAndroidPlatformIntegration::m_defaultPhysicalSizeWidth = 50;
-int QAndroidPlatformIntegration::m_defaultPhysicalSizeHeight = 71;
+using namespace Qt::StringLiterals;
+
+Q_CONSTINIT QSize QAndroidPlatformIntegration::m_defaultScreenSize = QSize(320, 455);
+Q_CONSTINIT QRect QAndroidPlatformIntegration::m_defaultAvailableGeometry = QRect(0, 0, 320, 455);
+Q_CONSTINIT QSize QAndroidPlatformIntegration::m_defaultPhysicalSize = QSize(50, 71);
Qt::ScreenOrientation QAndroidPlatformIntegration::m_orientation = Qt::PrimaryOrientation;
Qt::ScreenOrientation QAndroidPlatformIntegration::m_nativeOrientation = Qt::PrimaryOrientation;
bool QAndroidPlatformIntegration::m_showPasswordEnabled = false;
+Q_DECLARE_JNI_CLASS(QtNative, "org/qtproject/qt/android/QtNative")
+Q_DECLARE_JNI_CLASS(QtDisplayManager, "org/qtproject/qt/android/QtDisplayManager")
+Q_DECLARE_JNI_CLASS(Display, "android/view/Display")
+
+Q_DECLARE_JNI_CLASS(List, "java/util/List")
+
+namespace {
+
+QAndroidPlatformScreen* createScreenForDisplayId(int displayId)
+{
+ const QJniObject display = QtJniTypes::QtDisplayManager::callStaticMethod<QtJniTypes::Display>(
+ "getDisplay", QtAndroidPrivate::context(), displayId);
+ if (!display.isValid())
+ return nullptr;
+ return new QAndroidPlatformScreen(display);
+}
+
+} // anonymous namespace
+
void *QAndroidPlatformNativeInterface::nativeResourceForIntegration(const QByteArray &resource)
{
if (resource=="JavaVM")
return QtAndroid::javaVM();
- if (resource == "QtActivity")
- return QtAndroid::activity();
- if (resource == "QtService")
- return QtAndroid::service();
+ if (resource == "QtActivity") {
+ extern Q_CORE_EXPORT jobject qt_androidActivity();
+ return qt_androidActivity();
+ }
+ if (resource == "QtService") {
+ extern Q_CORE_EXPORT jobject qt_androidService();
+ return qt_androidService();
+ }
if (resource == "AndroidStyleData") {
if (m_androidStyle) {
if (m_androidStyle->m_styleData.isEmpty())
@@ -113,14 +98,14 @@ void *QAndroidPlatformNativeInterface::nativeResourceForIntegration(const QByteA
if (resource == "AndroidStandardPalette") {
if (m_androidStyle)
return &m_androidStyle->m_standardPalette;
- else
- return nullptr;
+
+ return nullptr;
}
if (resource == "AndroidQWidgetFonts") {
if (m_androidStyle)
return &m_androidStyle->m_QWidgetsFonts;
- else
- return nullptr;
+
+ return nullptr;
}
if (resource == "AndroidDeviceName") {
static QString deviceName = QtAndroid::deviceName();
@@ -146,6 +131,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)
@@ -154,12 +152,18 @@ void QAndroidPlatformNativeInterface::customEvent(QEvent *event)
QMutexLocker lock(QtAndroid::platformInterfaceMutex());
QAndroidPlatformIntegration *api = static_cast<QAndroidPlatformIntegration *>(QGuiApplicationPrivate::platformIntegration());
QtAndroid::setAndroidPlatformIntegration(api);
+
+#if QT_CONFIG(accessibility)
+ // Android accessibility activation event might have been already received
+ api->accessibility()->setActive(QtAndroidAccessibility::isActive());
+#endif // QT_CONFIG(accessibility)
+
api->flushPendingUpdates();
}
QAndroidPlatformIntegration::QAndroidPlatformIntegration(const QStringList &paramList)
: m_touchDevice(nullptr)
-#ifndef QT_NO_ACCESSIBILITY
+#if QT_CONFIG(accessibility)
, m_accessibility(nullptr)
#endif
{
@@ -177,11 +181,32 @@ QAndroidPlatformIntegration::QAndroidPlatformIntegration(const QStringList &para
if (Q_UNLIKELY(!eglBindAPI(EGL_OPENGL_ES_API)))
qFatal("Could not bind GL_ES API");
- m_primaryScreen = new QAndroidPlatformScreen();
- QWindowSystemInterface::handleScreenAdded(m_primaryScreen);
- m_primaryScreen->setPhysicalSize(QSize(m_defaultPhysicalSizeWidth, m_defaultPhysicalSizeHeight));
- m_primaryScreen->setSize(QSize(m_defaultScreenWidth, m_defaultScreenHeight));
- m_primaryScreen->setAvailableGeometry(QRect(0, 0, m_defaultGeometryWidth, m_defaultGeometryHeight));
+ using namespace QtJniTypes;
+ m_primaryDisplayId = Display::getStaticField<jint>("DEFAULT_DISPLAY");
+ const QJniObject nativeDisplaysList = QtDisplayManager::callStaticMethod<List>(
+ "getAvailableDisplays", QtAndroidPrivate::context());
+
+ const int numberOfAvailableDisplays = nativeDisplaysList.callMethod<jint>("size");
+ for (int i = 0; i < numberOfAvailableDisplays; ++i) {
+ const QJniObject display =
+ nativeDisplaysList.callObjectMethod<jobject, jint>("get", jint(i));
+ const int displayId = display.callMethod<jint>("getDisplayId");
+ const bool isPrimary = (m_primaryDisplayId == displayId);
+ auto screen = new QAndroidPlatformScreen(display);
+
+ if (isPrimary)
+ m_primaryScreen = screen;
+
+ QWindowSystemInterface::handleScreenAdded(screen, isPrimary);
+ m_screens[displayId] = screen;
+ }
+
+ if (numberOfAvailableDisplays == 0) {
+ // If no displays are found, add a dummy display
+ auto defaultScreen = new QAndroidPlatformScreen(QJniObject {});
+ m_primaryScreen = defaultScreen;
+ QWindowSystemInterface::handleScreenAdded(defaultScreen, true);
+ }
m_mainThread = QThread::currentThread();
@@ -194,51 +219,68 @@ QAndroidPlatformIntegration::QAndroidPlatformIntegration(const QStringList &para
m_androidSystemLocale = new QAndroidSystemLocale;
-#ifndef QT_NO_ACCESSIBILITY
+#if QT_CONFIG(accessibility)
m_accessibility = new QAndroidPlatformAccessibility();
-#endif // QT_NO_ACCESSIBILITY
+#endif // QT_CONFIG(accessibility)
- QJNIObjectPrivate javaActivity(QtAndroid::activity());
+ QJniObject javaActivity = QtAndroidPrivate::activity();
if (!javaActivity.isValid())
- javaActivity = QtAndroid::service();
+ javaActivity = QtAndroidPrivate::service();
if (javaActivity.isValid()) {
- QJNIObjectPrivate resources = javaActivity.callObjectMethod("getResources", "()Landroid/content/res/Resources;");
- QJNIObjectPrivate configuration = resources.callObjectMethod("getConfiguration", "()Landroid/content/res/Configuration;");
+ QJniObject resources = javaActivity.callObjectMethod("getResources", "()Landroid/content/res/Resources;");
+ QJniObject configuration = resources.callObjectMethod("getConfiguration", "()Landroid/content/res/Configuration;");
int touchScreen = configuration.getField<jint>("touchscreen");
- if (touchScreen == QJNIObjectPrivate::getStaticField<jint>("android/content/res/Configuration", "TOUCHSCREEN_FINGER")
- || touchScreen == QJNIObjectPrivate::getStaticField<jint>("android/content/res/Configuration", "TOUCHSCREEN_STYLUS"))
+ if (touchScreen == QJniObject::getStaticField<jint>("android/content/res/Configuration", "TOUCHSCREEN_FINGER")
+ || touchScreen == QJniObject::getStaticField<jint>("android/content/res/Configuration", "TOUCHSCREEN_STYLUS"))
{
- m_touchDevice = new QTouchDevice;
- m_touchDevice->setType(QTouchDevice::TouchScreen);
- m_touchDevice->setCapabilities(QTouchDevice::Position
- | QTouchDevice::Area
- | QTouchDevice::Pressure
- | QTouchDevice::NormalizedPosition);
-
- QJNIObjectPrivate pm = javaActivity.callObjectMethod("getPackageManager", "()Landroid/content/pm/PackageManager;");
+ QJniObject pm = javaActivity.callObjectMethod("getPackageManager", "()Landroid/content/pm/PackageManager;");
Q_ASSERT(pm.isValid());
+ int maxTouchPoints = 1;
if (pm.callMethod<jboolean>("hasSystemFeature","(Ljava/lang/String;)Z",
- QJNIObjectPrivate::getStaticObjectField("android/content/pm/PackageManager", "FEATURE_TOUCHSCREEN_MULTITOUCH_JAZZHAND", "Ljava/lang/String;").object())) {
- m_touchDevice->setMaximumTouchPoints(10);
+ QJniObject::getStaticObjectField("android/content/pm/PackageManager",
+ "FEATURE_TOUCHSCREEN_MULTITOUCH_JAZZHAND",
+ "Ljava/lang/String;").object())) {
+ maxTouchPoints = 10;
} else if (pm.callMethod<jboolean>("hasSystemFeature","(Ljava/lang/String;)Z",
- QJNIObjectPrivate::getStaticObjectField("android/content/pm/PackageManager", "FEATURE_TOUCHSCREEN_MULTITOUCH_DISTINCT", "Ljava/lang/String;").object())) {
- m_touchDevice->setMaximumTouchPoints(4);
+ QJniObject::getStaticObjectField("android/content/pm/PackageManager",
+ "FEATURE_TOUCHSCREEN_MULTITOUCH_DISTINCT",
+ "Ljava/lang/String;").object())) {
+ maxTouchPoints = 4;
} else if (pm.callMethod<jboolean>("hasSystemFeature","(Ljava/lang/String;)Z",
- QJNIObjectPrivate::getStaticObjectField("android/content/pm/PackageManager", "FEATURE_TOUCHSCREEN_MULTITOUCH", "Ljava/lang/String;").object())) {
- m_touchDevice->setMaximumTouchPoints(2);
+ QJniObject::getStaticObjectField("android/content/pm/PackageManager",
+ "FEATURE_TOUCHSCREEN_MULTITOUCH",
+ "Ljava/lang/String;").object())) {
+ maxTouchPoints = 2;
}
- QWindowSystemInterface::registerTouchDevice(m_touchDevice);
+
+ m_touchDevice = new QPointingDevice("Android touchscreen", 1,
+ QInputDevice::DeviceType::TouchScreen,
+ QPointingDevice::PointerType::Finger,
+ QPointingDevice::Capability::Position
+ | QPointingDevice::Capability::Area
+ | QPointingDevice::Capability::Pressure
+ | QPointingDevice::Capability::NormalizedPosition,
+ maxTouchPoints,
+ 0);
+ QWindowSystemInterface::registerInputDevice(m_touchDevice);
+
+ QWindowSystemInterface::registerInputDevice(
+ new QInputDevice("Virtual keyboard"_L1, 0, QInputDevice::DeviceType::Keyboard,
+ {}, qApp));
}
auto contentResolver = javaActivity.callObjectMethod("getContentResolver", "()Landroid/content/ContentResolver;");
Q_ASSERT(contentResolver.isValid());
- QJNIObjectPrivate txtShowPassValue = QJNIObjectPrivate::callStaticObjectMethod("android/provider/Settings$System",
- "getString",
- "(Landroid/content/ContentResolver;Ljava/lang/String;)Ljava/lang/String;",
- contentResolver.object(),
- QJNIObjectPrivate::getStaticObjectField("android/provider/Settings$System", "TEXT_SHOW_PASSWORD", "Ljava/lang/String;").object());
+ QJniObject txtShowPassValue = QJniObject::callStaticObjectMethod(
+ "android/provider/Settings$System",
+ "getString",
+ "(Landroid/content/ContentResolver;Ljava/lang/String;)Ljava/lang/String;",
+ contentResolver.object(),
+ QJniObject::getStaticObjectField("android/provider/Settings$System",
+ "TEXT_SHOW_PASSWORD",
+ "Ljava/lang/String;").object());
if (txtShowPassValue.isValid()) {
bool ok = false;
const int txtShowPass = txtShowPassValue.toString().toInt(&ok);
@@ -254,19 +296,19 @@ QAndroidPlatformIntegration::QAndroidPlatformIntegration(const QStringList &para
static bool needsBasicRenderloopWorkaround()
{
static bool needsWorkaround =
- QtAndroid::deviceName().compare(QLatin1String("samsung SM-T211"), Qt::CaseInsensitive) == 0
- || QtAndroid::deviceName().compare(QLatin1String("samsung SM-T210"), Qt::CaseInsensitive) == 0
- || QtAndroid::deviceName().compare(QLatin1String("samsung SM-T215"), Qt::CaseInsensitive) == 0;
+ QtAndroid::deviceName().compare("samsung SM-T211"_L1, Qt::CaseInsensitive) == 0
+ || QtAndroid::deviceName().compare("samsung SM-T210"_L1, Qt::CaseInsensitive) == 0
+ || QtAndroid::deviceName().compare("samsung SM-T215"_L1, Qt::CaseInsensitive) == 0;
return needsWorkaround;
}
void QAndroidPlatformIntegration::initialize()
{
- const QString icStr = QPlatformInputContextFactory::requested();
- if (icStr.isNull())
+ const auto icStrs = QPlatformInputContextFactory::requested();
+ if (icStrs.isEmpty())
m_inputContext.reset(new QAndroidInputContext);
else
- m_inputContext.reset(QPlatformInputContextFactory::create(icStr));
+ m_inputContext.reset(QPlatformInputContextFactory::create(icStrs));
}
bool QAndroidPlatformIntegration::hasCapability(Capability cap) const
@@ -274,12 +316,16 @@ bool QAndroidPlatformIntegration::hasCapability(Capability cap) const
switch (cap) {
case ApplicationState: return true;
case ThreadedPixmaps: return true;
- case NativeWidgets: return QtAndroid::activity();
- case OpenGL: return QtAndroid::activity();
- case ForeignWindows: return QtAndroid::activity();
- case ThreadedOpenGL: return !needsBasicRenderloopWorkaround() && QtAndroid::activity();
- case RasterGLSurface: return QtAndroid::activity();
+ case NativeWidgets: return QtAndroidPrivate::activity().isValid();
+ case OpenGL: return QtAndroidPrivate::activity().isValid();
+ case ForeignWindows: return QtAndroidPrivate::activity().isValid();
+ case ThreadedOpenGL: return !needsBasicRenderloopWorkaround() && QtAndroidPrivate::activity().isValid();
+ case RasterGLSurface: return QtAndroidPrivate::activity().isValid();
case TopStackedNativeChildWindows: return false;
+ case MaximizeUsingFullscreenGeometry: return true;
+ // FIXME QTBUG-118849 - we do not implement grabWindow() anymore, calling it will return
+ // a null QPixmap also for raster windows - for OpenGL windows this was always true
+ case ScreenWindowGrabbing: return false;
default:
return QPlatformIntegration::hasCapability(cap);
}
@@ -287,33 +333,33 @@ bool QAndroidPlatformIntegration::hasCapability(Capability cap) const
QPlatformBackingStore *QAndroidPlatformIntegration::createPlatformBackingStore(QWindow *window) const
{
- if (!QtAndroid::activity())
+ if (!QtAndroidPrivate::activity().isValid())
return nullptr;
- auto *backingStore = new QAndroidPlatformBackingStore(window);
-#if QT_CONFIG(opengl)
- backingStore->setOpenGLSupport(new QPlatformBackingStoreOpenGLSupport(backingStore));
-#endif // QT_CONFIG(opengl)
- return backingStore;
+ return new QRhiBackingStore(window);
}
QPlatformOpenGLContext *QAndroidPlatformIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const
{
- if (!QtAndroid::activity())
+ if (!QtAndroidPrivate::activity().isValid())
return nullptr;
QSurfaceFormat format(context->format());
format.setAlphaBufferSize(8);
format.setRedBufferSize(8);
format.setGreenBufferSize(8);
format.setBlueBufferSize(8);
- auto ctx = new QAndroidPlatformOpenGLContext(format, context->shareHandle(), m_eglDisplay, context->nativeHandle());
- context->setNativeHandle(QVariant::fromValue<QEGLNativeContext>(QEGLNativeContext(ctx->eglContext(), m_eglDisplay)));
+ auto ctx = new QAndroidPlatformOpenGLContext(format, context->shareHandle(), m_eglDisplay);
return ctx;
}
+QOpenGLContext *QAndroidPlatformIntegration::createOpenGLContext(EGLContext context, EGLDisplay display, QOpenGLContext *shareContext) const
+{
+ return QEGLPlatformContext::createFrom<QAndroidPlatformOpenGLContext>(context, display, m_eglDisplay, shareContext);
+}
+
QPlatformOffscreenSurface *QAndroidPlatformIntegration::createPlatformOffscreenSurface(QOffscreenSurface *surface) const
{
- if (!QtAndroid::activity())
+ if (!QtAndroidPrivate::activity().isValid())
return nullptr;
QSurfaceFormat format(surface->requestedFormat());
@@ -322,19 +368,23 @@ QPlatformOffscreenSurface *QAndroidPlatformIntegration::createPlatformOffscreenS
format.setGreenBufferSize(8);
format.setBlueBufferSize(8);
- if (surface->nativeHandle()) {
- // Adopt existing offscreen Surface
- // The expectation is that nativeHandle is an ANativeWindow* representing
- // an android.view.Surface
- return new QAndroidPlatformOffscreenSurface(m_eglDisplay, format, surface);
- }
-
return new QEGLPbuffer(m_eglDisplay, format, surface);
}
+QOffscreenSurface *QAndroidPlatformIntegration::createOffscreenSurface(ANativeWindow *nativeSurface) const
+{
+ if (!QtAndroidPrivate::activity().isValid() || !nativeSurface)
+ return nullptr;
+
+ auto *surface = new QOffscreenSurface;
+ auto *surfacePrivate = QOffscreenSurfacePrivate::get(surface);
+ surfacePrivate->platformOffscreenSurface = new QAndroidPlatformOffscreenSurface(nativeSurface, m_eglDisplay, surface);
+ return surface;
+}
+
QPlatformWindow *QAndroidPlatformIntegration::createPlatformWindow(QWindow *window) const
{
- if (!QtAndroid::activity())
+ if (!QtAndroidPrivate::activity().isValid())
return nullptr;
#if QT_CONFIG(vulkan)
@@ -420,7 +470,7 @@ Qt::WindowState QAndroidPlatformIntegration::defaultWindowState(Qt::WindowFlags
return QPlatformIntegration::defaultWindowState(flags);
}
-static const QLatin1String androidThemeName("android");
+static const auto androidThemeName = "android"_L1;
QStringList QAndroidPlatformIntegration::themeNames() const
{
return QStringList(QString(androidThemeName));
@@ -429,25 +479,20 @@ QStringList QAndroidPlatformIntegration::themeNames() const
QPlatformTheme *QAndroidPlatformIntegration::createPlatformTheme(const QString &name) const
{
if (androidThemeName == name)
- return new QAndroidPlatformTheme(m_androidPlatformNativeInterface);
+ return QAndroidPlatformTheme::instance(m_androidPlatformNativeInterface);
return 0;
}
-void QAndroidPlatformIntegration::setDefaultDisplayMetrics(int gw, int gh, int sw, int sh, int screenWidth, int screenHeight)
+void QAndroidPlatformIntegration::setDefaultDisplayMetrics(int availableLeft, int availableTop,
+ int availableWidth, int availableHeight,
+ int physicalWidth, int physicalHeight,
+ int screenWidth, int screenHeight)
{
- m_defaultGeometryWidth = gw;
- m_defaultGeometryHeight = gh;
- m_defaultPhysicalSizeWidth = sw;
- m_defaultPhysicalSizeHeight = sh;
- m_defaultScreenWidth = screenWidth;
- m_defaultScreenHeight = screenHeight;
-}
-
-void QAndroidPlatformIntegration::setDefaultDesktopSize(int gw, int gh)
-{
- m_defaultGeometryWidth = gw;
- m_defaultGeometryHeight = gh;
+ m_defaultAvailableGeometry = QRect(availableLeft, availableTop,
+ availableWidth, availableHeight);
+ m_defaultPhysicalSize = QSize(physicalWidth, physicalHeight);
+ m_defaultScreenSize = QSize(screenWidth, screenHeight);
}
void QAndroidPlatformIntegration::setScreenOrientation(Qt::ScreenOrientation currentOrientation,
@@ -459,26 +504,26 @@ void QAndroidPlatformIntegration::setScreenOrientation(Qt::ScreenOrientation cur
void QAndroidPlatformIntegration::flushPendingUpdates()
{
- m_primaryScreen->setPhysicalSize(QSize(m_defaultPhysicalSizeWidth,
- m_defaultPhysicalSizeHeight));
- m_primaryScreen->setSize(QSize(m_defaultScreenWidth, m_defaultScreenHeight));
- m_primaryScreen->setAvailableGeometry(QRect(0, 0, m_defaultGeometryWidth, m_defaultGeometryHeight));
+ if (m_primaryScreen) {
+ m_primaryScreen->setSizeParameters(m_defaultPhysicalSize, m_defaultScreenSize,
+ m_defaultAvailableGeometry);
+ }
}
-#ifndef QT_NO_ACCESSIBILITY
+#if QT_CONFIG(accessibility)
QPlatformAccessibility *QAndroidPlatformIntegration::accessibility() const
{
return m_accessibility;
}
#endif
-void QAndroidPlatformIntegration::setDesktopSize(int width, int height)
+void QAndroidPlatformIntegration::setAvailableGeometry(const QRect &availableGeometry)
{
if (m_primaryScreen)
- QMetaObject::invokeMethod(m_primaryScreen, "setAvailableGeometry", Qt::AutoConnection, Q_ARG(QRect, QRect(0,0,width, height)));
+ QMetaObject::invokeMethod(m_primaryScreen, "setAvailableGeometry", Qt::AutoConnection, Q_ARG(QRect, availableGeometry));
}
-void QAndroidPlatformIntegration::setDisplayMetrics(int width, int height)
+void QAndroidPlatformIntegration::setPhysicalSize(int width, int height)
{
if (m_primaryScreen)
QMetaObject::invokeMethod(m_primaryScreen, "setPhysicalSize", Qt::AutoConnection, Q_ARG(QSize, QSize(width, height)));
@@ -490,6 +535,78 @@ void QAndroidPlatformIntegration::setScreenSize(int width, int height)
QMetaObject::invokeMethod(m_primaryScreen, "setSize", Qt::AutoConnection, Q_ARG(QSize, QSize(width, height)));
}
+Qt::ColorScheme QAndroidPlatformIntegration::m_colorScheme = Qt::ColorScheme::Light;
+
+void QAndroidPlatformIntegration::setColorScheme(Qt::ColorScheme colorScheme)
+{
+ if (m_colorScheme == colorScheme)
+ return;
+ m_colorScheme = colorScheme;
+
+ QMetaObject::invokeMethod(qGuiApp,
+ [] () { QAndroidPlatformTheme::instance()->updateColorScheme();});
+}
+
+void QAndroidPlatformIntegration::setScreenSizeParameters(const QSize &physicalSize,
+ const QSize &screenSize,
+ const QRect &availableGeometry)
+{
+ if (m_primaryScreen) {
+ QMetaObject::invokeMethod(m_primaryScreen, "setSizeParameters", Qt::AutoConnection,
+ Q_ARG(QSize, physicalSize), Q_ARG(QSize, screenSize),
+ Q_ARG(QRect, availableGeometry));
+ }
+}
+
+void QAndroidPlatformIntegration::setRefreshRate(qreal refreshRate)
+{
+ if (m_primaryScreen)
+ QMetaObject::invokeMethod(m_primaryScreen, "setRefreshRate", Qt::AutoConnection,
+ Q_ARG(qreal, refreshRate));
+}
+
+void QAndroidPlatformIntegration::handleScreenAdded(int displayId)
+{
+ auto result = m_screens.insert(displayId, nullptr);
+ if (result.first->second == nullptr) {
+ auto it = result.first;
+ it->second = createScreenForDisplayId(displayId);
+ if (it->second == nullptr)
+ return;
+ const bool isPrimary = (m_primaryDisplayId == displayId);
+ if (isPrimary)
+ m_primaryScreen = it->second;
+ QWindowSystemInterface::handleScreenAdded(it->second, isPrimary);
+ } else {
+ qWarning() << "Display with id" << displayId << "already exists.";
+ }
+}
+
+void QAndroidPlatformIntegration::handleScreenChanged(int displayId)
+{
+ auto it = m_screens.find(displayId);
+ if (it == m_screens.end() || it->second == nullptr) {
+ handleScreenAdded(displayId);
+ }
+ // We do not do anything more here as handling of change of
+ // rotation and refresh rate is done in QtActivityDelegate java class
+ // which calls QAndroidPlatformIntegration::setOrientation, and
+ // QAndroidPlatformIntegration::setRefreshRate accordingly.
+}
+
+void QAndroidPlatformIntegration::handleScreenRemoved(int displayId)
+{
+ auto it = m_screens.find(displayId);
+
+ if (it == m_screens.end())
+ return;
+
+ if (it->second != nullptr)
+ QWindowSystemInterface::handleScreenRemoved(it->second);
+
+ m_screens.erase(it);
+}
+
#if QT_CONFIG(vulkan)
QPlatformVulkanInstance *QAndroidPlatformIntegration::createPlatformVulkanInstance(QVulkanInstance *instance) const
diff --git a/src/plugins/platforms/android/qandroidplatformintegration.h b/src/plugins/platforms/android/qandroidplatformintegration.h
index ecbde4f951..5f1126fafc 100644
--- a/src/plugins/platforms/android/qandroidplatformintegration.h
+++ b/src/plugins/platforms/android/qandroidplatformintegration.h
@@ -1,62 +1,27 @@
-/****************************************************************************
-**
-** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QANDROIDPLATFORMINTERATION_H
#define QANDROIDPLATFORMINTERATION_H
-#include <QtGui/qtguiglobal.h>
+#include "qandroidinputcontext.h"
+#include "qandroidplatformscreen.h"
+#include <QtGui/qtguiglobal.h>
#include <qpa/qplatformintegration.h>
#include <qpa/qplatformmenu.h>
#include <qpa/qplatformnativeinterface.h>
+#include <qpa/qplatformopenglcontext.h>
+#include <qpa/qplatformoffscreensurface.h>
+#include <qpa/qplatformtheme.h>
+#include <private/qflatmap_p.h>
+#include <QtCore/qvarlengtharray.h>
#include <EGL/egl.h>
-#include <jni.h>
-#include "qandroidinputcontext.h"
-
-#include "qandroidplatformscreen.h"
-
#include <memory>
QT_BEGIN_NAMESPACE
-class QDesktopWidget;
class QAndroidPlatformServices;
class QAndroidSystemLocale;
class QPlatformAccessibility;
@@ -67,6 +32,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:
@@ -74,6 +40,8 @@ protected:
};
class QAndroidPlatformIntegration : public QPlatformIntegration
+ , QNativeInterface::Private::QEGLIntegration
+ , QNativeInterface::Private::QAndroidOffScreenIntegration
{
friend class QAndroidPlatformScreen;
@@ -89,17 +57,30 @@ public:
QPlatformWindow *createForeignWindow(QWindow *window, WId nativeHandle) const override;
QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const override;
QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const override;
+ QOpenGLContext *createOpenGLContext(EGLContext context, EGLDisplay display, QOpenGLContext *shareContext) const override;
QAbstractEventDispatcher *createEventDispatcher() const override;
QAndroidPlatformScreen *screen() { return m_primaryScreen; }
QPlatformOffscreenSurface *createPlatformOffscreenSurface(QOffscreenSurface *surface) const override;
+ QOffscreenSurface *createOffscreenSurface(ANativeWindow *nativeSurface) const override;
- virtual void setDesktopSize(int width, int height);
- virtual void setDisplayMetrics(int width, int height);
+ void setAvailableGeometry(const QRect &availableGeometry);
+ void setPhysicalSize(int width, int height);
void setScreenSize(int width, int height);
+ // The 3 methods above were replaced by a new one, so that we could have
+ // a better control over "geometry changed" event handling. Technically
+ // they are no longer used and can be removed. Not doing it now, because
+ // I'm not sure if it might be helpful to have them or not.
+ void setScreenSizeParameters(const QSize &physicalSize, const QSize &screenSize,
+ const QRect &availableGeometry);
+ void setRefreshRate(qreal refreshRate);
bool isVirtualDesktop() { return true; }
QPlatformFontDatabase *fontDatabase() const override;
+ void handleScreenAdded(int displayId);
+ void handleScreenChanged(int displayId);
+ void handleScreenRemoved(int displayId);
+
#ifndef QT_NO_CLIPBOARD
QPlatformClipboard *clipboard() const override;
#endif
@@ -108,7 +89,7 @@ public:
QPlatformNativeInterface *nativeInterface() const override;
QPlatformServices *services() const override;
-#ifndef QT_NO_ACCESSIBILITY
+#if QT_CONFIG(accessibility)
virtual QPlatformAccessibility *accessibility() const override;
#endif
@@ -118,39 +99,36 @@ public:
QStringList themeNames() const override;
QPlatformTheme *createPlatformTheme(const QString &name) const override;
- static void setDefaultDisplayMetrics(int gw, int gh, int sw, int sh, int width, int height);
- static void setDefaultDesktopSize(int gw, int gh);
+ static void setDefaultDisplayMetrics(int availableLeft, int availableTop, int availableWidth,
+ int availableHeight, int physicalWidth, int physicalHeight,
+ int screenWidth, int screenHeight);
static void setScreenOrientation(Qt::ScreenOrientation currentOrientation,
Qt::ScreenOrientation nativeOrientation);
- static QSize defaultDesktopSize()
- {
- return QSize(m_defaultGeometryWidth, m_defaultGeometryHeight);
- }
-
- QTouchDevice *touchDevice() const { return m_touchDevice; }
- void setTouchDevice(QTouchDevice *touchDevice) { m_touchDevice = touchDevice; }
+ QPointingDevice *touchDevice() const { return m_touchDevice; }
+ void setTouchDevice(QPointingDevice *touchDevice) { m_touchDevice = touchDevice; }
void flushPendingUpdates();
+ static void setColorScheme(Qt::ColorScheme colorScheme);
+ static Qt::ColorScheme colorScheme() { return m_colorScheme; }
#if QT_CONFIG(vulkan)
QPlatformVulkanInstance *createPlatformVulkanInstance(QVulkanInstance *instance) const override;
#endif
private:
EGLDisplay m_eglDisplay;
- QTouchDevice *m_touchDevice;
+ QPointingDevice *m_touchDevice;
QAndroidPlatformScreen *m_primaryScreen;
QThread *m_mainThread;
- static int m_defaultGeometryWidth;
- static int m_defaultGeometryHeight;
- static int m_defaultPhysicalSizeWidth;
- static int m_defaultPhysicalSizeHeight;
- static int m_defaultScreenWidth;
- static int m_defaultScreenHeight;
+ static Qt::ColorScheme m_colorScheme;
+
+ static QRect m_defaultAvailableGeometry;
+ static QSize m_defaultPhysicalSize;
+ static QSize m_defaultScreenSize;
static Qt::ScreenOrientation m_orientation;
static Qt::ScreenOrientation m_nativeOrientation;
@@ -160,12 +138,23 @@ private:
QAndroidPlatformNativeInterface *m_androidPlatformNativeInterface;
QAndroidPlatformServices *m_androidPlatformServices;
+ // Handling the multiple screens connected. Every display is identified
+ // with an unique (autoincremented) displayID. The values of this ID will
+ // not repeat during the OS runtime. We use this value as the key in the
+ // storage of screens.
+ QFlatMap<int, QAndroidPlatformScreen *, std::less<int>
+ , QVarLengthArray<int, 10>
+ , QVarLengthArray<QAndroidPlatformScreen *, 10> > m_screens;
+ // ID of the primary display, in documentation it is said to be always 0,
+ // but nevertheless it is retrieved
+ int m_primaryDisplayId = 0;
+
#ifndef QT_NO_CLIPBOARD
QPlatformClipboard *m_androidPlatformClipboard;
#endif
QAndroidSystemLocale *m_androidSystemLocale;
-#ifndef QT_NO_ACCESSIBILITY
+#if QT_CONFIG(accessibility)
mutable QPlatformAccessibility *m_accessibility;
#endif
diff --git a/src/plugins/platforms/android/qandroidplatformmenu.cpp b/src/plugins/platforms/android/qandroidplatformmenu.cpp
index 7ce603831f..e59fd2089d 100644
--- a/src/plugins/platforms/android/qandroidplatformmenu.cpp
+++ b/src/plugins/platforms/android/qandroidplatformmenu.cpp
@@ -1,46 +1,13 @@
-/****************************************************************************
-**
-** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+#include "androidjnimenu.h"
#include "qandroidplatformmenu.h"
#include "qandroidplatformmenuitem.h"
-#include "androidjnimenu.h"
-#include <QtCore/private/qjni_p.h>
+
+#include <QtCore/qjnienvironment.h>
+#include <QtCore/qjniobject.h>
QT_BEGIN_NAMESPACE
@@ -104,7 +71,7 @@ void QAndroidPlatformMenu::syncMenuItem(QPlatformMenuItem *menuItem)
void QAndroidPlatformMenu::syncSeparatorsCollapsible(bool enable)
{
- Q_UNUSED(enable)
+ Q_UNUSED(enable);
}
void QAndroidPlatformMenu::setText(const QString &text)
@@ -152,7 +119,7 @@ void QAndroidPlatformMenu::showPopup(const QWindow *parentWindow, const QRect &t
Q_UNUSED(parentWindow);
Q_UNUSED(item);
setVisible(true);
- QtAndroidMenu::showContextMenu(this, targetRect, QJNIEnvironmentPrivate());
+ QtAndroidMenu::showContextMenu(this, targetRect);
}
QPlatformMenuItem *QAndroidPlatformMenu::menuItemForTag(quintptr tag) const
diff --git a/src/plugins/platforms/android/qandroidplatformmenu.h b/src/plugins/platforms/android/qandroidplatformmenu.h
index b1d6a88787..4329b03e58 100644
--- a/src/plugins/platforms/android/qandroidplatformmenu.h
+++ b/src/plugins/platforms/android/qandroidplatformmenu.h
@@ -1,47 +1,12 @@
-/****************************************************************************
-**
-** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QANDROIDPLATFORMMENU_H
#define QANDROIDPLATFORMMENU_H
+#include <qhash.h>
#include <qpa/qplatformmenu.h>
-#include <qvector.h>
+#include <qlist.h>
#include <qmutex.h>
QT_BEGIN_NAMESPACE
@@ -50,7 +15,7 @@ class QAndroidPlatformMenuItem;
class QAndroidPlatformMenu: public QPlatformMenu
{
public:
- typedef QVector<QAndroidPlatformMenuItem *> PlatformMenuItemsType;
+ typedef QList<QAndroidPlatformMenuItem *> PlatformMenuItemsType;
public:
QAndroidPlatformMenu();
diff --git a/src/plugins/platforms/android/qandroidplatformmenubar.cpp b/src/plugins/platforms/android/qandroidplatformmenubar.cpp
index 7c6299b4b7..f3d99b9d90 100644
--- a/src/plugins/platforms/android/qandroidplatformmenubar.cpp
+++ b/src/plugins/platforms/android/qandroidplatformmenubar.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qandroidplatformmenubar.h"
#include "qandroidplatformmenu.h"
diff --git a/src/plugins/platforms/android/qandroidplatformmenubar.h b/src/plugins/platforms/android/qandroidplatformmenubar.h
index 81a26c72f4..0d2ee1b8b6 100644
--- a/src/plugins/platforms/android/qandroidplatformmenubar.h
+++ b/src/plugins/platforms/android/qandroidplatformmenubar.h
@@ -1,49 +1,13 @@
-/****************************************************************************
-**
-** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QANDROIDPLATFORMMENUBAR_H
#define QANDROIDPLATFORMMENUBAR_H
#include <qpa/qplatformmenu.h>
-#include <qvector.h>
-#include <qmutex.h>
#include <qhash.h>
+#include <qlist.h>
+#include <qmutex.h>
QT_BEGIN_NAMESPACE
@@ -51,7 +15,7 @@ class QAndroidPlatformMenu;
class QAndroidPlatformMenuBar: public QPlatformMenuBar
{
public:
- typedef QVector<QAndroidPlatformMenu *> PlatformMenusType;
+ typedef QList<QAndroidPlatformMenu *> PlatformMenusType;
public:
QAndroidPlatformMenuBar();
~QAndroidPlatformMenuBar();
diff --git a/src/plugins/platforms/android/qandroidplatformmenuitem.cpp b/src/plugins/platforms/android/qandroidplatformmenuitem.cpp
index e24c5f974e..3e3facef3e 100644
--- a/src/plugins/platforms/android/qandroidplatformmenuitem.cpp
+++ b/src/plugins/platforms/android/qandroidplatformmenuitem.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qandroidplatformmenuitem.h"
#include "qandroidplatformmenu.h"
@@ -118,7 +82,7 @@ bool QAndroidPlatformMenuItem::isSeparator() const
void QAndroidPlatformMenuItem::setFont(const QFont &font)
{
- Q_UNUSED(font)
+ Q_UNUSED(font);
}
void QAndroidPlatformMenuItem::setRole(QPlatformMenuItem::MenuRole role)
@@ -153,7 +117,7 @@ bool QAndroidPlatformMenuItem::isChecked() const
void QAndroidPlatformMenuItem::setShortcut(const QKeySequence &shortcut)
{
- Q_UNUSED(shortcut)
+ Q_UNUSED(shortcut);
}
void QAndroidPlatformMenuItem::setEnabled(bool enabled)
@@ -170,7 +134,7 @@ bool QAndroidPlatformMenuItem::isEnabled() const
void QAndroidPlatformMenuItem::setIconSize(int size)
{
- Q_UNUSED(size)
+ Q_UNUSED(size);
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/android/qandroidplatformmenuitem.h b/src/plugins/platforms/android/qandroidplatformmenuitem.h
index b8782f995d..e201a5d91a 100644
--- a/src/plugins/platforms/android/qandroidplatformmenuitem.h
+++ b/src/plugins/platforms/android/qandroidplatformmenuitem.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QANDROIDPLATFORMMENUITEM_H
#define QANDROIDPLATFORMMENUITEM_H
diff --git a/src/plugins/platforms/android/qandroidplatformoffscreensurface.cpp b/src/plugins/platforms/android/qandroidplatformoffscreensurface.cpp
index c7d832efb6..5237218d62 100644
--- a/src/plugins/platforms/android/qandroidplatformoffscreensurface.cpp
+++ b/src/plugins/platforms/android/qandroidplatformoffscreensurface.cpp
@@ -1,66 +1,25 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qandroidplatformoffscreensurface.h"
-#include <QtGui/QOffscreenSurface>
-#include <QtEglSupport/private/qeglconvenience_p.h>
-
-#include <android/native_window.h>
+#include <QtGui/private/qeglconvenience_p.h>
QT_BEGIN_NAMESPACE
-QAndroidPlatformOffscreenSurface::QAndroidPlatformOffscreenSurface(EGLDisplay display, const QSurfaceFormat &format, QOffscreenSurface *offscreenSurface)
- : QPlatformOffscreenSurface(offscreenSurface)
- , m_format(format)
- , m_display(display)
- , m_surface(EGL_NO_SURFACE)
+QAndroidPlatformOffscreenSurface::QAndroidPlatformOffscreenSurface(
+ ANativeWindow *nativeSurface, EGLDisplay display, QOffscreenSurface *offscreenSurface)
+ : QPlatformOffscreenSurface(offscreenSurface), m_display(display), m_surface(EGL_NO_SURFACE)
{
- // Get native handle
- ANativeWindow *surfaceTexture = (ANativeWindow*)offscreenSurface->nativeHandle();
-
- EGLConfig config = q_configFromGLFormat(m_display, m_format, false);
- if (config) {
- const EGLint attributes[] = {
- EGL_NONE
- };
- m_surface = eglCreateWindowSurface(m_display, config, surfaceTexture, attributes);
+ // FIXME: Read surface format properties from native surface using ANativeWindow_getFormat
+ m_format.setAlphaBufferSize(8);
+ m_format.setRedBufferSize(8);
+ m_format.setGreenBufferSize(8);
+ m_format.setBlueBufferSize(8);
+
+ if (EGLConfig config = q_configFromGLFormat(m_display, m_format, false)) {
+ const EGLint attributes[] = { EGL_NONE };
+ m_surface = eglCreateWindowSurface(m_display, config, nativeSurface, attributes);
}
}
diff --git a/src/plugins/platforms/android/qandroidplatformoffscreensurface.h b/src/plugins/platforms/android/qandroidplatformoffscreensurface.h
index 461f949254..a48a43ca98 100644
--- a/src/plugins/platforms/android/qandroidplatformoffscreensurface.h
+++ b/src/plugins/platforms/android/qandroidplatformoffscreensurface.h
@@ -1,61 +1,30 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QANDROIDPLATFORMOFFSCREENSURFACETEXTURE_H
#define QANDROIDPLATFORMOFFSCREENSURFACETEXTURE_H
#include <qpa/qplatformoffscreensurface.h>
-#include <QtEglSupport/private/qeglplatformcontext_p.h>
+#include <QtGui/qoffscreensurface_platform.h>
+
+#include <EGL/egl.h>
QT_BEGIN_NAMESPACE
class QOffscreenSurface;
-class QAndroidPlatformOffscreenSurface : public QPlatformOffscreenSurface
+class QAndroidPlatformOffscreenSurface : public QPlatformOffscreenSurface,
+ public QNativeInterface::QAndroidOffscreenSurface
{
public:
- QAndroidPlatformOffscreenSurface(EGLDisplay display, const QSurfaceFormat &format,
- QOffscreenSurface *offscreenSurface);
+ QAndroidPlatformOffscreenSurface(ANativeWindow *nativeSurface, EGLDisplay display, QOffscreenSurface *offscreenSurface);
~QAndroidPlatformOffscreenSurface();
QSurfaceFormat format() const override { return m_format; }
bool isValid() const override { return m_surface != EGL_NO_SURFACE; }
EGLSurface surface() const { return m_surface; }
+
+ ANativeWindow *nativeSurface() const override { return (ANativeWindow *)surface(); };
+
private:
QSurfaceFormat m_format;
EGLDisplay m_display;
diff --git a/src/plugins/platforms/android/qandroidplatformopenglcontext.cpp b/src/plugins/platforms/android/qandroidplatformopenglcontext.cpp
index 8d98882e9e..faccf8b117 100644
--- a/src/plugins/platforms/android/qandroidplatformopenglcontext.cpp
+++ b/src/plugins/platforms/android/qandroidplatformopenglcontext.cpp
@@ -1,49 +1,13 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 BogDan Vatra <bogdan@kde.org>
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2014 BogDan Vatra <bogdan@kde.org>
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qandroidplatformopenglcontext.h"
#include "qandroidplatformopenglwindow.h"
#include "qandroidplatformintegration.h"
#include "qandroidplatformoffscreensurface.h"
-#include <QtEglSupport/private/qeglpbuffer_p.h>
+#include <QtGui/private/qeglpbuffer_p.h>
#include <QSurface>
#include <QtGui/private/qopenglcontext_p.h>
@@ -51,9 +15,8 @@
QT_BEGIN_NAMESPACE
-QAndroidPlatformOpenGLContext::QAndroidPlatformOpenGLContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, EGLDisplay display,
- const QVariant &nativeHandle)
- :QEGLPlatformContext(format, share, display, nullptr, nativeHandle)
+QAndroidPlatformOpenGLContext::QAndroidPlatformOpenGLContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, EGLDisplay display)
+ : QEGLPlatformContext(format, share, display, nullptr)
{
}
@@ -77,9 +40,8 @@ EGLSurface QAndroidPlatformOpenGLContext::eglSurfaceForPlatformSurface(QPlatform
if (surface->surface()->surfaceClass() == QSurface::Window) {
return static_cast<QAndroidPlatformOpenGLWindow *>(surface)->eglSurface(eglConfig());
} else {
- auto platformOffscreenSurface = static_cast<QPlatformOffscreenSurface*>(surface);
- if (platformOffscreenSurface->offscreenSurface()->nativeHandle())
- return static_cast<QAndroidPlatformOffscreenSurface *>(surface)->surface();
+ if (auto *platformOffscreenSurface = dynamic_cast<QAndroidPlatformOffscreenSurface *>(surface))
+ return platformOffscreenSurface->surface();
else
return static_cast<QEGLPbuffer *>(surface)->pbuffer();
}
diff --git a/src/plugins/platforms/android/qandroidplatformopenglcontext.h b/src/plugins/platforms/android/qandroidplatformopenglcontext.h
index 8e65b4cc36..448f7d0d75 100644
--- a/src/plugins/platforms/android/qandroidplatformopenglcontext.h
+++ b/src/plugins/platforms/android/qandroidplatformopenglcontext.h
@@ -1,60 +1,24 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 BogDan Vatra <bogdan@kde.org>
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2014 BogDan Vatra <bogdan@kde.org>
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QANDROIDPLATFORMOPENGLCONTEXT_H
#define QANDROIDPLATFORMOPENGLCONTEXT_H
-#include <QtEglSupport/private/qeglplatformcontext_p.h>
+#include <QtGui/private/qeglplatformcontext_p.h>
QT_BEGIN_NAMESPACE
class QAndroidPlatformOpenGLContext : public QEGLPlatformContext
{
public:
- QAndroidPlatformOpenGLContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, EGLDisplay display, const QVariant &nativeHandle);
+ using QEGLPlatformContext::QEGLPlatformContext;
+ QAndroidPlatformOpenGLContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, EGLDisplay display);
void swapBuffers(QPlatformSurface *surface) override;
bool makeCurrent(QPlatformSurface *surface) override;
private:
EGLSurface eglSurfaceForPlatformSurface(QPlatformSurface *surface) override;
-
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/android/qandroidplatformopenglwindow.cpp b/src/plugins/platforms/android/qandroidplatformopenglwindow.cpp
index 3de5d30623..13d14eb391 100644
--- a/src/plugins/platforms/android/qandroidplatformopenglwindow.cpp
+++ b/src/plugins/platforms/android/qandroidplatformopenglwindow.cpp
@@ -1,100 +1,42 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 BogDan Vatra <bogdan@kde.org>
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2014 BogDan Vatra <bogdan@kde.org>
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qandroidplatformopenglwindow.h"
-#include "qandroidplatformscreen.h"
+#include "androiddeadlockprotector.h"
#include "androidjnimain.h"
#include "qandroideventdispatcher.h"
-#include "androiddeadlockprotector.h"
+#include "qandroidplatformscreen.h"
#include <QSurfaceFormat>
#include <QtGui/private/qwindow_p.h>
#include <QtGui/qguiapplication.h>
-#include <qpa/qwindowsysteminterface.h>
-#include <qpa/qplatformscreen.h>
-#include <QtEglSupport/private/qeglconvenience_p.h>
+#include <QtGui/private/qeglconvenience_p.h>
#include <android/native_window.h>
#include <android/native_window_jni.h>
+#include <qpa/qplatformscreen.h>
+#include <qpa/qwindowsysteminterface.h>
QT_BEGIN_NAMESPACE
QAndroidPlatformOpenGLWindow::QAndroidPlatformOpenGLWindow(QWindow *window, EGLDisplay display)
:QAndroidPlatformWindow(window), m_eglDisplay(display)
{
+ if (window->surfaceType() == QSurface::RasterSurface)
+ window->setSurfaceType(QSurface::OpenGLSurface);
}
QAndroidPlatformOpenGLWindow::~QAndroidPlatformOpenGLWindow()
{
m_surfaceWaitCondition.wakeOne();
lockSurface();
- if (m_nativeSurfaceId != -1)
- QtAndroid::destroySurface(m_nativeSurfaceId);
+ destroySurface();
clearEgl();
unlockSurface();
}
-void QAndroidPlatformOpenGLWindow::repaint(const QRegion &region)
-{
- // This is only for real raster top-level windows. Stop in all other cases.
- if ((window()->surfaceType() == QSurface::RasterGLSurface && qt_window_private(window())->compositing)
- || window()->surfaceType() == QSurface::OpenGLSurface
- || QAndroidPlatformWindow::parent())
- return;
-
- QRect currentGeometry = geometry();
-
- QRect dirtyClient = region.boundingRect();
- QRect dirtyRegion(currentGeometry.left() + dirtyClient.left(),
- currentGeometry.top() + dirtyClient.top(),
- dirtyClient.width(),
- dirtyClient.height());
- QRect mOldGeometryLocal = m_oldGeometry;
- m_oldGeometry = currentGeometry;
- // If this is a move, redraw the previous location
- if (mOldGeometryLocal != currentGeometry)
- platformScreen()->setDirty(mOldGeometryLocal);
- platformScreen()->setDirty(dirtyRegion);
-}
-
void QAndroidPlatformOpenGLWindow::setGeometry(const QRect &rect)
{
if (rect == geometry())
@@ -103,37 +45,34 @@ void QAndroidPlatformOpenGLWindow::setGeometry(const QRect &rect)
m_oldGeometry = geometry();
QAndroidPlatformWindow::setGeometry(rect);
- if (m_nativeSurfaceId != -1)
- QtAndroid::setSurfaceGeometry(m_nativeSurfaceId, rect);
+
+
+ setNativeGeometry(rect);
QRect availableGeometry = screen()->availableGeometry();
- if (m_oldGeometry.width() == 0
- && m_oldGeometry.height() == 0
- && rect.width() > 0
+ if (rect.width() > 0
&& rect.height() > 0
&& availableGeometry.width() > 0
&& availableGeometry.height() > 0) {
QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(0, 0), rect.size()));
}
-
- if (rect.topLeft() != m_oldGeometry.topLeft())
- repaint(QRegion(rect));
}
EGLSurface QAndroidPlatformOpenGLWindow::eglSurface(EGLConfig config)
{
- if (QAndroidEventDispatcherStopper::stopped() || QGuiApplication::applicationState() == Qt::ApplicationSuspended)
+ if (QAndroidEventDispatcherStopper::stopped() ||
+ QGuiApplication::applicationState() == Qt::ApplicationSuspended) {
return m_eglSurface;
+ }
QMutexLocker lock(&m_surfaceMutex);
- if (m_nativeSurfaceId == -1) {
+ if (!m_surfaceCreated) {
AndroidDeadlockProtector protector;
if (!protector.acquire())
return m_eglSurface;
- const bool windowStaysOnTop = bool(window()->flags() & Qt::WindowStaysOnTopHint);
- m_nativeSurfaceId = QtAndroid::createSurface(this, geometry(), windowStaysOnTop, 32);
+ createSurface();
m_surfaceWaitCondition.wait(&m_surfaceMutex);
}
@@ -148,7 +87,7 @@ EGLSurface QAndroidPlatformOpenGLWindow::eglSurface(EGLConfig config)
bool QAndroidPlatformOpenGLWindow::checkNativeSurface(EGLConfig config)
{
QMutexLocker lock(&m_surfaceMutex);
- if (m_nativeSurfaceId == -1 || !m_androidSurfaceObject.isValid())
+ if (!m_surfaceCreated || !m_androidSurfaceObject.isValid())
return false; // makeCurrent is NOT needed.
createEgl(config);
@@ -165,10 +104,7 @@ void QAndroidPlatformOpenGLWindow::applicationStateChanged(Qt::ApplicationState
QAndroidPlatformWindow::applicationStateChanged(state);
if (state <= Qt::ApplicationHidden) {
lockSurface();
- if (m_nativeSurfaceId != -1) {
- QtAndroid::destroySurface(m_nativeSurfaceId);
- m_nativeSurfaceId = -1;
- }
+ destroySurface();
clearEgl();
unlockSurface();
}
@@ -177,9 +113,9 @@ void QAndroidPlatformOpenGLWindow::applicationStateChanged(Qt::ApplicationState
void QAndroidPlatformOpenGLWindow::createEgl(EGLConfig config)
{
clearEgl();
- QJNIEnvironmentPrivate env;
- m_nativeWindow = ANativeWindow_fromSurface(env, m_androidSurfaceObject.object());
- m_androidSurfaceObject = QJNIObjectPrivate();
+ QJniEnvironment env;
+ m_nativeWindow = ANativeWindow_fromSurface(env.jniEnv(), m_androidSurfaceObject.object());
+ m_androidSurfaceObject = QJniObject();
m_eglSurface = eglCreateWindowSurface(m_eglDisplay, config, m_nativeWindow, NULL);
m_format = q_glFormatFromConfig(m_eglDisplay, config, window()->requestedFormat());
if (Q_UNLIKELY(m_eglSurface == EGL_NO_SURFACE)) {
@@ -193,8 +129,8 @@ QSurfaceFormat QAndroidPlatformOpenGLWindow::format() const
{
if (m_nativeWindow == 0)
return window()->requestedFormat();
- else
- return m_format;
+
+ return m_format;
}
void QAndroidPlatformOpenGLWindow::clearEgl()
@@ -211,24 +147,4 @@ void QAndroidPlatformOpenGLWindow::clearEgl()
}
}
-void QAndroidPlatformOpenGLWindow::surfaceChanged(JNIEnv *jniEnv, jobject surface, int w, int h)
-{
- Q_UNUSED(jniEnv);
- Q_UNUSED(w);
- Q_UNUSED(h);
-
- lockSurface();
- m_androidSurfaceObject = surface;
- if (surface) // wait until we have a valid surface to draw into
- m_surfaceWaitCondition.wakeOne();
- unlockSurface();
-
- if (surface) {
- // repaint the window, when we have a valid surface
- QRect availableGeometry = screen()->availableGeometry();
- if (geometry().width() > 0 && geometry().height() > 0 && availableGeometry.width() > 0 && availableGeometry.height() > 0)
- QWindowSystemInterface::handleExposeEvent(window(), QRegion(QRect(QPoint(), geometry().size())));
- }
-}
-
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/android/qandroidplatformopenglwindow.h b/src/plugins/platforms/android/qandroidplatformopenglwindow.h
index d3072f766d..c1ae57fe85 100644
--- a/src/plugins/platforms/android/qandroidplatformopenglwindow.h
+++ b/src/plugins/platforms/android/qandroidplatformopenglwindow.h
@@ -1,56 +1,21 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 BogDan Vatra <bogdan@kde.org>
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2014 BogDan Vatra <bogdan@kde.org>
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QANDROIDPLATFORMOPENGLWINDOW_H
#define QANDROIDPLATFORMOPENGLWINDOW_H
-#include <EGL/egl.h>
+#include "qandroidplatformwindow.h"
+
#include <QWaitCondition>
-#include <QtCore/private/qjni_p.h>
+#include <QtCore/qjnienvironment.h>
+#include <QtCore/qjniobject.h>
-#include "androidsurfaceclient.h"
-#include "qandroidplatformwindow.h"
+#include <EGL/egl.h>
QT_BEGIN_NAMESPACE
-class QAndroidPlatformOpenGLWindow : public QAndroidPlatformWindow, public AndroidSurfaceClient
+class QAndroidPlatformOpenGLWindow : public QAndroidPlatformWindow
{
public:
explicit QAndroidPlatformOpenGLWindow(QWindow *window, EGLDisplay display);
@@ -64,10 +29,7 @@ public:
void applicationStateChanged(Qt::ApplicationState) override;
- void repaint(const QRegion &region) override;
-
protected:
- void surfaceChanged(JNIEnv *jniEnv, jobject surface, int w, int h) override;
void createEgl(EGLConfig config);
void clearEgl();
@@ -76,9 +38,6 @@ private:
EGLSurface m_eglSurface = EGL_NO_SURFACE;
EGLNativeWindowType m_nativeWindow = nullptr;
- int m_nativeSurfaceId = -1;
- QJNIObjectPrivate m_androidSurfaceObject;
- QWaitCondition m_surfaceWaitCondition;
QSurfaceFormat m_format;
QRect m_oldGeometry;
};
diff --git a/src/plugins/platforms/android/qandroidplatformscreen.cpp b/src/plugins/platforms/android/qandroidplatformscreen.cpp
index 80757c2135..9e20b7ac4b 100644
--- a/src/plugins/platforms/android/qandroidplatformscreen.cpp
+++ b/src/plugins/platforms/android/qandroidplatformscreen.cpp
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 BogDan Vatra <bogdan@kde.org>
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2014 BogDan Vatra <bogdan@kde.org>
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QDebug>
#include <QTime>
@@ -44,7 +8,6 @@
#include <qpa/qwindowsysteminterface.h>
#include "qandroidplatformscreen.h"
-#include "qandroidplatformbackingstore.h"
#include "qandroidplatformintegration.h"
#include "qandroidplatformwindow.h"
#include "androidjnimain.h"
@@ -55,10 +18,11 @@
#include <android/native_window_jni.h>
#include <qguiapplication.h>
+#include <QtCore/QJniObject>
+#include <QtCore/QJniEnvironment>
#include <QtGui/QGuiApplication>
#include <QtGui/QWindow>
#include <QtGui/private/qwindow_p.h>
-
#include <vector>
QT_BEGIN_NAMESPACE
@@ -87,11 +51,22 @@ private:
# define PROFILE_SCOPE
#endif
-QAndroidPlatformScreen::QAndroidPlatformScreen()
+Q_DECLARE_JNI_CLASS(Display, "android/view/Display")
+Q_DECLARE_JNI_CLASS(DisplayMetrics, "android/util/DisplayMetrics")
+Q_DECLARE_JNI_CLASS(Resources, "android/content/res/Resources")
+Q_DECLARE_JNI_CLASS(Size, "android/util/Size")
+Q_DECLARE_JNI_CLASS(QtNative, "org/qtproject/qt/android/QtNative")
+Q_DECLARE_JNI_CLASS(QtDisplayManager, "org/qtproject/qt/android/QtDisplayManager")
+
+Q_DECLARE_JNI_CLASS(DisplayMode, "android/view/Display$Mode")
+
+QAndroidPlatformScreen::QAndroidPlatformScreen(const QJniObject &displayObject)
: QObject(), QPlatformScreen()
{
- m_availableGeometry = QRect(0, 0, QAndroidPlatformIntegration::m_defaultGeometryWidth, QAndroidPlatformIntegration::m_defaultGeometryHeight);
- m_size = QSize(QAndroidPlatformIntegration::m_defaultScreenWidth, QAndroidPlatformIntegration::m_defaultScreenHeight);
+ m_availableGeometry = QAndroidPlatformIntegration::m_defaultAvailableGeometry;
+ m_size = QAndroidPlatformIntegration::m_defaultScreenSize;
+ m_physicalSize = QAndroidPlatformIntegration::m_defaultPhysicalSize;
+
// Raster only apps should set QT_ANDROID_RASTER_IMAGE_DEPTH to 16
// is way much faster than 32
if (qEnvironmentVariableIntValue("QT_ANDROID_RASTER_IMAGE_DEPTH") == 16) {
@@ -101,30 +76,72 @@ QAndroidPlatformScreen::QAndroidPlatformScreen()
m_format = QImage::Format_ARGB32_Premultiplied;
m_depth = 32;
}
- m_physicalSize.setHeight(QAndroidPlatformIntegration::m_defaultPhysicalSizeHeight);
- m_physicalSize.setWidth(QAndroidPlatformIntegration::m_defaultPhysicalSizeWidth);
- connect(qGuiApp, &QGuiApplication::applicationStateChanged, this, &QAndroidPlatformScreen::applicationStateChanged);
+
+ connect(qGuiApp, &QGuiApplication::applicationStateChanged, this,
+ &QAndroidPlatformScreen::applicationStateChanged);
+
+ if (!displayObject.isValid())
+ return;
+
+ m_name = displayObject.callObjectMethod<jstring>("getName").toString();
+ m_refreshRate = displayObject.callMethod<jfloat>("getRefreshRate");
+ m_displayId = displayObject.callMethod<jint>("getDisplayId");
+
+ const QJniObject context = QNativeInterface::QAndroidApplication::context();
+ const auto displayContext = context.callMethod<QtJniTypes::Context>("createDisplayContext",
+ displayObject.object<QtJniTypes::Display>());
+
+ const auto sizeObj = QtJniTypes::QtDisplayManager::callStaticMethod<QtJniTypes::Size>(
+ "getDisplaySize", displayContext,
+ displayObject.object<QtJniTypes::Display>());
+ m_size = QSize(sizeObj.callMethod<int>("getWidth"), sizeObj.callMethod<int>("getHeight"));
+
+ const auto resources = displayContext.callMethod<QtJniTypes::Resources>("getResources");
+ const auto metrics = resources.callMethod<QtJniTypes::DisplayMetrics>("getDisplayMetrics");
+ const float xdpi = metrics.getField<float>("xdpi");
+ const float ydpi = metrics.getField<float>("ydpi");
+
+ // Potentially densityDpi could be used instead of xpdi/ydpi to do the calculation,
+ // but the results are not consistent with devices specs.
+ // (https://issuetracker.google.com/issues/194120500)
+ m_physicalSize.setWidth(qRound(m_size.width() / xdpi * 25.4));
+ m_physicalSize.setHeight(qRound(m_size.height() / ydpi * 25.4));
+
+ if (QNativeInterface::QAndroidApplication::sdkVersion() >= 23) {
+ const QJniObject currentMode = displayObject.callObjectMethod<QtJniTypes::DisplayMode>("getMode");
+ m_currentMode = currentMode.callMethod<jint>("getModeId");
+
+ const QJniObject supportedModes = displayObject.callObjectMethod<QtJniTypes::DisplayMode[]>(
+ "getSupportedModes");
+ const auto modeArray = jobjectArray(supportedModes.object());
+
+ QJniEnvironment env;
+ const auto size = env->GetArrayLength(modeArray);
+ for (jsize i = 0; i < size; ++i) {
+ const auto mode = QJniObject::fromLocalRef(env->GetObjectArrayElement(modeArray, i));
+ m_modes << QPlatformScreen::Mode {
+ .size = QSize { mode.callMethod<jint>("getPhysicalWidth"),
+ mode.callMethod<jint>("getPhysicalHeight") },
+ .refreshRate = mode.callMethod<jfloat>("getRefreshRate")
+ };
+ }
+ }
}
QAndroidPlatformScreen::~QAndroidPlatformScreen()
{
- if (m_id != -1) {
- QtAndroid::destroySurface(m_id);
- m_surfaceWaitCondition.wakeOne();
- releaseSurface();
- }
}
-QWindow *QAndroidPlatformScreen::topWindow() const
+QWindow *QAndroidPlatformScreen::topVisibleWindow() const
{
for (QAndroidPlatformWindow *w : m_windowStack) {
- if (w->window()->type() == Qt::Window ||
- w->window()->type() == Qt::Popup ||
- w->window()->type() == Qt::Dialog) {
+ Qt::WindowType type = w->window()->type();
+ if (w->window()->isVisible() &&
+ (type == Qt::Window || type == Qt::Popup || type == Qt::Dialog)) {
return w->window();
}
}
- return 0;
+ return nullptr;
}
QWindow *QAndroidPlatformScreen::topLevelAt(const QPoint &p) const
@@ -136,116 +153,105 @@ QWindow *QAndroidPlatformScreen::topLevelAt(const QPoint &p) const
return 0;
}
-bool QAndroidPlatformScreen::event(QEvent *event)
-{
- if (event->type() == QEvent::UpdateRequest) {
- doRedraw();
- m_updatePending = false;
- return true;
- }
- return QObject::event(event);
-}
-
void QAndroidPlatformScreen::addWindow(QAndroidPlatformWindow *window)
{
if (window->parent() && window->isRaster())
return;
- Q_ASSERT(!m_windowStack.contains(window));
+ if (m_windowStack.contains(window))
+ return;
+
m_windowStack.prepend(window);
- if (window->isRaster()) {
- m_rasterSurfaces.ref();
- setDirty(window->geometry());
- }
+ QtAndroid::qtActivityDelegate().callMethod<void>("addTopLevelWindow", window->nativeWindow());
- QWindow *w = topWindow();
- QWindowSystemInterface::handleWindowActivated(w);
- topWindowChanged(w);
+ if (window->window()->isVisible())
+ topVisibleWindowChanged();
}
void QAndroidPlatformScreen::removeWindow(QAndroidPlatformWindow *window)
{
- if (window->parent() && window->isRaster())
- return;
-
-
- Q_ASSERT(m_windowStack.contains(window));
m_windowStack.removeOne(window);
- Q_ASSERT(!m_windowStack.contains(window));
- if (window->isRaster()) {
- m_rasterSurfaces.deref();
- setDirty(window->geometry());
- }
+ if (m_windowStack.contains(window))
+ qWarning() << "Failed to remove window";
+
+ QtAndroid::qtActivityDelegate().callMethod<void>("removeTopLevelWindow", window->nativeViewId());
- QWindow *w = topWindow();
- QWindowSystemInterface::handleWindowActivated(w);
- topWindowChanged(w);
+ topVisibleWindowChanged();
}
void QAndroidPlatformScreen::raise(QAndroidPlatformWindow *window)
{
- if (window->parent() && window->isRaster())
- return;
-
int index = m_windowStack.indexOf(window);
- if (index <= 0)
+ if (index < 0)
return;
- m_windowStack.move(index, 0);
- if (window->isRaster()) {
- setDirty(window->geometry());
+ if (index > 0) {
+ m_windowStack.move(index, 0);
+ QtAndroid::qtActivityDelegate().callMethod<void>("bringChildToFront", window->nativeViewId());
}
- QWindow *w = topWindow();
- QWindowSystemInterface::handleWindowActivated(w);
- topWindowChanged(w);
+ topVisibleWindowChanged();
}
void QAndroidPlatformScreen::lower(QAndroidPlatformWindow *window)
{
- if (window->parent() && window->isRaster())
- return;
-
int index = m_windowStack.indexOf(window);
if (index == -1 || index == (m_windowStack.size() - 1))
return;
m_windowStack.move(index, m_windowStack.size() - 1);
- if (window->isRaster()) {
- setDirty(window->geometry());
- }
- QWindow *w = topWindow();
- QWindowSystemInterface::handleWindowActivated(w);
- topWindowChanged(w);
+ QtAndroid::qtActivityDelegate().callMethod<void>("bringChildToBack", window->nativeViewId());
+
+ topVisibleWindowChanged();
}
-void QAndroidPlatformScreen::scheduleUpdate()
+void QAndroidPlatformScreen::setPhysicalSize(const QSize &size)
+{
+ m_physicalSize = size;
+}
+
+void QAndroidPlatformScreen::setSize(const QSize &size)
{
- if (!m_updatePending) {
- m_updatePending = true;
- QCoreApplication::postEvent(this, new QEvent(QEvent::UpdateRequest));
+ m_size = size;
+ QWindowSystemInterface::handleScreenGeometryChange(QPlatformScreen::screen(), geometry(), availableGeometry());
+}
+
+void QAndroidPlatformScreen::setSizeParameters(const QSize &physicalSize, const QSize &size,
+ const QRect &availableGeometry)
+{
+ // The goal of this method is to set all geometry-related parameters
+ // at the same time and generate only one screen geometry change event.
+ m_physicalSize = physicalSize;
+ m_size = size;
+ // If available geometry has changed, the event will be handled in
+ // setAvailableGeometry. Otherwise we need to explicitly handle it to
+ // retain the behavior, because setSize() does the handling unconditionally.
+ if (m_availableGeometry != availableGeometry) {
+ setAvailableGeometry(availableGeometry);
+ } else {
+ QWindowSystemInterface::handleScreenGeometryChange(QPlatformScreen::screen(), geometry(),
+ this->availableGeometry());
}
}
-void QAndroidPlatformScreen::setDirty(const QRect &rect)
+int QAndroidPlatformScreen::displayId() const
{
- QRect intersection = rect.intersected(m_availableGeometry);
- m_dirtyRect |= intersection;
- scheduleUpdate();
+ return m_displayId;
}
-void QAndroidPlatformScreen::setPhysicalSize(const QSize &size)
+void QAndroidPlatformScreen::setRefreshRate(qreal refreshRate)
{
- m_physicalSize = size;
+ if (refreshRate == m_refreshRate)
+ return;
+ m_refreshRate = refreshRate;
+ QWindowSystemInterface::handleScreenRefreshRateChange(QPlatformScreen::screen(), refreshRate);
}
-void QAndroidPlatformScreen::setSize(const QSize &size)
+void QAndroidPlatformScreen::setOrientation(Qt::ScreenOrientation orientation)
{
- m_size = size;
- QWindowSystemInterface::handleScreenGeometryChange(QPlatformScreen::screen(), geometry(), availableGeometry());
+ QWindowSystemInterface::handleScreenOrientationChange(QPlatformScreen::screen(), orientation);
}
void QAndroidPlatformScreen::setAvailableGeometry(const QRect &rect)
{
- QMutexLocker lock(&m_surfaceMutex);
if (m_availableGeometry == rect)
return;
@@ -266,146 +272,31 @@ void QAndroidPlatformScreen::setAvailableGeometry(const QRect &rect)
}
}
}
-
- if (m_id != -1) {
- releaseSurface();
- QtAndroid::setSurfaceGeometry(m_id, rect);
- }
}
void QAndroidPlatformScreen::applicationStateChanged(Qt::ApplicationState state)
{
- for (QAndroidPlatformWindow *w : qAsConst(m_windowStack))
+ for (QAndroidPlatformWindow *w : std::as_const(m_windowStack))
w->applicationStateChanged(state);
-
- if (state <= Qt::ApplicationHidden) {
- lockSurface();
- QtAndroid::destroySurface(m_id);
- m_id = -1;
- releaseSurface();
- unlockSurface();
- }
}
-void QAndroidPlatformScreen::topWindowChanged(QWindow *w)
+void QAndroidPlatformScreen::topVisibleWindowChanged()
{
+ QWindow *w = topVisibleWindow();
+ QWindowSystemInterface::handleFocusWindowChanged(w, Qt::ActiveWindowFocusReason);
QtAndroidMenu::setActiveTopLevelWindow(w);
-
- if (w != 0) {
+ if (w && w->handle()) {
QAndroidPlatformWindow *platformWindow = static_cast<QAndroidPlatformWindow *>(w->handle());
- if (platformWindow != 0)
- platformWindow->updateStatusBarVisibility();
- }
-}
-
-int QAndroidPlatformScreen::rasterSurfaces()
-{
- return m_rasterSurfaces;
-}
-
-void QAndroidPlatformScreen::doRedraw()
-{
- PROFILE_SCOPE;
- if (!QtAndroid::activity())
- return;
-
- if (m_dirtyRect.isEmpty())
- return;
-
- // Stop if there are no visible raster windows. If we only have RasterGLSurface
- // windows that have renderToTexture children (i.e. they need the OpenGL path) then
- // we do not need an overlay surface.
- bool hasVisibleRasterWindows = false;
- for (QAndroidPlatformWindow *window : qAsConst(m_windowStack)) {
- if (window->window()->isVisible() && window->isRaster() && !qt_window_private(window->window())->compositing) {
- hasVisibleRasterWindows = true;
- break;
- }
- }
- if (!hasVisibleRasterWindows) {
- lockSurface();
- if (m_id != -1) {
- QtAndroid::destroySurface(m_id);
- releaseSurface();
- m_id = -1;
- }
- unlockSurface();
- return;
- }
- QMutexLocker lock(&m_surfaceMutex);
- if (m_id == -1 && m_rasterSurfaces) {
- m_id = QtAndroid::createSurface(this, m_availableGeometry, true, m_depth);
- AndroidDeadlockProtector protector;
- if (!protector.acquire())
- return;
- m_surfaceWaitCondition.wait(&m_surfaceMutex);
- }
-
- if (!m_nativeSurface)
- return;
-
- ANativeWindow_Buffer nativeWindowBuffer;
- ARect nativeWindowRect;
- nativeWindowRect.top = m_dirtyRect.top();
- nativeWindowRect.left = m_dirtyRect.left();
- nativeWindowRect.bottom = m_dirtyRect.bottom() + 1; // for some reason that I don't understand the QRect bottom needs to +1 to be the same with ARect bottom
- nativeWindowRect.right = m_dirtyRect.right() + 1; // same for the right
-
- int ret;
- if ((ret = ANativeWindow_lock(m_nativeSurface, &nativeWindowBuffer, &nativeWindowRect)) < 0) {
- qWarning() << "ANativeWindow_lock() failed! error=" << ret;
- return;
- }
-
- int bpp = 4;
- QImage::Format format = QImage::Format_RGBA8888_Premultiplied;
- if (nativeWindowBuffer.format == WINDOW_FORMAT_RGB_565) {
- bpp = 2;
- format = QImage::Format_RGB16;
- }
-
- QImage screenImage(reinterpret_cast<uchar *>(nativeWindowBuffer.bits)
- , nativeWindowBuffer.width, nativeWindowBuffer.height
- , nativeWindowBuffer.stride * bpp , format);
-
- QPainter compositePainter(&screenImage);
- compositePainter.setCompositionMode(QPainter::CompositionMode_Source);
-
- QRegion visibleRegion(m_dirtyRect);
- for (QAndroidPlatformWindow *window : qAsConst(m_windowStack)) {
- if (!window->window()->isVisible()
- || qt_window_private(window->window())->compositing
- || !window->isRaster())
- continue;
-
- for (const QRect &rect : std::vector<QRect>(visibleRegion.begin(), visibleRegion.end())) {
- QRect targetRect = window->geometry();
- targetRect &= rect;
-
- if (targetRect.isNull())
- continue;
-
- visibleRegion -= targetRect;
- QRect windowRect = targetRect.translated(-window->geometry().topLeft());
- QAndroidPlatformBackingStore *backingStore = static_cast<QAndroidPlatformWindow *>(window)->backingStore();
- if (backingStore)
- compositePainter.drawImage(targetRect.topLeft(), backingStore->toImage(), windowRect);
- }
+ if (platformWindow)
+ platformWindow->updateSystemUiVisibility();
}
-
- for (const QRect &rect : visibleRegion)
- compositePainter.fillRect(rect, QColor(Qt::transparent));
-
- ret = ANativeWindow_unlockAndPost(m_nativeSurface);
- if (ret >= 0)
- m_dirtyRect = QRect();
}
static const int androidLogicalDpi = 72;
QDpi QAndroidPlatformScreen::logicalDpi() const
{
- qreal lDpi = QtAndroid::scaledDensity() * androidLogicalDpi;
+ qreal lDpi = QtAndroid::pixelDensity() * androidLogicalDpi;
return QDpi(lDpi, lDpi);
}
@@ -423,27 +314,4 @@ Qt::ScreenOrientation QAndroidPlatformScreen::nativeOrientation() const
{
return QAndroidPlatformIntegration::m_nativeOrientation;
}
-
-void QAndroidPlatformScreen::surfaceChanged(JNIEnv *env, jobject surface, int w, int h)
-{
- lockSurface();
- if (surface && w > 0 && h > 0) {
- releaseSurface();
- m_nativeSurface = ANativeWindow_fromSurface(env, surface);
- QMetaObject::invokeMethod(this, "setDirty", Qt::QueuedConnection, Q_ARG(QRect, QRect(0, 0, w, h)));
- } else {
- releaseSurface();
- }
- unlockSurface();
- m_surfaceWaitCondition.wakeOne();
-}
-
-void QAndroidPlatformScreen::releaseSurface()
-{
- if (m_nativeSurface) {
- ANativeWindow_release(m_nativeSurface);
- m_nativeSurface = 0;
- }
-}
-
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/android/qandroidplatformscreen.h b/src/plugins/platforms/android/qandroidplatformscreen.h
index 5dc158e351..d850d0db09 100644
--- a/src/plugins/platforms/android/qandroidplatformscreen.h
+++ b/src/plugins/platforms/android/qandroidplatformscreen.h
@@ -1,66 +1,30 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 BogDan Vatra <bogdan@kde.org>
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2014 BogDan Vatra <bogdan@kde.org>
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QANDROIDPLATFORMSCREEN_H
#define QANDROIDPLATFORMSCREEN_H
-#include <qpa/qplatformscreen.h>
#include <QList>
#include <QPainter>
#include <QTimer>
#include <QWaitCondition>
-#include <QtCore/private/qjni_p.h>
-
-#include "androidsurfaceclient.h"
-
-#include <android/native_window.h>
+#include <QtCore/QJniObject>
+#include <qpa/qplatformscreen.h>
+#include <QtGui/qscreen_platform.h>
QT_BEGIN_NAMESPACE
class QAndroidPlatformWindow;
-class QAndroidPlatformScreen: public QObject, public QPlatformScreen, public AndroidSurfaceClient
+
+class QAndroidPlatformScreen : public QObject,
+ public QPlatformScreen,
+ public QNativeInterface::QAndroidScreen
{
Q_OBJECT
public:
- QAndroidPlatformScreen();
+ QAndroidPlatformScreen(const QJniObject &displayObject);
~QAndroidPlatformScreen();
QRect geometry() const override { return QRect(QPoint(), m_size); }
@@ -69,55 +33,50 @@ public:
QImage::Format format() const override { return m_format; }
QSizeF physicalSize() const override { return m_physicalSize; }
- inline QWindow *topWindow() const;
+ QString name() const override { return m_name; }
+ QList<Mode> modes() const override { return m_modes; }
+ int currentMode() const override { return m_currentMode; }
+ int preferredMode() const override { return m_currentMode; }
+ qreal refreshRate() const override { return m_refreshRate; }
+ inline QWindow *topVisibleWindow() const;
QWindow *topLevelAt(const QPoint & p) const override;
- // compositor api
void addWindow(QAndroidPlatformWindow *window);
void removeWindow(QAndroidPlatformWindow *window);
void raise(QAndroidPlatformWindow *window);
void lower(QAndroidPlatformWindow *window);
-
- void scheduleUpdate();
- void topWindowChanged(QWindow *w);
- int rasterSurfaces();
+ void topVisibleWindowChanged();
+ int displayId() const override;
public slots:
- void setDirty(const QRect &rect);
void setPhysicalSize(const QSize &size);
void setAvailableGeometry(const QRect &rect);
void setSize(const QSize &size);
+ void setSizeParameters(const QSize &physicalSize, const QSize &size,
+ const QRect &availableGeometry);
+ void setRefreshRate(qreal refreshRate);
+ void setOrientation(Qt::ScreenOrientation orientation);
protected:
- bool event(QEvent *event) override;
-
typedef QList<QAndroidPlatformWindow *> WindowStackType;
WindowStackType m_windowStack;
- QRect m_dirtyRect;
- bool m_updatePending = false;
-
QRect m_availableGeometry;
int m_depth;
QImage::Format m_format;
QSizeF m_physicalSize;
+ qreal m_refreshRate;
+ QString m_name;
+ QList<Mode> m_modes;
+ int m_currentMode = 0;
+ int m_displayId = -1;
private:
QDpi logicalDpi() const override;
QDpi logicalBaseDpi() const override;
Qt::ScreenOrientation orientation() const override;
Qt::ScreenOrientation nativeOrientation() const override;
- void surfaceChanged(JNIEnv *env, jobject surface, int w, int h) override;
- void releaseSurface();
void applicationStateChanged(Qt::ApplicationState);
-
-private slots:
- void doRedraw();
-
private:
- int m_id = -1;
- QAtomicInt m_rasterSurfaces = 0;
- ANativeWindow* m_nativeSurface = nullptr;
- QWaitCondition m_surfaceWaitCondition;
QSize m_size;
};
diff --git a/src/plugins/platforms/android/qandroidplatformservices.cpp b/src/plugins/platforms/android/qandroidplatformservices.cpp
index 136637800b..f43e7cdd6a 100644
--- a/src/plugins/platforms/android/qandroidplatformservices.cpp
+++ b/src/plugins/platforms/android/qandroidplatformservices.cpp
@@ -1,76 +1,95 @@
-/****************************************************************************
-**
-** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qandroidplatformservices.h"
-#include <QUrl>
-#include <QFile>
+
#include <QDebug>
+#include <QDesktopServices>
+#include <QFile>
#include <QMimeDatabase>
-#include <QtCore/private/qjni_p.h>
+#include <QtCore/QJniObject>
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qscopedvaluerollback.h>
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
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);
}
+Q_DECLARE_JNI_CLASS(UriType, "android/net/Uri")
+Q_DECLARE_JNI_CLASS(FileType, "java/io/File")
+Q_DECLARE_JNI_CLASS(File, "java/io/File")
+Q_DECLARE_JNI_CLASS(FileProvider, "androidx/core/content/FileProvider");
+
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
- if ((url.scheme().isEmpty() && QFile::exists(url.path())) || url.isLocalFile()) {
- // a real URL including the scheme is needed, else the Intent can not be started
- url.setScheme(QLatin1String("file"));
-
- QMimeDatabase mimeDb;
- mime = mimeDb.mimeTypeForUrl(url).name();
- }
-
- QJNIObjectPrivate urlString = QJNIObjectPrivate::fromString(url.toString());
- QJNIObjectPrivate mimeString = QJNIObjectPrivate::fromString(mime);
- return QJNIObjectPrivate::callStaticMethod<jboolean>(QtAndroid::applicationClass(),
- "openURL",
- "(Ljava/lang/String;Ljava/lang/String;)Z",
- urlString.object(), mimeString.object());
+ const auto fileScheme = "file"_L1;
+
+ // a real URL including the scheme is needed, else the Intent can not be started
+ if (url.scheme().isEmpty())
+ url.setScheme(fileScheme);
+
+ if (url.scheme() == fileScheme)
+ mime = QMimeDatabase().mimeTypeForUrl(url).name();
+
+ const QJniObject mimeString = QJniObject::fromString(mime);
+
+ using namespace QNativeInterface;
+
+ auto openUrl = [mimeString](const QJniObject &url) {
+ return QJniObject::callStaticMethod<jboolean>(QtAndroid::applicationClass(), "openURL",
+ QAndroidApplication::context(), url.object<jstring>(), mimeString.object<jstring>());
+ };
+
+ if (url.scheme() != fileScheme || QNativeInterface::QAndroidApplication::sdkVersion() < 24)
+ return openUrl(QJniObject::fromString(url.toString()));
+
+ // Use FileProvider for file scheme with sdk >= 24
+ const QJniObject context = QAndroidApplication::context();
+ const auto appId = context.callMethod<jstring>("getPackageName").toString();
+ const auto providerName = QJniObject::fromString(appId + ".qtprovider"_L1);
+
+ const auto urlPath = QJniObject::fromString(url.path());
+ const auto urlFile = QJniObject(QtJniTypes::Traits<QtJniTypes::File>::className(),
+ urlPath.object<jstring>());
+
+ const auto fileProviderUri = QJniObject::callStaticMethod<QtJniTypes::UriType>(
+ QtJniTypes::Traits<QtJniTypes::FileProvider>::className(), "getUriForFile",
+ QAndroidApplication::context(), providerName.object<jstring>(),
+ urlFile.object<QtJniTypes::FileType>());
+
+ if (fileProviderUri.isValid())
+ return openUrl(fileProviderUri.callMethod<jstring>("toString"));
+
+ return false;
}
bool QAndroidPlatformServices::openDocument(const QUrl &url)
@@ -83,4 +102,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..762d14deeb 100644
--- a/src/plugins/platforms/android/qandroidplatformservices.h
+++ b/src/plugins/platforms/android/qandroidplatformservices.h
@@ -1,57 +1,33 @@
-/****************************************************************************
-**
-** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef ANDROIDPLATFORMDESKTOPSERVICE_H
#define ANDROIDPLATFORMDESKTOPSERVICE_H
#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 d3a8a53241..7b9072df69 100644
--- a/src/plugins/platforms/android/qandroidplatformtheme.cpp
+++ b/src/plugins/platforms/android/qandroidplatformtheme.cpp
@@ -1,45 +1,10 @@
-/****************************************************************************
-**
-** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "androidjnimain.h"
#include "androidjnimenu.h"
#include "qandroidplatformtheme.h"
+#include "qandroidplatformiconengine.h"
#include "qandroidplatformmenubar.h"
#include "qandroidplatformmenu.h"
#include "qandroidplatformmenuitem.h"
@@ -58,6 +23,10 @@
QT_BEGIN_NAMESPACE
+Q_LOGGING_CATEGORY(lcQpaMenus, "qt.qpa.menus")
+
+using namespace Qt::StringLiterals;
+
namespace {
const int textStyle_bold = 1;
const int textStyle_italic = 2;
@@ -69,44 +38,44 @@ namespace {
static int fontType(const QString &androidControl)
{
- if (androidControl == QLatin1String("defaultStyle"))
+ if (androidControl == "defaultStyle"_L1)
return QPlatformTheme::SystemFont;
- if (androidControl == QLatin1String("textViewStyle"))
+ if (androidControl == "textViewStyle"_L1)
return QPlatformTheme::LabelFont;
- else if (androidControl == QLatin1String("buttonStyle"))
+ else if (androidControl == "buttonStyle"_L1)
return QPlatformTheme::PushButtonFont;
- else if (androidControl == QLatin1String("checkboxStyle"))
+ else if (androidControl == "checkboxStyle"_L1)
return QPlatformTheme::CheckBoxFont;
- else if (androidControl == QLatin1String("radioButtonStyle"))
+ else if (androidControl == "radioButtonStyle"_L1)
return QPlatformTheme::RadioButtonFont;
- else if (androidControl == QLatin1String("simple_list_item_single_choice"))
+ else if (androidControl == "simple_list_item_single_choice"_L1)
return QPlatformTheme::ItemViewFont;
- else if (androidControl == QLatin1String("simple_spinner_dropdown_item"))
+ else if (androidControl == "simple_spinner_dropdown_item"_L1)
return QPlatformTheme::ComboMenuItemFont;
- else if (androidControl == QLatin1String("spinnerStyle"))
+ else if (androidControl == "spinnerStyle"_L1)
return QPlatformTheme::ComboLineEditFont;
- else if (androidControl == QLatin1String("simple_list_item"))
+ else if (androidControl == "simple_list_item"_L1)
return QPlatformTheme::ListViewFont;
return -1;
}
static int paletteType(const QString &androidControl)
{
- if (androidControl == QLatin1String("defaultStyle"))
+ if (androidControl == "defaultStyle"_L1)
return QPlatformTheme::SystemPalette;
- if (androidControl == QLatin1String("textViewStyle"))
+ if (androidControl == "textViewStyle"_L1)
return QPlatformTheme::LabelPalette;
- else if (androidControl == QLatin1String("buttonStyle"))
+ else if (androidControl == "buttonStyle"_L1)
return QPlatformTheme::ButtonPalette;
- else if (androidControl == QLatin1String("checkboxStyle"))
+ else if (androidControl == "checkboxStyle"_L1)
return QPlatformTheme::CheckBoxPalette;
- else if (androidControl == QLatin1String("radioButtonStyle"))
+ else if (androidControl == "radioButtonStyle"_L1)
return QPlatformTheme::RadioButtonPalette;
- else if (androidControl == QLatin1String("simple_list_item_single_choice"))
+ else if (androidControl == "simple_list_item_single_choice"_L1)
return QPlatformTheme::ItemViewPalette;
- else if (androidControl == QLatin1String("editTextStyle"))
+ else if (androidControl == "editTextStyle"_L1)
return QPlatformTheme::TextLineEditPalette;
- else if (androidControl == QLatin1String("spinnerStyle"))
+ else if (androidControl == "spinnerStyle"_L1)
return QPlatformTheme::ComboBoxPalette;
return -1;
}
@@ -118,17 +87,17 @@ static void setPaletteColor(const QVariantMap &object,
// QPalette::Active -> ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET
palette.setColor(QPalette::Active,
role,
- QRgb(object.value(QLatin1String("ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET")).toInt()));
+ QRgb(object.value("ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET"_L1).toInt()));
// QPalette::Inactive -> ENABLED_STATE_SET
palette.setColor(QPalette::Inactive,
role,
- QRgb(object.value(QLatin1String("ENABLED_STATE_SET")).toInt()));
+ QRgb(object.value("ENABLED_STATE_SET"_L1).toInt()));
// QPalette::Disabled -> EMPTY_STATE_SET
palette.setColor(QPalette::Disabled,
role,
- QRgb(object.value(QLatin1String("EMPTY_STATE_SET")).toInt()));
+ QRgb(object.value("EMPTY_STATE_SET"_L1).toInt()));
palette.setColor(QPalette::Current, role, palette.color(QPalette::Active, role));
@@ -137,17 +106,17 @@ static void setPaletteColor(const QVariantMap &object,
// QPalette::Active -> PRESSED_ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET
palette.setColor(QPalette::Active,
QPalette::BrightText,
- QRgb(object.value(QLatin1String("PRESSED_ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET")).toInt()));
+ QRgb(object.value("PRESSED_ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET"_L1).toInt()));
// QPalette::Inactive -> PRESSED_ENABLED_STATE_SET
palette.setColor(QPalette::Inactive,
QPalette::BrightText,
- QRgb(object.value(QLatin1String("PRESSED_ENABLED_STATE_SET")).toInt()));
+ QRgb(object.value("PRESSED_ENABLED_STATE_SET"_L1).toInt()));
// QPalette::Disabled -> PRESSED_STATE_SET
palette.setColor(QPalette::Disabled,
QPalette::BrightText,
- QRgb(object.value(QLatin1String("PRESSED_STATE_SET")).toInt()));
+ QRgb(object.value("PRESSED_STATE_SET"_L1).toInt()));
palette.setColor(QPalette::Current, QPalette::BrightText, palette.color(QPalette::Active, QPalette::BrightText));
@@ -155,17 +124,17 @@ static void setPaletteColor(const QVariantMap &object,
// QPalette::Active -> ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET
palette.setColor(QPalette::Active,
QPalette::HighlightedText,
- QRgb(object.value(QLatin1String("ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET")).toInt()));
+ QRgb(object.value("ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET"_L1).toInt()));
// QPalette::Inactive -> ENABLED_SELECTED_STATE_SET
palette.setColor(QPalette::Inactive,
QPalette::HighlightedText,
- QRgb(object.value(QLatin1String("ENABLED_SELECTED_STATE_SET")).toInt()));
+ QRgb(object.value("ENABLED_SELECTED_STATE_SET"_L1).toInt()));
// QPalette::Disabled -> SELECTED_STATE_SET
palette.setColor(QPalette::Disabled,
QPalette::HighlightedText,
- QRgb(object.value(QLatin1String("SELECTED_STATE_SET")).toInt()));
+ QRgb(object.value("SELECTED_STATE_SET"_L1).toInt()));
palette.setColor(QPalette::Current,
QPalette::HighlightedText,
@@ -187,25 +156,17 @@ static void setPaletteColor(const QVariantMap &object,
QJsonObject AndroidStyle::loadStyleData()
{
- QString stylePath(QLatin1String(qgetenv("MINISTRO_ANDROID_STYLE_PATH")));
+ QString stylePath(QLatin1StringView(qgetenv("ANDROID_STYLE_PATH")));
const QLatin1Char slashChar('/');
if (!stylePath.isEmpty() && !stylePath.endsWith(slashChar))
stylePath += slashChar;
- QString androidTheme = QLatin1String(qgetenv("QT_ANDROID_THEME"));
- if (!androidTheme.isEmpty() && !androidTheme.endsWith(slashChar))
- androidTheme += slashChar;
+ if (QAndroidPlatformIntegration::colorScheme() == Qt::ColorScheme::Dark)
+ stylePath += "darkUiMode/"_L1;
- 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;
-
- QFile f(stylePath + QLatin1String("style.json"));
+ QFile f(stylePath + "style.json"_L1);
if (!f.open(QIODevice::ReadOnly))
return QJsonObject();
@@ -223,13 +184,27 @@ QJsonObject AndroidStyle::loadStyleData()
return document.object();
}
-static std::shared_ptr<AndroidStyle> loadAndroidStyle(QPalette *defaultPalette)
+static void loadAndroidStyle(QPalette *defaultPalette, std::shared_ptr<AndroidStyle> &style)
{
double pixelDensity = QHighDpiScaling::isActive() ? QtAndroid::pixelDensity() : 1.0;
- std::shared_ptr<AndroidStyle> style = std::make_shared<AndroidStyle>();
+ if (style) {
+ style->m_standardPalette = QPalette();
+ style->m_palettes.clear();
+ style->m_fonts.clear();
+ style->m_QWidgetsFonts.clear();
+ } else {
+ style = std::make_shared<AndroidStyle>();
+ }
+
style->m_styleData = AndroidStyle::loadStyleData();
+
if (style->m_styleData.isEmpty())
- return std::shared_ptr<AndroidStyle>();
+ return;
+
+ {
+ QFont font("Droid Sans Mono"_L1, 14.0 * 100 / 72);
+ style->m_fonts.insert(QPlatformTheme::FixedFont, font);
+ }
for (QJsonObject::const_iterator objectIterator = style->m_styleData.constBegin();
objectIterator != style->m_styleData.constEnd();
@@ -241,7 +216,7 @@ static std::shared_ptr<AndroidStyle> loadAndroidStyle(QPalette *defaultPalette)
continue;
}
QJsonObject item = value.toObject();
- QJsonObject::const_iterator attributeIterator = item.find(QLatin1String("qtClass"));
+ QJsonObject::const_iterator attributeIterator = item.find("qtClass"_L1);
QByteArray qtClassName;
if (attributeIterator != item.constEnd()) {
// The item has palette and font information for a specific Qt Class (e.g. QWidget, QPushButton, etc.)
@@ -253,12 +228,12 @@ static std::shared_ptr<AndroidStyle> loadAndroidStyle(QPalette *defaultPalette)
QFont font;
// Font size (in pixels)
- attributeIterator = item.find(QLatin1String("TextAppearance_textSize"));
+ attributeIterator = item.find("TextAppearance_textSize"_L1);
if (attributeIterator != item.constEnd())
font.setPixelSize(int(attributeIterator.value().toDouble() / pixelDensity));
// Font style
- attributeIterator = item.find(QLatin1String("TextAppearance_textStyle"));
+ attributeIterator = item.find("TextAppearance_textStyle"_L1);
if (attributeIterator != item.constEnd()) {
const int style = int(attributeIterator.value().toDouble());
font.setBold(style & textStyle_bold);
@@ -266,7 +241,7 @@ static std::shared_ptr<AndroidStyle> loadAndroidStyle(QPalette *defaultPalette)
}
// Font typeface
- attributeIterator = item.find(QLatin1String("TextAppearance_typeface"));
+ attributeIterator = item.find("TextAppearance_typeface"_L1);
if (attributeIterator != item.constEnd()) {
QFont::StyleHint styleHint = QFont::AnyStyle;
switch (int(attributeIterator.value().toDouble())) {
@@ -298,23 +273,23 @@ static std::shared_ptr<AndroidStyle> loadAndroidStyle(QPalette *defaultPalette)
// Extract palette information
QPalette palette = *defaultPalette;
- attributeIterator = item.find(QLatin1String("defaultTextColorPrimary"));
+ attributeIterator = item.find("defaultTextColorPrimary"_L1);
if (attributeIterator != item.constEnd())
palette.setColor(QPalette::WindowText, QRgb(int(attributeIterator.value().toDouble())));
- attributeIterator = item.find(QLatin1String("defaultBackgroundColor"));
+ attributeIterator = item.find("defaultBackgroundColor"_L1);
if (attributeIterator != item.constEnd())
- palette.setColor(QPalette::Background, QRgb(int(attributeIterator.value().toDouble())));
+ palette.setColor(QPalette::Window, QRgb(int(attributeIterator.value().toDouble())));
- attributeIterator = item.find(QLatin1String("TextAppearance_textColor"));
+ attributeIterator = item.find("TextAppearance_textColor"_L1);
if (attributeIterator != item.constEnd())
setPaletteColor(attributeIterator.value().toObject().toVariantMap(), palette, QPalette::WindowText);
- attributeIterator = item.find(QLatin1String("TextAppearance_textColorLink"));
+ attributeIterator = item.find("TextAppearance_textColorLink"_L1);
if (attributeIterator != item.constEnd())
setPaletteColor(attributeIterator.value().toObject().toVariantMap(), palette, QPalette::Link);
- attributeIterator = item.find(QLatin1String("TextAppearance_textColorHighlight"));
+ attributeIterator = item.find("TextAppearance_textColorHighlight"_L1);
if (attributeIterator != item.constEnd())
palette.setColor(QPalette::Highlight, QRgb(int(attributeIterator.value().toDouble())));
@@ -326,11 +301,43 @@ static std::shared_ptr<AndroidStyle> loadAndroidStyle(QPalette *defaultPalette)
// Extract palette information
}
}
- return style;
+}
+
+QAndroidPlatformTheme *QAndroidPlatformTheme::m_instance = nullptr;
+
+QAndroidPlatformTheme *QAndroidPlatformTheme::instance(
+ QAndroidPlatformNativeInterface *androidPlatformNativeInterface)
+{
+ if (androidPlatformNativeInterface && !m_instance) {
+ m_instance = new QAndroidPlatformTheme(androidPlatformNativeInterface);
+ }
+ return m_instance;
}
QAndroidPlatformTheme::QAndroidPlatformTheme(QAndroidPlatformNativeInterface *androidPlatformNativeInterface)
{
+ updateStyle();
+
+ androidPlatformNativeInterface->m_androidStyle = m_androidStyleData;
+
+ // default in case the style has not set a font
+ m_systemFont = QFont("Roboto"_L1, 14.0 * 100 / 72); // keep default size the same after changing from 100 dpi to 72 dpi
+}
+
+QAndroidPlatformTheme::~QAndroidPlatformTheme()
+{
+ m_instance = nullptr;
+}
+
+void QAndroidPlatformTheme::updateColorScheme()
+{
+ updateStyle();
+ QWindowSystemInterface::handleThemeChange();
+}
+
+void QAndroidPlatformTheme::updateStyle()
+{
+ QColor windowText = Qt::black;
QColor background(229, 229, 229);
QColor light = background.lighter(150);
QColor mid(background.darker(130));
@@ -347,7 +354,27 @@ QAndroidPlatformTheme::QAndroidPlatformTheme(QAndroidPlatformNativeInterface *an
QColor highlight(148, 210, 231);
QColor disabledShadow = shadow.lighter(150);
- m_defaultPalette = QPalette(Qt::black,background,light,dark,mid,text,base);
+ if (colorScheme() == Qt::ColorScheme::Dark) {
+ // Colors were prepared based on Theme.DeviceDefault.DayNight
+ windowText = QColor(250, 250, 250);
+ background = QColor(48, 48, 48);
+ light = background.darker(150);
+ mid = background.lighter(130);
+ midLight = mid.darker(110);
+ base = background;
+ disabledBase = background;
+ dark = background.darker(150);
+ darkDisabled = dark.darker(110);
+ text = QColor(250, 250, 250);
+ highlightedText = QColor(250, 250, 250);
+ disabledText = QColor(96, 96, 96);
+ button = QColor(48, 48, 48);
+ shadow = QColor(32, 32, 32);
+ highlight = QColor(102, 178, 204);
+ disabledShadow = shadow.darker(150);
+ }
+
+ m_defaultPalette = QPalette(windowText,background,light,dark,mid,text,base);
m_defaultPalette.setBrush(QPalette::Midlight, midLight);
m_defaultPalette.setBrush(QPalette::Button, button);
m_defaultPalette.setBrush(QPalette::Shadow, shadow);
@@ -363,34 +390,42 @@ QAndroidPlatformTheme::QAndroidPlatformTheme(QAndroidPlatformNativeInterface *an
m_defaultPalette.setBrush(QPalette::Active, QPalette::Highlight, highlight);
m_defaultPalette.setBrush(QPalette::Inactive, QPalette::Highlight, highlight);
m_defaultPalette.setBrush(QPalette::Disabled, QPalette::Highlight, highlight.lighter(150));
- m_androidStyleData = loadAndroidStyle(&m_defaultPalette);
- QGuiApplication::setPalette(m_defaultPalette);
- androidPlatformNativeInterface->m_androidStyle = m_androidStyleData;
- // default in case the style has not set a font
- m_systemFont = QFont(QLatin1String("Roboto"), 14.0 * 100 / 72); // keep default size the same after changing from 100 dpi to 72 dpi
+ loadAndroidStyle(&m_defaultPalette, m_androidStyleData);
}
QPlatformMenuBar *QAndroidPlatformTheme::createPlatformMenuBar() const
{
- return new QAndroidPlatformMenuBar;
+ auto *menuBar = new QAndroidPlatformMenuBar;
+ qCDebug(lcQpaMenus) << "Created" << menuBar;
+ return menuBar;
}
QPlatformMenu *QAndroidPlatformTheme::createPlatformMenu() const
{
- return new QAndroidPlatformMenu;
+ auto *menu = new QAndroidPlatformMenu;
+ qCDebug(lcQpaMenus) << "Created" << menu;
+ return menu;
}
QPlatformMenuItem *QAndroidPlatformTheme::createPlatformMenuItem() const
{
- return new QAndroidPlatformMenuItem;
+ auto *menuItem = new QAndroidPlatformMenuItem;
+ qCDebug(lcQpaMenus) << "Created" << menuItem;
+ return menuItem;
}
void QAndroidPlatformTheme::showPlatformMenuBar()
{
+ qCDebug(lcQpaMenus) << "Showing platform menu bar";
QtAndroidMenu::openOptionsMenu();
}
+Qt::ColorScheme QAndroidPlatformTheme::colorScheme() const
+{
+ return QAndroidPlatformIntegration::colorScheme();
+}
+
static inline int paletteType(QPlatformTheme::Palette type)
{
switch (type) {
@@ -456,15 +491,20 @@ const QFont *QAndroidPlatformTheme::font(Font type) const
return 0;
}
+QIconEngine *QAndroidPlatformTheme::createIconEngine(const QString &iconName) const
+{
+ return new QAndroidPlatformIconEngine(iconName);
+}
+
QVariant QAndroidPlatformTheme::themeHint(ThemeHint hint) const
{
switch (hint) {
case StyleNames:
if (qEnvironmentVariableIntValue("QT_USE_ANDROID_NATIVE_STYLE")
&& m_androidStyleData) {
- return QStringList(QLatin1String("android"));
+ return QStringList("android"_L1);
}
- return QStringList(QLatin1String("fusion"));
+ return QStringList("Fusion"_L1);
case DialogButtonBoxLayout:
return QVariant(QPlatformDialogHelper::AndroidLayout);
case MouseDoubleClickDistance:
diff --git a/src/plugins/platforms/android/qandroidplatformtheme.h b/src/plugins/platforms/android/qandroidplatformtheme.h
index b49d2516f1..ce3d6d5f73 100644
--- a/src/plugins/platforms/android/qandroidplatformtheme.h
+++ b/src/plugins/platforms/android/qandroidplatformtheme.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QANDROIDPLATFORMTHEME_H
#define QANDROIDPLATFORMTHEME_H
@@ -43,13 +7,17 @@
#include <qpa/qplatformtheme.h>
#include <QtGui/qfont.h>
#include <QtGui/qpalette.h>
-
+#include <QtCore/qhash.h>
+#include <QtCore/qbytearray.h>
+#include <QtCore/qloggingcategory.h>
#include <QJsonObject>
#include <memory>
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(lcQpaMenus)
+
struct AndroidStyle
{
static QJsonObject loadStyleData();
@@ -64,20 +32,28 @@ class QAndroidPlatformNativeInterface;
class QAndroidPlatformTheme: public QPlatformTheme
{
public:
- QAndroidPlatformTheme(QAndroidPlatformNativeInterface * androidPlatformNativeInterface);
+ ~QAndroidPlatformTheme();
+ void updateColorScheme();
+ void updateStyle();
QPlatformMenuBar *createPlatformMenuBar() const override;
QPlatformMenu *createPlatformMenu() const override;
QPlatformMenuItem *createPlatformMenuItem() const override;
void showPlatformMenuBar() override;
+ Qt::ColorScheme colorScheme() const override;
const QPalette *palette(Palette type = SystemPalette) const override;
const QFont *font(Font type = SystemFont) const override;
+ QIconEngine *createIconEngine(const QString &iconName) const override;
QVariant themeHint(ThemeHint hint) const override;
QString standardButtonText(int button) const override;
bool usePlatformNativeDialog(DialogType type) const override;
QPlatformDialogHelper *createPlatformDialogHelper(DialogType type) const override;
+ static QAndroidPlatformTheme *instance(
+ QAndroidPlatformNativeInterface * androidPlatformNativeInterface = nullptr);
private:
+ QAndroidPlatformTheme(QAndroidPlatformNativeInterface * androidPlatformNativeInterface);
+ static QAndroidPlatformTheme * m_instance;
std::shared_ptr<AndroidStyle> m_androidStyleData;
QPalette m_defaultPalette;
QFont m_systemFont;
diff --git a/src/plugins/platforms/android/qandroidplatformvulkaninstance.cpp b/src/plugins/platforms/android/qandroidplatformvulkaninstance.cpp
index a411d0f007..8d90b9dea1 100644
--- a/src/plugins/platforms/android/qandroidplatformvulkaninstance.cpp
+++ b/src/plugins/platforms/android/qandroidplatformvulkaninstance.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qandroidplatformvulkaninstance.h"
diff --git a/src/plugins/platforms/android/qandroidplatformvulkaninstance.h b/src/plugins/platforms/android/qandroidplatformvulkaninstance.h
index 67edcceed9..ad7de71867 100644
--- a/src/plugins/platforms/android/qandroidplatformvulkaninstance.h
+++ b/src/plugins/platforms/android/qandroidplatformvulkaninstance.h
@@ -1,46 +1,10 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QANDROIDPLATFORMVULKANINSTANCE_H
#define QANDROIDPLATFORMVULKANINSTANCE_H
-#include <QtVulkanSupport/private/qbasicvulkanplatforminstance_p.h>
+#include <QtGui/private/qbasicvulkanplatforminstance_p.h>
#include <QLibrary>
QT_BEGIN_NAMESPACE
diff --git a/src/plugins/platforms/android/qandroidplatformvulkanwindow.cpp b/src/plugins/platforms/android/qandroidplatformvulkanwindow.cpp
index cc41a871f3..4bf4f44fa1 100644
--- a/src/plugins/platforms/android/qandroidplatformvulkanwindow.cpp
+++ b/src/plugins/platforms/android/qandroidplatformvulkanwindow.cpp
@@ -1,51 +1,15 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#include "qandroidplatformvulkanwindow.h"
-#include "qandroidplatformscreen.h"
+#include "androiddeadlockprotector.h"
#include "androidjnimain.h"
#include "qandroideventdispatcher.h"
-#include "androiddeadlockprotector.h"
+#include "qandroidplatformscreen.h"
+#include "qandroidplatformvulkanwindow.h"
#include <QSurfaceFormat>
-#include <qpa/qwindowsysteminterface.h>
#include <qpa/qplatformscreen.h>
+#include <qpa/qwindowsysteminterface.h>
#include <android/native_window.h>
#include <android/native_window_jni.h>
@@ -54,7 +18,6 @@ QT_BEGIN_NAMESPACE
QAndroidPlatformVulkanWindow::QAndroidPlatformVulkanWindow(QWindow *window)
: QAndroidPlatformWindow(window),
- m_nativeSurfaceId(-1),
m_nativeWindow(nullptr),
m_vkSurface(0),
m_createVkSurface(nullptr),
@@ -65,11 +28,7 @@ QAndroidPlatformVulkanWindow::QAndroidPlatformVulkanWindow(QWindow *window)
QAndroidPlatformVulkanWindow::~QAndroidPlatformVulkanWindow()
{
m_surfaceWaitCondition.wakeOne();
- lockSurface();
- if (m_nativeSurfaceId != -1)
- QtAndroid::destroySurface(m_nativeSurfaceId);
- clearSurface();
- unlockSurface();
+ destroyAndClearSurface();
}
void QAndroidPlatformVulkanWindow::setGeometry(const QRect &rect)
@@ -80,34 +39,23 @@ void QAndroidPlatformVulkanWindow::setGeometry(const QRect &rect)
m_oldGeometry = geometry();
QAndroidPlatformWindow::setGeometry(rect);
- if (m_nativeSurfaceId != -1)
- QtAndroid::setSurfaceGeometry(m_nativeSurfaceId, rect);
+ if (m_surfaceCreated)
+ setNativeGeometry(rect);
QRect availableGeometry = screen()->availableGeometry();
- if (m_oldGeometry.width() == 0
- && m_oldGeometry.height() == 0
- && rect.width() > 0
+ if (rect.width() > 0
&& rect.height() > 0
&& availableGeometry.width() > 0
&& availableGeometry.height() > 0) {
QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(0, 0), rect.size()));
}
-
- if (rect.topLeft() != m_oldGeometry.topLeft())
- repaint(QRegion(rect));
}
void QAndroidPlatformVulkanWindow::applicationStateChanged(Qt::ApplicationState state)
{
QAndroidPlatformWindow::applicationStateChanged(state);
if (state <= Qt::ApplicationHidden) {
- lockSurface();
- if (m_nativeSurfaceId != -1) {
- QtAndroid::destroySurface(m_nativeSurfaceId);
- m_nativeSurfaceId = -1;
- }
- clearSurface();
- unlockSurface();
+ destroyAndClearSurface();
}
}
@@ -129,27 +77,12 @@ void QAndroidPlatformVulkanWindow::clearSurface()
}
}
-void QAndroidPlatformVulkanWindow::sendExpose()
+void QAndroidPlatformVulkanWindow::destroyAndClearSurface()
{
- QRect availableGeometry = screen()->availableGeometry();
- if (geometry().width() > 0 && geometry().height() > 0 && availableGeometry.width() > 0 && availableGeometry.height() > 0)
- QWindowSystemInterface::handleExposeEvent(window(), QRegion(QRect(QPoint(), geometry().size())));
-}
-
-void QAndroidPlatformVulkanWindow::surfaceChanged(JNIEnv *jniEnv, jobject surface, int w, int h)
-{
- Q_UNUSED(jniEnv);
- Q_UNUSED(w);
- Q_UNUSED(h);
-
lockSurface();
- m_androidSurfaceObject = surface;
- if (surface)
- m_surfaceWaitCondition.wakeOne();
+ destroySurface();
+ clearSurface();
unlockSurface();
-
- if (surface)
- sendExpose();
}
VkSurfaceKHR *QAndroidPlatformVulkanWindow::vkSurface()
@@ -162,20 +95,19 @@ VkSurfaceKHR *QAndroidPlatformVulkanWindow::vkSurface()
clearSurface();
QMutexLocker lock(&m_surfaceMutex);
- if (m_nativeSurfaceId == -1) {
+ if (!m_surfaceCreated) {
AndroidDeadlockProtector protector;
if (!protector.acquire())
return &m_vkSurface;
- const bool windowStaysOnTop = bool(window()->flags() & Qt::WindowStaysOnTopHint);
- m_nativeSurfaceId = QtAndroid::createSurface(this, geometry(), windowStaysOnTop, 32);
+ createSurface();
m_surfaceWaitCondition.wait(&m_surfaceMutex);
}
- if (m_nativeSurfaceId == -1 || !m_androidSurfaceObject.isValid())
+ if (!m_surfaceCreated || !m_androidSurfaceObject.isValid())
return &m_vkSurface;
- QJNIEnvironmentPrivate env;
- m_nativeWindow = ANativeWindow_fromSurface(env, m_androidSurfaceObject.object());
+ QJniEnvironment env;
+ m_nativeWindow = ANativeWindow_fromSurface(env.jniEnv(), m_androidSurfaceObject.object());
VkAndroidSurfaceCreateInfoKHR surfaceInfo;
memset(&surfaceInfo, 0, sizeof(surfaceInfo));
diff --git a/src/plugins/platforms/android/qandroidplatformvulkanwindow.h b/src/plugins/platforms/android/qandroidplatformvulkanwindow.h
index 19eca98720..fa959239d1 100644
--- a/src/plugins/platforms/android/qandroidplatformvulkanwindow.h
+++ b/src/plugins/platforms/android/qandroidplatformvulkanwindow.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QANDROIDPLATFORMVULKANWINDOW_H
#define QANDROIDPLATFORMVULKANWINDOW_H
@@ -46,17 +10,16 @@
#define VK_USE_PLATFORM_ANDROID_KHR
-#include <QWaitCondition>
-#include <QtCore/private/qjni_p.h>
-
-#include "androidsurfaceclient.h"
+#include "qandroidplatformvulkaninstance.h"
#include "qandroidplatformwindow.h"
-#include "qandroidplatformvulkaninstance.h"
+#include <QWaitCondition>
+#include <QtCore/QJniEnvironment>
+#include <QtCore/QJniObject>
QT_BEGIN_NAMESPACE
-class QAndroidPlatformVulkanWindow : public QAndroidPlatformWindow, public AndroidSurfaceClient
+class QAndroidPlatformVulkanWindow : public QAndroidPlatformWindow
{
public:
explicit QAndroidPlatformVulkanWindow(QWindow *window);
@@ -68,17 +31,11 @@ public:
VkSurfaceKHR *vkSurface();
-protected:
- void surfaceChanged(JNIEnv *jniEnv, jobject surface, int w, int h) override;
-
private:
- void sendExpose();
void clearSurface();
+ void destroyAndClearSurface();
- int m_nativeSurfaceId;
ANativeWindow *m_nativeWindow;
- QJNIObjectPrivate m_androidSurfaceObject;
- QWaitCondition m_surfaceWaitCondition;
QSurfaceFormat m_format;
QRect m_oldGeometry;
VkSurfaceKHR m_vkSurface;
diff --git a/src/plugins/platforms/android/qandroidplatformwindow.cpp b/src/plugins/platforms/android/qandroidplatformwindow.cpp
index 4f691ce112..e47281664d 100644
--- a/src/plugins/platforms/android/qandroidplatformwindow.cpp
+++ b/src/plugins/platforms/android/qandroidplatformwindow.cpp
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 BogDan Vatra <bogdan@kde.org>
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2014 BogDan Vatra <bogdan@kde.org>
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qandroidplatformwindow.h"
#include "qandroidplatformopenglcontext.h"
@@ -46,53 +10,132 @@
#include <qguiapplication.h>
#include <qpa/qwindowsysteminterface.h>
+#include <private/qhighdpiscaling_p.h>
QT_BEGIN_NAMESPACE
-static QBasicAtomicInt winIdGenerator = Q_BASIC_ATOMIC_INITIALIZER(0);
+Q_LOGGING_CATEGORY(lcQpaWindow, "qt.qpa.window")
QAndroidPlatformWindow::QAndroidPlatformWindow(QWindow *window)
- : QPlatformWindow(window)
+ : QPlatformWindow(window), m_nativeQtWindow(nullptr),
+ m_surfaceContainerType(SurfaceContainer::TextureView), m_nativeParentQtWindow(nullptr),
+ m_androidSurfaceObject(nullptr)
{
m_windowFlags = Qt::Widget;
m_windowState = Qt::WindowNoState;
- m_windowId = winIdGenerator.fetchAndAddRelaxed(1) + 1;
+ // the surfaceType is overwritten in QAndroidPlatformOpenGLWindow ctor so let's save
+ // the fact that it's a raster window for now
+ m_isRaster = window->surfaceType() == QSurface::RasterSurface;
setWindowState(window->windowStates());
+
+ // the following is in relation to the virtual geometry
+ const bool forceMaximize = m_windowState & (Qt::WindowMaximized | Qt::WindowFullScreen);
+ const QRect nativeScreenGeometry = platformScreen()->availableGeometry();
+ if (forceMaximize) {
+ setGeometry(nativeScreenGeometry);
+ } else {
+ const QRect requestedNativeGeometry = QHighDpi::toNativePixels(window->geometry(), window);
+ const QRect availableDeviceIndependentGeometry = (window->parent())
+ ? window->parent()->geometry()
+ : QHighDpi::fromNativePixels(nativeScreenGeometry, window);
+ // initialGeometry returns in native pixels
+ const QRect finalNativeGeometry = QPlatformWindow::initialGeometry(
+ window, requestedNativeGeometry, availableDeviceIndependentGeometry.width(),
+ availableDeviceIndependentGeometry.height());
+ if (requestedNativeGeometry != finalNativeGeometry)
+ setGeometry(finalNativeGeometry);
+ }
+
+ if (isEmbeddingContainer())
+ return;
+
+ if (parent()) {
+ QAndroidPlatformWindow *androidParent = static_cast<QAndroidPlatformWindow*>(parent());
+ if (!androidParent->isEmbeddingContainer())
+ m_nativeParentQtWindow = androidParent->nativeWindow();
+ }
+
+ m_nativeQtWindow = QJniObject::construct<QtJniTypes::QtWindow>(
+ QNativeInterface::QAndroidApplication::context(),
+ m_nativeParentQtWindow,
+ QtAndroid::qtInputDelegate());
+ m_nativeViewId = m_nativeQtWindow.callMethod<jint>("getId");
+
+ if (window->isTopLevel())
+ platformScreen()->addWindow(this);
+
+ // TODO should handle case where this changes at runtime -> need to change existing window
+ // into TextureView (or perhaps not, if the parent window would be SurfaceView, as long as
+ // onTop was false it would stay below the children)
+ if (platformScreen()->windows().size() <= 1)
+ m_surfaceContainerType = SurfaceContainer::SurfaceView;
}
+QAndroidPlatformWindow::~QAndroidPlatformWindow()
+{
+ if (window()->isTopLevel())
+ platformScreen()->removeWindow(this);
+}
+
+
void QAndroidPlatformWindow::lower()
{
+ if (m_nativeParentQtWindow.isValid()) {
+ m_nativeParentQtWindow.callMethod<void>("bringChildToBack", nativeViewId());
+ return;
+ }
platformScreen()->lower(this);
}
void QAndroidPlatformWindow::raise()
{
- updateStatusBarVisibility();
+ if (m_nativeParentQtWindow.isValid()) {
+ m_nativeParentQtWindow.callMethod<void>("bringChildToFront", nativeViewId());
+ QWindowSystemInterface::handleFocusWindowChanged(window(), Qt::ActiveWindowFocusReason);
+ return;
+ }
+ updateSystemUiVisibility();
platformScreen()->raise(this);
}
+QMargins QAndroidPlatformWindow::safeAreaMargins() const
+{
+ if ((m_windowState & Qt::WindowMaximized) && (window()->flags() & Qt::MaximizeUsingFullscreenGeometryHint)) {
+ QRect availableGeometry = platformScreen()->availableGeometry();
+ return QMargins(availableGeometry.left(), availableGeometry.top(),
+ availableGeometry.right(), availableGeometry.bottom());
+ } else {
+ return QPlatformWindow::safeAreaMargins();
+ }
+}
+
void QAndroidPlatformWindow::setGeometry(const QRect &rect)
{
+ QPlatformWindow::setGeometry(rect);
QWindowSystemInterface::handleGeometryChange(window(), rect);
}
void QAndroidPlatformWindow::setVisible(bool visible)
{
- if (visible)
- updateStatusBarVisibility();
+ if (isEmbeddingContainer())
+ return;
+ m_nativeQtWindow.callMethod<void>("setVisible", visible);
if (visible) {
- if (m_windowState & Qt::WindowFullScreen)
- setGeometry(platformScreen()->geometry());
- else if (m_windowState & Qt::WindowMaximized)
- setGeometry(platformScreen()->availableGeometry());
+ if (window()->isTopLevel()) {
+ updateSystemUiVisibility();
+ if ((m_windowState & Qt::WindowFullScreen)
+ || ((m_windowState & Qt::WindowMaximized) && (window()->flags() & Qt::MaximizeUsingFullscreenGeometryHint))) {
+ setGeometry(platformScreen()->geometry());
+ } else if (m_windowState & Qt::WindowMaximized) {
+ setGeometry(platformScreen()->availableGeometry());
+ }
+ requestActivateWindow();
+ }
+ } else if (window()->isTopLevel() && window() == qGuiApp->focusWindow()) {
+ platformScreen()->topVisibleWindowChanged();
}
- if (visible)
- platformScreen()->addWindow(this);
- else
- platformScreen()->removeWindow(this);
-
QRect availableGeometry = screen()->availableGeometry();
if (geometry().width() > 0 && geometry().height() > 0 && availableGeometry.width() > 0 && availableGeometry.height() > 0)
QPlatformWindow::setVisible(visible);
@@ -107,7 +150,7 @@ void QAndroidPlatformWindow::setWindowState(Qt::WindowStates state)
m_windowState = state;
if (window()->isVisible())
- updateStatusBarVisibility();
+ updateSystemUiVisibility();
}
void QAndroidPlatformWindow::setWindowFlags(Qt::WindowFlags flags)
@@ -125,7 +168,30 @@ Qt::WindowFlags QAndroidPlatformWindow::windowFlags() const
void QAndroidPlatformWindow::setParent(const QPlatformWindow *window)
{
- Q_UNUSED(window);
+ using namespace QtJniTypes;
+
+ if (window) {
+ auto androidWindow = static_cast<const QAndroidPlatformWindow*>(window);
+ if (androidWindow->isEmbeddingContainer())
+ return;
+ // If we were a top level window, remove from screen
+ if (!m_nativeParentQtWindow.isValid())
+ platformScreen()->removeWindow(this);
+
+ const QtWindow parentWindow = androidWindow->nativeWindow();
+ // If this was a child window of another window, the java method takes care of that
+ m_nativeQtWindow.callMethod<void, QtWindow>("setParent", parentWindow.object());
+ m_nativeParentQtWindow = parentWindow;
+ } else if (QtAndroid::isQtApplication()) {
+ m_nativeQtWindow.callMethod<void, QtWindow>("setParent", nullptr);
+ m_nativeParentQtWindow = QJniObject();
+ platformScreen()->addWindow(this);
+ }
+}
+
+WId QAndroidPlatformWindow::winId() const
+{
+ return m_nativeQtWindow.isValid() ? reinterpret_cast<WId>(m_nativeQtWindow.object()) : 0L;
}
QAndroidPlatformScreen *QAndroidPlatformWindow::platformScreen() const
@@ -140,18 +206,22 @@ void QAndroidPlatformWindow::propagateSizeHints()
void QAndroidPlatformWindow::requestActivateWindow()
{
- platformScreen()->topWindowChanged(window());
+ // raise() will handle differences between top level and child windows, and requesting focus
+ if (!blockedByModal())
+ raise();
}
-void QAndroidPlatformWindow::updateStatusBarVisibility()
+void QAndroidPlatformWindow::updateSystemUiVisibility()
{
Qt::WindowFlags flags = window()->flags();
bool isNonRegularWindow = flags & (Qt::Popup | Qt::Dialog | Qt::Sheet) & ~Qt::Window;
if (!isNonRegularWindow) {
if (m_windowState & Qt::WindowFullScreen)
- QtAndroid::hideStatusBar();
+ QtAndroid::setSystemUiVisibility(QtAndroid::SYSTEM_UI_VISIBILITY_FULLSCREEN);
+ else if (flags & Qt::MaximizeUsingFullscreenGeometryHint)
+ QtAndroid::setSystemUiVisibility(QtAndroid::SYSTEM_UI_VISIBILITY_TRANSLUCENT);
else
- QtAndroid::showStatusBar();
+ QtAndroid::setSystemUiVisibility(QtAndroid::SYSTEM_UI_VISIBILITY_NORMAL);
}
}
@@ -172,4 +242,134 @@ void QAndroidPlatformWindow::applicationStateChanged(Qt::ApplicationState)
QWindowSystemInterface::flushWindowSystemEvents();
}
+void QAndroidPlatformWindow::createSurface()
+{
+ const QRect rect = geometry();
+ jint x = 0, y = 0, w = -1, h = -1;
+ if (!rect.isNull()) {
+ x = rect.x();
+ y = rect.y();
+ w = std::max(rect.width(), 1);
+ h = std::max(rect.height(), 1);
+ }
+
+ const bool windowStaysOnTop = bool(window()->flags() & Qt::WindowStaysOnTopHint);
+ const bool isOpaque = !format().hasAlpha() && qFuzzyCompare(window()->opacity(), 1.0);
+
+ m_nativeQtWindow.callMethod<void>("createSurface", windowStaysOnTop, x, y, w, h, 32, isOpaque,
+ m_surfaceContainerType);
+ m_surfaceCreated = true;
+}
+
+void QAndroidPlatformWindow::destroySurface()
+{
+ if (m_surfaceCreated) {
+ m_nativeQtWindow.callMethod<void>("destroySurface");
+ m_surfaceCreated = false;
+ }
+}
+
+void QAndroidPlatformWindow::setNativeGeometry(const QRect &geometry)
+{
+ if (!m_surfaceCreated)
+ return;
+
+ jint x = 0;
+ jint y = 0;
+ jint w = -1;
+ jint h = -1;
+ if (!geometry.isNull()) {
+ x = geometry.x();
+ y = geometry.y();
+ w = geometry.width();
+ h = geometry.height();
+ }
+ m_nativeQtWindow.callMethod<void>("setGeometry", x, y, w, h);
+}
+
+void QAndroidPlatformWindow::onSurfaceChanged(QtJniTypes::Surface surface)
+{
+ lockSurface();
+ m_androidSurfaceObject = surface;
+ if (m_androidSurfaceObject.isValid()) // wait until we have a valid surface to draw into
+ m_surfaceWaitCondition.wakeOne();
+ unlockSurface();
+
+ if (m_androidSurfaceObject.isValid()) {
+ // repaint the window, when we have a valid surface
+ sendExpose();
+ }
+}
+
+void QAndroidPlatformWindow::sendExpose() const
+{
+ QRect availableGeometry = screen()->availableGeometry();
+ if (!geometry().isNull() && !availableGeometry.isNull()) {
+ QWindowSystemInterface::handleExposeEvent(window(),
+ QRegion(QRect(QPoint(), geometry().size())));
+ }
+}
+
+bool QAndroidPlatformWindow::blockedByModal() const
+{
+ QWindow *modalWindow = QGuiApplication::modalWindow();
+ return modalWindow && modalWindow != window();
+}
+
+bool QAndroidPlatformWindow::isEmbeddingContainer() const
+{
+ // Returns true if the window is a wrapper for a foreign window solely to allow embedding Qt
+ // into a native Android app, in which case we should not try to control it more than we "need" to
+ return !QtAndroid::isQtApplication() && window()->isTopLevel();
+}
+
+void QAndroidPlatformWindow::setSurface(JNIEnv *env, jobject object, jint windowId,
+ QtJniTypes::Surface surface)
+{
+ Q_UNUSED(env)
+ Q_UNUSED(object)
+
+ if (!qGuiApp)
+ return;
+
+ const QList<QWindow*> windows = qGuiApp->allWindows();
+ for (QWindow * window : windows) {
+ if (!window->handle())
+ continue;
+ QAndroidPlatformWindow *platformWindow =
+ static_cast<QAndroidPlatformWindow *>(window->handle());
+ if (platformWindow->nativeViewId() == windowId)
+ platformWindow->onSurfaceChanged(surface);
+ }
+}
+
+void QAndroidPlatformWindow::windowFocusChanged(JNIEnv *env, jobject object,
+ jboolean focus, jint windowId)
+{
+ Q_UNUSED(env)
+ Q_UNUSED(object)
+ QWindow* window = QtAndroid::windowFromId(windowId);
+ Q_ASSERT_X(window, "QAndroidPlatformWindow", "windowFocusChanged event window should exist");
+ if (focus) {
+ QWindowSystemInterface::handleFocusWindowChanged(window);
+ } else if (!focus && window == qGuiApp->focusWindow()) {
+ // Clear focus if current window has lost focus
+ QWindowSystemInterface::handleFocusWindowChanged(nullptr);
+ }
+}
+
+bool QAndroidPlatformWindow::registerNatives(QJniEnvironment &env)
+{
+ if (!env.registerNativeMethods(QtJniTypes::Traits<QtJniTypes::QtWindow>::className(),
+ {
+ Q_JNI_NATIVE_SCOPED_METHOD(setSurface, QAndroidPlatformWindow),
+ Q_JNI_NATIVE_SCOPED_METHOD(windowFocusChanged, QAndroidPlatformWindow)
+ })) {
+ qCCritical(lcQpaWindow) << "RegisterNatives failed for"
+ << QtJniTypes::Traits<QtJniTypes::QtWindow>::className();
+ return false;
+ }
+ return true;
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/android/qandroidplatformwindow.h b/src/plugins/platforms/android/qandroidplatformwindow.h
index d8eb6b7b7f..3f1e8ac992 100644
--- a/src/plugins/platforms/android/qandroidplatformwindow.h
+++ b/src/plugins/platforms/android/qandroidplatformwindow.h
@@ -1,59 +1,38 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 BogDan Vatra <bogdan@kde.org>
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2014 BogDan Vatra <bogdan@kde.org>
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef ANDROIDPLATFORMWINDOW_H
#define ANDROIDPLATFORMWINDOW_H
#include <qobject.h>
#include <qrect.h>
#include <qpa/qplatformwindow.h>
+#include <QtCore/qjnienvironment.h>
+#include <QtCore/qjniobject.h>
+#include <QtCore/qjnitypes.h>
+#include <QtCore/qloggingcategory.h>
+#include <QtCore/qmutex.h>
+#include <QtCore/qwaitcondition.h>
+#include <jni.h>
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(lcQpaWindow)
+Q_DECLARE_JNI_CLASS(QtWindow, "org/qtproject/qt/android/QtWindow")
+Q_DECLARE_JNI_CLASS(Surface, "android/view/Surface")
+
class QAndroidPlatformScreen;
-class QAndroidPlatformBackingStore;
class QAndroidPlatformWindow: public QPlatformWindow
{
public:
- explicit QAndroidPlatformWindow(QWindow *window);
+ enum class SurfaceContainer {
+ SurfaceView,
+ TextureView
+ };
+ explicit QAndroidPlatformWindow(QWindow *window);
+ ~QAndroidPlatformWindow();
void lower() override;
void raise() override;
@@ -63,42 +42,59 @@ public:
void setWindowFlags(Qt::WindowFlags flags) override;
Qt::WindowFlags windowFlags() const;
void setParent(const QPlatformWindow *window) override;
- WId winId() const override { return m_windowId; }
+
+ WId winId() const override;
bool setMouseGrabEnabled(bool grab) override { Q_UNUSED(grab); return false; }
bool setKeyboardGrabEnabled(bool grab) override { Q_UNUSED(grab); return false; }
QAndroidPlatformScreen *platformScreen() const;
+ QMargins safeAreaMargins() const override;
+
void propagateSizeHints() override;
void requestActivateWindow() override;
- void updateStatusBarVisibility();
- inline bool isRaster() const {
- if (isForeignWindow())
- return false;
-
- return window()->surfaceType() == QSurface::RasterSurface
- || window()->surfaceType() == QSurface::RasterGLSurface;
- }
+ void updateSystemUiVisibility();
+ inline bool isRaster() const { return m_isRaster; }
bool isExposed() const override;
+ QtJniTypes::QtWindow nativeWindow() const { return m_nativeQtWindow; }
virtual void applicationStateChanged(Qt::ApplicationState);
+ int nativeViewId() const { return m_nativeViewId; }
- void setBackingStore(QAndroidPlatformBackingStore *store) { m_backingStore = store; }
- QAndroidPlatformBackingStore *backingStore() const { return m_backingStore; }
-
- virtual void repaint(const QRegion &) { }
+ static bool registerNatives(QJniEnvironment &env);
+ void onSurfaceChanged(QtJniTypes::Surface surface);
protected:
void setGeometry(const QRect &rect) override;
+ void lockSurface() { m_surfaceMutex.lock(); }
+ void unlockSurface() { m_surfaceMutex.unlock(); }
+ void createSurface();
+ void destroySurface();
+ void setNativeGeometry(const QRect &geometry);
+ void sendExpose() const;
+ bool blockedByModal() const;
+ bool isEmbeddingContainer() const;
-protected:
Qt::WindowFlags m_windowFlags;
Qt::WindowStates m_windowState;
-
- WId m_windowId;
-
- QAndroidPlatformBackingStore *m_backingStore = nullptr;
+ bool m_isRaster;
+
+ int m_nativeViewId = -1;
+ QtJniTypes::QtWindow m_nativeQtWindow;
+ SurfaceContainer m_surfaceContainerType = SurfaceContainer::SurfaceView;
+ QtJniTypes::QtWindow m_nativeParentQtWindow;
+ // The Android Surface, accessed from multiple threads, guarded by m_surfaceMutex
+ QtJniTypes::Surface m_androidSurfaceObject;
+ QWaitCondition m_surfaceWaitCondition;
+ bool m_surfaceCreated = false;
+ QMutex m_surfaceMutex;
+
+private:
+ static void setSurface(JNIEnv *env, jobject obj, jint windowId, QtJniTypes::Surface surface);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(setSurface)
+ static void windowFocusChanged(JNIEnv *env, jobject object, jboolean focus, jint windowId);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(windowFocusChanged)
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/android/qandroidsystemlocale.cpp b/src/plugins/platforms/android/qandroidsystemlocale.cpp
index f9d566ff1a..c5f2e59097 100644
--- a/src/plugins/platforms/android/qandroidsystemlocale.cpp
+++ b/src/plugins/platforms/android/qandroidsystemlocale.cpp
@@ -1,80 +1,49 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#include "qandroidsystemlocale.h"
#include "androidjnimain.h"
-#include <QtCore/private/qjni_p.h>
-#include <QtCore/private/qjnihelpers_p.h>
+#include "qandroidsystemlocale.h"
#include "qdatetime.h"
#include "qstringlist.h"
#include "qvariant.h"
+#include <QtCore/private/qjnihelpers_p.h>
+#include <QtCore/QJniObject>
+
QT_BEGIN_NAMESPACE
+Q_DECLARE_JNI_CLASS(Locale, "java/util/Locale")
+Q_DECLARE_JNI_CLASS(Resources, "android/content/res/Resources")
+Q_DECLARE_JNI_CLASS(Configuration, "android/content/res/Configuration")
+Q_DECLARE_JNI_CLASS(LocaleList, "android/os/LocaleList")
+
+using namespace QtJniTypes;
+
QAndroidSystemLocale::QAndroidSystemLocale() : m_locale(QLocale::C)
{
}
void QAndroidSystemLocale::getLocaleFromJava() const
{
- QWriteLocker locker(&m_lock);
-
- QJNIObjectPrivate javaLocaleObject;
- QJNIObjectPrivate javaActivity(QtAndroid::activity());
- if (!javaActivity.isValid())
- javaActivity = QtAndroid::service();
- if (javaActivity.isValid()) {
- QJNIObjectPrivate resources = javaActivity.callObjectMethod("getResources", "()Landroid/content/res/Resources;");
- QJNIObjectPrivate configuration = resources.callObjectMethod("getConfiguration", "()Landroid/content/res/Configuration;");
-
- javaLocaleObject = configuration.getObjectField("locale", "Ljava/util/Locale;");
- } else {
- javaLocaleObject = QJNIObjectPrivate::callStaticObjectMethod("java/util/Locale", "getDefault", "()Ljava/util/Locale;");
- }
+ const Locale javaLocaleObject = []{
+ const QJniObject javaContext = QtAndroidPrivate::context();
+ if (javaContext.isValid()) {
+ const QJniObject resources = javaContext.callMethod<Resources>("getResources");
+ const QJniObject configuration = resources.callMethod<Configuration>("getConfiguration");
+ return configuration.getField<Locale>("locale");
+ } else {
+ return Locale::callStaticMethod<Locale>("getDefault");
+ }
+ }();
- QString languageCode = javaLocaleObject.callObjectMethod("getLanguage", "()Ljava/lang/String;").toString();
- QString countryCode = javaLocaleObject.callObjectMethod("getCountry", "()Ljava/lang/String;").toString();
+ const QString languageCode = javaLocaleObject.callMethod<QString>("getLanguage");
+ const QString countryCode = javaLocaleObject.callMethod<QString>("getCountry");
- m_locale = QLocale(languageCode + QLatin1Char('_') + countryCode);
+ QWriteLocker locker(&m_lock);
+ m_locale = QLocale(languageCode + u'_' + countryCode);
}
-QVariant QAndroidSystemLocale::query(QueryType type, QVariant in) const
+QVariant QAndroidSystemLocale::query(QueryType type, QVariant &&in) const
{
if (type == LocaleChanged) {
getLocaleFromJava();
@@ -104,14 +73,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:
@@ -139,16 +120,16 @@ QVariant QAndroidSystemLocale::query(QueryType type, QVariant in) const
case CurrencySymbol:
return m_locale .currencySymbol(QLocale::CurrencySymbolFormat(in.toUInt()));
case CurrencyToString: {
- switch (in.type()) {
- case QVariant::Int:
+ switch (in.metaType().id()) {
+ case QMetaType::Int:
return m_locale .toCurrencyString(in.toInt());
- case QVariant::UInt:
+ case QMetaType::UInt:
return m_locale .toCurrencyString(in.toUInt());
- case QVariant::Double:
+ case QMetaType::Double:
return m_locale .toCurrencyString(in.toDouble());
- case QVariant::LongLong:
+ case QMetaType::LongLong:
return m_locale .toCurrencyString(in.toLongLong());
- case QVariant::ULongLong:
+ case QMetaType::ULongLong:
return m_locale .toCurrencyString(in.toULongLong());
default:
break;
@@ -156,21 +137,18 @@ QVariant QAndroidSystemLocale::query(QueryType type, QVariant in) const
return QString();
}
case StringToStandardQuotation:
- return m_locale.quoteString(in.value<QStringRef>());
+ return m_locale.quoteString(in.value<QStringView>());
case StringToAlternateQuotation:
- return m_locale.quoteString(in.value<QStringRef>(), QLocale::AlternateQuotation);
+ return m_locale.quoteString(in.value<QStringView>(), QLocale::AlternateQuotation);
case ListToSeparatedString:
return m_locale.createSeparatedList(in.value<QStringList>());
case LocaleChanged:
Q_ASSERT_X(false, Q_FUNC_INFO, "This can't happen.");
case UILanguages: {
if (QtAndroidPrivate::androidSdkVersion() >= 24) {
- QJNIObjectPrivate localeListObject =
- QJNIObjectPrivate::callStaticObjectMethod("android/os/LocaleList", "getDefault",
- "()Landroid/os/LocaleList;");
+ LocaleList localeListObject = LocaleList::callStaticMethod<LocaleList>("getDefault");
if (localeListObject.isValid()) {
- QString lang = localeListObject.callObjectMethod("toLanguageTags",
- "()Ljava/lang/String;").toString();
+ QString lang = localeListObject.callMethod<QString>("toLanguageTags");
// Some devices return with it enclosed in []'s so check if both exists before
// removing to ensure it is formatted correctly
if (lang.startsWith(QChar('[')) && lang.endsWith(QChar(']')))
@@ -186,7 +164,7 @@ QVariant QAndroidSystemLocale::query(QueryType type, QVariant in) const
return QVariant();
}
-QLocale QAndroidSystemLocale::fallbackUiLocale() const
+QLocale QAndroidSystemLocale::fallbackLocale() const
{
QReadLocker locker(&m_lock);
return m_locale;
diff --git a/src/plugins/platforms/android/qandroidsystemlocale.h b/src/plugins/platforms/android/qandroidsystemlocale.h
index bc96d2e8f6..cd37b48270 100644
--- a/src/plugins/platforms/android/qandroidsystemlocale.h
+++ b/src/plugins/platforms/android/qandroidsystemlocale.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QANDROIDSYSTEMLOCALE_H
#define QANDROIDSYSTEMLOCALE_H
@@ -47,11 +11,12 @@ QT_BEGIN_NAMESPACE
class QAndroidSystemLocale : public QSystemLocale
{
+ Q_DISABLE_COPY_MOVE(QAndroidSystemLocale)
public:
QAndroidSystemLocale();
- QVariant query(QueryType type, QVariant in) const override;
- QLocale fallbackUiLocale() const override;
+ QVariant query(QueryType type, QVariant &&in) const override;
+ QLocale fallbackLocale() const override;
private:
void getLocaleFromJava() const;
diff --git a/src/plugins/platforms/bsdfb/bsdfb.pro b/src/plugins/platforms/bsdfb/bsdfb.pro
deleted file mode 100644
index 770145a8ff..0000000000
--- a/src/plugins/platforms/bsdfb/bsdfb.pro
+++ /dev/null
@@ -1,19 +0,0 @@
-TARGET = qbsdfb
-
-QT += \
- core-private gui-private \
- service_support-private eventdispatcher_support-private \
- fontdatabase_support-private fb_support-private
-
-qtHaveModule(input_support-private): \
- QT += input_support-private
-
-SOURCES = main.cpp qbsdfbintegration.cpp qbsdfbscreen.cpp
-HEADERS = qbsdfbintegration.h qbsdfbscreen.h
-
-OTHER_FILES += bsdfb.json
-
-PLUGIN_TYPE = platforms
-PLUGIN_CLASS_NAME = QBsdFbIntegrationPlugin
-!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = -
-load(qt_plugin)
diff --git a/src/plugins/platforms/bsdfb/main.cpp b/src/plugins/platforms/bsdfb/main.cpp
index b2cd1373a7..99868567a9 100644
--- a/src/plugins/platforms/bsdfb/main.cpp
+++ b/src/plugins/platforms/bsdfb/main.cpp
@@ -1,48 +1,14 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Copyright (C) 2015-2016 Oleksandr Tymoshenko <gonzo@bluezbox.com>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// Copyright (C) 2015-2016 Oleksandr Tymoshenko <gonzo@bluezbox.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <qpa/qplatformintegrationplugin.h>
#include "qbsdfbintegration.h"
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
class QBsdFbIntegrationPlugin : public QPlatformIntegrationPlugin
{
Q_OBJECT
@@ -54,7 +20,7 @@ public:
QPlatformIntegration* QBsdFbIntegrationPlugin::create(const QString& system, const QStringList& paramList)
{
Q_UNUSED(paramList);
- if (!system.compare(QLatin1String("bsdfb"), Qt::CaseInsensitive))
+ if (!system.compare("bsdfb"_L1, Qt::CaseInsensitive))
return new QBsdFbIntegration(paramList);
return nullptr;
diff --git a/src/plugins/platforms/bsdfb/qbsdfbintegration.cpp b/src/plugins/platforms/bsdfb/qbsdfbintegration.cpp
index e4c90d26af..c56499b3a4 100644
--- a/src/plugins/platforms/bsdfb/qbsdfbintegration.cpp
+++ b/src/plugins/platforms/bsdfb/qbsdfbintegration.cpp
@@ -1,49 +1,13 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Copyright (C) 2015-2016 Oleksandr Tymoshenko <gonzo@bluezbox.com>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// Copyright (C) 2015-2016 Oleksandr Tymoshenko <gonzo@bluezbox.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qbsdfbintegration.h"
#include "qbsdfbscreen.h"
-#include <QtFontDatabaseSupport/private/qgenericunixfontdatabase_p.h>
-#include <QtServiceSupport/private/qgenericunixservices_p.h>
-#include <QtEventDispatcherSupport/private/qgenericunixeventdispatcher_p.h>
+#include <QtGui/private/qgenericunixfontdatabase_p.h>
+#include <QtGui/private/qgenericunixservices_p.h>
+#include <QtGui/private/qgenericunixeventdispatcher_p.h>
#include <QtFbSupport/private/qfbvthandler_p.h>
#include <QtFbSupport/private/qfbbackingstore_p.h>
@@ -61,6 +25,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
QBsdFbIntegration::QBsdFbIntegration(const QStringList &paramList)
{
m_fontDb.reset(new QGenericUnixFontDatabase);
@@ -95,6 +61,8 @@ bool QBsdFbIntegration::hasCapability(QPlatformIntegration::Capability cap) cons
return true;
case WindowManagement:
return false;
+ case RhiBasedRendering:
+ return false;
default:
return QPlatformIntegration::hasCapability(cap);
}
@@ -137,7 +105,7 @@ void QBsdFbIntegration::createInputHandlers()
#if QT_CONFIG(tslib)
const bool useTslib = qEnvironmentVariableIntValue("QT_QPA_FB_TSLIB");
if (useTslib)
- new QTsLibMouseHandler(QLatin1String("TsLib"), QString());
+ new QTsLibMouseHandler("TsLib"_L1, QString());
#endif
}
diff --git a/src/plugins/platforms/bsdfb/qbsdfbintegration.h b/src/plugins/platforms/bsdfb/qbsdfbintegration.h
index 81195edf7e..8d2b572fb6 100644
--- a/src/plugins/platforms/bsdfb/qbsdfbintegration.h
+++ b/src/plugins/platforms/bsdfb/qbsdfbintegration.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QBSDFBINTEGRATION_H
#define QBSDFBINTEGRATION_H
diff --git a/src/plugins/platforms/bsdfb/qbsdfbscreen.cpp b/src/plugins/platforms/bsdfb/qbsdfbscreen.cpp
index d752b539a0..31f8dab091 100644
--- a/src/plugins/platforms/bsdfb/qbsdfbscreen.cpp
+++ b/src/plugins/platforms/bsdfb/qbsdfbscreen.cpp
@@ -1,46 +1,11 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Copyright (C) 2015-2016 Oleksandr Tymoshenko <gonzo@bluezbox.com>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// Copyright (C) 2015-2016 Oleksandr Tymoshenko <gonzo@bluezbox.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qbsdfbscreen.h"
#include <QtFbSupport/private/qfbcursor_p.h>
#include <QtFbSupport/private/qfbwindow_p.h>
+#include <QtCore/QFile>
#include <QtCore/QRegularExpression>
#include <QtGui/QPainter>
@@ -65,6 +30,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
enum {
DefaultDPI = 100
};
@@ -151,17 +118,17 @@ QBsdFbScreen::~QBsdFbScreen()
bool QBsdFbScreen::initialize()
{
- QRegularExpression fbRx(QLatin1String("fb=(.*)"));
- QRegularExpression mmSizeRx(QLatin1String("mmsize=(\\d+)x(\\d+)"));
- QRegularExpression sizeRx(QLatin1String("size=(\\d+)x(\\d+)"));
- QRegularExpression offsetRx(QLatin1String("offset=(\\d+)x(\\d+)"));
+ QRegularExpression fbRx("fb=(.*)"_L1);
+ QRegularExpression mmSizeRx("mmsize=(\\d+)x(\\d+)"_L1);
+ QRegularExpression sizeRx("size=(\\d+)x(\\d+)"_L1);
+ QRegularExpression offsetRx("offset=(\\d+)x(\\d+)"_L1);
QString fbDevice;
QSize userMmSize;
QRect userGeometry;
// Parse arguments
- for (const QString &arg : qAsConst(m_arguments)) {
+ for (const QString &arg : std::as_const(m_arguments)) {
QRegularExpressionMatch match;
if (arg.contains(mmSizeRx, &match))
userMmSize = QSize(match.captured(1).toInt(), match.captured(2).toInt());
diff --git a/src/plugins/platforms/bsdfb/qbsdfbscreen.h b/src/plugins/platforms/bsdfb/qbsdfbscreen.h
index 6002e3664e..d22fb66920 100644
--- a/src/plugins/platforms/bsdfb/qbsdfbscreen.h
+++ b/src/plugins/platforms/bsdfb/qbsdfbscreen.h
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Copyright (C) 2015-2016 Oleksandr Tymoshenko <gonzo@bluezbox.com>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// Copyright (C) 2015-2016 Oleksandr Tymoshenko <gonzo@bluezbox.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QBSDFBSCREEN_H
#define QBSDFBSCREEN_H
diff --git a/src/plugins/platforms/cocoa/.prev_CMakeLists.txt b/src/plugins/platforms/cocoa/.prev_CMakeLists.txt
deleted file mode 100644
index 1491340b65..0000000000
--- a/src/plugins/platforms/cocoa/.prev_CMakeLists.txt
+++ /dev/null
@@ -1,150 +0,0 @@
-# Generated from cocoa.pro.
-
-#####################################################################
-## QCocoaIntegrationPlugin Plugin:
-#####################################################################
-
-qt_add_plugin(QCocoaIntegrationPlugin
- OUTPUT_NAME qcocoa
- TYPE platforms
- SOURCES
- main.mm
- messages.cpp messages.h
- qcocoaapplication.h qcocoaapplication.mm
- qcocoaapplicationdelegate.h qcocoaapplicationdelegate.mm
- qcocoabackingstore.h qcocoabackingstore.mm
- qcocoaclipboard.h qcocoaclipboard.mm
- qcocoacursor.h qcocoacursor.mm
- qcocoadrag.h qcocoadrag.mm
- qcocoaeventdispatcher.h qcocoaeventdispatcher.mm
- qcocoahelpers.h qcocoahelpers.mm
- qcocoainputcontext.h qcocoainputcontext.mm
- qcocoaintegration.h qcocoaintegration.mm
- qcocoaintrospection.h qcocoaintrospection.mm
- qcocoakeymapper.h qcocoakeymapper.mm
- qcocoamenu.h qcocoamenu.mm
- qcocoamenubar.h qcocoamenubar.mm
- qcocoamenuitem.h qcocoamenuitem.mm
- qcocoamenuloader.h qcocoamenuloader.mm
- qcocoamimetypes.h qcocoamimetypes.mm
- qcocoanativeinterface.h qcocoanativeinterface.mm
- qcocoansmenu.h qcocoansmenu.mm
- qcocoascreen.h qcocoascreen.mm
- qcocoaservices.h qcocoaservices.mm
- qcocoasystemtrayicon.h qcocoasystemtrayicon.mm
- qcocoatheme.h qcocoatheme.mm
- qcocoawindow.h qcocoawindow.mm
- qcocoawindowmanager.h qcocoawindowmanager.mm
- qiosurfacegraphicsbuffer.h qiosurfacegraphicsbuffer.mm
- qmacclipboard.h qmacclipboard.mm
- qmultitouch_mac.mm qmultitouch_mac_p.h
- qnsview.h qnsview.mm
- qnswindow.h qnswindow.mm
- qnswindowdelegate.h qnswindowdelegate.mm
- PUBLIC_LIBRARIES
- ${FWAppKit}
- ${FWCarbon}
- ${FWCoreServices}
- ${FWCoreVideo}
- ${FWIOKit}
- ${FWIOSurface}
- ${FWMetal}
- ${FWQuartzCore}
- Cups::Cups
- Qt::ClipboardSupportPrivate
- Qt::Core
- Qt::CorePrivate
- Qt::FontDatabaseSupportPrivate
- Qt::GraphicsSupportPrivate
- Qt::Gui
- Qt::GuiPrivate
- Qt::ThemeSupportPrivate
-)
-
-# Resources:
-set(qcocoaresources_resource_files
- "images/sizeallcursor.png"
- "images/spincursor.png"
- "images/waitcursor.png"
-)
-
-qt_add_resource(QCocoaIntegrationPlugin "qcocoaresources"
- PREFIX
- "/qt-project.org/mac/cursors"
- FILES
- ${qcocoaresources_resource_files}
-)
-
-
-#### Keys ignored in scope 1:.:.:cocoa.pro:<TRUE>:
-# OTHER_FILES = "cocoa.json"
-
-## Scopes:
-#####################################################################
-
-qt_extend_target(QCocoaIntegrationPlugin CONDITION QT_FEATURE_opengl
- SOURCES
- qcocoaglcontext.h qcocoaglcontext.mm
-)
-
-qt_extend_target(QCocoaIntegrationPlugin CONDITION QT_FEATURE_vulkan
- SOURCES
- qcocoavulkaninstance.h qcocoavulkaninstance.mm
- PUBLIC_LIBRARIES
- Qt::VulkanSupportPrivate
-)
-
-qt_extend_target(QCocoaIntegrationPlugin CONDITION QT_FEATURE_accessibility
- SOURCES
- qcocoaaccessibility.h qcocoaaccessibility.mm
- qcocoaaccessibilityelement.h qcocoaaccessibilityelement.mm
- PUBLIC_LIBRARIES
- Qt::AccessibilitySupportPrivate
-)
-
-qt_extend_target(QCocoaIntegrationPlugin CONDITION QT_FEATURE_sessionmanager
- SOURCES
- qcocoasessionmanager.cpp qcocoasessionmanager.h
-)
-
-qt_extend_target(QCocoaIntegrationPlugin CONDITION TARGET Qt::PlatformCompositorSupportPrivate
- PUBLIC_LIBRARIES
- Qt::PlatformCompositorSupportPrivate
-)
-
-qt_extend_target(QCocoaIntegrationPlugin CONDITION TARGET Qt::Widgets
- SOURCES
- qpaintengine_mac.mm qpaintengine_mac_p.h
- PUBLIC_LIBRARIES
- Qt::WidgetsPrivate
-)
-
-#### Keys ignored in scope 8:.:.:cocoa.pro:TARGET Qt::Widgets:
-# QT_FOR_CONFIG = "widgets"
-
-qt_extend_target(QCocoaIntegrationPlugin CONDITION TARGET Qt::PrintSupport AND TARGET Qt::Widgets
- SOURCES
- qcocoaprintdevice.h qcocoaprintdevice.mm
- qcocoaprintersupport.h qcocoaprintersupport.mm
- qprintengine_mac.mm qprintengine_mac_p.h
- PUBLIC_LIBRARIES
- Qt::PrintSupportPrivate
-)
-
-qt_extend_target(QCocoaIntegrationPlugin CONDITION QT_FEATURE_colordialog AND TARGET Qt::Widgets
- SOURCES
- qcocoacolordialoghelper.h qcocoacolordialoghelper.mm
-)
-
-qt_extend_target(QCocoaIntegrationPlugin CONDITION QT_FEATURE_filedialog AND TARGET Qt::Widgets
- SOURCES
- qcocoafiledialoghelper.h qcocoafiledialoghelper.mm
-)
-
-qt_extend_target(QCocoaIntegrationPlugin CONDITION QT_FEATURE_fontdialog AND TARGET Qt::Widgets
- SOURCES
- qcocoafontdialoghelper.h qcocoafontdialoghelper.mm
-)
-
-#### Keys ignored in scope 13:.:.:cocoa.pro:NOT TARGET___equals____ss_QT_DEFAULT_QPA_PLUGIN:
-# PLUGIN_EXTENDS = "-"
diff --git a/src/plugins/platforms/cocoa/CMakeLists.txt b/src/plugins/platforms/cocoa/CMakeLists.txt
index 9e8b162aec..92e681d8fb 100644
--- a/src/plugins/platforms/cocoa/CMakeLists.txt
+++ b/src/plugins/platforms/cocoa/CMakeLists.txt
@@ -1,19 +1,16 @@
-# Generated from cocoa.pro.
-
-# special case:
-qt_find_package(Cups PROVIDED_TARGETS Cups::Cups)
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## QCocoaIntegrationPlugin Plugin:
#####################################################################
-qt_add_plugin(QCocoaIntegrationPlugin
+qt_internal_add_plugin(QCocoaIntegrationPlugin
OUTPUT_NAME qcocoa
- DEFAULT_IF ${QT_QPA_DEFAULT_PLATFORM} MATCHES cocoa # special case
- TYPE platforms
+ DEFAULT_IF ${QT_QPA_DEFAULT_PLATFORM} MATCHES cocoa
+ PLUGIN_TYPE platforms
SOURCES
main.mm
- messages.cpp messages.h
qcocoaapplication.h qcocoaapplication.mm
qcocoaapplicationdelegate.h qcocoaapplicationdelegate.mm
qcocoabackingstore.h qcocoabackingstore.mm
@@ -25,7 +22,6 @@ qt_add_plugin(QCocoaIntegrationPlugin
qcocoainputcontext.h qcocoainputcontext.mm
qcocoaintegration.h qcocoaintegration.mm
qcocoaintrospection.h qcocoaintrospection.mm
- qcocoakeymapper.h qcocoakeymapper.mm
qcocoamenu.h qcocoamenu.mm
qcocoamenubar.h qcocoamenubar.mm
qcocoamenuitem.h qcocoamenuitem.mm
@@ -45,7 +41,13 @@ qt_add_plugin(QCocoaIntegrationPlugin
qnsview.h qnsview.mm
qnswindow.h qnswindow.mm
qnswindowdelegate.h qnswindowdelegate.mm
- PUBLIC_LIBRARIES
+ qcocoacolordialoghelper.h qcocoacolordialoghelper.mm
+ qcocoafiledialoghelper.h qcocoafiledialoghelper.mm
+ qcocoafontdialoghelper.h qcocoafontdialoghelper.mm
+ qcocoamessagedialog.h qcocoamessagedialog.mm
+ DEFINES
+ QT_NO_FOREACH
+ LIBRARIES
${FWAppKit}
${FWCarbon}
${FWCoreServices}
@@ -54,17 +56,15 @@ qt_add_plugin(QCocoaIntegrationPlugin
${FWIOSurface}
${FWMetal}
${FWQuartzCore}
- Cups::Cups
- Qt::ClipboardSupportPrivate
+ ${FWUniformTypeIdentifiers}
Qt::Core
Qt::CorePrivate
- Qt::FontDatabaseSupportPrivate
- Qt::GraphicsSupportPrivate
Qt::Gui
Qt::GuiPrivate
- Qt::ThemeSupportPrivate
)
+qt_disable_apple_app_extension_api_only(QCocoaIntegrationPlugin)
+
# Resources:
set(qcocoaresources_resource_files
"images/sizeallcursor.png"
@@ -72,83 +72,33 @@ set(qcocoaresources_resource_files
"images/waitcursor.png"
)
-qt_add_resource(QCocoaIntegrationPlugin "qcocoaresources"
+qt_internal_add_resource(QCocoaIntegrationPlugin "qcocoaresources"
PREFIX
"/qt-project.org/mac/cursors"
FILES
${qcocoaresources_resource_files}
)
-
-#### Keys ignored in scope 1:.:.:cocoa.pro:<TRUE>:
-# OTHER_FILES = "cocoa.json"
-
## Scopes:
#####################################################################
-qt_extend_target(QCocoaIntegrationPlugin CONDITION QT_FEATURE_opengl
+qt_internal_extend_target(QCocoaIntegrationPlugin CONDITION QT_FEATURE_opengl
SOURCES
qcocoaglcontext.h qcocoaglcontext.mm
)
-qt_extend_target(QCocoaIntegrationPlugin CONDITION QT_FEATURE_vulkan
+qt_internal_extend_target(QCocoaIntegrationPlugin CONDITION QT_FEATURE_vulkan
SOURCES
qcocoavulkaninstance.h qcocoavulkaninstance.mm
- PUBLIC_LIBRARIES
- Qt::VulkanSupportPrivate
)
-qt_extend_target(QCocoaIntegrationPlugin CONDITION QT_FEATURE_accessibility
+qt_internal_extend_target(QCocoaIntegrationPlugin CONDITION QT_FEATURE_accessibility
SOURCES
qcocoaaccessibility.h qcocoaaccessibility.mm
qcocoaaccessibilityelement.h qcocoaaccessibilityelement.mm
- PUBLIC_LIBRARIES
- Qt::AccessibilitySupportPrivate
)
-qt_extend_target(QCocoaIntegrationPlugin CONDITION QT_FEATURE_sessionmanager
+qt_internal_extend_target(QCocoaIntegrationPlugin CONDITION QT_FEATURE_sessionmanager
SOURCES
qcocoasessionmanager.cpp qcocoasessionmanager.h
)
-
-qt_extend_target(QCocoaIntegrationPlugin CONDITION TARGET Qt::PlatformCompositorSupportPrivate
- PUBLIC_LIBRARIES
- Qt::PlatformCompositorSupportPrivate
-)
-
-qt_extend_target(QCocoaIntegrationPlugin CONDITION TARGET Qt::Widgets
- SOURCES
- qpaintengine_mac.mm qpaintengine_mac_p.h
- PUBLIC_LIBRARIES
- Qt::WidgetsPrivate
-)
-
-#### Keys ignored in scope 8:.:.:cocoa.pro:TARGET Qt::Widgets:
-# QT_FOR_CONFIG = "widgets"
-
-qt_extend_target(QCocoaIntegrationPlugin CONDITION TARGET Qt::PrintSupport AND TARGET Qt::Widgets
- SOURCES
- qcocoaprintdevice.h qcocoaprintdevice.mm
- qcocoaprintersupport.h qcocoaprintersupport.mm
- qprintengine_mac.mm qprintengine_mac_p.h
- PUBLIC_LIBRARIES
- Qt::PrintSupportPrivate
-)
-
-qt_extend_target(QCocoaIntegrationPlugin CONDITION QT_FEATURE_colordialog AND TARGET Qt::Widgets
- SOURCES
- qcocoacolordialoghelper.h qcocoacolordialoghelper.mm
-)
-
-qt_extend_target(QCocoaIntegrationPlugin CONDITION QT_FEATURE_filedialog AND TARGET Qt::Widgets
- SOURCES
- qcocoafiledialoghelper.h qcocoafiledialoghelper.mm
-)
-
-qt_extend_target(QCocoaIntegrationPlugin CONDITION QT_FEATURE_fontdialog AND TARGET Qt::Widgets
- SOURCES
- qcocoafontdialoghelper.h qcocoafontdialoghelper.mm
-)
-
-#### Keys ignored in scope 13:.:.:cocoa.pro:NOT TARGET___equals____ss_QT_DEFAULT_QPA_PLUGIN:
-# PLUGIN_EXTENDS = "-"
diff --git a/src/plugins/platforms/cocoa/cocoa.pro b/src/plugins/platforms/cocoa/cocoa.pro
deleted file mode 100644
index 953346c56e..0000000000
--- a/src/plugins/platforms/cocoa/cocoa.pro
+++ /dev/null
@@ -1,149 +0,0 @@
-TARGET = qcocoa
-
-SOURCES += main.mm \
- qcocoaintegration.mm \
- qcocoascreen.mm \
- qcocoatheme.mm \
- qcocoabackingstore.mm \
- qcocoawindow.mm \
- qcocoawindowmanager.mm \
- qnsview.mm \
- qnswindow.mm \
- qnswindowdelegate.mm \
- qcocoanativeinterface.mm \
- qcocoaeventdispatcher.mm \
- qcocoaapplicationdelegate.mm \
- qcocoaapplication.mm \
- qcocoansmenu.mm \
- qcocoamenu.mm \
- qcocoamenuitem.mm \
- qcocoamenubar.mm \
- qcocoamenuloader.mm \
- qcocoahelpers.mm \
- qmultitouch_mac.mm \
- qcocoacursor.mm \
- qcocoaclipboard.mm \
- qcocoadrag.mm \
- qmacclipboard.mm \
- qcocoainputcontext.mm \
- qcocoaservices.mm \
- qcocoasystemtrayicon.mm \
- qcocoaintrospection.mm \
- qcocoakeymapper.mm \
- qcocoamimetypes.mm \
- qiosurfacegraphicsbuffer.mm \
- messages.cpp
-
-HEADERS += qcocoaintegration.h \
- qcocoascreen.h \
- qcocoatheme.h \
- qcocoabackingstore.h \
- qcocoawindow.h \
- qcocoawindowmanager.h \
- qnsview.h \
- qnswindow.h \
- qnswindowdelegate.h \
- qcocoanativeinterface.h \
- qcocoaeventdispatcher.h \
- qcocoaapplicationdelegate.h \
- qcocoaapplication.h \
- qcocoansmenu.h \
- qcocoamenu.h \
- qcocoamenuitem.h \
- qcocoamenubar.h \
- qcocoamenuloader.h \
- qcocoahelpers.h \
- qmultitouch_mac_p.h \
- qcocoacursor.h \
- qcocoaclipboard.h \
- qcocoadrag.h \
- qmacclipboard.h \
- qcocoainputcontext.h \
- qcocoaservices.h \
- qcocoasystemtrayicon.h \
- qcocoaintrospection.h \
- qcocoakeymapper.h \
- messages.h \
- qiosurfacegraphicsbuffer.h \
- qcocoamimetypes.h
-
-qtConfig(opengl.*) {
- SOURCES += qcocoaglcontext.mm
- HEADERS += qcocoaglcontext.h
-}
-
-qtConfig(vulkan) {
- SOURCES += qcocoavulkaninstance.mm
- HEADERS += qcocoavulkaninstance.h
-}
-
-qtConfig(accessibility) {
- QT += accessibility_support-private
- SOURCES += qcocoaaccessibilityelement.mm \
- qcocoaaccessibility.mm
- HEADERS += qcocoaaccessibilityelement.h \
- qcocoaaccessibility.h
-}
-
-qtConfig(sessionmanager) {
- SOURCES += qcocoasessionmanager.cpp
- HEADERS += qcocoasessionmanager.h
-}
-
-RESOURCES += qcocoaresources.qrc
-
-LIBS += -framework AppKit -framework CoreServices -framework Carbon -framework IOKit -framework QuartzCore -framework CoreVideo -framework Metal -framework IOSurface -lcups
-
-QT += \
- core-private gui-private \
- clipboard_support-private theme_support-private \
- fontdatabase_support-private graphics_support-private
-
-qtConfig(vulkan): QT += vulkan_support-private
-
-qtHaveModule(platformcompositor_support-private): QT += platformcompositor_support-private
-
-CONFIG += no_app_extension_api_only
-
-qtHaveModule(widgets) {
- QT_FOR_CONFIG += widgets
-
- SOURCES += qpaintengine_mac.mm
- HEADERS += qpaintengine_mac_p.h
-
- qtHaveModule(printsupport) {
- QT += printsupport-private
- SOURCES += \
- qprintengine_mac.mm \
- qcocoaprintersupport.mm \
- qcocoaprintdevice.mm
- HEADERS += \
- qcocoaprintersupport.h \
- qcocoaprintdevice.h \
- qprintengine_mac_p.h
- }
-
- qtConfig(colordialog) {
- SOURCES += qcocoacolordialoghelper.mm
- HEADERS += qcocoacolordialoghelper.h
- }
-
- qtConfig(filedialog) {
- SOURCES += qcocoafiledialoghelper.mm
- HEADERS += qcocoafiledialoghelper.h
- }
-
- qtConfig(fontdialog) {
- SOURCES += qcocoafontdialoghelper.mm
- HEADERS += qcocoafontdialoghelper.h
- }
-
- QT += widgets-private
-}
-
-OTHER_FILES += cocoa.json
-
-PLUGIN_TYPE = platforms
-PLUGIN_CLASS_NAME = QCocoaIntegrationPlugin
-!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = -
-load(qt_plugin)
diff --git a/src/plugins/platforms/cocoa/main.mm b/src/plugins/platforms/cocoa/main.mm
index 89ecdf46f9..7fbf26cb75 100644
--- a/src/plugins/platforms/cocoa/main.mm
+++ b/src/plugins/platforms/cocoa/main.mm
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <AppKit/AppKit.h>
@@ -44,8 +8,12 @@
#include "qcocoaintegration.h"
#include "qcocoatheme.h"
+#include <QtCore/private/qcore_mac_p.h>
+
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
class QCocoaIntegrationPlugin : public QPlatformIntegrationPlugin
{
Q_OBJECT
@@ -57,7 +25,7 @@ public:
QPlatformIntegration * QCocoaIntegrationPlugin::create(const QString& system, const QStringList& paramList)
{
QMacAutoReleasePool pool;
- if (system.compare(QLatin1String("cocoa"), Qt::CaseInsensitive) == 0)
+ if (system.compare("cocoa"_L1, Qt::CaseInsensitive) == 0)
return new QCocoaIntegration(paramList);
return nullptr;
diff --git a/src/plugins/platforms/cocoa/messages.cpp b/src/plugins/platforms/cocoa/messages.cpp
deleted file mode 100644
index 06e3dd454e..0000000000
--- a/src/plugins/platforms/cocoa/messages.cpp
+++ /dev/null
@@ -1,115 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 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 "messages.h"
-
-#include <QtCore/qcoreapplication.h>
-#include <QtCore/qregularexpression.h>
-
-// Translatable messages should go into this .cpp file for them to be picked up by lupdate.
-
-QT_BEGIN_NAMESPACE
-
-QString msgAboutQt()
-{
- return QCoreApplication::translate("QCocoaMenuItem", "About Qt");
-}
-
-static const char *application_menu_strings[] =
-{
- QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU","About %1"),
- QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU","Preferences..."),
- QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU","Services"),
- QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU","Hide %1"),
- QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU","Hide Others"),
- QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU","Show All"),
- QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU","Quit %1")
-};
-
-QString qt_mac_applicationmenu_string(int type)
-{
- QString menuString = QString::fromLatin1(application_menu_strings[type]);
- const QString translated = QCoreApplication::translate("QMenuBar", application_menu_strings[type]);
- if (translated != menuString) {
- return translated;
- } else {
- return QCoreApplication::translate("MAC_APPLICATION_MENU", application_menu_strings[type]);
- }
-}
-
-QPlatformMenuItem::MenuRole detectMenuRole(const QString &caption)
-{
- QString captionNoAmpersand(caption);
- captionNoAmpersand.remove(QLatin1Char('&'));
- const QString aboutString = QCoreApplication::translate("QCocoaMenuItem", "About");
- if (captionNoAmpersand.startsWith(aboutString, Qt::CaseInsensitive)
- || captionNoAmpersand.endsWith(aboutString, Qt::CaseInsensitive)) {
- static const QRegularExpression qtRegExp(QLatin1String("qt$"), QRegularExpression::CaseInsensitiveOption);
- if (captionNoAmpersand.contains(qtRegExp))
- return QPlatformMenuItem::AboutQtRole;
- return QPlatformMenuItem::AboutRole;
- }
- if (captionNoAmpersand.startsWith(QCoreApplication::translate("QCocoaMenuItem", "Config"), Qt::CaseInsensitive)
- || captionNoAmpersand.startsWith(QCoreApplication::translate("QCocoaMenuItem", "Preference"), Qt::CaseInsensitive)
- || captionNoAmpersand.startsWith(QCoreApplication::translate("QCocoaMenuItem", "Options"), Qt::CaseInsensitive)
- || captionNoAmpersand.startsWith(QCoreApplication::translate("QCocoaMenuItem", "Setting"), Qt::CaseInsensitive)
- || captionNoAmpersand.startsWith(QCoreApplication::translate("QCocoaMenuItem", "Setup"), Qt::CaseInsensitive)) {
- return QPlatformMenuItem::PreferencesRole;
- }
- if (captionNoAmpersand.startsWith(QCoreApplication::translate("QCocoaMenuItem", "Quit"), Qt::CaseInsensitive)
- || captionNoAmpersand.startsWith(QCoreApplication::translate("QCocoaMenuItem", "Exit"), Qt::CaseInsensitive)) {
- return QPlatformMenuItem::QuitRole;
- }
- if (!captionNoAmpersand.compare(QCoreApplication::translate("QCocoaMenuItem", "Cut"), Qt::CaseInsensitive))
- return QPlatformMenuItem::CutRole;
- if (!captionNoAmpersand.compare(QCoreApplication::translate("QCocoaMenuItem", "Copy"), Qt::CaseInsensitive))
- return QPlatformMenuItem::CopyRole;
- if (!captionNoAmpersand.compare(QCoreApplication::translate("QCocoaMenuItem", "Paste"), Qt::CaseInsensitive))
- return QPlatformMenuItem::PasteRole;
- if (!captionNoAmpersand.compare(QCoreApplication::translate("QCocoaMenuItem", "Select All"), Qt::CaseInsensitive))
- return QPlatformMenuItem::SelectAllRole;
- return QPlatformMenuItem::NoRole;
-}
-
-QString msgDialogButtonDiscard()
-{
- return QCoreApplication::translate("QCocoaTheme", "Don't Save");
-}
-
-QT_END_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/messages.h b/src/plugins/platforms/cocoa/messages.h
deleted file mode 100644
index 3a9eaf604e..0000000000
--- a/src/plugins/platforms/cocoa/messages.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 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 MESSAGES_H
-#define MESSAGES_H
-
-#include <QString>
-#include <qpa/qplatformmenu.h>
-
-QT_BEGIN_NAMESPACE
-
-enum {
- AboutAppMenuItem = 0,
- PreferencesAppMenuItem,
- ServicesAppMenuItem,
- HideAppMenuItem,
- HideOthersAppMenuItem,
- ShowAllAppMenuItem,
- QuitAppMenuItem
-};
-
-
-QString msgAboutQt();
-
-QString qt_mac_applicationmenu_string(int type);
-
-QPlatformMenuItem::MenuRole detectMenuRole(const QString &caption);
-
-QString msgDialogButtonDiscard();
-
-QT_END_NAMESPACE
-
-#endif // MESSAGES_H
diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibility.h b/src/plugins/platforms/cocoa/qcocoaaccessibility.h
index 539d876094..cdd9aafc80 100644
--- a/src/plugins/platforms/cocoa/qcocoaaccessibility.h
+++ b/src/plugins/platforms/cocoa/qcocoaaccessibility.h
@@ -1,53 +1,17 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
#ifndef QCOCOAACCESIBILITY_H
#define QCOCOAACCESIBILITY_H
-#include <AppKit/AppKit.h>
+#include <QtGui/qtguiglobal.h>
+
+#if QT_CONFIG(accessibility)
-#include <QtGui>
#include <qpa/qplatformaccessibility.h>
#include "qcocoaaccessibilityelement.h"
-#ifndef QT_NO_ACCESSIBILITY
-
QT_BEGIN_NAMESPACE
class QCocoaAccessibility : public QPlatformAccessibility
@@ -81,6 +45,7 @@ namespace QCocoaAccessible {
demand.
*/
+#if defined(__OBJC__)
NSString *macRole(QAccessibleInterface *interface);
NSString *macSubrole(QAccessibleInterface *interface);
bool shouldBeIgnored(QAccessibleInterface *interface);
@@ -89,11 +54,12 @@ NSString *getTranslatedAction(const QString &qtAction);
QString translateAction(NSString *nsAction, QAccessibleInterface *interface);
bool hasValueAttribute(QAccessibleInterface *interface);
id getValueAttribute(QAccessibleInterface *interface);
+#endif // __OBJC__
}
QT_END_NAMESPACE
-#endif // QT_NO_ACCESSIBILITY
+#endif // QT_CONFIG(accessibility)
#endif // QCOCOAACCESIBILITY_H
diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibility.mm b/src/plugins/platforms/cocoa/qcocoaaccessibility.mm
index 106c226adc..c5e40a4087 100644
--- a/src/plugins/platforms/cocoa/qcocoaaccessibility.mm
+++ b/src/plugins/platforms/cocoa/qcocoaaccessibility.mm
@@ -1,49 +1,19 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <AppKit/AppKit.h>
+
#include "qcocoaaccessibility.h"
#include "qcocoaaccessibilityelement.h"
#include <QtGui/qaccessible.h>
+#include <QtCore/qmap.h>
#include <private/qcore_mac_p.h>
QT_BEGIN_NAMESPACE
-#ifndef QT_NO_ACCESSIBILITY
+using namespace Qt::StringLiterals;
+
+#if QT_CONFIG(accessibility)
QCocoaAccessibility::QCocoaAccessibility()
{
@@ -84,6 +54,10 @@ void QCocoaAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event)
case QAccessible::NameChanged:
NSAccessibilityPostNotification(element, NSAccessibilityTitleChangedNotification);
break;
+ case QAccessible::TableModelChanged:
+ // ### Could NSAccessibilityRowCountChangedNotification be relevant here?
+ [element updateTableModel];
+ break;
default:
break;
}
@@ -91,7 +65,7 @@ void QCocoaAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event)
void QCocoaAccessibility::setRootObject(QObject *o)
{
- Q_UNUSED(o)
+ Q_UNUSED(o);
}
void QCocoaAccessibility::initialize()
@@ -143,7 +117,6 @@ static void populateRoleMap()
roleMap[QAccessible::ColumnHeader] = NSAccessibilityColumnRole;
roleMap[QAccessible::Row] = NSAccessibilityRowRole;
roleMap[QAccessible::RowHeader] = NSAccessibilityRowRole;
- roleMap[QAccessible::Cell] = NSAccessibilityTextFieldRole;
roleMap[QAccessible::Button] = NSAccessibilityButtonRole;
roleMap[QAccessible::EditableText] = NSAccessibilityTextFieldRole;
roleMap[QAccessible::Link] = NSAccessibilityLinkRole;
@@ -151,7 +124,7 @@ static void populateRoleMap()
roleMap[QAccessible::Splitter] = NSAccessibilitySplitGroupRole;
roleMap[QAccessible::List] = NSAccessibilityListRole;
roleMap[QAccessible::ListItem] = NSAccessibilityStaticTextRole;
- roleMap[QAccessible::Cell] = NSAccessibilityStaticTextRole;
+ roleMap[QAccessible::Cell] = NSAccessibilityCellRole;
roleMap[QAccessible::Client] = NSAccessibilityGroupRole;
roleMap[QAccessible::Paragraph] = NSAccessibilityGroupRole;
roleMap[QAccessible::Section] = NSAccessibilityGroupRole;
@@ -163,6 +136,7 @@ static void populateRoleMap()
roleMap[QAccessible::Note] = NSAccessibilityGroupRole;
roleMap[QAccessible::ComplementaryContent] = NSAccessibilityGroupRole;
roleMap[QAccessible::Graphic] = NSAccessibilityImageRole;
+ roleMap[QAccessible::Tree] = NSAccessibilityOutlineRole;
}
/*
@@ -181,6 +155,8 @@ NSString *macRole(QAccessibleInterface *interface)
if (roleMap.contains(qtRole)) {
// MAC_ACCESSIBILTY_DEBUG() << "return" << roleMap[qtRole];
+ if (roleMap[qtRole] == NSAccessibilityComboBoxRole && !interface->state().editable)
+ return NSAccessibilityMenuButtonRole;
if (roleMap[qtRole] == NSAccessibilityTextFieldRole && interface->state().multiLine)
return NSAccessibilityTextAreaRole;
return roleMap[qtRole];
@@ -244,12 +220,12 @@ bool shouldBeIgnored(QAccessibleInterface *interface)
return true;
if (QObject * const object = interface->object()) {
- const QString className = QLatin1String(object->metaObject()->className());
+ const QString className = QLatin1StringView(object->metaObject()->className());
// VoiceOver focusing on tool tips can be confusing. The contents of the
// tool tip is available through the description attribute anyway, so
// we disable accessibility for tool tips.
- if (className == QLatin1String("QTipLabel"))
+ if (className == "QTipLabel"_L1)
return true;
}
@@ -386,6 +362,8 @@ id getValueAttribute(QAccessibleInterface *interface)
}
if (interface->state().checkable) {
+ if (interface->state().checkStateMixed)
+ return @(2);
return interface->state().checked ? @(1) : @(0);
}
@@ -394,7 +372,7 @@ id getValueAttribute(QAccessibleInterface *interface)
} // namespace QCocoaAccessible
-#endif // QT_NO_ACCESSIBILITY
+#endif // QT_CONFIG(accessibility)
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.h b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.h
index 141ce6bf1a..a96ab55735 100644
--- a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.h
+++ b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.h
@@ -1,64 +1,25 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
#ifndef QCOCOAACCESIBILITYELEMENT_H
#define QCOCOAACCESIBILITYELEMENT_H
-#include <QtCore/qglobal.h>
-
-#include "qt_mac_p.h"
-
-#ifndef QT_NO_ACCESSIBILITY
+#include <QtGui/qtguiglobal.h>
-#import <Cocoa/Cocoa.h>
-#import <AppKit/NSAccessibility.h>
+#if QT_CONFIG(accessibility)
-#import <qaccessible.h>
-
-@interface QT_MANGLE_NAMESPACE(QMacAccessibilityElement) : NSObject <NSAccessibilityElement>
+#include <QtCore/private/qcore_mac_p.h>
+#include <QtGui/qaccessible.h>
+QT_DECLARE_NAMESPACED_OBJC_INTERFACE(QMacAccessibilityElement, NSObject <NSAccessibilityElement>
- (instancetype)initWithId:(QAccessible::Id)anId;
+- (instancetype)initWithId:(QAccessible::Id)anId role:(NSAccessibilityRole)role;
+ (instancetype)elementWithId:(QAccessible::Id)anId;
++ (instancetype)elementWithInterface:(QAccessibleInterface *)iface;
+- (void)updateTableModel;
+- (QAccessibleInterface *)qtInterface;
+)
-@end
-
-QT_NAMESPACE_ALIAS_OBJC_CLASS(QMacAccessibilityElement);
-
-#endif // QT_NO_ACCESSIBILITY
+#endif // QT_CONFIG(accessibility)
#endif // QCOCOAACCESIBILITYELEMENT_H
diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm
index 3560c9d9b5..8d4d6d683d 100644
--- a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm
+++ b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm
@@ -1,55 +1,26 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <AppKit/AppKit.h>
+
#include "qcocoaaccessibilityelement.h"
#include "qcocoaaccessibility.h"
#include "qcocoahelpers.h"
#include "qcocoawindow.h"
#include "qcocoascreen.h"
-#include "private/qaccessiblecache_p.h"
-#include <QtAccessibilitySupport/private/qaccessiblebridgeutils_p.h>
-#include <QtGui/qaccessible.h>
-#import <AppKit/NSAccessibility.h>
+#include <QtCore/qlogging.h>
+#include <QtGui/private/qaccessiblecache_p.h>
+#include <QtGui/private/qaccessiblebridgeutils_p.h>
+#include <QtGui/qaccessible.h>
QT_USE_NAMESPACE
-#ifndef QT_NO_ACCESSIBILITY
+Q_LOGGING_CATEGORY(lcAccessibilityTable, "qt.accessibility.table")
+
+using namespace Qt::Literals::StringLiterals;
+
+#if QT_CONFIG(accessibility)
/**
* Converts between absolute character offsets and line numbers of a
@@ -114,14 +85,92 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
@implementation QMacAccessibilityElement {
QAccessible::Id axid;
+ int m_rowIndex;
+ int m_columnIndex;
+
+ // used by NSAccessibilityTable
+ NSMutableArray<QMacAccessibilityElement *> *rows; // corresponds to accessibilityRows
+ NSMutableArray<QMacAccessibilityElement *> *columns; // corresponds to accessibilityColumns
+
+ // If synthesizedRole is set, this means that this objects does not have a corresponding
+ // QAccessibleInterface, but it is synthesized by the cocoa plugin in order to meet the
+ // NSAccessibility requirements.
+ // The ownership is controlled by the parent object identified with the axid member variable.
+ // (Therefore, if this member is set, this objects axid member is the same as the parents axid
+ // member)
+ NSString *synthesizedRole;
}
- (instancetype)initWithId:(QAccessible::Id)anId
{
+ return [self initWithId:anId role:nil];
+}
+
+- (instancetype)initWithId:(QAccessible::Id)anId role:(NSAccessibilityRole)role
+{
Q_ASSERT((int)anId < 0);
self = [super init];
if (self) {
axid = anId;
+ m_rowIndex = -1;
+ m_columnIndex = -1;
+ rows = nil;
+ columns = nil;
+ synthesizedRole = role;
+ // table: if this is not created as an element managed by the table, then
+ // it's either the table itself, or an element created for an already existing
+ // cell interface (or an element that's not at all related to a table).
+ if (!synthesizedRole) {
+ if (QAccessibleInterface *iface = QAccessible::accessibleInterface(axid)) {
+ if (iface->tableInterface()) {
+ [self updateTableModel];
+ } else if (const auto *cell = iface->tableCellInterface()) {
+ // If we create an element for a table cell, initialize it with row/column
+ // and insert it into the corresponding row's columns array.
+ m_rowIndex = cell->rowIndex();
+ m_columnIndex = cell->columnIndex();
+ QAccessibleInterface *table = cell->table();
+ Q_ASSERT(table);
+ QAccessibleTableInterface *tableInterface = table->tableInterface();
+ if (tableInterface) {
+ auto *tableElement = [QMacAccessibilityElement elementWithInterface:table];
+ Q_ASSERT(tableElement);
+ if (!tableElement->rows
+ || int(tableElement->rows.count) <= m_rowIndex
+ || int(tableElement->rows.count) != tableInterface->rowCount()) {
+ qCWarning(lcAccessibilityTable)
+ << "Cell requested for row" << m_rowIndex << "is out of"
+ << "bounds for table with" << (tableElement->rows ?
+ tableElement->rows.count : tableInterface->rowCount())
+ << "rows! Resizing table model.";
+ [tableElement updateTableModel];
+ }
+
+ Q_ASSERT(tableElement->rows);
+ Q_ASSERT(int(tableElement->rows.count) > m_rowIndex);
+
+ auto *rowElement = tableElement->rows[m_rowIndex];
+ if (!rowElement->columns || int(rowElement->columns.count) != tableInterface->columnCount()) {
+ if (rowElement->columns) {
+ qCWarning(lcAccessibilityTable)
+ << "Table representation column count is out of sync:"
+ << rowElement->columns.count << "!=" << tableInterface->columnCount();
+ }
+ rowElement->columns = [rowElement populateTableRow:rowElement->columns
+ count:tableInterface->columnCount()];
+ }
+
+ qCDebug(lcAccessibilityTable) << "Creating cell representation for"
+ << m_rowIndex << m_columnIndex
+ << "in table with"
+ << tableElement->rows.count << "rows and"
+ << rowElement->columns.count << "columns";
+
+ rowElement->columns[m_columnIndex] = self;
+ }
+ }
+ }
+ }
}
return self;
@@ -137,30 +186,45 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
QMacAccessibilityElement *element = cache->elementForId(anId);
if (!element) {
- QAccessibleInterface *iface = QAccessible::accessibleInterface(anId);
- Q_ASSERT(iface);
- if (!iface || !iface->isValid())
- return nil;
+ Q_ASSERT(QAccessible::accessibleInterface(anId));
element = [[self alloc] initWithId:anId];
cache->insertElement(anId, element);
}
return element;
}
++ (instancetype)elementWithInterface:(QAccessibleInterface *)iface
+{
+ Q_ASSERT(iface);
+ if (!iface)
+ return nil;
+
+ const QAccessible::Id anId = QAccessible::uniqueId(iface);
+ return [self elementWithId:anId];
+}
+
- (void)invalidate {
axid = 0;
+ rows = nil;
+ columns = nil;
+ synthesizedRole = nil;
+
NSAccessibilityPostNotification(self, NSAccessibilityUIElementDestroyedNotification);
[self release];
}
- (void)dealloc {
+ if (rows)
+ [rows release]; // will also release all entries first
+ if (columns)
+ [columns release]; // will also release all entries first
[super dealloc];
}
- (BOOL)isEqual:(id)object {
if ([object isKindOfClass:[QMacAccessibilityElement class]]) {
QMacAccessibilityElement *other = object;
- return other->axid == axid;
+ return other->axid == axid && other->synthesizedRole == synthesizedRole;
} else {
return NO;
}
@@ -170,16 +234,137 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
return axid;
}
+- (BOOL)isManagedByParent {
+ return synthesizedRole != nil;
+}
+
+- (NSMutableArray *)populateTableArray:(NSMutableArray *)array role:(NSAccessibilityRole)role count:(int)count
+{
+ if (QAccessibleInterface *iface = self.qtInterface) {
+ if (array && int(array.count) != count) {
+ [array release];
+ array = nil;
+ }
+ if (!array) {
+ array = [NSMutableArray<QMacAccessibilityElement *> arrayWithCapacity:count];
+ [array retain];
+ } else {
+ [array removeAllObjects];
+ }
+ Q_ASSERT(array);
+ for (int n = 0; n < count; ++n) {
+ // columns will have same axid as table (but not inserted in cache)
+ QMacAccessibilityElement *element =
+ [[QMacAccessibilityElement alloc] initWithId:axid role:role];
+ if (element) {
+ if (role == NSAccessibilityRowRole)
+ element->m_rowIndex = n;
+ else if (role == NSAccessibilityColumnRole)
+ element->m_columnIndex = n;
+ [array addObject:element];
+ [element release];
+ } else {
+ qWarning("QCocoaAccessibility: invalid child");
+ }
+ }
+ return array;
+ }
+ return nil;
+}
+
+- (NSMutableArray *)populateTableRow:(NSMutableArray *)array count:(int)count
+{
+ Q_ASSERT(synthesizedRole == NSAccessibilityRowRole);
+ if (array && int(array.count) != count) {
+ [array release];
+ array = nil;
+ }
+
+ if (!array) {
+ array = [NSMutableArray<QMacAccessibilityElement *> arrayWithCapacity:count];
+ [array retain];
+ // When macOS asks for the children of a row, then we populate the row's column
+ // array with synthetic elements as place holders. This way, we don't have to
+ // create QAccessibleInterfaces for every cell before they are really needed.
+ // We don't add those synthetic elements into the cache, and we give them the
+ // same axid as the table. This way, we can get easily to the table, and from
+ // there to the QAccessibleInterface for the cell, when we have to eventually
+ // associate such an interface with the element (at which point it is no longer
+ // a placeholder).
+ for (int n = 0; n < count; ++n) {
+ // columns will have same axid as table (but not inserted in cache)
+ QMacAccessibilityElement *cell =
+ [[QMacAccessibilityElement alloc] initWithId:axid role:NSAccessibilityCellRole];
+ if (cell) {
+ cell->m_rowIndex = m_rowIndex;
+ cell->m_columnIndex = n;
+ [array addObject:cell];
+ }
+ }
+ }
+ Q_ASSERT(array);
+ return array;
+}
+
+- (void)updateTableModel
+{
+ if (QAccessibleInterface *iface = self.qtInterface) {
+ if (QAccessibleTableInterface *table = iface->tableInterface()) {
+ Q_ASSERT(!self.isManagedByParent);
+ qCDebug(lcAccessibilityTable) << "Updating table representation with"
+ << table->rowCount() << table->columnCount();
+ rows = [self populateTableArray:rows role:NSAccessibilityRowRole count:table->rowCount()];
+ columns = [self populateTableArray:columns role:NSAccessibilityColumnRole count:table->columnCount()];
+ }
+ }
+}
+
+- (QAccessibleInterface *)qtInterface
+{
+ QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
+ if (!iface || !iface->isValid())
+ return nullptr;
+
+ // If this is a placeholder element for a table cell, associate it with the
+ // cell interface (which will be created now, if needed). The current axid is
+ // for the table to which the cell belongs, so iface is pointing at the table.
+ if (synthesizedRole == NSAccessibilityCellRole) {
+ // get the cell interface - there must be a valid one
+ QAccessibleTableInterface *table = iface->tableInterface();
+ Q_ASSERT(table);
+ QAccessibleInterface *cell = table->cellAt(m_rowIndex, m_columnIndex);
+ if (!cell)
+ return nullptr;
+ Q_ASSERT(cell->isValid());
+ iface = cell;
+
+ // no longer a placeholder
+ axid = QAccessible::uniqueId(cell);
+ synthesizedRole = nil;
+
+ QAccessibleCache *cache = QAccessibleCache::instance();
+ if (QMacAccessibilityElement *cellElement = cache->elementForId(axid)) {
+ // there already is another, non-placeholder element in the cache
+ Q_ASSERT(cellElement->synthesizedRole == nil);
+ // we have to release it if it's not us
+ if (cellElement != self) {
+ // for the same cell position
+ Q_ASSERT(cellElement->m_rowIndex == m_rowIndex && cellElement->m_columnIndex == m_columnIndex);
+ [cellElement release];
+ }
+ }
+
+ cache->insertElement(axid, self);
+ }
+ return iface;
+}
+
//
// accessibility protocol
//
- (BOOL)isAccessibilityFocused
{
- QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
- if (!iface || !iface->isValid()) {
- return false;
- }
// Just check if the app thinks we're focused.
id focusedElement = NSApp.accessibilityApplicationFocusedUIElement;
return [focusedElement isEqual:self];
@@ -189,8 +374,8 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
+ (id) lineNumberForIndex: (int)index forText:(const QString &)text
{
- QStringRef textBefore = QStringRef(&text, 0, index);
- int newlines = textBefore.count(QLatin1Char('\n'));
+ auto textBefore = QStringView(text).left(index);
+ qsizetype newlines = textBefore.count(u'\n');
return @(newlines);
}
@@ -199,31 +384,119 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
}
- (NSString *) accessibilityRole {
- QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
- if (!iface || !iface->isValid())
- return NSAccessibilityUnknownRole;
- return QCocoaAccessible::macRole(iface);
+ // shortcut for cells, rows, and columns in a table
+ if (synthesizedRole)
+ return synthesizedRole;
+ if (QAccessibleInterface *iface = self.qtInterface)
+ return QCocoaAccessible::macRole(iface);
+ return NSAccessibilityUnknownRole;
}
- (NSString *) accessibilitySubRole {
- QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
- if (!iface || !iface->isValid())
- return NSAccessibilityUnknownRole;
- return QCocoaAccessible::macSubrole(iface);
+ if (QAccessibleInterface *iface = self.qtInterface)
+ return QCocoaAccessible::macSubrole(iface);
+ return NSAccessibilityUnknownRole;
}
- (NSString *) accessibilityRoleDescription {
- QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
- if (!iface || !iface->isValid())
- return NSAccessibilityUnknownRole;
- return NSAccessibilityRoleDescription(self.accessibilityRole, self.accessibilitySubRole);
+ if (QAccessibleInterface *iface = self.qtInterface)
+ return NSAccessibilityRoleDescription(self.accessibilityRole, self.accessibilitySubRole);
+ return NSAccessibilityUnknownRole;
}
- (NSArray *) accessibilityChildren {
+ // shortcut for cells
+ if (synthesizedRole == NSAccessibilityCellRole)
+ return nil;
+
+ QAccessibleInterface *iface = self.qtInterface;
+ if (!iface)
+ return nil;
+ if (QAccessibleTableInterface *table = iface->tableInterface()) {
+ // either a table or table rows/columns
+ if (!synthesizedRole) {
+ // This is the table element, parent of all rows and columns
+ /*
+ * Typical 2x2 table hierarchy as can be observed in a table found under
+ * Apple -> System Settings -> General -> Login Items (macOS 13)
+ *
+ * (AXTable)
+ * | Columns: NSArray* (2 items)
+ * | Rows: NSArray* (2 items)
+ * | Visible Columns: NSArray* (2 items)
+ * | Visible Rows: NSArray* (2 items)
+ * | Children: NSArray* (5 items)
+ +----<--| Header: (AXGroup)
+ | * +-- (AXRow)
+ | * | +-- (AXText)
+ | * | +-- (AXTextField)
+ | * +-- (AXRow)
+ | * | +-- (AXText)
+ | * | +-- (AXTextField)
+ | * +-- (AXColumn)
+ | * | Header: "Item" (sort button)
+ | * | Index: 0
+ | * | Rows: NSArray* (2 items)
+ | * | Visible Rows: NSArray* (2 items)
+ | * +-- (AXColumn)
+ | * | Header: "Kind" (sort button)
+ | * | Index: 1
+ | * | Rows: NSArray* (2 items)
+ | * | Visible Rows: NSArray* (2 items)
+ +----> +-- (AXGroup)
+ * +-- (AXButton/AXSortButton) Item [NSAccessibilityTableHeaderCellProxy]
+ * +-- (AXButton/AXSortButton) Kind [NSAccessibilityTableHeaderCellProxy]
+ */
+ NSArray *rs = [self accessibilityRows];
+ NSArray *cs = [self accessibilityColumns];
+ const int rCount = int([rs count]);
+ const int cCount = int([cs count]);
+ int childCount = rCount + cCount;
+ NSMutableArray<QMacAccessibilityElement *> *tableChildren =
+ [NSMutableArray<QMacAccessibilityElement *> arrayWithCapacity:childCount];
+ for (int i = 0; i < rCount; ++i) {
+ [tableChildren addObject:[rs objectAtIndex:i]];
+ }
+ for (int i = 0; i < cCount; ++i) {
+ [tableChildren addObject:[cs objectAtIndex:i]];
+ }
+ return NSAccessibilityUnignoredChildren(tableChildren);
+ } else if (synthesizedRole == NSAccessibilityColumnRole) {
+ return nil;
+ } else if (synthesizedRole == NSAccessibilityRowRole) {
+ // axid matches the parent table axid so that we can easily find the parent table
+ // children of row are cell/any items
+ Q_ASSERT(m_rowIndex >= 0);
+ const int numColumns = table->columnCount();
+ columns = [self populateTableRow:columns count:numColumns];
+ return NSAccessibilityUnignoredChildren(columns);
+ }
+ }
+ return QCocoaAccessible::unignoredChildren(iface);
+}
+
+- (NSArray *) accessibilitySelectedChildren {
QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
if (!iface || !iface->isValid())
return nil;
- return QCocoaAccessible::unignoredChildren(iface);
+
+ QAccessibleSelectionInterface *selection = iface->selectionInterface();
+ if (!selection)
+ return nil;
+
+ const QList<QAccessibleInterface *> selectedList = selection->selectedItems();
+ const qsizetype numSelected = selectedList.size();
+ NSMutableArray<QMacAccessibilityElement *> *selectedChildren =
+ [NSMutableArray<QMacAccessibilityElement *> arrayWithCapacity:numSelected];
+ for (QAccessibleInterface *selectedChild : selectedList) {
+ if (selectedChild && selectedChild->isValid()) {
+ QAccessible::Id id = QAccessible::uniqueId(selectedChild);
+ QMacAccessibilityElement *element = [QMacAccessibilityElement elementWithId:id];
+ if (element)
+ [selectedChildren addObject:element];
+ }
+ }
+ return NSAccessibilityUnignoredChildren(selectedChildren);
}
- (id) accessibilityWindow {
@@ -237,36 +510,66 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
}
- (NSString *) accessibilityTitle {
- QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
- if (!iface || !iface->isValid())
- return nil;
- if (iface->role() == QAccessible::StaticText)
- return nil;
- return iface->text(QAccessible::Name).toNSString();
+ if (QAccessibleInterface *iface = self.qtInterface) {
+ if (iface->role() == QAccessible::StaticText)
+ return nil;
+ if (self.isManagedByParent)
+ return nil;
+ return iface->text(QAccessible::Name).toNSString();
+ }
+ return nil;
}
-- (BOOL) accessibilityEnabledAttribute {
- QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
- if (!iface || !iface->isValid())
- return false;
- return !iface->state().disabled;
+- (BOOL) isAccessibilityEnabled {
+ if (QAccessibleInterface *iface = self.qtInterface)
+ return !iface->state().disabled;
+ return false;
}
- (id)accessibilityParent {
- QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
- if (!iface || !iface->isValid())
+ if (synthesizedRole == NSAccessibilityCellRole) {
+ // a synthetic cell without interface - shortcut to the row
+ QMacAccessibilityElement *tableElement =
+ [QMacAccessibilityElement elementWithId:axid];
+ Q_ASSERT(tableElement && tableElement->rows);
+ Q_ASSERT(int(tableElement->rows.count) > m_rowIndex);
+ QMacAccessibilityElement *rowElement = tableElement->rows[m_rowIndex];
+ return rowElement;
+ }
+
+ QAccessibleInterface *iface = self.qtInterface;
+ if (!iface)
return nil;
+ if (self.isManagedByParent) {
+ // axid is the same for the parent element
+ return NSAccessibilityUnignoredAncestor([QMacAccessibilityElement elementWithId:axid]);
+ }
+
// macOS expects that the hierarchy is:
// App -> Window -> Children
// We don't actually have the window reflected properly in QAccessibility.
// Check if the parent is the application and then instead return the native window.
if (QAccessibleInterface *parent = iface->parent()) {
- if (parent->role() != QAccessible::Application) {
- QAccessible::Id parentId = QAccessible::uniqueId(parent);
- return NSAccessibilityUnignoredAncestor([QMacAccessibilityElement elementWithId: parentId]);
+ if (parent->tableInterface()) {
+ QMacAccessibilityElement *tableElement =
+ [QMacAccessibilityElement elementWithInterface:parent];
+
+ // parent of cell should be row
+ int rowIndex = -1;
+ if (m_rowIndex >= 0 && m_columnIndex >= 0)
+ rowIndex = m_rowIndex;
+ else if (QAccessibleTableCellInterface *cell = iface->tableCellInterface())
+ rowIndex = cell->rowIndex();
+ Q_ASSERT(tableElement->rows);
+ if (rowIndex > int([tableElement->rows count]) || rowIndex == -1)
+ return nil;
+ QMacAccessibilityElement *rowElement = tableElement->rows[rowIndex];
+ return NSAccessibilityUnignoredAncestor(rowElement);
}
+ if (parent->role() != QAccessible::Application)
+ return NSAccessibilityUnignoredAncestor([QMacAccessibilityElement elementWithInterface: parent]);
}
if (QWindow *window = iface->window()) {
@@ -280,78 +583,91 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
}
- (NSRect)accessibilityFrame {
- QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
- if (!iface || !iface->isValid())
+ QAccessibleInterface *iface = self.qtInterface;
+ if (!iface)
return NSZeroRect;
- return QCocoaScreen::mapToNative(iface->rect());
-}
-- (NSString*)accessibilityLabel {
- QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
- if (!iface || !iface->isValid()) {
- qWarning() << "Called accessibilityLabel on invalid object: " << axid;
- return nil;
+ QRect rect;
+ if (self.isManagedByParent) {
+ if (QAccessibleTableInterface *table = iface->tableInterface()) {
+ // Construct the geometry of the Row/Column by looking at the individual table cells
+ // ### Assumes that cells logical coordinates have spatial ordering (e.g finds the
+ // rows width by taking the union between the leftmost item and the rightmost item in
+ // a row).
+ // Otherwise, we have to iterate over *all* cells in a row/columns to
+ // find out the Row/Column geometry
+ const bool isRow = synthesizedRole == NSAccessibilityRowRole;
+ QPoint cellPos;
+ int &row = isRow ? cellPos.ry() : cellPos.rx();
+ int &col = isRow ? cellPos.rx() : cellPos.ry();
+
+ NSUInteger trackIndex = self.accessibilityIndex;
+ if (trackIndex != NSNotFound) {
+ row = int(trackIndex);
+ if (QAccessibleInterface *firstCell = table->cellAt(cellPos.y(), cellPos.x())) {
+ rect = firstCell->rect();
+ col = isRow ? table->columnCount() : table->rowCount();
+ if (col > 1) {
+ --col;
+ if (QAccessibleInterface *lastCell =
+ table->cellAt(cellPos.y(), cellPos.x()))
+ rect = rect.united(lastCell->rect());
+ }
+ }
+ }
+ }
+ } else {
+ rect = iface->rect();
}
- return iface->text(QAccessible::Description).toNSString();
-}
-- (void)setAccessibilityLabel:(NSString*)label{
- QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
- if (!iface || !iface->isValid())
- return;
- iface->setText(QAccessible::Description, QString::fromNSString(label));
+ return QCocoaScreen::mapToNative(rect);
}
-- (id) accessibilityMinValue:(QAccessibleInterface*)iface {
- if (QAccessibleValueInterface *val = iface->valueInterface())
- return @(val->minimumValue().toDouble());
+- (NSString*)accessibilityLabel {
+ if (QAccessibleInterface *iface = self.qtInterface)
+ return iface->text(QAccessible::Description).toNSString();
+ qWarning() << "Called accessibilityLabel on invalid object: " << axid;
return nil;
}
-- (id) accessibilityMaxValue:(QAccessibleInterface*)iface {
- if (QAccessibleValueInterface *val = iface->valueInterface())
- return @(val->maximumValue().toDouble());
- return nil;
+- (void)setAccessibilityLabel:(NSString*)label{
+ if (QAccessibleInterface *iface = self.qtInterface)
+ iface->setText(QAccessible::Description, QString::fromNSString(label));
}
- (id) accessibilityValue {
- QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
- if (!iface || !iface->isValid())
- return nil;
-
- // VoiceOver asks for the value attribute for all elements. Return nil
- // if we don't want the element to have a value attribute.
- if (!QCocoaAccessible::hasValueAttribute(iface))
- return nil;
-
- return QCocoaAccessible::getValueAttribute(iface);
+ if (QAccessibleInterface *iface = self.qtInterface) {
+ // VoiceOver asks for the value attribute for all elements. Return nil
+ // if we don't want the element to have a value attribute.
+ if (QCocoaAccessible::hasValueAttribute(iface))
+ return QCocoaAccessible::getValueAttribute(iface);
+ }
+ return nil;
}
- (NSInteger) accessibilityNumberOfCharacters {
- QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
- if (!iface || !iface->isValid())
- return 0;
- if (QAccessibleTextInterface *text = iface->textInterface())
- return text->characterCount();
+ if (QAccessibleInterface *iface = self.qtInterface) {
+ if (QAccessibleTextInterface *text = iface->textInterface())
+ return text->characterCount();
+ }
return 0;
}
- (NSString *) accessibilitySelectedText {
- QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
- if (!iface || !iface->isValid())
- return nil;
- if (QAccessibleTextInterface *text = iface->textInterface()) {
- int start = 0;
- int end = 0;
- text->selection(0, &start, &end);
- return text->text(start, end).toNSString();
+ if (QAccessibleInterface *iface = self.qtInterface) {
+ if (QAccessibleTextInterface *text = iface->textInterface()) {
+ int start = 0;
+ int end = 0;
+ text->selection(0, &start, &end);
+ return text->text(start, end).toNSString();
+ }
}
return nil;
}
- (NSRange) accessibilitySelectedTextRange {
- QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
- if (!iface || !iface->isValid())
+ QAccessibleInterface *iface = self.qtInterface;
+ if (!iface)
return NSRange();
if (QAccessibleTextInterface *text = iface->textInterface()) {
int start = 0;
@@ -368,8 +684,8 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
}
- (NSInteger)accessibilityLineForIndex:(NSInteger)index {
- QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
- if (!iface || !iface->isValid())
+ QAccessibleInterface *iface = self.qtInterface;
+ if (!iface)
return 0;
if (QAccessibleTextInterface *text = iface->textInterface()) {
QString textToPos = text->text(0, index);
@@ -379,8 +695,8 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
}
- (NSRange)accessibilityVisibleCharacterRange {
- QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
- if (!iface || !iface->isValid())
+ QAccessibleInterface *iface = self.qtInterface;
+ if (!iface)
return NSRange();
// FIXME This is not correct and may impact performance for big texts
if (QAccessibleTextInterface *text = iface->textInterface())
@@ -389,8 +705,8 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
}
- (NSInteger) accessibilityInsertionPointLineNumber {
- QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
- if (!iface || !iface->isValid())
+ QAccessibleInterface *iface = self.qtInterface;
+ if (!iface)
return 0;
if (QAccessibleTextInterface *text = iface->textInterface()) {
int position = text->cursorPosition();
@@ -401,8 +717,8 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
- (NSArray *)accessibilityParameterizedAttributeNames {
- QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
- if (!iface || !iface->isValid()) {
+ QAccessibleInterface *iface = self.qtInterface;
+ if (!iface) {
qWarning() << "Called attribute on invalid object: " << axid;
return nil;
}
@@ -425,8 +741,8 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
}
- (id)accessibilityAttributeValue:(NSString *)attribute forParameter:(id)parameter {
- QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
- if (!iface || !iface->isValid()) {
+ QAccessibleInterface *iface = self.qtInterface;
+ if (!iface) {
qWarning() << "Called attribute on invalid object: " << axid;
return nil;
}
@@ -466,7 +782,7 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
QRectF rect;
if (range.length > 0) {
NSUInteger position = range.location + range.length - 1;
- if (position > range.location && iface->textInterface()->text(position, position + 1) == QStringLiteral("\n"))
+ if (position > range.location && iface->textInterface()->text(position, position + 1) == "\n"_L1)
--position;
QRect lastRect = iface->textInterface()->characterRect(position);
rect = firstRect.united(lastRect);
@@ -494,8 +810,8 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
}
- (BOOL)accessibilityIsAttributeSettable:(NSString *)attribute {
- QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
- if (!iface || !iface->isValid())
+ QAccessibleInterface *iface = self.qtInterface;
+ if (!iface)
return NO;
if ([attribute isEqualToString:NSAccessibilityFocusedAttribute]) {
@@ -513,8 +829,8 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
}
- (void)accessibilitySetValue:(id)value forAttribute:(NSString *)attribute {
- QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
- if (!iface || !iface->isValid())
+ QAccessibleInterface *iface = self.qtInterface;
+ if (!iface)
return;
if ([attribute isEqualToString:NSAccessibilityFocusedAttribute]) {
if (QAccessibleActionInterface *action = iface->actionInterface())
@@ -542,12 +858,12 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
- (NSArray *)accessibilityActionNames {
NSMutableArray *nsActions = [[NSMutableArray new] autorelease];
- QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
- if (!iface || !iface->isValid())
+ QAccessibleInterface *iface = self.qtInterface;
+ if (!iface)
return nsActions;
const QStringList &supportedActionNames = QAccessibleBridgeUtils::effectiveActionNames(iface);
- foreach (const QString &qtAction, supportedActionNames) {
+ for (const QString &qtAction : supportedActionNames) {
NSString *nsAction = QCocoaAccessible::getTranslatedAction(qtAction);
if (nsAction)
[nsActions addObject : nsAction];
@@ -557,8 +873,8 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
}
- (NSString *)accessibilityActionDescription:(NSString *)action {
- QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
- if (!iface || !iface->isValid())
+ QAccessibleInterface *iface = self.qtInterface;
+ if (!iface)
return nil; // FIXME is that the right return type??
QString qtAction = QCocoaAccessible::translateAction(action, iface);
QString description;
@@ -575,8 +891,7 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
}
- (void)accessibilityPerformAction:(NSString *)action {
- QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
- if (iface && iface->isValid()) {
+ if (QAccessibleInterface *iface = self.qtInterface) {
const QString qtAction = QCocoaAccessible::translateAction(action, iface);
QAccessibleBridgeUtils::performEffectiveAction(iface, qtAction);
}
@@ -585,15 +900,20 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
// misc
- (BOOL)accessibilityIsIgnored {
- QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
- if (!iface || !iface->isValid())
- return true;
- return QCocoaAccessible::shouldBeIgnored(iface);
+ // Short-cut for placeholders and synthesized elements. Working around a bug
+ // that corrups lists returned by NSAccessibilityUnignoredChildren, otherwise
+ // we could ignore rows and columns that are outside the table.
+ if (self.isManagedByParent)
+ return false;
+
+ if (QAccessibleInterface *iface = self.qtInterface)
+ return QCocoaAccessible::shouldBeIgnored(iface);
+ return true;
}
- (id)accessibilityHitTest:(NSPoint)point {
- QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
- if (!iface || !iface->isValid()) {
+ QAccessibleInterface *iface = self.qtInterface;
+ if (!iface) {
// qDebug("Hit test: INVALID");
return NSAccessibilityUnignoredAncestor(self);
}
@@ -612,32 +932,79 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
childInterface = childOfChildInterface;
} while (childOfChildInterface && childOfChildInterface->isValid());
- QAccessible::Id childId = QAccessible::uniqueId(childInterface);
// hit a child, forward to child accessible interface.
- QMacAccessibilityElement *accessibleElement = [QMacAccessibilityElement elementWithId:childId];
+ QMacAccessibilityElement *accessibleElement = [QMacAccessibilityElement elementWithInterface:childInterface];
if (accessibleElement)
return NSAccessibilityUnignoredAncestor(accessibleElement);
return NSAccessibilityUnignoredAncestor(self);
}
- (id)accessibilityFocusedUIElement {
- QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
-
- if (!iface || !iface->isValid()) {
+ QAccessibleInterface *iface = self.qtInterface;
+ if (!iface) {
qWarning("FocusedUIElement for INVALID");
return nil;
}
QAccessibleInterface *childInterface = iface->focusChild();
if (childInterface && childInterface->isValid()) {
- QAccessible::Id childAxid = QAccessible::uniqueId(childInterface);
- QMacAccessibilityElement *accessibleElement = [QMacAccessibilityElement elementWithId:childAxid];
+ QMacAccessibilityElement *accessibleElement = [QMacAccessibilityElement elementWithInterface:childInterface];
return NSAccessibilityUnignoredAncestor(accessibleElement);
}
return NSAccessibilityUnignoredAncestor(self);
}
+- (NSString *) accessibilityHelp {
+ if (QAccessibleInterface *iface = self.qtInterface) {
+ const QString helpText = iface->text(QAccessible::Help);
+ if (!helpText.isEmpty())
+ return helpText.toNSString();
+ }
+ return nil;
+}
+
+/*
+ * Support for table
+ */
+- (NSInteger) accessibilityIndex {
+ NSInteger index = 0;
+ if (synthesizedRole == NSAccessibilityCellRole)
+ return m_columnIndex;
+ if (QAccessibleInterface *iface = self.qtInterface) {
+ if (self.isManagedByParent) {
+ // axid matches the parent table axid so that we can easily find the parent table
+ // children of row are cell/any items
+ if (QAccessibleTableInterface *table = iface->tableInterface()) {
+ if (m_rowIndex >= 0)
+ index = NSInteger(m_rowIndex);
+ else if (m_columnIndex >= 0)
+ index = NSInteger(m_columnIndex);
+ }
+ }
+ }
+ return index;
+}
+
+- (NSArray *) accessibilityRows {
+ if (!synthesizedRole && rows) {
+ QAccessibleInterface *iface = self.qtInterface;
+ if (iface && iface->tableInterface())
+ return NSAccessibilityUnignoredChildren(rows);
+ }
+ return nil;
+}
+
+- (NSArray *) accessibilityColumns {
+ if (!synthesizedRole && columns) {
+ QAccessibleInterface *iface = self.qtInterface;
+ if (iface && iface->tableInterface())
+ return NSAccessibilityUnignoredChildren(columns);
+ }
+ return nil;
+}
+
@end
-#endif // QT_NO_ACCESSIBILITY
+#endif // QT_CONFIG(accessibility)
+
diff --git a/src/plugins/platforms/cocoa/qcocoaapplication.h b/src/plugins/platforms/cocoa/qcocoaapplication.h
index 15530d8281..706923c337 100644
--- a/src/plugins/platforms/cocoa/qcocoaapplication.h
+++ b/src/plugins/platforms/cocoa/qcocoaapplication.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
/****************************************************************************
**
@@ -83,16 +47,13 @@
// We mean it.
//
-#include "qglobal.h"
-#include "private/qcore_mac_p.h"
-
-#import <AppKit/AppKit.h>
-
+#ifndef QCOCOAAPPLICATION_H
+#define QCOCOAAPPLICATION_H
-@interface QT_MANGLE_NAMESPACE(QNSApplication) : NSApplication
-@end
+#include <qglobal.h>
+#include <QtCore/private/qcore_mac_p.h>
-QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSApplication);
+QT_DECLARE_NAMESPACED_OBJC_INTERFACE(QNSApplication, NSApplication)
QT_BEGIN_NAMESPACE
@@ -101,3 +62,4 @@ void qt_resetNSApplicationSendEvent();
QT_END_NAMESPACE
+#endif // QCOCOAAPPLICATION_H
diff --git a/src/plugins/platforms/cocoa/qcocoaapplication.mm b/src/plugins/platforms/cocoa/qcocoaapplication.mm
index c6029bcf03..a68f993acf 100644
--- a/src/plugins/platforms/cocoa/qcocoaapplication.mm
+++ b/src/plugins/platforms/cocoa/qcocoaapplication.mm
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
/****************************************************************************
**
@@ -71,6 +35,8 @@
**
****************************************************************************/
+#include <AppKit/AppKit.h>
+
#include "qcocoaapplication.h"
#include "qcocoaintrospection.h"
diff --git a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.h b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.h
index 8ec9d6fbe0..67634dd26d 100644
--- a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.h
+++ b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 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$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
/****************************************************************************
@@ -84,24 +48,26 @@
// We mean it.
//
-
-#import <AppKit/AppKit.h>
+#ifndef QCOCOAAPPLICATIONDELEGATE_H
+#define QCOCOAAPPLICATIONDELEGATE_H
#include <qglobal.h>
#include <private/qcore_mac_p.h>
+
#include "qcocoansmenu.h"
-@interface QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate) : NSObject <NSApplicationDelegate>
+QT_DECLARE_NAMESPACED_OBJC_INTERFACE(QCocoaApplicationDelegate, NSObject <NSApplicationDelegate>
@property (nonatomic, retain) NSMenu *dockMenu;
+ (instancetype)sharedDelegate;
- (void)setReflectionDelegate:(NSObject<NSApplicationDelegate> *)oldDelegate;
- (void)removeAppleEventHandlers;
- (bool)inLaunch;
-@end
-
-QT_NAMESPACE_ALIAS_OBJC_CLASS(QCocoaApplicationDelegate);
+)
+#if defined(__OBJC__)
@interface QCocoaApplicationDelegate (MenuAPI)
- (void)qt_itemFired:(QCocoaNSMenuItem *)item;
@end
+#endif
+#endif // QCOCOAAPPLICATIONDELEGATE_H
diff --git a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm
index 3fb9e83d35..d7f8a1665e 100644
--- a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm
+++ b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 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$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
/****************************************************************************
**
@@ -71,13 +35,16 @@
**
****************************************************************************/
+#include <AppKit/AppKit.h>
-#import "qcocoaapplicationdelegate.h"
+#include "qcocoaapplicationdelegate.h"
#include "qcocoaintegration.h"
+#include "qcocoamenubar.h"
#include "qcocoamenu.h"
#include "qcocoamenuloader.h"
#include "qcocoamenuitem.h"
#include "qcocoansmenu.h"
+#include "qcocoahelpers.h"
#if QT_CONFIG(sessionmanager)
# include "qcocoasessionmanager.h"
@@ -87,14 +54,9 @@
#include <qurl.h>
#include <qdebug.h>
#include <qguiapplication.h>
-#include "qt_mac_p.h"
#include <qpa/qwindowsysteminterface.h>
#include <qwindowdefs.h>
-QT_BEGIN_NAMESPACE
-Q_LOGGING_CATEGORY(lcQpaApplication, "qt.qpa.application");
-QT_END_NAMESPACE
-
QT_USE_NAMESPACE
@implementation QCocoaApplicationDelegate {
@@ -186,7 +148,8 @@ QT_USE_NAMESPACE
- (void)applicationWillFinishLaunching:(NSNotification *)notification
{
- Q_UNUSED(notification);
+ if ([reflectionDelegate respondsToSelector:_cmd])
+ [reflectionDelegate applicationWillFinishLaunching:notification];
/*
From the Cocoa documentation: "A good place to install event handlers
@@ -223,16 +186,37 @@ QT_USE_NAMESPACE
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
- Q_UNUSED(aNotification);
+ if ([reflectionDelegate respondsToSelector:_cmd])
+ [reflectionDelegate applicationDidFinishLaunching:aNotification];
+
inLaunch = false;
if (qEnvironmentVariableIsEmpty("QT_MAC_DISABLE_FOREGROUND_APPLICATION_TRANSFORM")) {
- // Move the application window to front to avoid launching behind the terminal.
- // Ignoring other apps is necessary (we must ignore the terminal), but makes
- // Qt apps play slightly less nice with other apps when lanching from Finder
- // (See the activateIgnoringOtherApps docs.)
- [[NSApplication sharedApplication] activateIgnoringOtherApps:YES];
+ auto frontmostApplication = NSWorkspace.sharedWorkspace.frontmostApplication;
+ auto currentApplication = NSRunningApplication.currentApplication;
+ if (frontmostApplication != currentApplication) {
+ // Move the application to front to avoid launching behind the terminal.
+ // Ignoring other apps is necessary (we must ignore the terminal), but makes
+ // Qt apps play slightly less nice with other apps when launching from Finder
+ // (see the activateIgnoringOtherApps docs). FIXME: Try to distinguish between
+ // being non-active here because another application stole activation in the
+ // time it took us to launch from Finder, and being non-active because we were
+ // launched from Terminal or something that doesn't activate us at all.
+ qCDebug(lcQpaApplication) << "Launched with" << frontmostApplication
+ << "as frontmost application. Activating" << currentApplication << "instead.";
+ [NSApplication.sharedApplication activateIgnoringOtherApps:YES];
+ }
+
+ // Qt windows are typically shown in main(), at which point the application
+ // is not active yet. When the application is activated, either externally
+ // or via the override above, it will only bring the main and key windows
+ // forward, which differs from the behavior if these windows had been shown
+ // once the application was already active. To work around this, we explicitly
+ // activate the current application again, bringing all windows to the front.
+ [currentApplication activateWithOptions:NSApplicationActivateAllWindows];
}
+
+ QCocoaMenuBar::insertWindowMenu();
}
- (void)application:(NSApplication *)sender openFiles:(NSArray *)filenames
@@ -268,10 +252,25 @@ QT_USE_NAMESPACE
- (void)applicationDidBecomeActive:(NSNotification *)notification
{
+ if (QCocoaWindow::s_applicationActivationObserver) {
+ [[[NSWorkspace sharedWorkspace] notificationCenter] removeObserver:QCocoaWindow::s_applicationActivationObserver];
+ QCocoaWindow::s_applicationActivationObserver = nil;
+ }
+
if ([reflectionDelegate respondsToSelector:_cmd])
[reflectionDelegate applicationDidBecomeActive:notification];
QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationActive);
+
+ if (QCocoaWindow::s_windowUnderMouse) {
+ QPointF windowPoint;
+ QPointF screenPoint;
+ QNSView *view = qnsview_cast(QCocoaWindow::s_windowUnderMouse->m_view);
+ [view convertFromScreen:[NSEvent mouseLocation] toWindowPoint:&windowPoint andScreenPoint:&screenPoint];
+ QWindow *windowUnderMouse = QCocoaWindow::s_windowUnderMouse->window();
+ qCInfo(lcQpaMouse) << "Application activated with mouse at" << windowPoint << "; sending" << QEvent::Enter << "to" << windowUnderMouse;
+ QWindowSystemInterface::handleEnterEvent(windowUnderMouse, windowPoint, screenPoint);
+ }
}
- (void)applicationDidResignActive:(NSNotification *)notification
@@ -280,6 +279,12 @@ QT_USE_NAMESPACE
[reflectionDelegate applicationDidResignActive:notification];
QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationInactive);
+
+ if (QCocoaWindow::s_windowUnderMouse) {
+ QWindow *windowUnderMouse = QCocoaWindow::s_windowUnderMouse->window();
+ qCInfo(lcQpaMouse) << "Application deactivated; sending" << QEvent::Leave << "to" << windowUnderMouse;
+ QWindowSystemInterface::handleLeaveEvent(windowUnderMouse);
+ }
}
- (BOOL)applicationShouldHandleReopen:(NSApplication *)theApplication hasVisibleWindows:(BOOL)flag
@@ -333,20 +338,48 @@ QT_USE_NAMESPACE
{
Q_UNUSED(replyEvent);
NSString *urlString = [[event paramDescriptorForKeyword:keyDirectObject] stringValue];
- QWindowSystemInterface::handleFileOpenEvent(QUrl(QString::fromNSString(urlString)));
+ // The string we get from the requesting application might not necessarily meet
+ // QUrl's requirement for a IDN-compliant host. So if we can't parse into a QUrl,
+ // then we pass the string on to the application as the name of a file (and
+ // QFileOpenEvent::file is not guaranteed to be the path to a local, open'able
+ // file anyway).
+ const QString qurlString = QString::fromNSString(urlString);
+ if (const QUrl url(qurlString); url.isValid())
+ QWindowSystemInterface::handleFileOpenEvent(url);
+ else
+ QWindowSystemInterface::handleFileOpenEvent(qurlString);
+}
+
+- (BOOL)applicationSupportsSecureRestorableState:(NSApplication *)application
+{
+ if (@available(macOS 12, *)) {
+ if ([reflectionDelegate respondsToSelector:_cmd])
+ return [reflectionDelegate applicationSupportsSecureRestorableState:application];
+ }
+
+ // We don't support or implement state restorations via the AppKit
+ // state restoration APIs, but if we did, we would/should support
+ // secure state restoration. This is the default for apps linked
+ // against the macOS 14 SDK, but as we target versions below that
+ // as well we need to return YES here explicitly to silence a runtime
+ // warning.
+ return YES;
}
+
@end
@implementation QCocoaApplicationDelegate (Menus)
- (BOOL)validateMenuItem:(NSMenuItem*)item
{
+ qCDebug(lcQpaMenus) << "Validating" << item << "for" << self;
+
auto *nativeItem = qt_objc_cast<QCocoaNSMenuItem *>(item);
if (!nativeItem)
return item.enabled; // FIXME Test with with Qt as plugin or embedded QWindow.
auto *platformItem = nativeItem.platformMenuItem;
- if (!platformItem) // Try a bit harder with orphan menu itens
+ if (!platformItem) // Try a bit harder with orphan menu items
return item.hasSubmenu || (item.enabled && (item.action != @selector(qt_itemFired:)));
// Menu-holding items are always enabled, as it's conventional in Cocoa
@@ -362,6 +395,8 @@ QT_USE_NAMESPACE
- (void)qt_itemFired:(QCocoaNSMenuItem *)item
{
+ qCDebug(lcQpaMenus) << "Activating" << item;
+
if (item.hasSubmenu)
return;
@@ -373,8 +408,7 @@ QT_USE_NAMESPACE
if (!platformItem || platformItem->menu())
return;
- QScopedScopeLevelCounter scopeLevelCounter(QGuiApplicationPrivate::instance()->threadData.loadRelaxed());
- QGuiApplicationPrivate::modifier_buttons = [QNSView convertKeyModifiers:[NSEvent modifierFlags]];
+ QGuiApplicationPrivate::modifier_buttons = QAppleKeyMapper::fromCocoaModifiers([NSEvent modifierFlags]);
static QMetaMethod activatedSignal = QMetaMethod::fromSignal(&QCocoaMenuItem::activated);
activatedSignal.invoke(platformItem, Qt::QueuedConnection);
diff --git a/src/plugins/platforms/cocoa/qcocoabackingstore.h b/src/plugins/platforms/cocoa/qcocoabackingstore.h
index b57deacb57..71b6015a54 100644
--- a/src/plugins/platforms/cocoa/qcocoabackingstore.h
+++ b/src/plugins/platforms/cocoa/qcocoabackingstore.h
@@ -1,78 +1,30 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QBACKINGSTORE_COCOA_H
#define QBACKINGSTORE_COCOA_H
-#include <QtGraphicsSupport/private/qrasterbackingstore_p.h>
+#include <QtGui/private/qrasterbackingstore_p.h>
#include <private/qcore_mac_p.h>
#include <QScopedPointer>
#include "qiosurfacegraphicsbuffer.h"
+#include <unordered_map>
+
QT_BEGIN_NAMESPACE
-class QCocoaBackingStore : public QRasterBackingStore
+class QCocoaBackingStore : public QPlatformBackingStore
{
protected:
QCocoaBackingStore(QWindow *window);
QCFType<CGColorSpaceRef> colorSpace() const;
};
-class QNSWindowBackingStore : public QCocoaBackingStore
-{
-public:
- QNSWindowBackingStore(QWindow *window);
- ~QNSWindowBackingStore();
-
- void resize(const QSize &size, const QRegion &staticContents) override;
- void flush(QWindow *, const QRegion &, const QPoint &) override;
-
-private:
- bool windowHasUnifiedToolbar() const;
- QImage::Format format() const override;
- void redrawRoundedBottomCorners(CGRect) const;
-};
-
-class QCALayerBackingStore : public QCocoaBackingStore
+class QCALayerBackingStore : public QObject, public QCocoaBackingStore
{
+ Q_OBJECT
public:
QCALayerBackingStore(QWindow *window);
~QCALayerBackingStore();
@@ -83,18 +35,26 @@ public:
QPaintDevice *paintDevice() override;
void endPaint() override;
+ bool scroll(const QRegion &region, int dx, int dy) override;
+
void flush(QWindow *, const QRegion &, const QPoint &) override;
-#ifndef QT_NO_OPENGL
- void composeAndFlush(QWindow *window, const QRegion &region, const QPoint &offset,
- QPlatformTextureList *textures, bool translucentBackground) override;
-#endif
+
+ FlushResult rhiFlush(QWindow *window,
+ qreal sourceDevicePixelRatio,
+ const QRegion &region,
+ const QPoint &offset,
+ QPlatformTextureList *textures,
+ bool translucentBackground) override;
QImage toImage() const override;
QPlatformGraphicsBuffer *graphicsBuffer() const override;
private:
+ void observeBackingPropertiesChanges();
+ bool eventFilter(QObject *watched, QEvent *event) override;
+
QSize m_requestedSize;
- QRegion m_paintedRegion;
+ QRegion m_staticContents;
class GraphicsBuffer : public QIOSurfaceGraphicsBuffer
{
@@ -105,20 +65,32 @@ private:
QRegion dirtyRegion; // In unscaled coordinates
QImage *asImage();
qreal devicePixelRatio() const { return m_devicePixelRatio; }
+ bool isDirty() const { return !dirtyRegion.isEmpty(); }
+ QRegion validRegion() const;
private:
qreal m_devicePixelRatio;
QImage m_image;
};
+ void updateDirtyStates(const QRegion &paintedRegion);
+
void ensureBackBuffer();
bool recreateBackBufferIfNeeded();
- bool prepareForFlush();
+ void finalizeBackBuffer();
+
+ void blitBuffer(GraphicsBuffer *sourceBuffer, const QRegion &sourceRegion,
+ GraphicsBuffer *destinationBuffer, const QPoint &destinationOffset = QPoint());
void backingPropertiesChanged();
QMacNotificationObserver m_backingPropertiesObserver;
std::list<std::unique_ptr<GraphicsBuffer>> m_buffers;
+
+ void flushSubWindow(QWindow *window);
+ std::unordered_map<QWindow*, std::unique_ptr<QCALayerBackingStore>> m_subWindowBackingstores;
+ void windowDestroyed(QObject *object);
+ bool m_clearSurfaceOnPaint = true;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/qcocoabackingstore.mm b/src/plugins/platforms/cocoa/qcocoabackingstore.mm
index 2e15d11564..b211b5d02d 100644
--- a/src/plugins/platforms/cocoa/qcocoabackingstore.mm
+++ b/src/plugins/platforms/cocoa/qcocoabackingstore.mm
@@ -1,41 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <AppKit/AppKit.h>
#include "qcocoabackingstore.h"
@@ -43,326 +9,75 @@
#include "qcocoahelpers.h"
#include <QtCore/qmath.h>
+#include <QtCore/private/qcore_mac_p.h>
+#include <QtGui/qpainter.h>
#include <QuartzCore/CATransaction.h>
QT_BEGIN_NAMESPACE
QCocoaBackingStore::QCocoaBackingStore(QWindow *window)
- : QRasterBackingStore(window)
+ : QPlatformBackingStore(window)
{
}
QCFType<CGColorSpaceRef> QCocoaBackingStore::colorSpace() const
{
- NSView *view = static_cast<QCocoaWindow *>(window()->handle())->view();
- return QCFType<CGColorSpaceRef>::constructFromGet(view.window.colorSpace.CGColorSpace);
+ const auto *platformWindow = static_cast<QCocoaWindow *>(window()->handle());
+ const QNSView *view = qnsview_cast(platformWindow->view());
+ return QCFType<CGColorSpaceRef>::constructFromGet(view.colorSpace.CGColorSpace);
}
// ----------------------------------------------------------------------------
-QNSWindowBackingStore::QNSWindowBackingStore(QWindow *window)
+QCALayerBackingStore::QCALayerBackingStore(QWindow *window)
: QCocoaBackingStore(window)
{
- // Choose an appropriate window depth based on the requested surface format.
- // On deep color displays the default bit depth is 16-bit, so unless we need
- // that level of precision we opt out of it (and the expensive RGB32 -> RGB64
- // conversions that come with it if our backingstore depth does not match).
-
- NSWindow *nsWindow = static_cast<QCocoaWindow *>(window->handle())->view().window;
- auto colorSpaceName = NSColorSpaceFromDepth(nsWindow.depthLimit);
-
- static const int kDefaultBitDepth = 8;
- auto surfaceFormat = window->requestedFormat();
- auto bitsPerSample = qMax(kDefaultBitDepth, qMax(surfaceFormat.redBufferSize(),
- qMax(surfaceFormat.greenBufferSize(), surfaceFormat.blueBufferSize())));
-
- // NSBestDepth does not seem to guarantee a window depth deep enough for the
- // given bits per sample, even if documented as such. For example, requesting
- // 10 bits per sample will not give us a 16-bit format, even if that's what's
- // available. Work around this by manually bumping the bit depth.
- bitsPerSample = !(bitsPerSample & (bitsPerSample - 1))
- ? bitsPerSample : qNextPowerOfTwo(bitsPerSample);
-
- auto bestDepth = NSBestDepth(colorSpaceName, bitsPerSample, 0, NO, nullptr);
+ qCDebug(lcQpaBackingStore) << "Creating QCALayerBackingStore for" << window
+ << "with" << window->format();
- // Disable dynamic depth limit, otherwise our depth limit will be overwritten
- // by AppKit if the window moves to a screen with a different depth. We call
- // this before setting the depth limit, as the call will reset the depth to 0.
- [nsWindow setDynamicDepthLimit:NO];
-
- qCDebug(lcQpaBackingStore) << "Using" << NSBitsPerSampleFromDepth(bestDepth)
- << "bit window depth for" << nsWindow;
+ m_buffers.resize(1);
- nsWindow.depthLimit = bestDepth;
+ observeBackingPropertiesChanges();
+ window->installEventFilter(this);
}
-QNSWindowBackingStore::~QNSWindowBackingStore()
+QCALayerBackingStore::~QCALayerBackingStore()
{
}
-bool QNSWindowBackingStore::windowHasUnifiedToolbar() const
+void QCALayerBackingStore::observeBackingPropertiesChanges()
{
Q_ASSERT(window()->handle());
- return static_cast<QCocoaWindow *>(window()->handle())->m_drawContentBorderGradient;
-}
-
-QImage::Format QNSWindowBackingStore::format() const
-{
- if (windowHasUnifiedToolbar())
- return QImage::Format_ARGB32_Premultiplied;
-
- return QRasterBackingStore::format();
-}
-
-void QNSWindowBackingStore::resize(const QSize &size, const QRegion &staticContents)
-{
- qCDebug(lcQpaBackingStore) << "Resize requested to" << size;
- QRasterBackingStore::resize(size, staticContents);
-
- // The window shadow rendered by AppKit is based on the shape/content of the
- // NSWindow surface. Technically any flush of the backingstore can result in
- // a potentially new shape of the window, and would need a shadow invalidation,
- // but this is likely too expensive to do at every flush for the few cases where
- // clients change the shape dynamically. One case where we do know that the shadow
- // likely needs invalidation, if the window has partially transparent content,
- // is after a resize, where AppKit's default shadow may be based on the previous
- // window content.
- QCocoaWindow *cocoaWindow = static_cast<QCocoaWindow *>(window()->handle());
- if (cocoaWindow->isContentView() && !cocoaWindow->isOpaque())
- cocoaWindow->m_needsInvalidateShadow = true;
-}
-
-/*!
- Flushes the given \a region from the specified \a window onto the
- screen.
-
- The \a window is the top level window represented by this backingstore,
- or a non-transient child of that window.
-
- If the \a window is a child window, the \a region will be in child window
- coordinates, and the \a offset will be the child window's offset in relation
- to the backingstore's top level window.
-*/
-void QNSWindowBackingStore::flush(QWindow *window, const QRegion &region, const QPoint &offset)
-{
- if (m_image.isNull())
- return;
-
- // Use local pool so that any stale image references are cleaned up after flushing
- QMacAutoReleasePool pool;
-
- const QWindow *topLevelWindow = this->window();
-
- Q_ASSERT(topLevelWindow->handle() && window->handle());
- Q_ASSERT(!topLevelWindow->handle()->isForeignWindow() && !window->handle()->isForeignWindow());
-
- QNSView *topLevelView = qnsview_cast(static_cast<QCocoaWindow *>(topLevelWindow->handle())->view());
- QNSView *view = qnsview_cast(static_cast<QCocoaWindow *>(window->handle())->view());
-
- if (lcQpaBackingStore().isDebugEnabled()) {
- QString targetViewDescription;
- if (view != topLevelView) {
- QDebug targetDebug(&targetViewDescription);
- targetDebug << "onto" << topLevelView << "at" << offset;
- }
- qCDebug(lcQpaBackingStore) << "Flushing" << region << "of" << view << qPrintable(targetViewDescription);
- }
-
- // Normally a NSView is drawn via drawRect, as part of the display cycle in the
- // main runloop, via setNeedsDisplay and friends. AppKit will lock focus on each
- // individual view, starting with the top level and then traversing any subviews,
- // calling drawRect for each of them. This pull model results in expose events
- // sent to Qt, which result in drawing to the backingstore and flushing it.
- // Qt may also decide to paint and flush the backingstore via e.g. timers,
- // or other events such as mouse events, in which case we're in a push model.
- // If there is no focused view, it means we're in the latter case, and need
- // to manually flush the NSWindow after drawing to its graphic context.
- const bool drawingOutsideOfDisplayCycle = ![NSView focusView];
-
- // We also need to ensure the flushed view has focus, so that the graphics
- // context is set up correctly (coordinate system, clipping, etc). Outside
- // of the normal display cycle there is no focused view, as explained above,
- // so we have to handle it manually. There's also a corner case inside the
- // normal display cycle due to way QWidgetRepaintManager composits native child
- // widgets, where we'll get a flush of a native child during the drawRect of
- // its parent/ancestor, and the parent/ancestor being the one locked by AppKit.
- // In this case we also need to lock and unlock focus manually.
- const bool shouldHandleViewLockManually = [NSView focusView] != view;
- if (shouldHandleViewLockManually && ![view lockFocusIfCanDraw]) {
- qWarning() << "failed to lock focus of" << view;
- return;
- }
-
- const qreal devicePixelRatio = m_image.devicePixelRatio();
-
- // If the flushed window is a content view, and we're filling the drawn area
- // completely, or it doesn't have a window background we need to preserve,
- // we can get away with copying instead of blending the backing store.
- QCocoaWindow *cocoaWindow = static_cast<QCocoaWindow *>(window->handle());
- const NSCompositingOperation compositingOperation = cocoaWindow->isContentView()
- && (cocoaWindow->isOpaque() || view.window.backgroundColor == NSColor.clearColor)
- ? NSCompositingOperationCopy : NSCompositingOperationSourceOver;
-
-#ifdef QT_DEBUG
- static bool debugBackingStoreFlush = [[NSUserDefaults standardUserDefaults]
- boolForKey:@"QtCocoaDebugBackingStoreFlush"];
-#endif
-
- // -------------------------------------------------------------------------
-
- // The current contexts is typically a NSWindowGraphicsContext, but can be
- // NSBitmapGraphicsContext e.g. when debugging the view hierarchy in Xcode.
- // If we need to distinguish things here in the future, we can use e.g.
- // [NSGraphicsContext drawingToScreen], or the attributes of the context.
- NSGraphicsContext *graphicsContext = [NSGraphicsContext currentContext];
- Q_ASSERT_X(graphicsContext, "QCocoaBackingStore",
- "Focusing the view should give us a current graphics context");
-
- // Tag backingstore image with color space based on the window.
- // Note: This does not copy the underlying image data.
- QCFType<CGImageRef> cgImage = CGImageCreateCopyWithColorSpace(
- QCFType<CGImageRef>(m_image.toCGImage()), colorSpace());
-
- // Create temporary image to use for blitting, without copying image data
- NSImage *backingStoreImage = [[[NSImage alloc] initWithCGImage:cgImage size:NSZeroSize] autorelease];
-
- QRegion clippedRegion = region;
- for (QWindow *w = window; w; w = w->parent()) {
- if (!w->mask().isEmpty()) {
- clippedRegion &= w == window ? w->mask()
- : w->mask().translated(window->mapFromGlobal(w->mapToGlobal(QPoint(0, 0))));
- }
- }
-
- for (const QRect &viewLocalRect : clippedRegion) {
- QPoint backingStoreOffset = viewLocalRect.topLeft() + offset;
- QRect backingStoreRect(backingStoreOffset * devicePixelRatio, viewLocalRect.size() * devicePixelRatio);
- if (graphicsContext.flipped) // Flip backingStoreRect to match graphics context
- backingStoreRect.moveTop(m_image.height() - (backingStoreRect.y() + backingStoreRect.height()));
-
- CGRect viewRect = viewLocalRect.toCGRect();
-
- [backingStoreImage drawInRect:viewRect fromRect:backingStoreRect.toCGRect()
- operation:compositingOperation fraction:1.0 respectFlipped:YES hints:nil];
-
-#ifdef QT_DEBUG
- if (Q_UNLIKELY(debugBackingStoreFlush)) {
- [[NSColor colorWithCalibratedRed:drand48() green:drand48() blue:drand48() alpha:0.3] set];
- [NSBezierPath fillRect:viewRect];
-
- if (drawingOutsideOfDisplayCycle) {
- [[[NSColor magentaColor] colorWithAlphaComponent:0.5] set];
- [NSBezierPath strokeLineFromPoint:viewLocalRect.topLeft().toCGPoint()
- toPoint:viewLocalRect.bottomRight().toCGPoint()];
- }
- }
-#endif
- }
-
- // -------------------------------------------------------------------------
-
- if (shouldHandleViewLockManually)
- [view unlockFocus];
-
- if (drawingOutsideOfDisplayCycle) {
- redrawRoundedBottomCorners([view convertRect:region.boundingRect().toCGRect() toView:nil]);
- [view.window flushWindow];
- }
-
-
- // Done flushing to NSWindow backingstore
-
- QCocoaWindow *topLevelCocoaWindow = static_cast<QCocoaWindow *>(topLevelWindow->handle());
- if (Q_UNLIKELY(topLevelCocoaWindow->m_needsInvalidateShadow)) {
- qCDebug(lcQpaBackingStore) << "Invalidating window shadow for" << topLevelCocoaWindow;
- [topLevelView.window invalidateShadow];
- topLevelCocoaWindow->m_needsInvalidateShadow = false;
- }
-}
-
-/*
- When drawing outside of the display cycle, which Qt Widget does a lot,
- we end up drawing over the NSThemeFrame, losing the rounded corners of
- windows in the process.
-
- To work around this, until we've enabled updates via setNeedsDisplay and/or
- enabled layer-backed views, we ask the NSWindow to redraw the bottom corners
- if they intersect with the flushed region.
-
- This is the same logic used internally by e.g [NSView displayIfNeeded],
- [NSRulerView _scrollToMatchContentView], and [NSClipView _immediateScrollToPoint:],
- as well as the workaround used by WebKit to fix a similar bug:
-
- https://trac.webkit.org/changeset/85376/webkit
-*/
-void QNSWindowBackingStore::redrawRoundedBottomCorners(CGRect windowRect) const
-{
-#if !defined(QT_APPLE_NO_PRIVATE_APIS)
- Q_ASSERT(this->window()->handle());
- NSWindow *window = static_cast<QCocoaWindow *>(this->window()->handle())->nativeWindow();
-
- static SEL intersectBottomCornersWithRect = NSSelectorFromString(
- [NSString stringWithFormat:@"_%s%s:", "intersectBottomCorners", "WithRect"]);
- if (NSMethodSignature *signature = [window methodSignatureForSelector:intersectBottomCornersWithRect]) {
- NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
- invocation.target = window;
- invocation.selector = intersectBottomCornersWithRect;
- [invocation setArgument:&windowRect atIndex:2];
- [invocation invoke];
-
- NSRect cornerOverlap = NSZeroRect;
- [invocation getReturnValue:&cornerOverlap];
- if (!NSIsEmptyRect(cornerOverlap)) {
- static SEL maskRoundedBottomCorners = NSSelectorFromString(
- [NSString stringWithFormat:@"_%s%s:", "maskRounded", "BottomCorners"]);
- if ((signature = [window methodSignatureForSelector:maskRoundedBottomCorners])) {
- invocation = [NSInvocation invocationWithMethodSignature:signature];
- invocation.target = window;
- invocation.selector = maskRoundedBottomCorners;
- [invocation setArgument:&cornerOverlap atIndex:2];
- [invocation invoke];
- }
- }
- }
-#else
- Q_UNUSED(windowRect);
-#endif
-}
-
-// ----------------------------------------------------------------------------
-
-QCALayerBackingStore::QCALayerBackingStore(QWindow *window)
- : QCocoaBackingStore(window)
-{
- qCDebug(lcQpaBackingStore) << "Creating QCALayerBackingStore for" << window;
- m_buffers.resize(1);
-
- // Ideally this would be plumbed from the platform layer to QtGui, and
- // the QBackingStore would be recreated, but we don't have that code yet,
- // so at least make sure we update our backingstore when the backing
- // properties (color space e.g.) are changed.
- NSView *view = static_cast<QCocoaWindow *>(window->handle())->view();
+ NSView *view = static_cast<QCocoaWindow *>(window()->handle())->view();
m_backingPropertiesObserver = QMacNotificationObserver(view.window,
NSWindowDidChangeBackingPropertiesNotification, [this]() {
- qCDebug(lcQpaBackingStore) << "Backing properties for"
- << this->window() << "did change";
backingPropertiesChanged();
});
}
-QCALayerBackingStore::~QCALayerBackingStore()
+bool QCALayerBackingStore::eventFilter(QObject *watched, QEvent *event)
{
+ Q_ASSERT(watched == window());
+
+ if (event->type() == QEvent::PlatformSurface) {
+ auto *surfaceEvent = static_cast<QPlatformSurfaceEvent*>(event);
+ if (surfaceEvent->surfaceEventType() == QPlatformSurfaceEvent::SurfaceCreated)
+ observeBackingPropertiesChanges();
+ else
+ m_backingPropertiesObserver = QMacNotificationObserver();
+ }
+
+ return false;
}
void QCALayerBackingStore::resize(const QSize &size, const QRegion &staticContents)
{
- qCDebug(lcQpaBackingStore) << "Resize requested to" << size;
-
- if (!staticContents.isNull())
- qCWarning(lcQpaBackingStore) << "QCALayerBackingStore does not support static contents";
+ qCDebug(lcQpaBackingStore) << "Resize requested to" << size
+ << "with static contents" << staticContents;
m_requestedSize = size;
+ m_staticContents = staticContents;
}
void QCALayerBackingStore::beginPaint(const QRegion &region)
@@ -382,7 +97,7 @@ void QCALayerBackingStore::beginPaint(const QRegion &region)
// Although undocumented, QBackingStore::beginPaint expects the painted region
// to be cleared before use if the window has a surface format with an alpha.
// Fresh IOSurfaces are already cleared, so we don't need to clear those.
- if (!bufferWasRecreated && window()->format().hasAlpha()) {
+ if (m_clearSurfaceOnPaint && !bufferWasRecreated && window()->format().hasAlpha()) {
qCDebug(lcQpaBackingStore) << "Clearing" << region << "before use";
QPainter painter(m_buffers.back()->asImage());
painter.setCompositionMode(QPainter::CompositionMode_Source);
@@ -390,7 +105,8 @@ void QCALayerBackingStore::beginPaint(const QRegion &region)
painter.fillRect(rect, Qt::transparent);
}
- m_paintedRegion += region;
+ // We assume the client is going to paint the entire region
+ updateDirtyStates(region);
}
void QCALayerBackingStore::ensureBackBuffer()
@@ -398,13 +114,6 @@ void QCALayerBackingStore::ensureBackBuffer()
if (window()->format().swapBehavior() == QSurfaceFormat::SingleBuffer)
return;
- // The current back buffer may have been assigned to a layer in a previous flush,
- // but we deferred the swap. Do it now if the surface has been picked up by CA.
- if (m_buffers.back() && m_buffers.back()->isInUse() && m_buffers.back() != m_buffers.front()) {
- qCInfo(lcQpaBackingStore) << "Back buffer has been picked up by CA, swapping to front";
- std::swap(m_buffers.back(), m_buffers.front());
- }
-
if (Q_UNLIKELY(lcQpaBackingStore().isDebugEnabled())) {
// ┌───────┬───────┬───────┬─────┬──────┐
// │ front ┊ spare ┊ spare ┊ ... ┊ back │
@@ -480,11 +189,50 @@ bool QCALayerBackingStore::recreateBackBufferIfNeeded()
}
#endif
- qCInfo(lcQpaBackingStore) << "Creating surface of" << requestedBufferSize
- << "based on requested" << m_requestedSize << "and dpr =" << devicePixelRatio;
+ qCInfo(lcQpaBackingStore)<< "Creating surface of" << requestedBufferSize
+ << "for" << window() << "based on requested" << m_requestedSize
+ << "dpr =" << devicePixelRatio << "and color space" << colorSpace();
static auto pixelFormat = QImage::toPixelFormat(QImage::Format_ARGB32_Premultiplied);
- m_buffers.back().reset(new GraphicsBuffer(requestedBufferSize, devicePixelRatio, pixelFormat, colorSpace()));
+ auto *newBackBuffer = new GraphicsBuffer(requestedBufferSize, devicePixelRatio, pixelFormat, colorSpace());
+
+ if (!m_staticContents.isEmpty() && m_buffers.back()) {
+ // We implicitly support static backingstore content as a result of
+ // finalizing the back buffer on flush, where we copy any non-painted
+ // areas from the front buffer. But there is no guarantee that a resize
+ // will always come after a flush, where we have a pristine front buffer
+ // to copy from. It may come after a few begin/endPaints, where the back
+ // buffer then contains (part of) the latest state. We also have the case
+ // of single-buffered backingstore, where the front and back buffer is
+ // the same, which means we must do the copy from the old back buffer
+ // to the newly resized buffer now, before we replace it below.
+
+ // If the back buffer has been partially filled already, we need to
+ // copy parts of the static content from that. The rest we copy from
+ // the front buffer.
+ const QRegion backBufferRegion = m_staticContents - m_buffers.back()->dirtyRegion;
+ const QRegion frontBufferRegion = m_staticContents - backBufferRegion;
+
+ qCInfo(lcQpaBackingStore) << "Preserving static content" << backBufferRegion
+ << "from back buffer, and" << frontBufferRegion << "from front buffer";
+
+ newBackBuffer->lock(QPlatformGraphicsBuffer::SWWriteAccess);
+ blitBuffer(m_buffers.back().get(), backBufferRegion, newBackBuffer);
+ Q_ASSERT(frontBufferRegion.isEmpty() || m_buffers.front());
+ blitBuffer(m_buffers.front().get(), frontBufferRegion, newBackBuffer);
+ newBackBuffer->unlock();
+
+ // The new back buffer now is valid for the static contents region.
+ // We don't need to maintain the static contents region for resizes
+ // of any other buffers in the swap chain, as these will finalize
+ // their content on flush from the buffer we just filled, and we
+ // don't need to mark them dirty for the area we just filled, as
+ // new buffers are fully dirty when created.
+ newBackBuffer->dirtyRegion -= m_staticContents;
+ m_staticContents = {};
+ }
+
+ m_buffers.back().reset(newBackBuffer);
return true;
}
@@ -499,8 +247,68 @@ QPaintDevice *QCALayerBackingStore::paintDevice()
void QCALayerBackingStore::endPaint()
{
- qCInfo(lcQpaBackingStore) << "Paint ended with painted region" << m_paintedRegion;
+ qCInfo(lcQpaBackingStore) << "Paint ended. Back buffer valid region is now" << m_buffers.back()->validRegion();
+ m_buffers.back()->unlock();
+
+ // Since we can have multiple begin/endPaint rounds before a flush
+ // we defer finalizing the back buffer until its content is needed.
+}
+
+bool QCALayerBackingStore::scroll(const QRegion &region, int dx, int dy)
+{
+ if (!m_buffers.back()) {
+ qCInfo(lcQpaBackingStore) << "Scroll requested with no back buffer. Ignoring.";
+ return false;
+ }
+
+ const QPoint scrollDelta(dx, dy);
+ qCInfo(lcQpaBackingStore) << "Scrolling" << region << "by" << scrollDelta;
+
+ ensureBackBuffer();
+ recreateBackBufferIfNeeded();
+
+ const QRegion inPlaceRegion = region - m_buffers.back()->dirtyRegion;
+ const QRegion frontBufferRegion = region - inPlaceRegion;
+
+ QMacAutoReleasePool pool;
+
+ m_buffers.back()->lock(QPlatformGraphicsBuffer::SWWriteAccess);
+
+ if (!inPlaceRegion.isEmpty()) {
+ // We have to scroll everything in one go, instead of scrolling the
+ // individual rects of the region, as otherwise we may end up reading
+ // already overwritten (scrolled) pixels.
+ const QRect inPlaceBoundingRect = inPlaceRegion.boundingRect();
+
+ qCDebug(lcQpaBackingStore) << "Scrolling" << inPlaceBoundingRect << "in place";
+ QImage *backBufferImage = m_buffers.back()->asImage();
+ const qreal devicePixelRatio = backBufferImage->devicePixelRatio();
+ const QPoint devicePixelDelta = scrollDelta * devicePixelRatio;
+
+ extern void qt_scrollRectInImage(QImage &, const QRect &, const QPoint &);
+
+ qt_scrollRectInImage(*backBufferImage,
+ QRect(inPlaceBoundingRect.topLeft() * devicePixelRatio,
+ inPlaceBoundingRect.size() * devicePixelRatio),
+ devicePixelDelta);
+ }
+
+ if (!frontBufferRegion.isEmpty()) {
+ qCDebug(lcQpaBackingStore) << "Scrolling" << frontBufferRegion << "by copying from front buffer";
+ blitBuffer(m_buffers.front().get(), frontBufferRegion, m_buffers.back().get(), scrollDelta);
+ }
+
m_buffers.back()->unlock();
+
+ // Mark the target region as filled. Note: We do not mark the source region
+ // as dirty, even though the content has conceptually been "moved", as that
+ // would complicate things when preserving from the front buffer. This matches
+ // the behavior of other backingstore implementations using qt_scrollRectInImage.
+ updateDirtyStates(region.translated(scrollDelta));
+
+ qCInfo(lcQpaBackingStore) << "Scroll ended. Back buffer valid region is now" << m_buffers.back()->validRegion();
+
+ return true;
}
void QCALayerBackingStore::flush(QWindow *flushedWindow, const QRegion &region, const QPoint &offset)
@@ -508,12 +316,25 @@ void QCALayerBackingStore::flush(QWindow *flushedWindow, const QRegion &region,
Q_UNUSED(region);
Q_UNUSED(offset);
- if (!prepareForFlush())
+ if (!m_buffers.back()) {
+ qCWarning(lcQpaBackingStore) << "Tried to flush backingstore without painting to it first";
return;
+ }
+
+ finalizeBackBuffer();
+
+ if (flushedWindow != window()) {
+ flushSubWindow(flushedWindow);
+ return;
+ }
+
+ if (m_buffers.front()->isInUse() && !m_buffers.front()->isDirty()) {
+ qCInfo(lcQpaBackingStore) << "Asked to flush, but front buffer is up to date. Ignoring.";
+ return;
+ }
QMacAutoReleasePool pool;
- NSView *backingStoreView = static_cast<QCocoaWindow *>(window()->handle())->view();
NSView *flushedView = static_cast<QCocoaWindow *>(flushedWindow->handle())->view();
// If the backingstore is just flushed, without being painted to first, then we may
@@ -532,78 +353,111 @@ void QCALayerBackingStore::flush(QWindow *flushedWindow, const QRegion &region,
flushedView.layer.contentsScale = m_buffers.back()->devicePixelRatio();
}
+ const bool isSingleBuffered = window()->format().swapBehavior() == QSurfaceFormat::SingleBuffer;
+
id backBufferSurface = (__bridge id)m_buffers.back()->surface();
- if (flushedView.layer.contents == backBufferSurface) {
- // We've managed to paint to the back buffer again before Core Animation had time
- // to flush the transaction and persist the layer changes to the window server, or
- // we've been asked to flush without painting anything. The layer already knows about
- // the back buffer, and we don't need to re-apply it to pick up any possible surface
- // changes, so bail out early.
- qCInfo(lcQpaBackingStore).nospace() << "Skipping flush of " << flushedView
- << ", layer already reflects back buffer";
- return;
- }
// Trigger a new display cycle if there isn't one. This ensures that our layer updates
// are committed as part of a display-cycle instead of on the next runloop pass. This
// means CA won't try to throttle us if we flush too fast, and we'll coalesce our flush
// with other pending view and layer updates.
- backingStoreView.window.viewsNeedDisplay = YES;
+ flushedView.window.viewsNeedDisplay = YES;
- if (window()->format().swapBehavior() == QSurfaceFormat::SingleBuffer) {
+ if (isSingleBuffered) {
// The private API [CALayer reloadValueForKeyPath:@"contents"] would be preferable,
// but barring any side effects or performance issues we opt for the hammer for now.
flushedView.layer.contents = nil;
}
- if (flushedView == backingStoreView) {
- qCInfo(lcQpaBackingStore) << "Flushing" << backBufferSurface
- << "to" << flushedView.layer << "of" << flushedView;
- flushedView.layer.contents = backBufferSurface;
- } else {
- auto subviewRect = [flushedView convertRect:flushedView.bounds toView:backingStoreView];
- auto scale = flushedView.layer.contentsScale;
- subviewRect = CGRectApplyAffineTransform(subviewRect, CGAffineTransformMakeScale(scale, scale));
-
- // We make a copy of the image data up front, which means we don't
- // need to mark the IOSurface as being in use. FIXME: Investigate
- // if there's a cheaper way to get sub-image data to a layer.
- m_buffers.back()->lock(QPlatformGraphicsBuffer::SWReadAccess);
- QImage subImage = m_buffers.back()->asImage()->copy(QRectF::fromCGRect(subviewRect).toRect());
- m_buffers.back()->unlock();
+ qCInfo(lcQpaBackingStore) << "Flushing" << backBufferSurface
+ << "to" << flushedView.layer << "of" << flushedView;
+
+ flushedView.layer.contents = backBufferSurface;
+
+ if (!isSingleBuffered) {
+ // Mark the surface as in use, so that we don't end up rendering
+ // to it while it's assigned to a layer.
+ IOSurfaceIncrementUseCount(m_buffers.back()->surface());
- qCInfo(lcQpaBackingStore) << "Flushing" << subImage
- << "to" << flushedView.layer << "of subview" << flushedView;
- QCFType<CGImageRef> cgImage = subImage.toCGImage();
- flushedView.layer.contents = (__bridge id)static_cast<CGImageRef>(cgImage);
+ if (m_buffers.back() != m_buffers.front()) {
+ qCInfo(lcQpaBackingStore) << "Swapping back buffer to front";
+ std::swap(m_buffers.back(), m_buffers.front());
+ IOSurfaceDecrementUseCount(m_buffers.back()->surface());
+ }
}
+}
+
+void QCALayerBackingStore::flushSubWindow(QWindow *subWindow)
+{
+ qCInfo(lcQpaBackingStore) << "Flushing sub-window" << subWindow
+ << "via its own backingstore";
+
+ auto &subWindowBackingStore = m_subWindowBackingstores[subWindow];
+ if (!subWindowBackingStore) {
+ subWindowBackingStore.reset(new QCALayerBackingStore(subWindow));
+ QObject::connect(subWindow, &QObject::destroyed, this, &QCALayerBackingStore::windowDestroyed);
+ subWindowBackingStore->m_clearSurfaceOnPaint = false;
+ }
+
+ auto subWindowSize = subWindow->size();
+ static const auto kNoStaticContents = QRegion();
+ subWindowBackingStore->resize(subWindowSize, kNoStaticContents);
+
+ auto subWindowLocalRect = QRect(QPoint(), subWindowSize);
+ subWindowBackingStore->beginPaint(subWindowLocalRect);
- // Since we may receive multiple flushes before a new frame is started, we do not
- // swap any buffers just yet. Instead we check in the next beginPaint if the layer's
- // surface is in use, and if so swap to an unused surface as the new back buffer.
+ QPainter painter(subWindowBackingStore->m_buffers.back()->asImage());
+ painter.setCompositionMode(QPainter::CompositionMode_Source);
- // Note: Ideally CoreAnimation would mark a surface as in use the moment we assign
- // it to a layer, but as that's not the case we may end up painting to the same back
- // buffer once more if we are painting faster than CA can ship the surfaces over to
- // the window server.
+ NSView *backingStoreView = static_cast<QCocoaWindow *>(window()->handle())->view();
+ NSView *flushedView = static_cast<QCocoaWindow *>(subWindow->handle())->view();
+ auto subviewRect = [flushedView convertRect:flushedView.bounds toView:backingStoreView];
+ auto scale = flushedView.layer.contentsScale;
+ subviewRect = CGRectApplyAffineTransform(subviewRect, CGAffineTransformMakeScale(scale, scale));
+
+ m_buffers.back()->lock(QPlatformGraphicsBuffer::SWReadAccess);
+ const QImage *backingStoreImage = m_buffers.back()->asImage();
+ painter.drawImage(subWindowLocalRect, *backingStoreImage, QRectF::fromCGRect(subviewRect));
+ m_buffers.back()->unlock();
+
+ painter.end();
+ subWindowBackingStore->endPaint();
+ subWindowBackingStore->flush(subWindow, subWindowLocalRect, QPoint());
+
+ qCInfo(lcQpaBackingStore) << "Done flushing sub-window" << subWindow;
}
-#ifndef QT_NO_OPENGL
-void QCALayerBackingStore::composeAndFlush(QWindow *window, const QRegion &region, const QPoint &offset,
- QPlatformTextureList *textures, bool translucentBackground)
+void QCALayerBackingStore::windowDestroyed(QObject *object)
{
- if (!prepareForFlush())
- return;
+ auto *window = static_cast<QWindow*>(object);
+ qCInfo(lcQpaBackingStore) << "Removing backingstore for sub-window" << window;
+ m_subWindowBackingstores.erase(window);
+}
+
+QPlatformBackingStore::FlushResult QCALayerBackingStore::rhiFlush(QWindow *window,
+ qreal sourceDevicePixelRatio,
+ const QRegion &region,
+ const QPoint &offset,
+ QPlatformTextureList *textures,
+ bool translucentBackground)
+{
+ if (!m_buffers.back()) {
+ qCWarning(lcQpaBackingStore) << "Tried to flush backingstore without painting to it first";
+ return FlushFailed;
+ }
- QPlatformBackingStore::composeAndFlush(window, region, offset, textures, translucentBackground);
+ finalizeBackBuffer();
+
+ return QPlatformBackingStore::rhiFlush(window, sourceDevicePixelRatio, region, offset, textures, translucentBackground);
}
-#endif
QImage QCALayerBackingStore::toImage() const
{
- if (!const_cast<QCALayerBackingStore*>(this)->prepareForFlush())
+ if (!m_buffers.back())
return QImage();
+ const_cast<QCALayerBackingStore*>(this)->finalizeBackBuffer();
+
// We need to make a copy here, as the returned image could be used just
// for reading, in which case it won't detach, and then the underlying
// image data might change under the feet of the client when we re-use
@@ -616,10 +470,20 @@ QImage QCALayerBackingStore::toImage() const
void QCALayerBackingStore::backingPropertiesChanged()
{
- qCDebug(lcQpaBackingStore) << "Updating color space of existing buffers";
+ // Ideally this would be plumbed from the platform layer to QtGui, and
+ // the QBackingStore would be recreated, but we don't have that code yet,
+ // so at least make sure we update our backingstore when the backing
+ // properties (color space e.g.) are changed.
+
+ Q_ASSERT(window()->handle());
+
+ qCDebug(lcQpaBackingStore) << "Backing properties for" << window() << "did change";
+
+ const auto newColorSpace = colorSpace();
+ qCDebug(lcQpaBackingStore) << "Updating color space of existing buffers to" << newColorSpace;
for (auto &buffer : m_buffers) {
if (buffer)
- buffer->setColorSpace(colorSpace());
+ buffer->setColorSpace(newColorSpace);
}
}
@@ -628,69 +492,99 @@ QPlatformGraphicsBuffer *QCALayerBackingStore::graphicsBuffer() const
return m_buffers.back().get();
}
-bool QCALayerBackingStore::prepareForFlush()
+void QCALayerBackingStore::updateDirtyStates(const QRegion &paintedRegion)
{
- if (!m_buffers.back()) {
- qCWarning(lcQpaBackingStore) << "Tried to flush backingstore without painting to it first";
- return false;
- }
-
// Update dirty state of buffers based on what was painted. The back buffer will be
// less dirty, since we painted to it, while other buffers will become more dirty.
// This allows us to minimize copies between front and back buffers on swap in the
// cases where the painted region overlaps with the previous frame (front buffer).
for (const auto &buffer : m_buffers) {
if (buffer == m_buffers.back())
- buffer->dirtyRegion -= m_paintedRegion;
+ buffer->dirtyRegion -= paintedRegion;
else
- buffer->dirtyRegion += m_paintedRegion;
+ buffer->dirtyRegion += paintedRegion;
}
+}
+void QCALayerBackingStore::finalizeBackBuffer()
+{
// After painting, the back buffer is only guaranteed to have content for the painted
// region, and may still have dirty areas that need to be synced up with the front buffer,
// if we have one. We know that the front buffer is always up to date.
- if (!m_buffers.back()->dirtyRegion.isEmpty() && m_buffers.front() != m_buffers.back()) {
- QRegion preserveRegion = m_buffers.back()->dirtyRegion;
- qCDebug(lcQpaBackingStore) << "Preserving" << preserveRegion << "from front to back buffer";
- m_buffers.front()->lock(QPlatformGraphicsBuffer::SWReadAccess);
- const QImage *frontBuffer = m_buffers.front()->asImage();
+ if (!m_buffers.back()->isDirty())
+ return;
- const QRect frontSurfaceBounds(QPoint(0, 0), m_buffers.front()->size());
- const qreal sourceDevicePixelRatio = frontBuffer->devicePixelRatio();
+ qCDebug(lcQpaBackingStore) << "Finalizing back buffer with dirty region" << m_buffers.back()->dirtyRegion;
+ if (m_buffers.back() != m_buffers.front()) {
m_buffers.back()->lock(QPlatformGraphicsBuffer::SWWriteAccess);
- QPainter painter(m_buffers.back()->asImage());
- painter.setCompositionMode(QPainter::CompositionMode_Source);
+ blitBuffer(m_buffers.front().get(), m_buffers.back()->dirtyRegion, m_buffers.back().get());
+ m_buffers.back()->unlock();
+ } else {
+ qCDebug(lcQpaBackingStore) << "Front and back buffer is the same. Can not finalize back buffer.";
+ }
- // Let painter operate in device pixels, to make it easier to compare coordinates
- const qreal targetDevicePixelRatio = painter.device()->devicePixelRatio();
- painter.scale(1.0 / targetDevicePixelRatio, 1.0 / targetDevicePixelRatio);
+ // The back buffer is now completely in sync, ready to be presented
+ m_buffers.back()->dirtyRegion = QRegion();
+}
- for (const QRect &rect : preserveRegion) {
- QRect sourceRect(rect.topLeft() * sourceDevicePixelRatio, rect.size() * sourceDevicePixelRatio);
- QRect targetRect(rect.topLeft() * targetDevicePixelRatio, rect.size() * targetDevicePixelRatio);
+/*
+ \internal
-#ifdef QT_DEBUG
- if (Q_UNLIKELY(!frontSurfaceBounds.contains(sourceRect.bottomRight()))) {
- qCWarning(lcQpaBackingStore) << "Front buffer too small to preserve"
- << QRegion(sourceRect).subtracted(frontSurfaceBounds);
- }
-#endif
- painter.drawImage(targetRect, *frontBuffer, sourceRect);
- }
+ Blits \a sourceRegion from \a sourceBuffer to \a destinationBuffer,
+ at offset \a destinationOffset.
- m_buffers.back()->unlock();
- m_buffers.front()->unlock();
+ The source buffer is automatically locked for read only access
+ during the blit.
- // The back buffer is now completely in sync, ready to be presented
- m_buffers.back()->dirtyRegion = QRegion();
- }
+ The destination buffer has to be locked for write access by the
+ caller.
+*/
+
+void QCALayerBackingStore::blitBuffer(GraphicsBuffer *sourceBuffer, const QRegion &sourceRegion,
+ GraphicsBuffer *destinationBuffer, const QPoint &destinationOffset)
+{
+ Q_ASSERT(sourceBuffer && destinationBuffer);
+ Q_ASSERT(sourceBuffer != destinationBuffer);
+
+ if (sourceRegion.isEmpty())
+ return;
- // Prepare for another round of painting
- m_paintedRegion = QRegion();
+ qCDebug(lcQpaBackingStore) << "Blitting" << sourceRegion << "of" << sourceBuffer
+ << "to" << sourceRegion.translated(destinationOffset) << "of" << destinationBuffer;
- return true;
+ Q_ASSERT(destinationBuffer->isLocked() == QPlatformGraphicsBuffer::SWWriteAccess);
+
+ sourceBuffer->lock(QPlatformGraphicsBuffer::SWReadAccess);
+ const QImage *sourceImage = sourceBuffer->asImage();
+
+ const QRect sourceBufferBounds(QPoint(0, 0), sourceBuffer->size());
+ const qreal sourceDevicePixelRatio = sourceImage->devicePixelRatio();
+
+ QPainter painter(destinationBuffer->asImage());
+ painter.setCompositionMode(QPainter::CompositionMode_Source);
+
+ // Let painter operate in device pixels, to make it easier to compare coordinates
+ const qreal destinationDevicePixelRatio = painter.device()->devicePixelRatio();
+ painter.scale(1.0 / destinationDevicePixelRatio, 1.0 / destinationDevicePixelRatio);
+
+ for (const QRect &rect : sourceRegion) {
+ QRect sourceRect(rect.topLeft() * sourceDevicePixelRatio,
+ rect.size() * sourceDevicePixelRatio);
+ QRect destinationRect((rect.topLeft() + destinationOffset) * destinationDevicePixelRatio,
+ rect.size() * destinationDevicePixelRatio);
+
+#ifdef QT_DEBUG
+ if (Q_UNLIKELY(!sourceBufferBounds.contains(sourceRect.bottomRight()))) {
+ qCWarning(lcQpaBackingStore) << "Source buffer of size" << sourceBuffer->size()
+ << "is too small to blit" << sourceRect;
+ }
+#endif
+ painter.drawImage(destinationRect, *sourceImage, sourceRect);
+ }
+
+ sourceBuffer->unlock();
}
// ----------------------------------------------------------------------------
@@ -698,12 +592,19 @@ bool QCALayerBackingStore::prepareForFlush()
QCALayerBackingStore::GraphicsBuffer::GraphicsBuffer(const QSize &size, qreal devicePixelRatio,
const QPixelFormat &format, QCFType<CGColorSpaceRef> colorSpace)
: QIOSurfaceGraphicsBuffer(size, format)
- , dirtyRegion(0, 0, size.width() / devicePixelRatio, size.height() / devicePixelRatio)
+ , dirtyRegion(QRect(QPoint(0, 0), size / devicePixelRatio))
, m_devicePixelRatio(devicePixelRatio)
{
setColorSpace(colorSpace);
}
+QRegion QCALayerBackingStore::GraphicsBuffer::validRegion() const
+{
+
+ QRegion fullRegion = QRect(QPoint(0, 0), size() / m_devicePixelRatio);
+ return fullRegion - dirtyRegion;
+}
+
QImage *QCALayerBackingStore::GraphicsBuffer::asImage()
{
if (m_image.isNull()) {
@@ -722,3 +623,5 @@ QImage *QCALayerBackingStore::GraphicsBuffer::asImage()
}
QT_END_NAMESPACE
+
+#include "moc_qcocoabackingstore.cpp"
diff --git a/src/plugins/platforms/cocoa/qcocoaclipboard.h b/src/plugins/platforms/cocoa/qcocoaclipboard.h
index a78d8f4187..11912d6122 100644
--- a/src/plugins/platforms/cocoa/qcocoaclipboard.h
+++ b/src/plugins/platforms/cocoa/qcocoaclipboard.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QCOCOACLIPBOARD_H
#define QCOCOACLIPBOARD_H
diff --git a/src/plugins/platforms/cocoa/qcocoaclipboard.mm b/src/plugins/platforms/cocoa/qcocoaclipboard.mm
index 141940cc50..241faadbec 100644
--- a/src/plugins/platforms/cocoa/qcocoaclipboard.mm
+++ b/src/plugins/platforms/cocoa/qcocoaclipboard.mm
@@ -1,51 +1,17 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qcocoaclipboard.h"
+#include <QtGui/qutimimeconverter.h>
+
#ifndef QT_NO_CLIPBOARD
QT_BEGIN_NAMESPACE
QCocoaClipboard::QCocoaClipboard()
- :m_clipboard(new QMacPasteboard(kPasteboardClipboard, QMacInternalPasteboardMime::MIME_CLIP))
- ,m_find(new QMacPasteboard(kPasteboardFind, QMacInternalPasteboardMime::MIME_CLIP))
+ :m_clipboard(new QMacPasteboard(kPasteboardClipboard, QUtiMimeConverter::HandlerScopeFlag::Clipboard))
+ ,m_find(new QMacPasteboard(kPasteboardFind, QUtiMimeConverter::HandlerScopeFlag::Clipboard))
{
connect(qGuiApp, &QGuiApplication::applicationStateChanged, this, &QCocoaClipboard::handleApplicationStateChanged);
}
@@ -104,8 +70,8 @@ void QCocoaClipboard::handleApplicationStateChanged(Qt::ApplicationState state)
emitChanged(QClipboard::FindBuffer);
}
-#include "moc_qcocoaclipboard.cpp"
-
QT_END_NAMESPACE
+#include "moc_qcocoaclipboard.cpp"
+
#endif // QT_NO_CLIPBOARD
diff --git a/src/plugins/platforms/cocoa/qcocoacolordialoghelper.h b/src/plugins/platforms/cocoa/qcocoacolordialoghelper.h
index 01ac7e181d..c9be2a588f 100644
--- a/src/plugins/platforms/cocoa/qcocoacolordialoghelper.h
+++ b/src/plugins/platforms/cocoa/qcocoacolordialoghelper.h
@@ -1,52 +1,12 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QCOCOACOLORDIALOGHELPER_H
#define QCOCOACOLORDIALOGHELPER_H
-#include <QtWidgets/qtwidgetsglobal.h>
-
#include <QObject>
#include <qpa/qplatformdialoghelper.h>
-QT_REQUIRE_CONFIG(colordialog);
-
QT_BEGIN_NAMESPACE
class QCocoaColorDialogHelper : public QPlatformColorDialogHelper
diff --git a/src/plugins/platforms/cocoa/qcocoacolordialoghelper.mm b/src/plugins/platforms/cocoa/qcocoacolordialoghelper.mm
index c9fa035d87..b58f58caeb 100644
--- a/src/plugins/platforms/cocoa/qcocoacolordialoghelper.mm
+++ b/src/plugins/platforms/cocoa/qcocoacolordialoghelper.mm
@@ -1,41 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <AppKit/AppKit.h>
#include <QtCore/qdebug.h>
#include <QtCore/qtimer.h>
@@ -44,8 +10,7 @@
#include "qcocoacolordialoghelper.h"
#include "qcocoahelpers.h"
#include "qcocoaeventdispatcher.h"
-
-#import <AppKit/AppKit.h>
+#include "private/qcoregraphics_p.h"
QT_USE_NAMESPACE
@@ -180,34 +145,34 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSColorPanelDelegate);
- (void)updateQtColor
{
- NSColor *color = [mColorPanel color];
- NSString *colorSpaceName = [color colorSpaceName];
- if (colorSpaceName == NSDeviceCMYKColorSpace) {
- CGFloat cyan = 0, magenta = 0, yellow = 0, black = 0, alpha = 0;
- [color getCyan:&cyan magenta:&magenta yellow:&yellow black:&black alpha:&alpha];
- mQtColor.setCmykF(cyan, magenta, yellow, black, alpha);
- } else if (colorSpaceName == NSCalibratedRGBColorSpace || colorSpaceName == NSDeviceRGBColorSpace) {
- CGFloat red = 0, green = 0, blue = 0, alpha = 0;
- [color getRed:&red green:&green blue:&blue alpha:&alpha];
- mQtColor.setRgbF(red, green, blue, alpha);
- } else if (colorSpaceName == NSNamedColorSpace) {
- NSColor *tmpColor = [color colorUsingColorSpaceName:NSCalibratedRGBColorSpace];
+ // Discard the color space and pass the color components to QColor. This
+ // is a good option as long as QColor is color-unmanaged: we preserve the
+ // exact RGB value from the color picker, which is predictable. Further,
+ // painting with the color will reproduce the same color on-screen, as
+ // long as the the same screen is used for selecting the color.
+ NSColor *componentColor = [[mColorPanel color] colorUsingType:NSColorTypeComponentBased];
+ switch (componentColor.colorSpace.colorSpaceModel)
+ {
+ case NSColorSpaceModelGray: {
+ CGFloat white = 0, alpha = 0;
+ [componentColor getWhite:&white alpha:&alpha];
+ mQtColor.setRgbF(white, white, white, alpha);
+ } break;
+ case NSColorSpaceModelRGB: {
CGFloat red = 0, green = 0, blue = 0, alpha = 0;
- [tmpColor getRed:&red green:&green blue:&blue alpha:&alpha];
+ [componentColor getRed:&red green:&green blue:&blue alpha:&alpha];
mQtColor.setRgbF(red, green, blue, alpha);
- } else {
- NSColorSpace *colorSpace = [color colorSpace];
- if ([colorSpace colorSpaceModel] == NSCMYKColorSpaceModel && [color numberOfComponents] == 5){
- CGFloat components[5];
- [color getComponents:components];
- mQtColor.setCmykF(components[0], components[1], components[2], components[3], components[4]);
- } else {
- NSColor *tmpColor = [color colorUsingColorSpaceName:NSCalibratedRGBColorSpace];
- CGFloat red = 0, green = 0, blue = 0, alpha = 0;
- [tmpColor getRed:&red green:&green blue:&blue alpha:&alpha];
- mQtColor.setRgbF(red, green, blue, alpha);
- }
+ } break;
+ case NSColorSpaceModelCMYK: {
+ CGFloat cyan = 0, magenta = 0, yellow = 0, black = 0, alpha = 0;
+ [componentColor getCyan:&cyan magenta:&magenta yellow:&yellow black:&black alpha:&alpha];
+ mQtColor.setCmykF(cyan, magenta, yellow, black, alpha);
+ } break;
+ default:
+ qWarning("QNSColorPanelDelegate: Unsupported color space model");
+ break;
}
+
if (mHelper)
emit mHelper->currentColorChanged(mQtColor);
}
@@ -217,7 +182,17 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSColorPanelDelegate);
mDialogIsExecuting = false;
mResultSet = false;
mClosingDueToKnownButton = false;
- [mColorPanel makeKeyAndOrderFront:mColorPanel];
+ // Make this an asynchronous call, so the panel is made key only
+ // in the next event loop run. This is to make sure that by
+ // the time the modal loop is run in runModalForWindow below,
+ // which internally also sets the panel to key window,
+ // the panel is not yet key, and the NSApp still has the right
+ // reference to the _previousKeyWindow. Otherwise both NSApp.key
+ // and NSApp._previousKeyWindow would wrongly point to the panel,
+ // loosing any reference to the window that was key before.
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [mColorPanel makeKeyAndOrderFront:mColorPanel];
+ });
}
- (BOOL)runApplicationModalPanel
@@ -235,6 +210,11 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSColorPanelDelegate);
[NSApp runModalForWindow:mColorPanel];
mDialogIsExecuting = false;
+
+ // Wake up the event dispatcher so it can check whether the
+ // current event loop should continue spinning or not.
+ QCoreApplication::eventDispatcher()->wakeUp();
+
return (mResultCode == NSModalResponseOK);
}
@@ -324,9 +304,9 @@ public:
bool show(Qt::WindowModality windowModality, QWindow *parent)
{
Q_UNUSED(parent);
- if (windowModality != Qt::WindowModal)
+ if (windowModality != Qt::ApplicationModal)
[mDelegate showModelessPanel];
- // no need to show a Qt::WindowModal dialog here, because it's necessary to call exec() in that case
+ // no need to show a Qt::ApplicationModal dialog here, because it will be shown in runApplicationModalPanel
return true;
}
@@ -390,9 +370,8 @@ void QCocoaColorDialogHelper::exec()
bool QCocoaColorDialogHelper::show(Qt::WindowFlags, Qt::WindowModality windowModality, QWindow *parent)
{
- if (windowModality == Qt::WindowModal)
- windowModality = Qt::ApplicationModal;
-
+ if (windowModality == Qt::ApplicationModal)
+ windowModality = Qt::WindowModal;
// Workaround for Apple rdar://25792119: If you invoke
// -setShowsAlpha: multiple times before showing the color
// picker, its height grows irrevocably. Instead, only
diff --git a/src/plugins/platforms/cocoa/qcocoacursor.h b/src/plugins/platforms/cocoa/qcocoacursor.h
index 5b008eff35..82c0357376 100644
--- a/src/plugins/platforms/cocoa/qcocoacursor.h
+++ b/src/plugins/platforms/cocoa/qcocoacursor.h
@@ -1,50 +1,14 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QWINDOWSCURSOR_H
#define QWINDOWSCURSOR_H
-#include <AppKit/AppKit.h>
-
#include <QtCore>
#include <qpa/qplatformcursor.h>
+Q_FORWARD_DECLARE_OBJC_CLASS(NSCursor);
+
QT_BEGIN_NAMESPACE
class QCocoaCursor : public QPlatformCursor
@@ -63,8 +27,8 @@ private:
QHash<Qt::CursorShape, NSCursor *> m_cursors;
NSCursor *convertCursor(QCursor *cursor);
NSCursor *createCursorData(QCursor * cursor);
- NSCursor *createCursorFromBitmap(const QBitmap *bitmap, const QBitmap *mask, const QPoint hotspot = QPoint());
- NSCursor *createCursorFromPixmap(const QPixmap pixmap, const QPoint hotspot = QPoint());
+ NSCursor *createCursorFromBitmap(const QBitmap &bitmap, const QBitmap &mask, const QPoint hotspot = QPoint());
+ NSCursor *createCursorFromPixmap(const QPixmap &pixmap, const QPoint hotspot = QPoint());
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/qcocoacursor.mm b/src/plugins/platforms/cocoa/qcocoacursor.mm
index e0d623fc4c..aaa35a91ef 100644
--- a/src/plugins/platforms/cocoa/qcocoacursor.mm
+++ b/src/plugins/platforms/cocoa/qcocoacursor.mm
@@ -1,41 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <AppKit/AppKit.h>
#include "qcocoacursor.h"
#include "qcocoawindow.h"
@@ -45,8 +11,19 @@
#include <QtGui/QBitmap>
+#if !defined(QT_APPLE_NO_PRIVATE_APIS)
+@interface NSCursor()
++ (id)_windowResizeNorthWestSouthEastCursor;
++ (id)_windowResizeNorthEastSouthWestCursor;
++ (id)_windowResizeNorthSouthCursor;
++ (id)_windowResizeEastWestCursor;
+@end
+#endif // QT_APPLE_NO_PRIVATE_APIS
+
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
QCocoaCursor::QCocoaCursor()
{
}
@@ -116,7 +93,7 @@ NSCursor *QCocoaCursor::convertCursor(QCursor *cursor)
return nil;
const Qt::CursorShape newShape = cursor->shape();
- NSCursor *cocoaCursor;
+ NSCursor *cocoaCursor = nil;
// Check for a suitable built-in NSCursor first:
switch (newShape) {
@@ -157,7 +134,29 @@ NSCursor *QCocoaCursor::convertCursor(QCursor *cursor)
case Qt::DragLinkCursor:
cocoaCursor = [NSCursor dragLinkCursor];
break;
- default : {
+#if !defined(QT_APPLE_NO_PRIVATE_APIS)
+ case Qt::SizeVerCursor:
+ if ([NSCursor respondsToSelector:@selector(_windowResizeNorthSouthCursor)])
+ cocoaCursor = [NSCursor _windowResizeNorthSouthCursor];
+ break;
+ case Qt::SizeHorCursor:
+ if ([NSCursor respondsToSelector:@selector(_windowResizeEastWestCursor)])
+ cocoaCursor = [NSCursor _windowResizeEastWestCursor];
+ break;
+ case Qt::SizeBDiagCursor:
+ if ([NSCursor respondsToSelector:@selector(_windowResizeNorthEastSouthWestCursor)])
+ cocoaCursor = [NSCursor _windowResizeNorthEastSouthWestCursor];
+ break;
+ case Qt::SizeFDiagCursor:
+ if ([NSCursor respondsToSelector:@selector(_windowResizeNorthWestSouthEastCursor)])
+ cocoaCursor = [NSCursor _windowResizeNorthWestSouthEastCursor];
+ break;
+#endif // QT_APPLE_NO_PRIVATE_APIS
+ default:
+ break;
+ }
+
+ if (!cocoaCursor) {
// No suitable OS cursor exist, use cursors provided
// by Qt for the rest. Check for a cached cursor:
cocoaCursor = m_cursors.value(newShape);
@@ -172,8 +171,6 @@ NSCursor *QCocoaCursor::convertCursor(QCursor *cursor)
m_cursors.insert(newShape, cocoaCursor);
}
-
- break; }
}
return cocoaCursor;
}
@@ -253,15 +250,15 @@ NSCursor *QCocoaCursor::createCursorData(QCursor *cursor)
return createCursorFromPixmap(pixmap);
break; }
case Qt::WaitCursor: {
- QPixmap pixmap = QPixmap(QLatin1String(":/qt-project.org/mac/cursors/images/spincursor.png"));
+ QPixmap pixmap = QPixmap(":/qt-project.org/mac/cursors/images/spincursor.png"_L1);
return createCursorFromPixmap(pixmap, hotspot);
break; }
case Qt::SizeAllCursor: {
- QPixmap pixmap = QPixmap(QLatin1String(":/qt-project.org/mac/cursors/images/sizeallcursor.png"));
+ QPixmap pixmap = QPixmap(":/qt-project.org/mac/cursors/images/sizeallcursor.png"_L1);
return createCursorFromPixmap(pixmap, QPoint(8, 8));
break; }
case Qt::BusyCursor: {
- QPixmap pixmap = QPixmap(QLatin1String(":/qt-project.org/mac/cursors/images/waitcursor.png"));
+ QPixmap pixmap = QPixmap(":/qt-project.org/mac/cursors/images/waitcursor.png"_L1);
return createCursorFromPixmap(pixmap, hotspot);
break; }
#define QT_USE_APPROXIMATE_CURSORS
@@ -301,17 +298,17 @@ NSCursor *QCocoaCursor::createCursorData(QCursor *cursor)
if (cursorData) {
QBitmap bitmap(QBitmap::fromData(QSize(16, 16), cursorData, QImage::Format_Mono));
QBitmap mask(QBitmap::fromData(QSize(16, 16), cursorMaskData, QImage::Format_Mono));
- return (createCursorFromBitmap(&bitmap, &mask, hotspot));
+ return (createCursorFromBitmap(bitmap, mask, hotspot));
}
return nil; // should not happen, all cases covered above
}
-NSCursor *QCocoaCursor::createCursorFromBitmap(const QBitmap *bitmap, const QBitmap *mask, const QPoint hotspot)
+NSCursor *QCocoaCursor::createCursorFromBitmap(const QBitmap &bitmap, const QBitmap &mask, const QPoint hotspot)
{
- QImage finalCursor(bitmap->size(), QImage::Format_ARGB32);
- QImage bmi = bitmap->toImage().convertToFormat(QImage::Format_RGB32);
- QImage bmmi = mask->toImage().convertToFormat(QImage::Format_RGB32);
+ QImage finalCursor(bitmap.size(), QImage::Format_ARGB32);
+ QImage bmi = bitmap.toImage().convertToFormat(QImage::Format_RGB32);
+ QImage bmmi = mask.toImage().convertToFormat(QImage::Format_RGB32);
for (int row = 0; row < finalCursor.height(); ++row) {
QRgb *bmData = reinterpret_cast<QRgb *>(bmi.scanLine(row));
QRgb *bmmData = reinterpret_cast<QRgb *>(bmmi.scanLine(row));
@@ -332,27 +329,11 @@ NSCursor *QCocoaCursor::createCursorFromBitmap(const QBitmap *bitmap, const QBit
return createCursorFromPixmap(QPixmap::fromImage(finalCursor), hotspot);
}
-NSCursor *QCocoaCursor::createCursorFromPixmap(const QPixmap pixmap, const QPoint hotspot)
+NSCursor *QCocoaCursor::createCursorFromPixmap(const QPixmap &pixmap, const QPoint hotspot)
{
NSPoint hotSpot = NSMakePoint(hotspot.x(), hotspot.y());
- NSImage *nsimage;
- if (pixmap.devicePixelRatio() > 1.0) {
- QSize layoutSize = pixmap.size() / pixmap.devicePixelRatio();
- QPixmap scaledPixmap = pixmap.scaled(layoutSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
- scaledPixmap.setDevicePixelRatio(1.0);
- nsimage = static_cast<NSImage *>(qt_mac_create_nsimage(scaledPixmap));
- CGImageRef cgImage = qt_mac_toCGImage(pixmap.toImage());
- NSBitmapImageRep *imageRep = [[NSBitmapImageRep alloc] initWithCGImage:cgImage];
- [nsimage addRepresentation:imageRep];
- [imageRep release];
- CGImageRelease(cgImage);
- } else {
- nsimage = static_cast<NSImage *>(qt_mac_create_nsimage(pixmap));
- }
-
- NSCursor *nsCursor = [[NSCursor alloc] initWithImage:nsimage hotSpot: hotSpot];
- [nsimage release];
- return nsCursor;
+ auto *image = [NSImage imageFromQImage:pixmap.toImage()];
+ return [[NSCursor alloc] initWithImage:image hotSpot:hotSpot];
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/qcocoadrag.h b/src/plugins/platforms/cocoa/qcocoadrag.h
index 5a5b985c6e..dedf8a7fd9 100644
--- a/src/plugins/platforms/cocoa/qcocoadrag.h
+++ b/src/plugins/platforms/cocoa/qcocoadrag.h
@@ -1,46 +1,9 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QCOCOADRAG_H
#define QCOCOADRAG_H
-#include <AppKit/AppKit.h>
#include <QtGui>
#include <qpa/qplatformdrag.h>
#include <private/qsimpledrag_p.h>
@@ -48,6 +11,12 @@
#include <QtGui/private/qdnd_p.h>
#include <QtGui/private/qinternalmimedata_p.h>
+#include <QtCore/qeventloop.h>
+
+Q_FORWARD_DECLARE_OBJC_CLASS(NSView);
+Q_FORWARD_DECLARE_OBJC_CLASS(NSEvent);
+Q_FORWARD_DECLARE_OBJC_CLASS(NSPasteboard);
+
QT_BEGIN_NAMESPACE
class QCocoaDrag : public QPlatformDrag
@@ -69,11 +38,15 @@ public:
void setLastMouseEvent(NSEvent *event, NSView *view);
void setAcceptedAction(Qt::DropAction act);
+ void exitDragLoop();
private:
QDrag *m_drag;
NSEvent *m_lastEvent;
NSView *m_lastView;
Qt::DropAction m_executed_drop_action;
+ QEventLoop *m_internalDragLoop = nullptr;
+
+ bool maybeDragMultipleItems();
QPixmap dragPixmap(QDrag *drag, QPoint &hotSpot) const;
};
@@ -86,7 +59,7 @@ public:
protected:
bool hasFormat_sys(const QString &mimeType) const;
QStringList formats_sys() const;
- QVariant retrieveData_sys(const QString &mimeType, QVariant::Type type) const;
+ QVariant retrieveData_sys(const QString &mimeType, QMetaType type) const;
public:
CFStringRef dropPasteboard;
};
diff --git a/src/plugins/platforms/cocoa/qcocoadrag.mm b/src/plugins/platforms/cocoa/qcocoadrag.mm
index 95808b8a11..a8404889e9 100644
--- a/src/plugins/platforms/cocoa/qcocoadrag.mm
+++ b/src/plugins/platforms/cocoa/qcocoadrag.mm
@@ -1,52 +1,23 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <AppKit/AppKit.h>
+#include <UniformTypeIdentifiers/UTCoreTypes.h>
#include "qcocoadrag.h"
#include "qmacclipboard.h"
#include "qcocoahelpers.h"
-#ifndef QT_NO_WIDGETS
-#include <QtWidgets/qwidget.h>
-#endif
#include <QtGui/private/qcoregraphics_p.h>
+#include <QtGui/qutimimeconverter.h>
+#include <QtCore/qsysinfo.h>
+#include <QtCore/private/qcore_mac_p.h>
+
+#include <vector>
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
static const int dragImageMaxChars = 26;
QCocoaDrag::QCocoaDrag() :
@@ -128,26 +99,28 @@ Qt::DropAction QCocoaDrag::drag(QDrag *o)
m_drag = o;
m_executed_drop_action = Qt::IgnoreAction;
+ QMacPasteboard dragBoard(CFStringRef(NSPasteboardNameDrag), QUtiMimeConverter::HandlerScopeFlag::DnD);
+ m_drag->mimeData()->setData("application/x-qt-mime-type-name"_L1, QByteArray("dummy"));
+ dragBoard.setMimeData(m_drag->mimeData(), QMacPasteboard::LazyRequest);
+
+ if (maybeDragMultipleItems())
+ return m_executed_drop_action;
+
QPoint hotSpot = m_drag->hotSpot();
QPixmap pm = dragPixmap(m_drag, hotSpot);
- QSize pmDeviceIndependentSize = pm.size() / pm.devicePixelRatio();
- NSImage *nsimage = qt_mac_create_nsimage(pm);
- [nsimage setSize:NSSizeFromCGSize(pmDeviceIndependentSize.toCGSize())];
-
- QMacPasteboard dragBoard(CFStringRef(NSPasteboardNameDrag), QMacInternalPasteboardMime::MIME_DND);
- m_drag->mimeData()->setData(QLatin1String("application/x-qt-mime-type-name"), QByteArray("dummy"));
- dragBoard.setMimeData(m_drag->mimeData(), QMacPasteboard::LazyRequest);
+ NSImage *dragImage = [NSImage imageFromQImage:pm.toImage()];
+ Q_ASSERT(dragImage);
NSPoint event_location = [m_lastEvent locationInWindow];
NSWindow *theWindow = [m_lastEvent window];
Q_ASSERT(theWindow);
event_location.x -= hotSpot.x();
- CGFloat flippedY = pmDeviceIndependentSize.height() - hotSpot.y();
+ CGFloat flippedY = dragImage.size.height - hotSpot.y();
event_location.y -= flippedY;
NSSize mouseOffset_unused = NSMakeSize(0.0, 0.0);
NSPasteboard *pboard = [NSPasteboard pasteboardWithName:NSPasteboardNameDrag];
- [theWindow dragImage:nsimage
+ [theWindow dragImage:dragImage
at:event_location
offset:mouseOffset_unused
event:m_lastEvent
@@ -155,17 +128,111 @@ Qt::DropAction QCocoaDrag::drag(QDrag *o)
source:m_lastView
slideBack:YES];
- [nsimage release];
-
m_drag = nullptr;
return m_executed_drop_action;
}
+bool QCocoaDrag::maybeDragMultipleItems()
+{
+ Q_ASSERT(m_drag && m_drag->mimeData());
+ Q_ASSERT(m_executed_drop_action == Qt::IgnoreAction);
+
+ if (QOperatingSystemVersion::current() < QOperatingSystemVersion::MacOSMojave) {
+ // -dragImage: stopped working in 10.14 first.
+ return false;
+ }
+
+ const QMacAutoReleasePool pool;
+
+ NSView *view = m_lastView ? m_lastView : m_lastEvent.window.contentView;
+ if (![view respondsToSelector:@selector(draggingSession:sourceOperationMaskForDraggingContext:)])
+ return false;
+
+ auto *sourceView = static_cast<NSView<NSDraggingSource>*>(view);
+
+ const auto &qtUrls = m_drag->mimeData()->urls();
+ NSPasteboard *dragBoard = [NSPasteboard pasteboardWithName:NSPasteboardNameDrag];
+
+ if (qtUrls.size() <= 1) {
+ // Good old -dragImage: works perfectly for this ...
+ return false;
+ }
+
+ std::vector<NSPasteboardItem *> nonUrls;
+ for (NSPasteboardItem *item in dragBoard.pasteboardItems) {
+ bool isUrl = false;
+ for (NSPasteboardType type in item.types) {
+ if ([type isEqualToString:UTTypeFileURL.identifier]) {
+ isUrl = true;
+ break;
+ }
+ }
+
+ if (!isUrl)
+ nonUrls.push_back(item);
+ }
+
+ QPoint hotSpot = m_drag->hotSpot();
+ const auto pixmap = dragPixmap(m_drag, hotSpot);
+ NSImage *dragImage = [NSImage imageFromQImage:pixmap.toImage()];
+ Q_ASSERT(dragImage);
+
+ NSMutableArray<NSDraggingItem *> *dragItems = [[[NSMutableArray alloc] init] autorelease];
+ const NSPoint itemLocation = m_drag->hotSpot().toCGPoint();
+ // 0. We start from URLs, which can be actually in a list (thus technically
+ // only ONE item in the pasteboard. The fact it's only one does not help, we are
+ // still getting an exception because of the number of items/images mismatch ...
+ // We only set the image for the first item and nil for the rest, the image already
+ // contains a combined picture for all urls we drag.
+ auto imageOrNil = dragImage;
+ for (const auto &qtUrl : qtUrls) {
+ if (!qtUrl.isValid())
+ continue;
+
+ if (qtUrl.isRelative()) // NSPasteboardWriting rejects such items.
+ continue;
+
+ NSURL *nsUrl = qtUrl.toNSURL();
+ auto *newItem = [[[NSDraggingItem alloc] initWithPasteboardWriter:nsUrl] autorelease];
+ const NSRect itemFrame = NSMakeRect(itemLocation.x, itemLocation.y,
+ dragImage.size.width,
+ dragImage.size.height);
+
+ [newItem setDraggingFrame:itemFrame contents:imageOrNil];
+ imageOrNil = nil;
+ [dragItems addObject:newItem];
+ }
+ // 1. Repeat for non-url items, if any:
+ for (auto *pbItem : nonUrls) {
+ auto *newItem = [[[NSDraggingItem alloc] initWithPasteboardWriter:pbItem] autorelease];
+ const NSRect itemFrame = NSMakeRect(itemLocation.x, itemLocation.y,
+ dragImage.size.width,
+ dragImage.size.height);
+ [newItem setDraggingFrame:itemFrame contents:imageOrNil];
+ [dragItems addObject:newItem];
+ }
+
+ [sourceView beginDraggingSessionWithItems:dragItems event:m_lastEvent source:sourceView];
+ QEventLoop eventLoop;
+ QScopedValueRollback updateGuard(m_internalDragLoop, &eventLoop);
+ eventLoop.exec();
+ return true;
+}
+
void QCocoaDrag::setAcceptedAction(Qt::DropAction act)
{
m_executed_drop_action = act;
}
+void QCocoaDrag::exitDragLoop()
+{
+ if (m_internalDragLoop) {
+ Q_ASSERT(m_internalDragLoop->isRunning());
+ m_internalDragLoop->exit();
+ }
+}
+
+
QPixmap QCocoaDrag::dragPixmap(QDrag *drag, QPoint &hotSpot) const
{
const QMimeData* data = drag->mimeData();
@@ -177,14 +244,14 @@ QPixmap QCocoaDrag::dragPixmap(QDrag *drag, QPoint &hotSpot) const
QFontMetrics fm(f);
if (data->hasImage()) {
- const QImage img = data->imageData().value<QImage>();
+ QImage img = data->imageData().value<QImage>();
if (!img.isNull()) {
- pm = QPixmap::fromImage(img).scaledToWidth(dragImageMaxChars *fm.averageCharWidth());
+ pm = QPixmap::fromImage(std::move(img)).scaledToWidth(dragImageMaxChars *fm.averageCharWidth());
}
}
if (pm.isNull() && (data->hasText() || data->hasUrls()) ) {
- QString s = data->hasText() ? data->text() : data->urls().first().toString();
+ QString s = data->hasText() ? data->text() : data->urls().constFirst().toString();
if (s.length() > dragImageMaxChars)
s = s.left(dragImageMaxChars -3) + QChar(0x2026);
if (!s.isEmpty()) {
@@ -192,19 +259,17 @@ QPixmap QCocoaDrag::dragPixmap(QDrag *drag, QPoint &hotSpot) const
const int height = fm.height();
if (width > 0 && height > 0) {
qreal dpr = 1.0;
- if (const QWindow *sourceWindow = qobject_cast<QWindow *>(drag->source())) {
- dpr = sourceWindow->devicePixelRatio();
- }
-#ifndef QT_NO_WIDGETS
- else if (const QWidget *sourceWidget = qobject_cast<QWidget *>(drag->source())) {
- if (const QWindow *sourceWindow = sourceWidget->window()->windowHandle())
- dpr = sourceWindow->devicePixelRatio();
- }
-#endif
- else {
- if (const QWindow *focusWindow = qApp->focusWindow())
- dpr = focusWindow->devicePixelRatio();
+ QWindow *window = qobject_cast<QWindow *>(drag->source());
+ if (!window && drag->source()->metaObject()->indexOfMethod("_q_closestWindowHandle()") != -1) {
+ QMetaObject::invokeMethod(drag->source(), "_q_closestWindowHandle",
+ Q_RETURN_ARG(QWindow *, window));
}
+ if (!window)
+ window = qApp->focusWindow();
+
+ if (window)
+ dpr = window->devicePixelRatio();
+
pm = QPixmap(width * dpr, height * dpr);
pm.setDevicePixelRatio(dpr);
QPainter p(&pm);
@@ -244,11 +309,11 @@ QStringList QCocoaDropData::formats_sys() const
qDebug("DnD: Cannot get PasteBoard!");
return formats;
}
- formats = QMacPasteboard(board, QMacInternalPasteboardMime::MIME_DND).formats();
+ formats = QMacPasteboard(board, QUtiMimeConverter::HandlerScopeFlag::DnD).formats();
return formats;
}
-QVariant QCocoaDropData::retrieveData_sys(const QString &mimeType, QVariant::Type type) const
+QVariant QCocoaDropData::retrieveData_sys(const QString &mimeType, QMetaType) const
{
QVariant data;
PasteboardRef board;
@@ -256,7 +321,7 @@ QVariant QCocoaDropData::retrieveData_sys(const QString &mimeType, QVariant::Typ
qDebug("DnD: Cannot get PasteBoard!");
return data;
}
- data = QMacPasteboard(board, QMacInternalPasteboardMime::MIME_DND).retrieveData(mimeType, type);
+ data = QMacPasteboard(board, QUtiMimeConverter::HandlerScopeFlag::DnD).retrieveData(mimeType);
CFRelease(board);
return data;
}
@@ -269,7 +334,7 @@ bool QCocoaDropData::hasFormat_sys(const QString &mimeType) const
qDebug("DnD: Cannot get PasteBoard!");
return has;
}
- has = QMacPasteboard(board, QMacInternalPasteboardMime::MIME_DND).hasFormat(mimeType);
+ has = QMacPasteboard(board, QUtiMimeConverter::HandlerScopeFlag::DnD).hasFormat(mimeType);
CFRelease(board);
return has;
}
diff --git a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h
index b8d2532b8e..96eb70dabc 100644
--- a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h
+++ b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
/****************************************************************************
**
@@ -91,20 +55,26 @@
#include <QtCore/private/qabstracteventdispatcher_p.h>
#include <QtCore/private/qcfsocketnotifier_p.h>
#include <QtCore/private/qtimerinfo_unix_p.h>
+#include <QtCore/qloggingcategory.h>
+#include <QtCore/qpointer.h>
#include <CoreFoundation/CoreFoundation.h>
+Q_FORWARD_DECLARE_OBJC_CLASS(NSWindow);
+
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(lcEventDispatcher);
+
typedef struct _NSModalSession *NSModalSession;
typedef struct _QCocoaModalSessionInfo {
QPointer<QWindow> window;
NSModalSession session;
- void *nswindow;
+ NSWindow *nswindow;
} QCocoaModalSessionInfo;
class QCocoaEventDispatcherPrivate;
-class QCocoaEventDispatcher : public QAbstractEventDispatcher
+class QCocoaEventDispatcher : public QAbstractEventDispatcherV2
{
Q_OBJECT
Q_DECLARE_PRIVATE(QCocoaEventDispatcher)
@@ -115,21 +85,19 @@ public:
~QCocoaEventDispatcher();
bool processEvents(QEventLoop::ProcessEventsFlags flags);
- bool hasPendingEvents();
void registerSocketNotifier(QSocketNotifier *notifier);
void unregisterSocketNotifier(QSocketNotifier *notifier);
- void registerTimer(int timerId, int interval, Qt::TimerType timerType, QObject *object);
- bool unregisterTimer(int timerId);
- bool unregisterTimers(QObject *object);
- QList<TimerInfo> registeredTimers(QObject *object) const;
-
- int remainingTime(int timerId);
+ void registerTimer(Qt::TimerId timerId, Duration interval, Qt::TimerType timerType,
+ QObject *object) final;
+ bool unregisterTimer(Qt::TimerId timerId) final;
+ bool unregisterTimers(QObject *object) final;
+ QList<TimerInfoV2> timersForObject(QObject *object) const final;
+ Duration remainingTime(Qt::TimerId timerId) const final;
void wakeUp();
void interrupt();
- void flush();
static void clearCurrentThreadCocoaEventDispatcherInterruptFlag();
@@ -164,6 +132,7 @@ public:
QStack<QCocoaModalSessionInfo> cocoaModalSessionStack;
bool currentExecIsNSAppRun;
bool nsAppRunCalledByQt;
+ bool initializingNSApplication = false;
bool cleanupModalSessionsNeeded;
uint processEventsCalled;
NSModalSession currentModalSessionCached;
@@ -182,7 +151,6 @@ public:
QList<void *> queuedUserInputEvents; // NSEvent *
CFRunLoopSourceRef postedEventsSource;
CFRunLoopObserverRef waitingObserver;
- CFRunLoopObserverRef firstTimeObserver;
QAtomicInt serialNumber;
int lastSerial;
bool interrupt;
@@ -191,7 +159,6 @@ public:
static void postedEventsSourceCallback(void *info);
static void waitingObserverCallback(CFRunLoopObserverRef observer,
CFRunLoopActivity activity, void *info);
- static void firstLoopEntry(CFRunLoopObserverRef ref, CFRunLoopActivity activity, void *info);
bool sendQueuedUserInputEvents();
void processPostedEvents();
};
diff --git a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm
index 94b9e62eab..739fbda4f5 100644
--- a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm
+++ b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
/****************************************************************************
**
@@ -71,25 +35,31 @@
**
****************************************************************************/
+#include <AppKit/AppKit.h>
+
#include "qcocoaeventdispatcher.h"
#include "qcocoawindow.h"
-
#include "qcocoahelpers.h"
-#include "qguiapplication.h"
-#include "qevent.h"
-#include "qmutex.h"
-#include "qsocketnotifier.h"
+
+#include <QtGui/qevent.h>
+#include <QtGui/qguiapplication.h>
+#include <QtGui/private/qguiapplication_p.h>
+
+#include <QtCore/qmutex.h>
+#include <QtCore/qscopeguard.h>
+#include <QtCore/qsocketnotifier.h>
+#include <QtCore/private/qthread_p.h>
+#include <QtCore/private/qcore_mac_p.h>
+
#include <qpa/qplatformwindow.h>
#include <qpa/qplatformnativeinterface.h>
-#include "private/qthread_p.h"
-#include "private/qguiapplication_p.h"
-#include <qdebug.h>
-#include <qscopeguard.h>
-#include <AppKit/AppKit.h>
+#include <QtCore/qdebug.h>
QT_BEGIN_NAMESPACE
+Q_LOGGING_CATEGORY(lcEventDispatcher, "qt.eventdispatcher");
+
static inline CFRunLoopRef mainRunLoop()
{
return CFRunLoopGetMain();
@@ -119,6 +89,13 @@ void QCocoaEventDispatcherPrivate::runLoopTimerCallback(CFRunLoopTimerRef, void
void QCocoaEventDispatcherPrivate::activateTimersSourceCallback(void *info)
{
QCocoaEventDispatcherPrivate *d = static_cast<QCocoaEventDispatcherPrivate *>(info);
+ if (d->initializingNSApplication) {
+ qCDebug(lcEventDispatcher) << "Deferring" << __FUNCTION__ << "due to NSApp initialization";
+ // We don't want to process any sources during explicit NSApplication
+ // initialization, so defer the source until the actual event processing.
+ CFRunLoopSourceSignal(d->activateTimersSourceRef);
+ return;
+ }
d->processTimers();
d->maybeCancelWaitForMoreEvents();
}
@@ -138,6 +115,7 @@ void QCocoaEventDispatcherPrivate::maybeStartCFRunLoopTimer()
return;
}
+ using DoubleSeconds = std::chrono::duration<double, std::ratio<1>>;
if (!runLoopTimerRef) {
// start the CFRunLoopTimer
CFAbsoluteTime ttf = CFAbsoluteTimeGetCurrent();
@@ -145,10 +123,10 @@ void QCocoaEventDispatcherPrivate::maybeStartCFRunLoopTimer()
CFTimeInterval oneyear = CFTimeInterval(3600. * 24. * 365.);
// Q: when should the CFRunLoopTimer fire for the first time?
- struct timespec tv;
- if (timerInfoList.timerWait(tv)) {
+ if (auto opt = timerInfoList.timerWait()) {
// A: when we have timers to fire, of course
- interval = qMax(tv.tv_sec + tv.tv_nsec / 1000000000., 0.0000001);
+ DoubleSeconds secs{*opt};
+ interval = qMax(secs.count(), 0.0000001);
} else {
// this shouldn't really happen, but in case it does, set the timer to fire a some point in the distant future
interval = oneyear;
@@ -168,10 +146,10 @@ void QCocoaEventDispatcherPrivate::maybeStartCFRunLoopTimer()
CFTimeInterval interval;
// Q: when should the timer first next?
- struct timespec tv;
- if (timerInfoList.timerWait(tv)) {
+ if (auto opt = timerInfoList.timerWait()) {
// A: when we have timers to fire, of course
- interval = qMax(tv.tv_sec + tv.tv_nsec / 1000000000., 0.0000001);
+ DoubleSeconds secs{*opt};
+ interval = qMax(secs.count(), 0.0000001);
} else {
// no timers can fire, but we cannot stop the CFRunLoopTimer, set the timer to fire at some
// point in the distant future (the timer interval is one year)
@@ -193,10 +171,11 @@ void QCocoaEventDispatcherPrivate::maybeStopCFRunLoopTimer()
runLoopTimerRef = nullptr;
}
-void QCocoaEventDispatcher::registerTimer(int timerId, int interval, Qt::TimerType timerType, QObject *obj)
+void QCocoaEventDispatcher::registerTimer(Qt::TimerId timerId, Duration interval,
+ Qt::TimerType timerType, QObject *obj)
{
#ifndef QT_NO_DEBUG
- if (timerId < 1 || interval < 0 || !obj) {
+ if (qToUnderlying(timerId) < 1 || interval.count() < 0 || !obj) {
qWarning("QCocoaEventDispatcher::registerTimer: invalid arguments");
return;
} else if (obj->thread() != thread() || thread() != QThread::currentThread()) {
@@ -210,10 +189,10 @@ void QCocoaEventDispatcher::registerTimer(int timerId, int interval, Qt::TimerTy
d->maybeStartCFRunLoopTimer();
}
-bool QCocoaEventDispatcher::unregisterTimer(int timerId)
+bool QCocoaEventDispatcher::unregisterTimer(Qt::TimerId timerId)
{
#ifndef QT_NO_DEBUG
- if (timerId < 1) {
+ if (qToUnderlying(timerId) < 1) {
qWarning("QCocoaEventDispatcher::unregisterTimer: invalid argument");
return false;
} else if (thread() != QThread::currentThread()) {
@@ -252,13 +231,13 @@ bool QCocoaEventDispatcher::unregisterTimers(QObject *obj)
return returnValue;
}
-QList<QCocoaEventDispatcher::TimerInfo>
-QCocoaEventDispatcher::registeredTimers(QObject *object) const
+QList<QCocoaEventDispatcher::TimerInfoV2>
+QCocoaEventDispatcher::timersForObject(QObject *object) const
{
#ifndef QT_NO_DEBUG
if (!object) {
qWarning("QCocoaEventDispatcher:registeredTimers: invalid argument");
- return QList<TimerInfo>();
+ return {};
}
#endif
@@ -285,13 +264,6 @@ void QCocoaEventDispatcher::unregisterSocketNotifier(QSocketNotifier *notifier)
d->cfSocketNotifier.unregisterSocketNotifier(notifier);
}
-bool QCocoaEventDispatcher::hasPendingEvents()
-{
- extern uint qGlobalPostedEventsCount();
- extern bool qt_is_gui_used; //qapplication.cpp
- return qGlobalPostedEventsCount() || (qt_is_gui_used && !CFRunLoopIsWaiting(CFRunLoopGetMain()));
-}
-
static bool isUserInputEvent(NSEvent* event)
{
switch ([event type]) {
@@ -404,6 +376,7 @@ bool QCocoaEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags)
// [NSApp run], which is the normal code path for cocoa applications.
if (NSModalSession session = d->currentModalSession()) {
QBoolBlocker execGuard(d->currentExecIsNSAppRun, false);
+ qCDebug(lcEventDispatcher) << "Running modal session" << session;
while ([NSApp runModalSession:session] == NSModalResponseContinue && !d->interrupt) {
qt_mac_waitForMoreEvents(NSModalPanelRunLoopMode);
if (session != d->currentModalSessionCached) {
@@ -447,6 +420,7 @@ bool QCocoaEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags)
// to use cocoa's native way of running modal sessions:
if (flags & QEventLoop::WaitForMoreEvents)
qt_mac_waitForMoreEvents(NSModalPanelRunLoopMode);
+ qCDebug(lcEventDispatcher) << "Running modal session" << session;
NSInteger status = [NSApp runModalSession:session];
if (status != NSModalResponseContinue && session == d->currentModalSessionCached) {
// INVARIANT: Someone called [NSApp stopModal:] from outside the event
@@ -501,6 +475,11 @@ bool QCocoaEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags)
retVal = true;
}
}
+
+ // Clean up the modal session list, call endModalSession.
+ if (d->cleanupModalSessionsNeeded)
+ d->cleanupModalSessions();
+
} while (!d->interrupt && event);
if ((d->processEventsFlags & QEventLoop::EventLoopExec) == 0) {
@@ -562,17 +541,17 @@ bool QCocoaEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags)
return retVal;
}
-int QCocoaEventDispatcher::remainingTime(int timerId)
+auto QCocoaEventDispatcher::remainingTime(Qt::TimerId timerId) const -> Duration
{
#ifndef QT_NO_DEBUG
- if (timerId < 1) {
+ if (qToUnderlying(timerId) < 1) {
qWarning("QCocoaEventDispatcher::remainingTime: invalid argument");
- return -1;
+ return Duration::min();
}
#endif
- Q_D(QCocoaEventDispatcher);
- return d->timerInfoList.timerRemainingTime(timerId);
+ Q_D(const QCocoaEventDispatcher);
+ return d->timerInfoList.remainingDuration(timerId);
}
void QCocoaEventDispatcher::wakeUp()
@@ -589,22 +568,42 @@ void QCocoaEventDispatcher::wakeUp()
void QCocoaEventDispatcherPrivate::ensureNSAppInitialized()
{
- // Some elements in Cocoa require NSApplication to be running before
- // they get fully initialized, in particular the menu bar. This
- // function is intended for cases where a dialog is told to execute before
- // QGuiApplication::exec is called, or the application spins the events loop
- // manually rather than calling QGuiApplication:exec.
- // The function makes sure that NSApplication starts running, but stops
- // it again as soon as the send posted events callback is called. That way
- // we let Cocoa finish the initialization it seems to need. We'll only
- // apply this trick at most once for any application, and we avoid doing it
- // for the common case where main just starts QGuiApplication::exec.
+ // Some elements in Cocoa require NSApplication to be initialized before
+ // use, for example the menu bar. Under normal circumstances this happens
+ // as part of [NSApp run], as a result of a call to QGuiApplication:exec(),
+ // but in the cases where a dialog is asked to execute before that happens,
+ // or the application spins the event loop manually via processEvents(),
+ // we need to explicitly ensure NSApplication initialization.
+
+ // We can unfortunately not do this via NSApplicationLoad(), as the function
+ // bails out early if there's already an NSApplication instance, which is
+ // the case if any code has called [NSApplication sharedApplication],
+ // or its short form 'NSApp'.
+
+ // Instead we do an actual [NSApp run], but stop the application as soon
+ // as possible, ensuring that AppKit will do the required initialization,
+ // including calling [NSApplication finishLaunching].
+
+ // We only apply this trick at most once for any application, and we avoid
+ // doing it for the common case where main just starts QGuiApplication::exec.
if (nsAppRunCalledByQt || [NSApp isRunning])
return;
+
+ qCDebug(lcEventDispatcher) << "Ensuring NSApplication is initialized";
nsAppRunCalledByQt = true;
- QBoolBlocker block1(interrupt, true);
- QBoolBlocker block2(currentExecIsNSAppRun, true);
+
+ // Stopping the application will still process runloop sources before
+ // actually stopping, so we need to explicitly guard our sources from
+ // doing anything, deferring their actions until later.
+ QBoolBlocker initializationGuard(initializingNSApplication, true);
+
+ CFRunLoopPerformBlock(mainRunLoop(), kCFRunLoopCommonModes, ^{
+ qCDebug(lcEventDispatcher) << "NSApplication has been initialized; Stopping NSApp";
+ [NSApp stop:NSApp];
+ cancelWaitForMoreEvents(); // Post event that wakes up the runloop
+ });
[NSApp run];
+ qCDebug(lcEventDispatcher) << "Finished ensuring NSApplication is initialized";
}
void QCocoaEventDispatcherPrivate::temporarilyStopAllModalSessions()
@@ -622,6 +621,8 @@ void QCocoaEventDispatcherPrivate::temporarilyStopAllModalSessions()
for (int i=0; i<stackSize; ++i) {
QCocoaModalSessionInfo &info = cocoaModalSessionStack[i];
if (info.session) {
+ qCDebug(lcEventDispatcher) << "Temporarily ending modal session" << info.session
+ << "for" << info.nswindow;
[NSApp endModalSession:info.session];
info.session = nullptr;
[(NSWindow*) info.nswindow release];
@@ -661,6 +662,8 @@ NSModalSession QCocoaEventDispatcherPrivate::currentModalSession()
[(NSWindow*) info.nswindow retain];
QRect rect = cocoaWindow->geometry();
info.session = [NSApp beginModalSessionForWindow:nswindow];
+ qCDebug(lcEventDispatcher) << "Begun modal session" << info.session
+ << "for" << nswindow;
// The call to beginModalSessionForWindow above processes events and may
// have deleted or destroyed the window. Check if it's still valid.
@@ -687,7 +690,7 @@ bool QCocoaEventDispatcherPrivate::hasModalSession() const
void QCocoaEventDispatcherPrivate::cleanupModalSessions()
{
// Go through the list of modal sessions, and end those
- // that no longer has a window assosiated; no window means
+ // that no longer has a window associated; no window means
// the session has logically ended. The reason we wait like
// this to actually end the sessions for real (rather than at the
// point they were marked as stopped), is that ending a session
@@ -709,6 +712,8 @@ void QCocoaEventDispatcherPrivate::cleanupModalSessions()
currentModalSessionCached = nullptr;
if (info.session) {
Q_ASSERT(info.nswindow);
+ qCDebug(lcEventDispatcher) << "Ending modal session" << info.session
+ << "for" << info.nswindow;
[NSApp endModalSession:info.session];
[(NSWindow *)info.nswindow release];
}
@@ -721,6 +726,14 @@ void QCocoaEventDispatcherPrivate::cleanupModalSessions()
void QCocoaEventDispatcherPrivate::beginModalSession(QWindow *window)
{
+ qCDebug(lcEventDispatcher) << "Adding modal session for" << window;
+
+ if (std::any_of(cocoaModalSessionStack.constBegin(), cocoaModalSessionStack.constEnd(),
+ [&](const auto &sessionInfo) { return sessionInfo.window == window; })) {
+ qCWarning(lcEventDispatcher) << "Modal session for" << window << "already exists!";
+ return;
+ }
+
// We need to start spinning the modal session. Usually this is done with
// QDialog::exec() for Qt Widgets based applications, but for others that
// just call show(), we need to interrupt().
@@ -741,6 +754,8 @@ void QCocoaEventDispatcherPrivate::beginModalSession(QWindow *window)
void QCocoaEventDispatcherPrivate::endModalSession(QWindow *window)
{
+ qCDebug(lcEventDispatcher) << "Removing modal session for" << window;
+
Q_Q(QCocoaEventDispatcher);
// Mark all sessions attached to window as pending to be stopped. We do this
@@ -787,7 +802,7 @@ void qt_mac_maybeCancelWaitForMoreEventsForwarder(QAbstractEventDispatcher *even
}
QCocoaEventDispatcher::QCocoaEventDispatcher(QObject *parent)
- : QAbstractEventDispatcher(*new QCocoaEventDispatcherPrivate, parent)
+ : QAbstractEventDispatcherV2(*new QCocoaEventDispatcherPrivate, parent)
{
Q_D(QCocoaEventDispatcher);
@@ -824,21 +839,6 @@ QCocoaEventDispatcher::QCocoaEventDispatcher(QObject *parent)
QCocoaEventDispatcherPrivate::waitingObserverCallback,
&observerContext);
CFRunLoopAddObserver(mainRunLoop(), d->waitingObserver, kCFRunLoopCommonModes);
-
- /* The first cycle in the loop adds the source and the events of the source
- are not processed.
- We use an observer to process the posted events for the first
- execution of the loop. */
- CFRunLoopObserverContext firstTimeObserverContext;
- bzero(&firstTimeObserverContext, sizeof(CFRunLoopObserverContext));
- firstTimeObserverContext.info = d;
- d->firstTimeObserver = CFRunLoopObserverCreate(kCFAllocatorDefault,
- kCFRunLoopEntry,
- /* repeats = */ false,
- 0,
- QCocoaEventDispatcherPrivate::firstLoopEntry,
- &firstTimeObserverContext);
- CFRunLoopAddObserver(mainRunLoop(), d->firstTimeObserver, kCFRunLoopCommonModes);
}
void QCocoaEventDispatcherPrivate::waitingObserverCallback(CFRunLoopObserverRef,
@@ -903,18 +903,17 @@ void QCocoaEventDispatcherPrivate::processPostedEvents()
}
}
-void QCocoaEventDispatcherPrivate::firstLoopEntry(CFRunLoopObserverRef ref,
- CFRunLoopActivity activity,
- void *info)
-{
- Q_UNUSED(ref);
- Q_UNUSED(activity);
- static_cast<QCocoaEventDispatcherPrivate *>(info)->processPostedEvents();
-}
-
void QCocoaEventDispatcherPrivate::postedEventsSourceCallback(void *info)
{
QCocoaEventDispatcherPrivate *d = static_cast<QCocoaEventDispatcherPrivate *>(info);
+ if (d->initializingNSApplication) {
+ qCDebug(lcEventDispatcher) << "Deferring" << __FUNCTION__ << "due to NSApp initialization";
+ // We don't want to process any sources during explicit NSApplication
+ // initialization, so defer the source until the actual event processing.
+ CFRunLoopSourceSignal(d->postedEventsSource);
+ return;
+ }
+
if (d->processEventsCalled && (d->processEventsFlags & QEventLoop::EventLoopExec) == 0) {
// processEvents() was called "manually," ignore this source for now
d->maybeCancelWaitForMoreEvents();
@@ -961,9 +960,6 @@ void QCocoaEventDispatcher::interrupt()
d->cancelWaitForMoreEvents();
}
-void QCocoaEventDispatcher::flush()
-{ }
-
// QTBUG-56746: The behavior of processEvents() has been changed to not clear
// the interrupt flag. Use this function to clear it.
void QCocoaEventDispatcher::clearCurrentThreadCocoaEventDispatcherInterruptFlag()
@@ -981,7 +977,7 @@ QCocoaEventDispatcher::~QCocoaEventDispatcher()
{
Q_D(QCocoaEventDispatcher);
- qDeleteAll(d->timerInfoList);
+ d->timerInfoList.clearTimers();
d->maybeStopCFRunLoopTimer();
CFRunLoopRemoveSource(mainRunLoop(), d->activateTimersSourceRef, kCFRunLoopCommonModes);
CFRelease(d->activateTimersSourceRef);
@@ -990,6 +986,8 @@ QCocoaEventDispatcher::~QCocoaEventDispatcher()
for (int i = 0; i < d->cocoaModalSessionStack.count(); ++i) {
QCocoaModalSessionInfo &info = d->cocoaModalSessionStack[i];
if (info.session) {
+ qCDebug(lcEventDispatcher) << "Ending modal session" << info.session
+ << "for" << info.nswindow << "during shutdown";
[NSApp endModalSession:info.session];
[(NSWindow *)info.nswindow release];
}
@@ -1008,9 +1006,6 @@ QCocoaEventDispatcher::~QCocoaEventDispatcher()
CFRunLoopObserverInvalidate(d->waitingObserver);
CFRelease(d->waitingObserver);
-
- CFRunLoopObserverInvalidate(d->firstTimeObserver);
- CFRelease(d->firstTimeObserver);
}
QtCocoaInterruptDispatcher* QtCocoaInterruptDispatcher::instance = nullptr;
diff --git a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.h b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.h
index dd0afbefe6..3ffccb10fd 100644
--- a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.h
+++ b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.h
@@ -1,61 +1,18 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QCOCOAFILEDIALOGHELPER_H
#define QCOCOAFILEDIALOGHELPER_H
#include <QObject>
-#include <QtWidgets/qtwidgetsglobal.h>
#include <qpa/qplatformdialoghelper.h>
#include <QtCore/private/qcore_mac_p.h>
-#import <AppKit/NSSavePanel.h>
-
-QT_REQUIRE_CONFIG(filedialog);
-
-@interface QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) : NSObject<NSOpenSavePanelDelegate>
-@end
-
-QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSOpenSavePanelDelegate);
+QT_DECLARE_NAMESPACED_OBJC_INTERFACE(QNSOpenSavePanelDelegate, NSObject<NSOpenSavePanelDelegate>)
QT_BEGIN_NAMESPACE
+class QEventLoop;
class QFileDialog;
class QFileDialogPrivate;
@@ -79,19 +36,16 @@ public:
void selectNameFilter(const QString &filter) override;
QString selectedNameFilter() const override;
-public:
- bool showCocoaFilePanel(Qt::WindowModality windowModality, QWindow *parent);
- bool hideCocoaFilePanel();
+public: // for QNSOpenSavePanelDelegate
+ void panelClosed(NSInteger result);
+ void panelDirectoryDidChange(NSString *path);
+private:
void createNSOpenSavePanelDelegate();
- void QNSOpenSavePanelDelegate_selectionChanged(const QString &newPath);
- void QNSOpenSavePanelDelegate_panelClosed(bool accepted);
- void QNSOpenSavePanelDelegate_directoryEntered(const QString &newDir);
- void QNSOpenSavePanelDelegate_filterSelected(int menuIndex);
-private:
- QNSOpenSavePanelDelegate *mDelegate;
- QUrl mDir;
+ QNSOpenSavePanelDelegate *m_delegate = nil;
+ QUrl m_directory;
+ QEventLoop *m_eventLoop = nullptr;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm
index 6aa21d78d1..044a282686 100644
--- a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm
+++ b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm
@@ -1,221 +1,195 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#include <qpa/qplatformtheme.h>
-
-#include "qcocoafiledialoghelper.h"
+#include <QtCore/qglobal.h>
-/*****************************************************************************
- QFileDialog debug facilities
- *****************************************************************************/
-//#define DEBUG_FILEDIALOG_FILTERS
+#include <AppKit/AppKit.h>
-#include <qguiapplication.h>
-#include <private/qguiapplication_p.h>
-#include "qt_mac_p.h"
+#include "qcocoafiledialoghelper.h"
#include "qcocoahelpers.h"
#include "qcocoaeventdispatcher.h"
-#include <qbuffer.h>
-#include <qdebug.h>
-#include <qstringlist.h>
-#include <qvarlengtharray.h>
-#include <stdlib.h>
-#include <qabstracteventdispatcher.h>
-#include <qsysinfo.h>
-#include <qoperatingsystemversion.h>
-#include <qglobal.h>
-#include <qdir.h>
-#include <qregularexpression.h>
+#include <QtCore/qbuffer.h>
+#include <QtCore/qdebug.h>
+#include <QtCore/qstringlist.h>
+#include <QtCore/qvarlengtharray.h>
+#include <QtCore/qabstracteventdispatcher.h>
+#include <QtCore/qsysinfo.h>
+#include <QtCore/qoperatingsystemversion.h>
+#include <QtCore/qdir.h>
+#include <QtCore/qregularexpression.h>
+#include <QtCore/qpointer.h>
+#include <QtCore/private/qcore_mac_p.h>
+
+#include <QtGui/qguiapplication.h>
+#include <QtGui/private/qguiapplication_p.h>
+
+#include <qpa/qplatformtheme.h>
#include <qpa/qplatformnativeinterface.h>
-#import <AppKit/NSSavePanel.h>
-#import <CoreFoundation/CFNumber.h>
+#include <UniformTypeIdentifiers/UniformTypeIdentifiers.h>
-QT_FORWARD_DECLARE_CLASS(QString)
-QT_FORWARD_DECLARE_CLASS(QStringList)
-QT_FORWARD_DECLARE_CLASS(QFileInfo)
-QT_FORWARD_DECLARE_CLASS(QWindow)
QT_USE_NAMESPACE
+using namespace Qt::StringLiterals;
+
+static NSString *strippedText(QString s)
+{
+ s.remove("..."_L1);
+ return QPlatformTheme::removeMnemonics(s).trimmed().toNSString();
+}
+
+// NSOpenPanel extends NSSavePanel with some extra APIs
+static NSOpenPanel *openpanel_cast(NSSavePanel *panel)
+{
+ if ([panel isKindOfClass:NSOpenPanel.class])
+ return static_cast<NSOpenPanel*>(panel);
+ else
+ return nil;
+}
+
typedef QSharedPointer<QFileDialogOptions> SharedPointerFileDialogOptions;
@implementation QNSOpenSavePanelDelegate {
- @public
- NSOpenPanel *mOpenPanel;
- NSSavePanel *mSavePanel;
- NSView *mAccessoryView;
- NSPopUpButton *mPopUpButton;
- NSTextField *mTextField;
- QCocoaFileDialogHelper *mHelper;
- NSString *mCurrentDir;
+ @public
+ NSSavePanel *m_panel;
+ NSView *m_accessoryView;
+ NSPopUpButton *m_popupButton;
+ NSTextField *m_textField;
+ QPointer<QCocoaFileDialogHelper> m_helper;
- int mReturnCode;
-
- SharedPointerFileDialogOptions mOptions;
- QString *mCurrentSelection;
- QStringList *mNameFilterDropDownList;
- QStringList *mSelectedNameFilter;
+ SharedPointerFileDialogOptions m_options;
+ QString m_currentSelection;
+ QStringList m_nameFilterDropDownList;
+ QStringList m_selectedNameFilter;
}
- (instancetype)initWithAcceptMode:(const QString &)selectFile
options:(SharedPointerFileDialogOptions)options
helper:(QCocoaFileDialogHelper *)helper
{
- self = [super init];
- mOptions = options;
- if (mOptions->acceptMode() == QFileDialogOptions::AcceptOpen){
- mOpenPanel = [NSOpenPanel openPanel];
- mSavePanel = mOpenPanel;
- } else {
- mSavePanel = [NSSavePanel savePanel];
- [mSavePanel setCanSelectHiddenExtension:YES];
- mOpenPanel = nil;
- }
-
- if ([mSavePanel respondsToSelector:@selector(setLevel:)])
- [mSavePanel setLevel:NSModalPanelWindowLevel];
+ if ((self = [super init])) {
+ m_options = options;
+
+ if (m_options->acceptMode() == QFileDialogOptions::AcceptOpen)
+ m_panel = [[NSOpenPanel openPanel] retain];
+ else
+ m_panel = [[NSSavePanel savePanel] retain];
+
+ m_panel.canSelectHiddenExtension = YES;
+ m_panel.level = NSModalPanelWindowLevel;
+
+ m_helper = helper;
+
+ m_nameFilterDropDownList = m_options->nameFilters();
+ QString selectedVisualNameFilter = m_options->initiallySelectedNameFilter();
+ m_selectedNameFilter = [self findStrippedFilterWithVisualFilterName:selectedVisualNameFilter];
+
+ m_panel.extensionHidden = [&]{
+ for (const auto &nameFilter : m_nameFilterDropDownList) {
+ const auto extensions = QPlatformFileDialogHelper::cleanFilterList(nameFilter);
+ for (const auto &extension : extensions) {
+ // Explicitly show extensions if we detect a filter
+ // of "all files", as clicking a single file with
+ // extensions hidden will then populate the name
+ // field with only the file name, without any
+ // extension.
+ if (extension == "*"_L1 || extension == "*.*"_L1)
+ return false;
+
+ // Explicitly show extensions if we detect a filter
+ // that has a multi-part extension. This prevents
+ // confusing situations where the user clicks e.g.
+ // 'foo.tar.gz' and 'foo.tar' is populated in the
+ // file name box, but when then clicking save macOS
+ // will warn that the file needs to end in .gz,
+ // due to thinking the user tried to save the file
+ // as a 'tar' file instead. Unfortunately this
+ // property can only be set before the panel is
+ // shown, so we can't toggle it on and off based
+ // on the active filter.
+ if (extension.count('.') > 1)
+ return false;
+ }
+ }
+ return true;
+ }();
+
+ const QFileInfo sel(selectFile);
+ if (sel.isDir() && !sel.isBundle()){
+ m_panel.directoryURL = [NSURL fileURLWithPath:sel.absoluteFilePath().toNSString()];
+ m_currentSelection.clear();
+ } else {
+ m_panel.directoryURL = [NSURL fileURLWithPath:sel.absolutePath().toNSString()];
+ m_currentSelection = sel.absoluteFilePath();
+ }
- mReturnCode = -1;
- mHelper = helper;
- mNameFilterDropDownList = new QStringList(mOptions->nameFilters());
- QString selectedVisualNameFilter = mOptions->initiallySelectedNameFilter();
- mSelectedNameFilter = new QStringList([self findStrippedFilterWithVisualFilterName:selectedVisualNameFilter]);
+ [self createPopUpButton:selectedVisualNameFilter hideDetails:options->testOption(QFileDialogOptions::HideNameFilterDetails)];
+ [self createTextField];
+ [self createAccessory];
- QFileInfo sel(selectFile);
- if (sel.isDir() && !sel.isBundle()){
- mCurrentDir = [sel.absoluteFilePath().toNSString() retain];
- mCurrentSelection = new QString;
- } else {
- mCurrentDir = [sel.absolutePath().toNSString() retain];
- mCurrentSelection = new QString(sel.absoluteFilePath());
- }
+ m_panel.accessoryView = m_nameFilterDropDownList.size() > 1 ? m_accessoryView : nil;
+ // -setAccessoryView: can result in -panel:directoryDidChange:
+ // resetting our current directory. Set the delegate
+ // here to make sure it gets the correct value.
+ m_panel.delegate = self;
- [mSavePanel setTitle:options->windowTitle().toNSString()];
- [self createPopUpButton:selectedVisualNameFilter hideDetails:options->testOption(QFileDialogOptions::HideNameFilterDetails)];
- [self createTextField];
- [self createAccessory];
- [mSavePanel setAccessoryView:mNameFilterDropDownList->size() > 1 ? mAccessoryView : nil];
- // -setAccessoryView: can result in -panel:directoryDidChange:
- // resetting our mCurrentDir, set the delegate
- // here to make sure it gets the correct value.
- [mSavePanel setDelegate:self];
- mOpenPanel.accessoryViewDisclosed = YES;
-
- if (mOptions->isLabelExplicitlySet(QFileDialogOptions::Accept))
- [mSavePanel setPrompt:[self strip:options->labelText(QFileDialogOptions::Accept)]];
- if (mOptions->isLabelExplicitlySet(QFileDialogOptions::FileName))
- [mSavePanel setNameFieldLabel:[self strip:options->labelText(QFileDialogOptions::FileName)]];
+ if (auto *openPanel = openpanel_cast(m_panel))
+ openPanel.accessoryViewDisclosed = YES;
- [self updateProperties];
- [mSavePanel retain];
+ [self updateProperties];
+ }
return self;
}
- (void)dealloc
{
- delete mNameFilterDropDownList;
- delete mSelectedNameFilter;
- delete mCurrentSelection;
-
- if ([mSavePanel respondsToSelector:@selector(orderOut:)])
- [mSavePanel orderOut:mSavePanel];
- [mSavePanel setAccessoryView:nil];
- [mPopUpButton release];
- [mTextField release];
- [mAccessoryView release];
- [mSavePanel setDelegate:nil];
- [mSavePanel release];
- [mCurrentDir release];
+ [m_panel orderOut:m_panel];
+ m_panel.accessoryView = nil;
+ [m_popupButton release];
+ [m_textField release];
+ [m_accessoryView release];
+ m_panel.delegate = nil;
+ [m_panel release];
[super dealloc];
}
-static QString strippedText(QString s)
+- (bool)showPanel:(Qt::WindowModality) windowModality withParent:(QWindow *)parent
{
- s.remove(QLatin1String("..."));
- return QPlatformTheme::removeMnemonics(s).trimmed();
-}
+ const QFileInfo info(m_currentSelection);
+ NSString *filepath = info.filePath().toNSString();
+ NSURL *url = [NSURL fileURLWithPath:filepath isDirectory:info.isDir()];
+ bool selectable = (m_options->acceptMode() == QFileDialogOptions::AcceptSave)
+ || [self panel:m_panel shouldEnableURL:url];
-- (NSString *)strip:(const QString &)label
-{
- return strippedText(label).toNSString();
-}
+ m_panel.nameFieldStringValue = selectable ? info.fileName().toNSString() : @"";
-- (void)closePanel
-{
- *mCurrentSelection = QString::fromNSString([[mSavePanel URL] path]).normalized(QString::NormalizationForm_C);
- if ([mSavePanel respondsToSelector:@selector(close)])
- [mSavePanel close];
- if ([mSavePanel isSheet])
- [NSApp endSheet: mSavePanel];
-}
+ [self updateProperties];
-- (void)showModelessPanel
-{
- if (mOpenPanel){
- QFileInfo info(*mCurrentSelection);
- NSString *filepath = info.filePath().toNSString();
- NSURL *url = [NSURL fileURLWithPath:filepath isDirectory:info.isDir()];
- bool selectable = (mOptions->acceptMode() == QFileDialogOptions::AcceptSave)
- || [self panel:mOpenPanel shouldEnableURL:url];
+ auto completionHandler = ^(NSInteger result) { m_helper->panelClosed(result); };
- [self updateProperties];
- [mSavePanel setNameFieldStringValue:selectable ? info.fileName().toNSString() : @""];
-
- [mOpenPanel beginWithCompletionHandler:^(NSInteger result){
- mReturnCode = result;
- if (mHelper)
- mHelper->QNSOpenSavePanelDelegate_panelClosed(result == NSModalResponseOK);
- }];
+ if (windowModality == Qt::WindowModal && parent) {
+ NSView *view = reinterpret_cast<NSView*>(parent->winId());
+ [m_panel beginSheetModalForWindow:view.window completionHandler:completionHandler];
+ } else if (windowModality == Qt::ApplicationModal) {
+ return true; // Defer until exec()
+ } else {
+ [m_panel beginWithCompletionHandler:completionHandler];
}
+
+ return true;
}
-- (BOOL)runApplicationModalPanel
+-(void)runApplicationModalPanel
{
- QFileInfo info(*mCurrentSelection);
- NSString *filepath = info.filePath().toNSString();
- NSURL *url = [NSURL fileURLWithPath:filepath isDirectory:info.isDir()];
- bool selectable = (mOptions->acceptMode() == QFileDialogOptions::AcceptSave)
- || [self panel:mSavePanel shouldEnableURL:url];
+ // Note: If NSApp is not running (which is the case if e.g a top-most
+ // QEventLoop has been interrupted, and the second-most event loop has not
+ // yet been reactivated (regardless if [NSApp run] is still on the stack)),
+ // showing a native modal dialog will fail.
+ if (!m_helper)
+ return;
- [mSavePanel setDirectoryURL: [NSURL fileURLWithPath:mCurrentDir]];
- [mSavePanel setNameFieldStringValue:selectable ? info.fileName().toNSString() : @""];
+ QMacAutoReleasePool pool;
// Call processEvents in case the event dispatcher has been interrupted, and needs to do
// cleanup of modal sessions. Do this before showing the native dialog, otherwise it will
@@ -225,220 +199,299 @@ static QString strippedText(QString s)
// Make sure we don't interrupt the runModal call below.
QCocoaEventDispatcher::clearCurrentThreadCocoaEventDispatcherInterruptFlag();
- mReturnCode = [mSavePanel runModal];
+ auto result = [m_panel runModal];
+ m_helper->panelClosed(result);
- QAbstractEventDispatcher::instance()->interrupt();
- return (mReturnCode == NSModalResponseOK);
+ // Wake up the event dispatcher so it can check whether the
+ // current event loop should continue spinning or not.
+ QCoreApplication::eventDispatcher()->wakeUp();
}
-- (QPlatformDialogHelper::DialogCode)dialogResultCode
-{
- return (mReturnCode == NSModalResponseOK) ? QPlatformDialogHelper::Accepted : QPlatformDialogHelper::Rejected;
-}
-
-- (void)showWindowModalSheet:(QWindow *)parent
+- (void)closePanel
{
- QFileInfo info(*mCurrentSelection);
- NSString *filepath = info.filePath().toNSString();
- NSURL *url = [NSURL fileURLWithPath:filepath isDirectory:info.isDir()];
- bool selectable = (mOptions->acceptMode() == QFileDialogOptions::AcceptSave)
- || [self panel:mSavePanel shouldEnableURL:url];
+ m_currentSelection = QString::fromNSString(m_panel.URL.path).normalized(QString::NormalizationForm_C);
- [self updateProperties];
- [mSavePanel setDirectoryURL: [NSURL fileURLWithPath:mCurrentDir]];
-
- [mSavePanel setNameFieldStringValue:selectable ? info.fileName().toNSString() : @""];
- NSWindow *nsparent = static_cast<NSWindow *>(qGuiApp->platformNativeInterface()->nativeResourceForWindow("nswindow", parent));
-
- [mSavePanel beginSheetModalForWindow:nsparent completionHandler:^(NSInteger result){
- mReturnCode = result;
- if (mHelper)
- mHelper->QNSOpenSavePanelDelegate_panelClosed(result == NSModalResponseOK);
- }];
-}
-
-- (BOOL)isHiddenFileAtURL:(NSURL *)url
-{
- BOOL hidden = NO;
- if (url) {
- CFBooleanRef isHiddenProperty;
- if (CFURLCopyResourcePropertyForKey((__bridge CFURLRef)url, kCFURLIsHiddenKey, &isHiddenProperty, nullptr)) {
- hidden = CFBooleanGetValue(isHiddenProperty);
- CFRelease(isHiddenProperty);
- }
- }
- return hidden;
+ if (m_panel.sheet)
+ [NSApp endSheet:m_panel];
+ else if (NSApp.modalWindow == m_panel)
+ [NSApp stopModal];
+ else
+ [m_panel close];
}
- (BOOL)panel:(id)sender shouldEnableURL:(NSURL *)url
{
Q_UNUSED(sender);
- NSString *filename = [url path];
- if ([filename length] == 0)
+ NSString *filename = url.path;
+ if (!filename.length)
return NO;
- // Always accept directories regardless of their names (unless it is a bundle):
- NSFileManager *fm = [NSFileManager defaultManager];
- NSDictionary *fileAttrs = [fm attributesOfItemAtPath:filename error:nil];
- if (!fileAttrs)
- return NO; // Error accessing the file means 'no'.
- NSString *fileType = [fileAttrs fileType];
- bool isDir = [fileType isEqualToString:NSFileTypeDirectory];
- if (isDir) {
- if ([mSavePanel treatsFilePackagesAsDirectories] == NO) {
- if ([[NSWorkspace sharedWorkspace] isFilePackageAtPath:filename] == NO)
- return YES;
- }
+ const QFileInfo fileInfo(QString::fromNSString(filename));
+
+ // Always accept directories regardless of their names.
+ // This also includes symlinks and aliases to directories.
+ if (fileInfo.isDir()) {
+ // Unless it's a bundle, and we should treat bundles as files.
+ // FIXME: We'd like to use QFileInfo::isBundle() here, but the
+ // detection in QFileInfo goes deeper than NSWorkspace does
+ // (likely a bug), and as a result causes TCC permission
+ // dialogs to pop up when used.
+ bool treatBundlesAsFiles = !m_panel.treatsFilePackagesAsDirectories;
+ if (!(treatBundlesAsFiles && [NSWorkspace.sharedWorkspace isFilePackageAtPath:filename]))
+ return YES;
}
- QString qtFileName = QFileInfo(QString::fromNSString(filename)).fileName();
- // No filter means accept everything
- bool nameMatches = mSelectedNameFilter->isEmpty();
- // Check if the current file name filter accepts the file:
- for (int i = 0; !nameMatches && i < mSelectedNameFilter->size(); ++i) {
- if (QDir::match(mSelectedNameFilter->at(i), qtFileName))
- nameMatches = true;
- }
- if (!nameMatches)
+ if (![self fileInfoMatchesCurrentNameFilter:fileInfo])
return NO;
- QDir::Filters filter = mOptions->filter();
- if ((!(filter & (QDir::Dirs | QDir::AllDirs)) && isDir)
- || (!(filter & QDir::Files) && [fileType isEqualToString:NSFileTypeRegular])
- || ((filter & QDir::NoSymLinks) && [fileType isEqualToString:NSFileTypeSymbolicLink]))
+ QDir::Filters filter = m_options->filter();
+ if ((!(filter & (QDir::Dirs | QDir::AllDirs)) && fileInfo.isDir())
+ || (!(filter & QDir::Files) && (fileInfo.isFile() && !fileInfo.isSymLink()))
+ || ((filter & QDir::NoSymLinks) && fileInfo.isSymLink()))
return NO;
bool filterPermissions = ((filter & QDir::PermissionMask)
&& (filter & QDir::PermissionMask) != QDir::PermissionMask);
if (filterPermissions) {
- if ((!(filter & QDir::Readable) && [fm isReadableFileAtPath:filename])
- || (!(filter & QDir::Writable) && [fm isWritableFileAtPath:filename])
- || (!(filter & QDir::Executable) && [fm isExecutableFileAtPath:filename]))
+ if ((!(filter & QDir::Readable) && fileInfo.isReadable())
+ || (!(filter & QDir::Writable) && fileInfo.isWritable())
+ || (!(filter & QDir::Executable) && fileInfo.isExecutable()))
return NO;
}
- if (!(filter & QDir::Hidden)
- && (qtFileName.startsWith(QLatin1Char('.')) || [self isHiddenFileAtURL:url]))
+
+ // We control the visibility of hidden files via the showsHiddenFiles
+ // property on the panel, based on QDir::Hidden being set. But the user
+ // can also toggle this via the Command+Shift+. keyboard shortcut,
+ // in which case they have explicitly requested to show hidden files,
+ // and we should enable them even if QDir::Hidden was not set. In
+ // effect, we don't need to filter on QDir::Hidden here.
+
+ return YES;
+}
+
+- (BOOL)panel:(id)sender validateURL:(NSURL *)url error:(NSError * _Nullable *)outError
+{
+ Q_ASSERT(sender == m_panel);
+
+ if (!m_panel.allowedFileTypes && !m_selectedNameFilter.isEmpty()) {
+ // The save panel hasn't done filtering on our behalf,
+ // either because we couldn't represent the filter via
+ // allowedFileTypes, or we opted out due to a multi part
+ // extension, so do the filtering/validation ourselves.
+ QFileInfo fileInfo(QString::fromNSString(url.path).normalized(QString::NormalizationForm_C));
+
+ if ([self fileInfoMatchesCurrentNameFilter:fileInfo])
+ return YES;
+
+ if (fileInfo.suffix().isEmpty()) {
+ // The filter requires a file name with an extension.
+ // We're going to add a default file name in selectedFiles,
+ // to match the native behavior. Check now that we can
+ // overwrite the file, if is already exists.
+ fileInfo = [self applyDefaultSuffixFromCurrentNameFilter:fileInfo];
+
+ if (!fileInfo.exists() || m_options->testOption(QFileDialogOptions::DontConfirmOverwrite))
+ return YES;
+
+ QMacAutoReleasePool pool;
+ auto *alert = [[NSAlert new] autorelease];
+ alert.alertStyle = NSAlertStyleCritical;
+
+ alert.messageText = [NSString stringWithFormat:qt_mac_AppKitString(@"SavePanel",
+ @"\\U201c%@\\U201d already exists. Do you want to replace it?"),
+ fileInfo.fileName().toNSString()];
+ alert.informativeText = [NSString stringWithFormat:qt_mac_AppKitString(@"SavePanel",
+ @"A file or folder with the same name already exists in the folder %@. "
+ "Replacing it will overwrite its current contents."),
+ fileInfo.absoluteDir().dirName().toNSString()];
+
+ auto *replaceButton = [alert addButtonWithTitle:qt_mac_AppKitString(@"SavePanel", @"Replace")];
+ replaceButton.hasDestructiveAction = YES;
+ replaceButton.tag = 1337;
+ [alert addButtonWithTitle:qt_mac_AppKitString(@"Common", @"Cancel")];
+
+ [alert beginSheetModalForWindow:m_panel
+ completionHandler:^(NSModalResponse returnCode) {
+ [NSApp stopModalWithCode:returnCode];
+ }];
+ return [NSApp runModalForWindow:alert.window] == replaceButton.tag;
+ } else {
+ QFileInfo firstFilter(m_selectedNameFilter.first());
+ auto *domain = qGuiApp->organizationDomain().toNSString();
+ *outError = [NSError errorWithDomain:domain code:0 userInfo:@{
+ NSLocalizedDescriptionKey:[NSString stringWithFormat:qt_mac_AppKitString(@"SavePanel",
+ @"You cannot save this document with extension \\U201c.%1$@\\U201d at the end "
+ "of the name. The required extension is \\U201c.%2$@\\U201d."),
+ fileInfo.completeSuffix().toNSString(), firstFilter.completeSuffix().toNSString()]
+ }];
return NO;
+ }
+ }
return YES;
}
-- (NSString *)panel:(id)sender userEnteredFilename:(NSString *)filename confirmed:(BOOL)okFlag
+- (QFileInfo)applyDefaultSuffixFromCurrentNameFilter:(const QFileInfo &)fileInfo
{
- Q_UNUSED(sender);
- if (!okFlag)
- return filename;
- if (!mOptions->testOption(QFileDialogOptions::DontConfirmOverwrite))
- return filename;
+ QFileInfo filterInfo(m_selectedNameFilter.first());
+ return QFileInfo(fileInfo.absolutePath(),
+ fileInfo.baseName() + '.' + filterInfo.completeSuffix());
+}
- // User has clicked save, and no overwrite confirmation should occur.
- // To get the latter, we need to change the name we return (hence the prefix):
- return [@"___qt_very_unlikely_prefix_" stringByAppendingString:filename];
+- (bool)fileInfoMatchesCurrentNameFilter:(const QFileInfo &)fileInfo
+{
+ // No filter means accept everything
+ if (m_selectedNameFilter.isEmpty())
+ return true;
+
+ // Check if the current file name filter accepts the file
+ for (const auto &filter : m_selectedNameFilter) {
+ if (QDir::match(filter, fileInfo.fileName()))
+ return true;
+ }
+
+ return false;
}
- (void)setNameFilters:(const QStringList &)filters hideDetails:(BOOL)hideDetails
{
- [mPopUpButton removeAllItems];
- *mNameFilterDropDownList = filters;
+ [m_popupButton removeAllItems];
+ m_nameFilterDropDownList = filters;
if (filters.size() > 0){
- for (int i=0; i<filters.size(); ++i) {
- QString filter = hideDetails ? [self removeExtensions:filters.at(i)] : filters.at(i);
- [mPopUpButton addItemWithTitle:filter.toNSString()];
+ for (int i = 0; i < filters.size(); ++i) {
+ const QString filter = hideDetails ? [self removeExtensions:filters.at(i)] : filters.at(i);
+ [m_popupButton.menu addItemWithTitle:filter.toNSString() action:nil keyEquivalent:@""];
}
- [mPopUpButton selectItemAtIndex:0];
- [mSavePanel setAccessoryView:mAccessoryView];
- } else
- [mSavePanel setAccessoryView:nil];
+ [m_popupButton selectItemAtIndex:0];
+ m_panel.accessoryView = m_accessoryView;
+ } else {
+ m_panel.accessoryView = nil;
+ }
[self filterChanged:self];
}
- (void)filterChanged:(id)sender
{
- // This mDelegate function is called when the _name_ filter changes.
+ // This m_delegate function is called when the _name_ filter changes.
Q_UNUSED(sender);
- QString selection = mNameFilterDropDownList->value([mPopUpButton indexOfSelectedItem]);
- *mSelectedNameFilter = [self findStrippedFilterWithVisualFilterName:selection];
- if ([mSavePanel respondsToSelector:@selector(validateVisibleColumns:)])
- [mSavePanel validateVisibleColumns];
+ if (!m_helper)
+ return;
+ const QString selection = m_nameFilterDropDownList.value([m_popupButton indexOfSelectedItem]);
+ m_selectedNameFilter = [self findStrippedFilterWithVisualFilterName:selection];
+ [m_panel validateVisibleColumns];
[self updateProperties];
- if (mHelper)
- mHelper->QNSOpenSavePanelDelegate_filterSelected([mPopUpButton indexOfSelectedItem]);
-}
-- (QString)currentNameFilter
-{
- return mNameFilterDropDownList->value([mPopUpButton indexOfSelectedItem]);
+ const QStringList filters = m_options->nameFilters();
+ const int menuIndex = m_popupButton.indexOfSelectedItem;
+ emit m_helper->filterSelected(menuIndex >= 0 && menuIndex < filters.size() ? filters.at(menuIndex) : QString());
}
- (QList<QUrl>)selectedFiles
{
- if (mOpenPanel) {
+ if (auto *openPanel = openpanel_cast(m_panel)) {
QList<QUrl> result;
- NSArray<NSURL *> *array = [mOpenPanel URLs];
- for (NSURL *url in array) {
+ for (NSURL *url in openPanel.URLs) {
QString path = QString::fromNSString(url.path).normalized(QString::NormalizationForm_C);
result << QUrl::fromLocalFile(path);
}
return result;
} else {
- QList<QUrl> result;
- QString filename = QString::fromNSString([[mSavePanel URL] path]).normalized(QString::NormalizationForm_C);
- const QString defaultSuffix = mOptions->defaultSuffix();
- const QFileInfo fileInfo(filename);
+ QString filename = QString::fromNSString(m_panel.URL.path).normalized(QString::NormalizationForm_C);
+ QFileInfo fileInfo(filename);
+
+ if (fileInfo.suffix().isEmpty() && ![self fileInfoMatchesCurrentNameFilter:fileInfo]) {
+ // We end up in this situation if we accept a file name without extension
+ // in panel:validateURL:error. If so, we match the behavior of the native
+ // save dialog and add the first of the accepted extension from the filter.
+ fileInfo = [self applyDefaultSuffixFromCurrentNameFilter:fileInfo];
+ }
+
// If neither the user or the NSSavePanel have provided a suffix, use
// the default suffix (if it exists).
+ const QString defaultSuffix = m_options->defaultSuffix();
if (fileInfo.suffix().isEmpty() && !defaultSuffix.isEmpty()) {
- filename.append('.').append(defaultSuffix);
+ fileInfo.setFile(fileInfo.absolutePath(),
+ fileInfo.baseName() + '.' + defaultSuffix);
}
- result << QUrl::fromLocalFile(filename.remove(QLatin1String("___qt_very_unlikely_prefix_")));
- return result;
+
+ return { QUrl::fromLocalFile(fileInfo.filePath()) };
}
}
- (void)updateProperties
{
- // Call this functions if mFileMode, mFileOptions,
- // mNameFilterDropDownList or mQDirFilter changes.
- // The savepanel does not contain the necessary functions for this.
- const QFileDialogOptions::FileMode fileMode = mOptions->fileMode();
+ const QFileDialogOptions::FileMode fileMode = m_options->fileMode();
bool chooseFilesOnly = fileMode == QFileDialogOptions::ExistingFile
|| fileMode == QFileDialogOptions::ExistingFiles;
bool chooseDirsOnly = fileMode == QFileDialogOptions::Directory
|| fileMode == QFileDialogOptions::DirectoryOnly
- || mOptions->testOption(QFileDialogOptions::ShowDirsOnly);
-
- [mOpenPanel setCanChooseFiles:!chooseDirsOnly];
- [mOpenPanel setCanChooseDirectories:!chooseFilesOnly];
- [mSavePanel setCanCreateDirectories:!(mOptions->testOption(QFileDialogOptions::ReadOnly))];
- [mOpenPanel setAllowsMultipleSelection:(fileMode == QFileDialogOptions::ExistingFiles)];
- [mOpenPanel setResolvesAliases:!(mOptions->testOption(QFileDialogOptions::DontResolveSymlinks))];
- [mOpenPanel setTitle:mOptions->windowTitle().toNSString()];
- [mSavePanel setTitle:mOptions->windowTitle().toNSString()];
- [mPopUpButton setHidden:chooseDirsOnly]; // TODO hide the whole sunken pane instead?
-
- if (mOptions->acceptMode() == QFileDialogOptions::AcceptSave) {
- const QStringList ext = [self acceptableExtensionsForSave];
- [mSavePanel setAllowedFileTypes:ext.isEmpty() ? nil : qt_mac_QStringListToNSMutableArray(ext)];
- } else {
- [mOpenPanel setAllowedFileTypes:nil]; // delegate panel:shouldEnableURL: does the file filtering for NSOpenPanel
+ || m_options->testOption(QFileDialogOptions::ShowDirsOnly);
+
+ m_panel.title = m_options->windowTitle().toNSString();
+ m_panel.canCreateDirectories = !(m_options->testOption(QFileDialogOptions::ReadOnly));
+
+ if (m_options->isLabelExplicitlySet(QFileDialogOptions::Accept))
+ m_panel.prompt = strippedText(m_options->labelText(QFileDialogOptions::Accept));
+ if (m_options->isLabelExplicitlySet(QFileDialogOptions::FileName))
+ m_panel.nameFieldLabel = strippedText(m_options->labelText(QFileDialogOptions::FileName));
+
+ if (auto *openPanel = openpanel_cast(m_panel)) {
+ openPanel.canChooseFiles = !chooseDirsOnly;
+ openPanel.canChooseDirectories = !chooseFilesOnly;
+ openPanel.allowsMultipleSelection = (fileMode == QFileDialogOptions::ExistingFiles);
+ openPanel.resolvesAliases = !(m_options->testOption(QFileDialogOptions::DontResolveSymlinks));
}
- if ([mSavePanel respondsToSelector:@selector(isVisible)] && [mSavePanel isVisible]) {
- if ([mSavePanel respondsToSelector:@selector(validateVisibleColumns)])
- [mSavePanel validateVisibleColumns];
+ m_popupButton.hidden = chooseDirsOnly; // TODO hide the whole sunken pane instead?
+
+ m_panel.allowedFileTypes = [self computeAllowedFileTypes];
+
+ // Setting allowedFileTypes to nil is not enough to reset any
+ // automatically added extension based on a previous filter.
+ // This is problematic because extensions can in some cases
+ // be hidden from the user, resulting in confusion when the
+ // resulting file name doesn't match the current empty filter.
+ // We work around this by temporarily resetting the allowed
+ // content type to one without an extension, which forces
+ // the save panel to update and remove the extension.
+ const bool nameFieldHasExtension = m_panel.nameFieldStringValue.pathExtension.length > 0;
+ if (!m_panel.allowedFileTypes && !nameFieldHasExtension && !openpanel_cast(m_panel)) {
+ if (!UTTypeDirectory.preferredFilenameExtension) {
+ m_panel.allowedContentTypes = @[ UTTypeDirectory ];
+ m_panel.allowedFileTypes = nil;
+ } else {
+ qWarning() << "UTTypeDirectory unexpectedly reported an extension";
+ }
}
+
+ m_panel.showsHiddenFiles = m_options->filter().testFlag(QDir::Hidden);
+
+ if (m_panel.visible)
+ [m_panel validateVisibleColumns];
}
- (void)panelSelectionDidChange:(id)sender
{
Q_UNUSED(sender);
- if (mHelper && [mSavePanel isVisible]) {
- QString selection = QString::fromNSString([[mSavePanel URL] path]);
- if (selection != mCurrentSelection) {
- *mCurrentSelection = selection;
- mHelper->QNSOpenSavePanelDelegate_selectionChanged(selection);
+
+ if (!m_helper)
+ return;
+
+ // Save panels only allow you to select directories, which
+ // means currentChanged will only be emitted when selecting
+ // a directory, and if so, with the latest chosen file name,
+ // which is confusing and inconsistent. We choose to bail
+ // out entirely for save panels, to give consistent behavior.
+ if (!openpanel_cast(m_panel))
+ return;
+
+ if (m_panel.visible) {
+ const QString selection = QString::fromNSString(m_panel.URL.path);
+ if (selection != m_currentSelection) {
+ m_currentSelection = selection;
+ emit m_helper->currentChanged(QUrl::fromLocalFile(selection));
}
}
}
@@ -446,36 +499,46 @@ static QString strippedText(QString s)
- (void)panel:(id)sender directoryDidChange:(NSString *)path
{
Q_UNUSED(sender);
- if (!mHelper)
- return;
- if (!(path && path.length) || [path isEqualToString:mCurrentDir])
+
+ if (!m_helper)
return;
- [mCurrentDir release];
- mCurrentDir = [path retain];
- mHelper->QNSOpenSavePanelDelegate_directoryEntered(QString::fromNSString(mCurrentDir));
+ m_helper->panelDirectoryDidChange(path);
}
/*
- Returns a list of extensions (e.g. "png", "jpg", "gif")
- for the current name filter. If a filter do not conform
- to the format *.xyz or * or *.*, an empty list
- is returned meaning accept everything.
+ Computes a list of extensions (e.g. "png", "jpg", "gif")
+ for the current name filter, and updates the save panel.
+
+ If a filter do not conform to the format *.xyz or * or *.*,
+ or contains an extensions with more than one part (e.g. "tar.gz")
+ we treat that as allowing all file types, and do our own
+ validation in panel:validateURL:error.
*/
-- (QStringList)acceptableExtensionsForSave
-{
- QStringList result;
- for (int i=0; i<mSelectedNameFilter->count(); ++i) {
- const QString &filter = mSelectedNameFilter->at(i);
- if (filter.startsWith(QLatin1String("*."))
- && !filter.contains(QLatin1Char('?'))
- && filter.count(QLatin1Char('*')) == 1) {
- result += filter.mid(2);
- } else {
- return QStringList(); // Accept everything
- }
+- (NSArray<NSString*>*)computeAllowedFileTypes
+{
+ if (m_options->acceptMode() != QFileDialogOptions::AcceptSave)
+ return nil; // panel:shouldEnableURL: does the file filtering for NSOpenPanel
+
+ QStringList fileTypes;
+ for (const QString &filter : std::as_const(m_selectedNameFilter)) {
+ if (!filter.startsWith("*."_L1))
+ continue;
+
+ if (filter.contains(u'?'))
+ continue;
+
+ if (filter.count(u'*') != 1)
+ continue;
+
+ auto extensions = filter.split('.', Qt::SkipEmptyParts);
+ if (extensions.count() > 2)
+ return nil;
+
+ fileTypes += extensions.last();
}
- return result;
+
+ return fileTypes.isEmpty() ? nil : qt_mac_QStringListToNSMutableArray(fileTypes);
}
- (QString)removeExtensions:(const QString &)filter
@@ -490,45 +553,44 @@ static QString strippedText(QString s)
- (void)createTextField
{
NSRect textRect = { { 0.0, 3.0 }, { 100.0, 25.0 } };
- mTextField = [[NSTextField alloc] initWithFrame:textRect];
- [[mTextField cell] setFont:[NSFont systemFontOfSize:
- [NSFont systemFontSizeForControlSize:NSControlSizeRegular]]];
- [mTextField setAlignment:NSTextAlignmentRight];
- [mTextField setEditable:false];
- [mTextField setSelectable:false];
- [mTextField setBordered:false];
- [mTextField setDrawsBackground:false];
- if (mOptions->isLabelExplicitlySet(QFileDialogOptions::FileType))
- [mTextField setStringValue:[self strip:mOptions->labelText(QFileDialogOptions::FileType)]];
+ m_textField = [[NSTextField alloc] initWithFrame:textRect];
+ m_textField.cell.font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSControlSizeRegular]];
+ m_textField.alignment = NSTextAlignmentRight;
+ m_textField.editable = false;
+ m_textField.selectable = false;
+ m_textField.bordered = false;
+ m_textField.drawsBackground = false;
+ if (m_options->isLabelExplicitlySet(QFileDialogOptions::FileType))
+ m_textField.stringValue = strippedText(m_options->labelText(QFileDialogOptions::FileType));
}
- (void)createPopUpButton:(const QString &)selectedFilter hideDetails:(BOOL)hideDetails
{
NSRect popUpRect = { { 100.0, 5.0 }, { 250.0, 25.0 } };
- mPopUpButton = [[NSPopUpButton alloc] initWithFrame:popUpRect pullsDown:NO];
- [mPopUpButton setTarget:self];
- [mPopUpButton setAction:@selector(filterChanged:)];
+ m_popupButton = [[NSPopUpButton alloc] initWithFrame:popUpRect pullsDown:NO];
+ m_popupButton.target = self;
+ m_popupButton.action = @selector(filterChanged:);
- if (mNameFilterDropDownList->size() > 0) {
+ if (!m_nameFilterDropDownList.isEmpty()) {
int filterToUse = -1;
- for (int i=0; i<mNameFilterDropDownList->size(); ++i) {
- QString currentFilter = mNameFilterDropDownList->at(i);
+ for (int i = 0; i < m_nameFilterDropDownList.size(); ++i) {
+ const QString currentFilter = m_nameFilterDropDownList.at(i);
if (selectedFilter == currentFilter ||
(filterToUse == -1 && currentFilter.startsWith(selectedFilter)))
filterToUse = i;
QString filter = hideDetails ? [self removeExtensions:currentFilter] : currentFilter;
- [mPopUpButton addItemWithTitle:filter.toNSString()];
+ [m_popupButton.menu addItemWithTitle:filter.toNSString() action:nil keyEquivalent:@""];
}
if (filterToUse != -1)
- [mPopUpButton selectItemAtIndex:filterToUse];
+ [m_popupButton selectItemAtIndex:filterToUse];
}
}
- (QStringList) findStrippedFilterWithVisualFilterName:(QString)name
{
- for (int i=0; i<mNameFilterDropDownList->size(); ++i) {
- if (mNameFilterDropDownList->at(i).startsWith(name))
- return QPlatformFileDialogHelper::cleanFilterList(mNameFilterDropDownList->at(i));
+ for (const QString &currentFilter : std::as_const(m_nameFilterDropDownList)) {
+ if (currentFilter.startsWith(name))
+ return QPlatformFileDialogHelper::cleanFilterList(currentFilter);
}
return QStringList();
}
@@ -536,9 +598,9 @@ static QString strippedText(QString s)
- (void)createAccessory
{
NSRect accessoryRect = { { 0.0, 0.0 }, { 450.0, 33.0 } };
- mAccessoryView = [[NSView alloc] initWithFrame:accessoryRect];
- [mAccessoryView addSubview:mTextField];
- [mAccessoryView addSubview:mPopUpButton];
+ m_accessoryView = [[NSView alloc] initWithFrame:accessoryRect];
+ [m_accessoryView addSubview:m_textField];
+ [m_accessoryView addSubview:m_popupButton];
}
@end
@@ -546,60 +608,53 @@ static QString strippedText(QString s)
QT_BEGIN_NAMESPACE
QCocoaFileDialogHelper::QCocoaFileDialogHelper()
- : mDelegate(nil)
{
}
QCocoaFileDialogHelper::~QCocoaFileDialogHelper()
{
- if (!mDelegate)
+ if (!m_delegate)
return;
- QMacAutoReleasePool pool;
- [mDelegate release];
- mDelegate = nil;
-}
-void QCocoaFileDialogHelper::QNSOpenSavePanelDelegate_selectionChanged(const QString &newPath)
-{
- emit currentChanged(QUrl::fromLocalFile(newPath));
+ QMacAutoReleasePool pool;
+ [m_delegate release];
+ m_delegate = nil;
}
-void QCocoaFileDialogHelper::QNSOpenSavePanelDelegate_panelClosed(bool accepted)
+void QCocoaFileDialogHelper::panelClosed(NSInteger result)
{
- if (accepted) {
+ if (result == NSModalResponseOK)
emit accept();
- } else {
+ else
emit reject();
- }
}
-void QCocoaFileDialogHelper::QNSOpenSavePanelDelegate_directoryEntered(const QString &newDir)
+void QCocoaFileDialogHelper::setDirectory(const QUrl &directory)
{
- // ### fixme: priv->setLastVisitedDirectory(newDir);
- emit directoryEntered(QUrl::fromLocalFile(newDir));
-}
+ m_directory = directory;
-void QCocoaFileDialogHelper::QNSOpenSavePanelDelegate_filterSelected(int menuIndex)
-{
- const QStringList filters = options()->nameFilters();
- emit filterSelected(menuIndex >= 0 && menuIndex < filters.size() ? filters.at(menuIndex) : QString());
+ if (m_delegate)
+ m_delegate->m_panel.directoryURL = [NSURL fileURLWithPath:directory.toLocalFile().toNSString()];
}
-void QCocoaFileDialogHelper::setDirectory(const QUrl &directory)
+QUrl QCocoaFileDialogHelper::directory() const
{
- if (mDelegate)
- [mDelegate->mSavePanel setDirectoryURL:[NSURL fileURLWithPath:directory.toLocalFile().toNSString()]];
- else
- mDir = directory;
+ return m_directory;
}
-QUrl QCocoaFileDialogHelper::directory() const
+void QCocoaFileDialogHelper::panelDirectoryDidChange(NSString *path)
{
- if (mDelegate) {
- QString path = QString::fromNSString([[mDelegate->mSavePanel directoryURL] path]).normalized(QString::NormalizationForm_C);
- return QUrl::fromLocalFile(path);
+ if (!path || [path isEqual:NSNull.null] || !path.length)
+ return;
+
+ const auto oldDirectory = m_directory;
+ m_directory = QUrl::fromLocalFile(
+ QString::fromNSString(path).normalized(QString::NormalizationForm_C));
+
+ if (m_directory != oldDirectory) {
+ // FIXME: Plumb old directory back to QFileDialog's lastVisitedDir?
+ emit directoryEntered(m_directory);
}
- return mDir;
}
void QCocoaFileDialogHelper::selectFile(const QUrl &filename)
@@ -615,23 +670,17 @@ void QCocoaFileDialogHelper::selectFile(const QUrl &filename)
QList<QUrl> QCocoaFileDialogHelper::selectedFiles() const
{
- if (mDelegate)
- return [mDelegate selectedFiles];
+ if (m_delegate)
+ return [m_delegate selectedFiles];
return QList<QUrl>();
}
void QCocoaFileDialogHelper::setFilter()
{
- if (!mDelegate)
+ if (!m_delegate)
return;
- const SharedPointerFileDialogOptions &opts = options();
- [mDelegate->mSavePanel setTitle:opts->windowTitle().toNSString()];
- if (opts->isLabelExplicitlySet(QFileDialogOptions::Accept))
- [mDelegate->mSavePanel setPrompt:[mDelegate strip:opts->labelText(QFileDialogOptions::Accept)]];
- if (opts->isLabelExplicitlySet(QFileDialogOptions::FileName))
- [mDelegate->mSavePanel setNameFieldLabel:[mDelegate strip:opts->labelText(QFileDialogOptions::FileName)]];
- [mDelegate updateProperties];
+ [m_delegate updateProperties];
}
void QCocoaFileDialogHelper::selectNameFilter(const QString &filter)
@@ -640,20 +689,20 @@ void QCocoaFileDialogHelper::selectNameFilter(const QString &filter)
return;
const int index = options()->nameFilters().indexOf(filter);
if (index != -1) {
- if (!mDelegate) {
+ if (!m_delegate) {
options()->setInitiallySelectedNameFilter(filter);
return;
}
- [mDelegate->mPopUpButton selectItemAtIndex:index];
- [mDelegate filterChanged:nil];
+ [m_delegate->m_popupButton selectItemAtIndex:index];
+ [m_delegate filterChanged:nil];
}
}
QString QCocoaFileDialogHelper::selectedNameFilter() const
{
- if (!mDelegate)
+ if (!m_delegate)
return options()->initiallySelectedNameFilter();
- int index = [mDelegate->mPopUpButton indexOfSelectedItem];
+ int index = [m_delegate->m_popupButton indexOfSelectedItem];
if (index >= options()->nameFilters().count())
return QString();
return index != -1 ? options()->nameFilters().at(index) : QString();
@@ -661,12 +710,17 @@ QString QCocoaFileDialogHelper::selectedNameFilter() const
void QCocoaFileDialogHelper::hide()
{
- hideCocoaFilePanel();
+ if (!m_delegate)
+ return;
+
+ [m_delegate closePanel];
+
+ if (m_eventLoop)
+ m_eventLoop->exit();
}
bool QCocoaFileDialogHelper::show(Qt::WindowFlags windowFlags, Qt::WindowModality windowModality, QWindow *parent)
{
-// Q_Q(QFileDialog);
if (windowFlags & Qt::WindowStaysOnTopHint) {
// The native file dialog tries all it can to stay
// on the NSModalPanel level. And it might also show
@@ -675,7 +729,9 @@ bool QCocoaFileDialogHelper::show(Qt::WindowFlags windowFlags, Qt::WindowModalit
return false;
}
- return showCocoaFilePanel(windowModality, parent);
+ createNSOpenSavePanelDelegate();
+
+ return [m_delegate showPanel:windowModality withParent:parent];
}
void QCocoaFileDialogHelper::createNSOpenSavePanelDelegate()
@@ -684,7 +740,7 @@ void QCocoaFileDialogHelper::createNSOpenSavePanelDelegate()
const SharedPointerFileDialogOptions &opts = options();
const QList<QUrl> selectedFiles = opts->initiallySelectedFiles();
- const QUrl directory = mDir.isEmpty() ? opts->initialDirectory() : mDir;
+ const QUrl directory = m_directory.isEmpty() ? opts->initialDirectory() : m_directory;
const bool selectDir = selectedFiles.isEmpty();
QString selection(selectDir ? directory.toLocalFile() : selectedFiles.front().toLocalFile());
QNSOpenSavePanelDelegate *delegate = [[QNSOpenSavePanelDelegate alloc]
@@ -693,51 +749,26 @@ void QCocoaFileDialogHelper::createNSOpenSavePanelDelegate()
options:opts
helper:this];
- [static_cast<QNSOpenSavePanelDelegate *>(mDelegate) release];
- mDelegate = delegate;
+ [static_cast<QNSOpenSavePanelDelegate *>(m_delegate) release];
+ m_delegate = delegate;
}
-bool QCocoaFileDialogHelper::showCocoaFilePanel(Qt::WindowModality windowModality, QWindow *parent)
+void QCocoaFileDialogHelper::exec()
{
- createNSOpenSavePanelDelegate();
- if (!mDelegate)
- return false;
- if (windowModality == Qt::NonModal)
- [mDelegate showModelessPanel];
- else if (windowModality == Qt::WindowModal && parent)
- [mDelegate showWindowModalSheet:parent];
- // no need to show a Qt::ApplicationModal dialog here, since it will be done in _q_platformRunNativeAppModalPanel()
- return true;
-}
+ Q_ASSERT(m_delegate);
-bool QCocoaFileDialogHelper::hideCocoaFilePanel()
-{
- if (!mDelegate){
- // Nothing to do. We return false to leave the question
- // open regarding whether or not to go native:
- return false;
+ if (m_delegate->m_panel.visible) {
+ // WindowModal or NonModal, so already shown above
+ QEventLoop eventLoop;
+ m_eventLoop = &eventLoop;
+ eventLoop.exec(QEventLoop::DialogExec);
+ m_eventLoop = nullptr;
} else {
- [mDelegate closePanel];
- // Even when we hide it, we are still using a
- // native dialog, so return true:
- return true;
+ // ApplicationModal, so show and block using native APIs
+ [m_delegate runApplicationModalPanel];
}
}
-void QCocoaFileDialogHelper::exec()
-{
- // Note: If NSApp is not running (which is the case if e.g a top-most
- // QEventLoop has been interrupted, and the second-most event loop has not
- // yet been reactivated (regardless if [NSApp run] is still on the stack)),
- // showing a native modal dialog will fail.
- QMacAutoReleasePool pool;
- if ([mDelegate runApplicationModalPanel])
- emit accept();
- else
- emit reject();
-
-}
-
bool QCocoaFileDialogHelper::defaultNameFilterDisables() const
{
return true;
diff --git a/src/plugins/platforms/cocoa/qcocoafontdialoghelper.h b/src/plugins/platforms/cocoa/qcocoafontdialoghelper.h
index 14f12f2d76..03824c76ce 100644
--- a/src/plugins/platforms/cocoa/qcocoafontdialoghelper.h
+++ b/src/plugins/platforms/cocoa/qcocoafontdialoghelper.h
@@ -1,51 +1,12 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QCOCOAFONTDIALOGHELPER_H
#define QCOCOAFONTDIALOGHELPER_H
#include <QObject>
-#include <QtWidgets/qtwidgetsglobal.h>
#include <qpa/qplatformdialoghelper.h>
-QT_REQUIRE_CONFIG(fontdialog);
-
QT_BEGIN_NAMESPACE
class QCocoaFontDialogHelper : public QPlatformFontDialogHelper
diff --git a/src/plugins/platforms/cocoa/qcocoafontdialoghelper.mm b/src/plugins/platforms/cocoa/qcocoafontdialoghelper.mm
index 7748c304e3..5cdf6bf02c 100644
--- a/src/plugins/platforms/cocoa/qcocoafontdialoghelper.mm
+++ b/src/plugins/platforms/cocoa/qcocoafontdialoghelper.mm
@@ -1,41 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <AppKit/AppKit.h>
#include <QtCore/qtimer.h>
#include <QtGui/qfontdatabase.h>
@@ -49,8 +15,6 @@
#include "qcocoahelpers.h"
#include "qcocoaeventdispatcher.h"
-#import <AppKit/AppKit.h>
-
#if !CGFLOAT_DEFINED
typedef float CGFloat; // Should only not be defined on 32-bit platforms
#endif
@@ -66,7 +30,7 @@ static QFont qfontForCocoaFont(NSFont *cocoaFont, const QFont &resolveFont)
QString family(QCFString((CFStringRef)CTFontDescriptorCopyAttribute(font, kCTFontFamilyNameAttribute)));
QString style(QCFString(((CFStringRef)CTFontDescriptorCopyAttribute(font, kCTFontStyleNameAttribute))));
- newFont = QFontDatabase().font(family, style, pSize);
+ newFont = QFontDatabase::font(family, style, pSize);
newFont.setUnderline(resolveFont.underline());
newFont.setStrikeOut(resolveFont.strikeOut());
}
@@ -202,7 +166,17 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSFontPanelDelegate);
{
mDialogIsExecuting = false;
mResultSet = false;
- [mFontPanel makeKeyAndOrderFront:mFontPanel];
+ // Make this an asynchronous call, so the panel is made key only
+ // in the next event loop run. This is to make sure that by
+ // the time the modal loop is run in runModalForWindow below,
+ // which internally also sets the panel to key window,
+ // the panel is not yet key, and the NSApp still has the right
+ // reference to the _previousKeyWindow. Otherwise both NSApp.key
+ // and NSApp._previousKeyWindow would wrongly point to the panel,
+ // loosing any reference to the window that was key before.
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [mFontPanel makeKeyAndOrderFront:mFontPanel];
+ });
}
- (BOOL)runApplicationModalPanel
@@ -218,6 +192,11 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSFontPanelDelegate);
[NSApp runModalForWindow:mFontPanel];
mDialogIsExecuting = false;
+
+ // Wake up the event dispatcher so it can check whether the
+ // current event loop should continue spinning or not.
+ QCoreApplication::eventDispatcher()->wakeUp();
+
return (mResultCode == NSModalResponseOK);
}
@@ -314,9 +293,9 @@ public:
bool show(Qt::WindowModality windowModality, QWindow *parent)
{
Q_UNUSED(parent);
- if (windowModality != Qt::WindowModal)
+ if (windowModality != Qt::ApplicationModal)
[mDelegate showModelessPanel];
- // no need to show a Qt::WindowModal dialog here, because it's necessary to call exec() in that case
+ // no need to show a Qt::ApplicationModal dialog here, because it will be shown in runApplicationModalPanel
return true;
}
@@ -380,8 +359,8 @@ void QCocoaFontDialogHelper::exec()
bool QCocoaFontDialogHelper::show(Qt::WindowFlags, Qt::WindowModality windowModality, QWindow *parent)
{
- if (windowModality == Qt::WindowModal)
- windowModality = Qt::ApplicationModal;
+ if (windowModality == Qt::ApplicationModal)
+ windowModality = Qt::WindowModal;
sharedFontPanel()->init(this);
return sharedFontPanel()->show(windowModality, parent);
}
diff --git a/src/plugins/platforms/cocoa/qcocoaglcontext.h b/src/plugins/platforms/cocoa/qcocoaglcontext.h
index 238067568b..919f7c240b 100644
--- a/src/plugins/platforms/cocoa/qcocoaglcontext.h
+++ b/src/plugins/platforms/cocoa/qcocoaglcontext.h
@@ -1,61 +1,29 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QCOCOAGLCONTEXT_H
#define QCOCOAGLCONTEXT_H
#include <QtCore/QPointer>
+#include <QtCore/QVarLengthArray>
#include <QtCore/private/qcore_mac_p.h>
#include <qpa/qplatformopenglcontext.h>
-#include <QtGui/QOpenGLContext>
+#include <QtGui/qopenglcontext.h>
+#include <QtGui/private/qopenglcontext_p.h>
#include <QtGui/QWindow>
-#include <AppKit/AppKit.h>
+Q_FORWARD_DECLARE_OBJC_CLASS(NSOpenGLContext);
+Q_FORWARD_DECLARE_OBJC_CLASS(NSOpenGLPixelFormat);
QT_BEGIN_NAMESPACE
class QCocoaWindow;
-class QCocoaGLContext : public QPlatformOpenGLContext
+class QCocoaGLContext : public QPlatformOpenGLContext, public QNativeInterface::QCocoaGLContext
{
public:
QCocoaGLContext(QOpenGLContext *context);
+ QCocoaGLContext(NSOpenGLContext *context);
~QCocoaGLContext();
void initialize() override;
@@ -70,7 +38,7 @@ public:
bool isSharing() const override;
bool isValid() const override;
- NSOpenGLContext *nativeContext() const;
+ NSOpenGLContext *nativeContext() const override;
QFunctionPointer getProcAddress(const char *procName) override;
@@ -78,7 +46,6 @@ private:
static NSOpenGLPixelFormat *pixelFormatForSurfaceFormat(const QSurfaceFormat &format);
bool setDrawable(QPlatformSurface *surface);
- void prepareDrawable(QCocoaWindow *platformWindow);
void updateSurfaceFormat();
NSOpenGLContext *m_context = nil;
diff --git a/src/plugins/platforms/cocoa/qcocoaglcontext.mm b/src/plugins/platforms/cocoa/qcocoaglcontext.mm
index 6db4bdb9fd..a65311175f 100644
--- a/src/plugins/platforms/cocoa/qcocoaglcontext.mm
+++ b/src/plugins/platforms/cocoa/qcocoaglcontext.mm
@@ -1,53 +1,18 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <AppKit/AppKit.h>
#include "qcocoaglcontext.h"
#include "qcocoawindow.h"
#include "qcocoahelpers.h"
#include "qcocoascreen.h"
+#include <QtCore/private/qcore_mac_p.h>
+
#include <qdebug.h>
-#include <QtPlatformHeaders/qcocoanativecontext.h>
#include <dlfcn.h>
-#import <AppKit/AppKit.h>
-
static inline QByteArray getGlString(GLenum param)
{
if (const GLubyte *s = glGetString(param))
@@ -65,30 +30,23 @@ QCocoaGLContext::QCocoaGLContext(QOpenGLContext *context)
{
}
-void QCocoaGLContext::initialize()
+QCocoaGLContext::QCocoaGLContext(NSOpenGLContext *nativeContext)
+ : QPlatformOpenGLContext()
{
- QVariant nativeHandle = context()->nativeHandle();
- if (!nativeHandle.isNull()) {
- if (!nativeHandle.canConvert<QCocoaNativeContext>()) {
- qCWarning(lcQpaOpenGLContext, "QOpenGLContext native handle must be a QCocoaNativeContext");
- return;
- }
- m_context = nativeHandle.value<QCocoaNativeContext>().context();
- if (!m_context) {
- qCWarning(lcQpaOpenGLContext, "QCocoaNativeContext's NSOpenGLContext cannot be null");
- return;
- }
-
- [m_context retain];
-
- // Note: We have no way of knowing whether the NSOpenGLContext was created with the
- // share context as reported by the QOpenGLContext, but we just have to trust that
- // it was. It's okey, as the only thing we're using it for is to report isShared().
- if (QPlatformOpenGLContext *shareContext = context()->shareHandle())
- m_shareContext = static_cast<QCocoaGLContext *>(shareContext)->nativeContext();
+ m_context = [nativeContext retain];
+}
- updateSurfaceFormat();
- return;
+void QCocoaGLContext::initialize()
+{
+ if (m_context) {
+ // Note: We have no way of knowing whether the NSOpenGLContext was created with the
+ // share context as reported by the QOpenGLContext, but we just have to trust that
+ // it was. It's okey, as the only thing we're using it for is to report isShared().
+ if (QPlatformOpenGLContext *shareContext = context()->shareHandle())
+ m_shareContext = static_cast<QCocoaGLContext *>(shareContext)->nativeContext();
+
+ updateSurfaceFormat();
+ return;
}
// ----------- Default case, we own the NSOpenGLContext -----------
@@ -139,23 +97,20 @@ void QCocoaGLContext::initialize()
return;
}
- // The native handle should reflect the underlying context, even if we created it
- context()->setNativeHandle(QVariant::fromValue<QCocoaNativeContext>(m_context));
-
// --------------------- Set NSOpenGLContext properties ---------------------
const GLint interval = m_format.swapInterval() >= 0 ? m_format.swapInterval() : 1;
- [m_context setValues:&interval forParameter:NSOpenGLCPSwapInterval];
+ [m_context setValues:&interval forParameter:NSOpenGLContextParameterSwapInterval];
if (m_format.alphaBufferSize() > 0) {
int zeroOpacity = 0;
- [m_context setValues:&zeroOpacity forParameter:NSOpenGLCPSurfaceOpacity];
+ [m_context setValues:&zeroOpacity forParameter:NSOpenGLContextParameterSurfaceOpacity];
}
// OpenGL surfaces can be ordered either above(default) or below the NSWindow
// FIXME: Promote to QSurfaceFormat option or property
const GLint order = qt_mac_resolveOption(1, "QT_MAC_OPENGL_SURFACE_ORDER");
- [m_context setValues:&order forParameter:NSOpenGLCPSurfaceOrder];
+ [m_context setValues:&order forParameter:NSOpenGLContextParameterSurfaceOrder];
updateSurfaceFormat();
@@ -342,7 +297,7 @@ void QCocoaGLContext::updateSurfaceFormat()
return value;
};
- m_format.setSwapInterval(glContextParameter(NSOpenGLCPSwapInterval));
+ m_format.setSwapInterval(glContextParameter(NSOpenGLContextParameterSwapInterval));
if (oldContext)
[oldContext makeCurrentContext];
@@ -357,6 +312,8 @@ QCocoaGLContext::~QCocoaGLContext()
bool QCocoaGLContext::makeCurrent(QPlatformSurface *surface)
{
+ QMacAutoReleasePool pool;
+
qCDebug(lcQpaOpenGLContext) << "Making" << this << "current"
<< "in" << QThread::currentThread() << "for" << surface;
@@ -390,7 +347,7 @@ bool QCocoaGLContext::setDrawable(QPlatformSurface *surface)
// Clear the current drawable and reset the active window, so that GL
// commands that don't target a specific FBO will not end up stomping
// on the previously set drawable.
- qCDebug(lcQpaOpenGLContext) << "Clearing current drawable" << m_context.view << "for" << m_context;
+ qCDebug(lcQpaOpenGLContext) << "Clearing current drawable" << QT_IGNORE_DEPRECATIONS(m_context.view) << "for" << m_context;
[m_context clearDrawable];
return true;
}
@@ -399,10 +356,16 @@ bool QCocoaGLContext::setDrawable(QPlatformSurface *surface)
auto *cocoaWindow = static_cast<QCocoaWindow *>(surface);
QNSView *view = qnsview_cast(cocoaWindow->view());
- if (view == m_context.view)
+ if (view == QT_IGNORE_DEPRECATIONS(m_context.view))
return true;
- prepareDrawable(cocoaWindow);
+ // We generally want high-DPI GL surfaces, unless the user has explicitly disabled them.
+ // According to the documentation, layer-backed views ignore wantsBestResolutionOpenGLSurface
+ // and configure their own backing surface at an appropriate resolution, but in some cases
+ // we've seen this fail (plugin views embedded in surface-backed hosts), so we do it anyways.
+ QT_IGNORE_DEPRECATIONS(view.wantsBestResolutionOpenGLSurface) = qt_mac_resolveOption(YES,
+ cocoaWindow->window(), "_q_mac_wantsBestResolutionOpenGLSurface",
+ "QT_MAC_WANTS_BEST_RESOLUTION_OPENGL_SURFACE");
// Setting the drawable may happen on a separate thread as a result of
// a call to makeCurrent, so we need to set up the observers before we
@@ -412,68 +375,49 @@ bool QCocoaGLContext::setDrawable(QPlatformSurface *surface)
auto updateCallback = [this, view]() {
Q_ASSERT(QThread::currentThread() == qApp->thread());
- if (m_context.view != view)
+ if (QT_IGNORE_DEPRECATIONS(m_context.view) != view)
return;
m_needsUpdate = true;
};
m_updateObservers.clear();
- if (view.layer) {
- m_updateObservers.append(QMacNotificationObserver(view, NSViewFrameDidChangeNotification, updateCallback));
- m_updateObservers.append(QMacNotificationObserver(view.window, NSWindowDidChangeScreenNotification, updateCallback));
- } else {
- m_updateObservers.append(QMacNotificationObserver(view, NSViewGlobalFrameDidChangeNotification, updateCallback));
- }
+ m_updateObservers.append(QMacNotificationObserver(view, NSViewFrameDidChangeNotification, updateCallback));
+ m_updateObservers.append(QMacNotificationObserver(view.window, NSWindowDidChangeScreenNotification, updateCallback));
m_updateObservers.append(QMacNotificationObserver([NSApplication sharedApplication],
NSApplicationDidChangeScreenParametersNotification, updateCallback));
+ m_updateObservers.append(QMacNotificationObserver(view,
+ QCocoaWindowWillReleaseQNSViewNotification, [this, view] {
+ if (QT_IGNORE_DEPRECATIONS(m_context.view) != view)
+ return;
+ qCDebug(lcQpaOpenGLContext) << view << "about to be released."
+ << "Clearing current drawable for" << m_context;
+ [m_context clearDrawable];
+ }));
+
// If any of the observers fire at this point it's fine. We check the
// view association (atomically) in the update callback, and skip the
// update if we haven't associated yet. Setting the drawable below will
// have the same effect as an update.
// Now we are ready to associate the view with the context
- m_context.view = view;
- if (m_context.view != view) {
+ QT_IGNORE_DEPRECATIONS(m_context.view) = view;
+ if (QT_IGNORE_DEPRECATIONS(m_context.view) != view) {
qCInfo(lcQpaOpenGLContext) << "Failed to set" << view << "as drawable for" << m_context;
m_updateObservers.clear();
return false;
}
- qCInfo(lcQpaOpenGLContext) << "Set drawable for" << m_context << "to" << m_context.view;
+ qCInfo(lcQpaOpenGLContext) << "Set drawable for" << m_context << "to" << QT_IGNORE_DEPRECATIONS(m_context.view);
return true;
}
-void QCocoaGLContext::prepareDrawable(QCocoaWindow *platformWindow)
-{
- // We generally want high-DPI GL surfaces, unless the user has explicitly disabled them
- bool prefersBestResolutionOpenGLSurface = qt_mac_resolveOption(YES,
- platformWindow->window(), "_q_mac_wantsBestResolutionOpenGLSurface",
- "QT_MAC_WANTS_BEST_RESOLUTION_OPENGL_SURFACE");
-
- auto *view = platformWindow->view();
-
- // The only case we have to opt out ourselves is when using the Apple software renderer
- // in combination with surface-backed views, as these together do not support high-DPI.
- if (prefersBestResolutionOpenGLSurface) {
- int rendererID = 0;
- [m_context getValues:&rendererID forParameter:NSOpenGLContextParameterCurrentRendererID];
- bool isSoftwareRenderer = (rendererID & kCGLRendererIDMatchingMask) == kCGLRendererGenericFloatID;
- if (isSoftwareRenderer && !view.layer) {
- qCInfo(lcQpaOpenGLContext) << "Disabling high resolution GL surface due to software renderer";
- prefersBestResolutionOpenGLSurface = false;
- }
- }
-
- view.wantsBestResolutionOpenGLSurface = prefersBestResolutionOpenGLSurface;
-}
-
// NSOpenGLContext is not re-entrant. Even when using separate contexts per thread,
// view, and window, calls into the API will still deadlock. For more information
// see https://openradar.appspot.com/37064579
-static QMutex s_reentrancyMutex;
+Q_CONSTINIT static QMutex s_reentrancyMutex;
void QCocoaGLContext::update()
{
@@ -483,12 +427,14 @@ void QCocoaGLContext::update()
QMacAutoReleasePool pool;
QMutexLocker locker(&s_reentrancyMutex);
- qCInfo(lcQpaOpenGLContext) << "Updating" << m_context << "for" << m_context.view;
+ qCInfo(lcQpaOpenGLContext) << "Updating" << m_context << "for" << QT_IGNORE_DEPRECATIONS(m_context.view);
[m_context update];
}
void QCocoaGLContext::swapBuffers(QPlatformSurface *surface)
{
+ QMacAutoReleasePool pool;
+
qCDebug(lcQpaOpenGLContext) << "Swapping" << m_context
<< "in" << QThread::currentThread() << "to" << surface;
@@ -501,19 +447,17 @@ void QCocoaGLContext::swapBuffers(QPlatformSurface *surface)
return;
}
- if (m_context.view.layer) {
- // Flushing an NSOpenGLContext will hit the screen immediately, ignoring
- // any Core Animation transactions in place. This may result in major
- // visual artifacts if the flush happens out of sync with the size
- // of the layer, view, and window reflected by other parts of the UI,
- // e.g. if the application flushes in the resize event or a timer during
- // window resizing, instead of in the expose event.
- auto *cocoaWindow = static_cast<QCocoaWindow *>(surface);
- if (cocoaWindow->geometry().size() != cocoaWindow->m_exposedRect.size()) {
- qCInfo(lcQpaOpenGLContext) << "Window exposed size does not match geometry (yet)."
- << "Skipping flush to avoid visual artifacts.";
- return;
- }
+ // Flushing an NSOpenGLContext will hit the screen immediately, ignoring
+ // any Core Animation transactions in place. This may result in major
+ // visual artifacts if the flush happens out of sync with the size
+ // of the layer, view, and window reflected by other parts of the UI,
+ // e.g. if the application flushes in the resize event or a timer during
+ // window resizing, instead of in the expose event.
+ auto *cocoaWindow = static_cast<QCocoaWindow *>(surface);
+ if (cocoaWindow->geometry().size() != cocoaWindow->m_exposedRect.size()) {
+ qCInfo(lcQpaOpenGLContext) << "Window exposed size does not match geometry (yet)."
+ << "Skipping flush to avoid visual artifacts.";
+ return;
}
QMutexLocker locker(&s_reentrancyMutex);
@@ -522,6 +466,8 @@ void QCocoaGLContext::swapBuffers(QPlatformSurface *surface)
void QCocoaGLContext::doneCurrent()
{
+ QMacAutoReleasePool pool;
+
qCDebug(lcQpaOpenGLContext) << "Clearing current context"
<< [NSOpenGLContext currentContext] << "in" << QThread::currentThread();
@@ -554,7 +500,7 @@ NSOpenGLContext *QCocoaGLContext::nativeContext() const
QFunctionPointer QCocoaGLContext::getProcAddress(const char *procName)
{
- return (QFunctionPointer)dlsym(RTLD_DEFAULT, procName);
+ return (QFunctionPointer)dlsym(RTLD_NEXT, procName);
}
#ifndef QT_NO_DEBUG_STREAM
diff --git a/src/plugins/platforms/cocoa/qcocoahelpers.h b/src/plugins/platforms/cocoa/qcocoahelpers.h
index 69a1854598..c6862a9e65 100644
--- a/src/plugins/platforms/cocoa/qcocoahelpers.h
+++ b/src/plugins/platforms/cocoa/qcocoahelpers.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QCOCOAHELPERS_H
#define QCOCOAHELPERS_H
@@ -45,20 +9,23 @@
// -------------
//
// This file is not part of the Qt API. It provides helper functions
-// for the Cocoa lighthouse plugin. This header file may
+// for the Cocoa plugin. This header file may
// change from version to version without notice, or even be removed.
//
// We mean it.
//
-#include "qt_mac_p.h"
+
#include <private/qguiapplication_p.h>
-#include <QtCore/qoperatingsystemversion.h>
+#include <QtCore/qloggingcategory.h>
#include <QtGui/qpalette.h>
#include <QtGui/qscreen.h>
+#include <qpa/qplatformdialoghelper.h>
#include <objc/runtime.h>
#include <objc/message.h>
+#if defined(__OBJC__)
+
Q_FORWARD_DECLARE_OBJC_CLASS(QT_MANGLE_NAMESPACE(QNSView));
struct mach_header;
@@ -68,7 +35,14 @@ 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)
+Q_DECLARE_LOGGING_CATEGORY(lcQpaDialogs)
+Q_DECLARE_LOGGING_CATEGORY(lcQpaMenus)
class QPixmap;
class QString;
@@ -82,16 +56,6 @@ NSDragOperation qt_mac_mapDropActions(Qt::DropActions actions);
Qt::DropAction qt_mac_mapNSDragOperation(NSDragOperation nsActions);
Qt::DropActions qt_mac_mapNSDragOperations(NSDragOperation nsActions);
-template <typename T>
-typename std::enable_if<std::is_pointer<T>::value, T>::type
-qt_objc_cast(id object)
-{
- if ([object isKindOfClass:[typename std::remove_pointer<T>::type class]])
- return static_cast<T>(object);
-
- return nil;
-}
-
QT_MANGLE_NAMESPACE(QNSView) *qnsview_cast(NSView *view);
// Misc
@@ -114,6 +78,9 @@ Qt::MouseButtons currentlyPressedMouseButtons();
// accelerators.
QString qt_mac_removeAmpersandEscapes(QString s);
+// Similar to __NXKitString for localized AppKit strings
+NSString *qt_mac_AppKitString(NSString *table, NSString *key);
+
enum {
QtCocoaEventSubTypeWakeup = SHRT_MAX,
QtCocoaEventSubTypePostMessage = SHRT_MAX-1
@@ -188,34 +155,6 @@ struct backwards_t {
template<class R>
constexpr backwards_t<R> backwards(R&& r) { return {std::forward<R>(r)}; }
-// -------------------------------------------------------------------------
-
-#if !defined(Q_PROCESSOR_X86_64)
-#error "32-bit builds are not supported"
-#endif
-
-class QMacVersion
-{
-public:
- enum VersionTarget {
- ApplicationBinary,
- QtLibraries
- };
-
- static QOperatingSystemVersion buildSDK(VersionTarget target = ApplicationBinary);
- static QOperatingSystemVersion deploymentTarget(VersionTarget target = ApplicationBinary);
- static QOperatingSystemVersion currentRuntime();
-
-private:
- QMacVersion() = default;
- using VersionTuple = QPair<QOperatingSystemVersion, QOperatingSystemVersion>;
- static VersionTuple versionsForImage(const mach_header *machHeader);
- static VersionTuple applicationVersion();
- static VersionTuple libraryVersion();
-};
-
-// -------------------------------------------------------------------------
-
QT_END_NAMESPACE
// @compatibility_alias doesn't work with protocols
@@ -237,7 +176,7 @@ QT_END_NAMESPACE
- (instancetype)initWithPanelDelegate:(id<QNSPanelDelegate>)panelDelegate;
- (void)dealloc;
-- (NSButton *)createButtonWithTitle:(const char *)title;
+- (NSButton *)createButtonWithTitle:(QPlatformDialogHelper::StandardButton)type;
- (void)layout;
@end
@@ -246,19 +185,6 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSPanelContentsWrapper);
// -------------------------------------------------------------------------
-// QAppleRefCounted expects the retain function to return the object
-io_object_t q_IOObjectRetain(io_object_t obj);
-// QAppleRefCounted expects the release function to return void
-void q_IOObjectRelease(io_object_t obj);
-
-template <typename T>
-class QIOType : public QAppleRefCounted<T, io_object_t, q_IOObjectRetain, q_IOObjectRelease>
-{
- using QAppleRefCounted<T, io_object_t, q_IOObjectRetain, q_IOObjectRelease>::QAppleRefCounted;
-};
-
-// -------------------------------------------------------------------------
-
// Depending on the ABI of the platform, we may need to use objc_msgSendSuper_stret:
// - http://www.sealiesoftware.com/blog/archive/2008/10/30/objc_explain_objc_msgSend_stret.html
// - https://lists.apple.com/archives/cocoa-dev/2008/Feb/msg02338.html
@@ -266,14 +192,16 @@ template <typename T>
struct objc_msgsend_requires_stret
{ static const bool value =
#if defined(Q_PROCESSOR_X86)
+ #define PLATFORM_USES_SEND_SUPER_STRET 1
// Any return value larger than two registers on i386/x86_64
sizeof(T) > sizeof(void*) * 2;
#elif defined(Q_PROCESSOR_ARM_32)
+ #define PLATFORM_USES_SEND_SUPER_STRET 1
// Any return value larger than a single register on arm
- sizeof(T) > sizeof(void*);
+ sizeof(T) > sizeof(void*);
#elif defined(Q_PROCESSOR_ARM_64)
- // Stret not used on arm64
- false;
+ #define PLATFORM_USES_SEND_SUPER_STRET 0
+ false; // Stret not used on arm64
#endif
};
@@ -293,6 +221,7 @@ ReturnType qt_msgSendSuper(id receiver, SEL selector, Args... args)
return superFn(&sup, selector, args...);
}
+#if PLATFORM_USES_SEND_SUPER_STRET
template <typename ReturnType, typename... Args>
ReturnType qt_msgSendSuper_stret(id receiver, SEL selector, Args... args)
{
@@ -307,6 +236,7 @@ ReturnType qt_msgSendSuper_stret(id receiver, SEL selector, Args... args)
superStretFn(&ret, &sup, selector, args...);
return ret;
}
+#endif
template<typename... Args>
class QSendSuperHelper {
@@ -347,11 +277,13 @@ private:
return qt_msgSendSuper<ReturnType>(m_receiver, m_selector, std::get<Is>(args)...);
}
+#if PLATFORM_USES_SEND_SUPER_STRET
template <typename ReturnType, int... Is>
if_requires_stret<ReturnType, true> msgSendSuper(std::tuple<Args...>& args, QtPrivate::IndexesList<Is...>)
{
return qt_msgSendSuper_stret<ReturnType>(m_receiver, m_selector, std::get<Is>(args)...);
}
+#endif
template <typename ReturnType>
ReturnType msgSendSuper(std::tuple<Args...>& args)
@@ -374,5 +306,46 @@ 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<int, 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 c9eafa81d0..1eba88d5e3 100644
--- a/src/plugins/platforms/cocoa/qcocoahelpers.mm
+++ b/src/plugins/platforms/cocoa/qcocoahelpers.mm
@@ -1,41 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <AppKit/AppKit.h>
#include <qpa/qplatformtheme.h>
@@ -49,21 +15,21 @@
#include <private/qwindow_p.h>
#include <QtGui/private/qcoregraphics_p.h>
-#ifndef QT_NO_WIDGETS
-#include <QtWidgets/QWidget>
-#endif
-
#include <algorithm>
-#include <mach-o/dyld.h>
-#include <dlfcn.h>
-
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")
+Q_LOGGING_CATEGORY(lcQpaDialogs, "qt.qpa.dialogs")
+Q_LOGGING_CATEGORY(lcQpaMenus, "qt.qpa.menus")
//
// Conversion Functions
@@ -157,7 +123,7 @@ Qt::DropActions qt_mac_mapNSDragOperations(NSDragOperation nsActions)
that the platform window is not a foreign window before using
this cast, via QPlatformWindow::isForeignWindow().
- Do not use this method soley to check for foreign windows, as
+ Do not use this method solely to check for foreign windows, as
that will make the code harder to read for people not working
primarily on macOS, who do not know the difference between the
NSView and QNSView cases.
@@ -225,7 +191,7 @@ QString qt_mac_applicationName()
if (appName.isEmpty()) {
QString arg0 = QGuiApplicationPrivate::instance()->appName();
if (arg0.contains("/")) {
- QStringList parts = arg0.split(QLatin1Char('/'));
+ QStringList parts = arg0.split(u'/');
appName = parts.at(parts.count() - 1);
} else {
appName = arg0;
@@ -370,90 +336,13 @@ QString qt_mac_removeAmpersandEscapes(QString s)
return QPlatformTheme::removeMnemonics(s).trimmed();
}
-// -------------------------------------------------------------------------
-
-#if !defined(Q_PROCESSOR_X86_64)
-#error "32-bit builds are not supported"
-#endif
-
-QOperatingSystemVersion QMacVersion::buildSDK(VersionTarget target)
+NSString *qt_mac_AppKitString(NSString *table, NSString *key)
{
- switch (target) {
- case ApplicationBinary: return applicationVersion().second;
- case QtLibraries: return libraryVersion().second;
- }
- Q_UNREACHABLE();
-}
+ static const NSBundle *appKit = [NSBundle bundleForClass:NSApplication.class];
+ if (!appKit)
+ return key;
-QOperatingSystemVersion QMacVersion::deploymentTarget(VersionTarget target)
-{
- switch (target) {
- case ApplicationBinary: return applicationVersion().first;
- case QtLibraries: return libraryVersion().first;
- }
- Q_UNREACHABLE();
-}
-
-QOperatingSystemVersion QMacVersion::currentRuntime()
-{
- return QOperatingSystemVersion::current();
-}
-
-QMacVersion::VersionTuple QMacVersion::versionsForImage(const mach_header *machHeader)
-{
- static auto makeVersionTuple = [](uint32_t dt, uint32_t sdk) {
- return qMakePair(
- QOperatingSystemVersion(QOperatingSystemVersion::MacOS,
- dt >> 16 & 0xffff, dt >> 8 & 0xff, dt & 0xff),
- QOperatingSystemVersion(QOperatingSystemVersion::MacOS,
- sdk >> 16 & 0xffff, sdk >> 8 & 0xff, sdk & 0xff)
- );
- };
-
- auto commandCursor = uintptr_t(machHeader) + sizeof(mach_header_64);
- for (uint32_t i = 0; i < machHeader->ncmds; ++i) {
- load_command *loadCommand = reinterpret_cast<load_command *>(commandCursor);
- if (loadCommand->cmd == LC_VERSION_MIN_MACOSX) {
- auto versionCommand = reinterpret_cast<version_min_command *>(loadCommand);
- return makeVersionTuple(versionCommand->version, versionCommand->sdk);
-#if QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_13)
- } else if (loadCommand->cmd == LC_BUILD_VERSION) {
- auto versionCommand = reinterpret_cast<build_version_command *>(loadCommand);
- return makeVersionTuple(versionCommand->minos, versionCommand->sdk);
-#endif
- }
- commandCursor += loadCommand->cmdsize;
- }
- Q_ASSERT_X(false, "QCocoaIntegration", "Could not find any version load command");
- Q_UNREACHABLE();
-}
-
-QMacVersion::VersionTuple QMacVersion::applicationVersion()
-{
- static VersionTuple version = []() {
- const mach_header *executableHeader = nullptr;
- for (uint32_t i = 0; i < _dyld_image_count(); ++i) {
- auto header = _dyld_get_image_header(i);
- if (header->filetype == MH_EXECUTE) {
- executableHeader = header;
- break;
- }
- }
- Q_ASSERT_X(executableHeader, "QCocoaIntegration", "Failed to resolve Mach-O header of executable");
- return versionsForImage(executableHeader);
- }();
- return version;
-}
-
-QMacVersion::VersionTuple QMacVersion::libraryVersion()
-{
- static VersionTuple version = []() {
- Dl_info cocoaPluginImage;
- dladdr((const void *)&QMacVersion::libraryVersion, &cocoaPluginImage);
- Q_ASSERT_X(cocoaPluginImage.dli_fbase, "QCocoaIntegration", "Failed to resolve Mach-O header of Cocoa plugin");
- return versionsForImage(static_cast<mach_header*>(cocoaPluginImage.dli_fbase));
- }();
- return version;
+ return [appKit localizedStringForKey:key value:nil table:table];
}
QT_END_NAMESPACE
@@ -483,11 +372,10 @@ QT_END_NAMESPACE
{
if ((self = [super initWithFrame:NSZeroRect])) {
// create OK and Cancel buttons and add these as subviews
- _okButton = [self createButtonWithTitle:"&OK"];
+ _okButton = [self createButtonWithTitle:QPlatformDialogHelper::Ok];
_okButton.action = @selector(onOkClicked);
_okButton.target = panelDelegate;
-
- _cancelButton = [self createButtonWithTitle:"Cancel"];
+ _cancelButton = [self createButtonWithTitle:QPlatformDialogHelper::Cancel];
_cancelButton.action = @selector(onCancelClicked);
_cancelButton.target = panelDelegate;
@@ -511,12 +399,13 @@ QT_END_NAMESPACE
[super dealloc];
}
-- (NSButton *)createButtonWithTitle:(const char *)title
+- (NSButton *)createButtonWithTitle:(QPlatformDialogHelper::StandardButton)type
{
NSButton *button = [[NSButton alloc] initWithFrame:NSZeroRect];
- button.buttonType = NSMomentaryLightButton;
- button.bezelStyle = NSRoundedBezelStyle;
- const QString &cleanTitle = QPlatformTheme::removeMnemonics(QCoreApplication::translate("QDialogButtonBox", title));
+ button.buttonType = NSButtonTypeMomentaryLight;
+ button.bezelStyle = NSBezelStyleRounded;
+ const QString &cleanTitle =
+ QPlatformTheme::removeMnemonics(QGuiApplicationPrivate::platformTheme()->standardButtonText(type));
// FIXME: Not obvious, from Cocoa's documentation, that QString::toNSString() makes a deep copy
button.title = (NSString *)cleanTitle.toCFString();
((NSButtonCell *)button.cell).font =
@@ -581,19 +470,45 @@ QT_END_NAMESPACE
[super layout];
}
+@end // QNSPanelContentsWrapper
+
// -------------------------------------------------------------------------
-io_object_t q_IOObjectRetain(io_object_t obj)
+InputMethodQueryResult queryInputMethod(QObject *object, Qt::InputMethodQueries queries)
{
- kern_return_t ret = IOObjectRetain(obj);
- Q_ASSERT(!ret);
- return obj;
+ 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 {};
}
-void q_IOObjectRelease(io_object_t obj)
+// -------------------------------------------------------------------------
+
+QDebug operator<<(QDebug debug, const NSRange &range)
{
- kern_return_t ret = IOObjectRelease(obj);
- Q_ASSERT(!ret);
+ if (range.location == NSNotFound) {
+ QDebugStateSaver saver(debug);
+ debug.nospace() << "{NSNotFound, " << range.length << "}";
+ } else {
+ debug << NSStringFromRange(range);
+ }
+ return debug;
}
-@end
+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..58d1d7ec86 100644
--- a/src/plugins/platforms/cocoa/qcocoainputcontext.h
+++ b/src/plugins/platforms/cocoa/qcocoainputcontext.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QCOCOAINPUTCONTEXT_H
#define QCOCOAINPUTCONTEXT_H
@@ -44,6 +8,8 @@
#include <QtCore/QLocale>
#include <QtCore/QPointer>
+#include <QtCore/private/qcore_mac_p.h>
+
QT_BEGIN_NAMESPACE
class QCocoaInputContext : public QPlatformInputContext
@@ -55,18 +21,18 @@ public:
bool isValid() const override { return true; }
+ void setFocusObject(QObject *object) override;
+
+ void commit() 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 d0baea5b36..70461376e2 100644
--- a/src/plugins/platforms/cocoa/qcocoainputcontext.mm
+++ b/src/plugins/platforms/cocoa/qcocoainputcontext.mm
@@ -1,41 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <AppKit/AppKit.h>
#include "qnsview.h"
#include "qcocoainputcontext.h"
@@ -55,8 +21,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
@@ -72,19 +38,20 @@ QT_BEGIN_NAMESPACE
\section1 Interaction
- Input method support in Cocoa uses NSTextInput protorol. Therefore
- almost all functionality is implemented in QNSView.
-
- \ingroup qt-lighthouse-cocoa
+ 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();
}
@@ -93,42 +60,69 @@ QCocoaInputContext::~QCocoaInputContext()
}
/*!
- \brief Cancels a composition.
+ Commits the current composition if there is one,
+ by "unmarking" the text in the edit buffer, and
+ informing the system input context of this fact.
*/
+void QCocoaInputContext::commit()
+{
+ qCDebug(lcQpaInputMethods) << "Committing composition";
+
+ if (!m_focusWindow)
+ return;
+
+ auto *platformWindow = m_focusWindow->handle();
+ if (!platformWindow)
+ return;
+
+ auto *cocoaWindow = static_cast<QCocoaWindow *>(platformWindow);
+ QNSView *view = qnsview_cast(cocoaWindow->view());
+ if (!view)
+ return;
+
+ [view unmarkText];
+
+ [view.inputContext discardMarkedText];
+ if (view.inputContext != NSTextInputContext.currentInputContext) {
+ // discardMarkedText will activate the TSM document of the given input context,
+ // which may not match the current input context. To ensure the current input
+ // context is not left in an inconsistent state with a deactivated document
+ // we need to manually activate it here.
+ [NSTextInputContext.currentInputContext activate];
+ }
+}
+
+/*!
+ \brief Cancels a composition.
+*/
void QCocoaInputContext::reset()
{
- QPlatformInputContext::reset();
+ qCDebug(lcQpaInputMethods) << "Resetting input method";
- 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;
- QMacAutoReleasePool pool;
if (NSTextInputContext *ctxt = [NSTextInputContext currentInputContext]) {
[ctxt discardMarkedText];
[view unmarkText];
}
}
-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 +134,34 @@ 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);
+
+ bool localeUpdated = m_locale != locale;
+ static bool firstUpdate = true;
+
+ m_locale = locale;
+
+ if (localeUpdated && !firstUpdate) {
+ qCDebug(lcQpaInputMethods) << "Reporting new locale" << locale;
+ emitLocaleChanged();
}
- CFRelease(source);
+
+ firstUpdate = false;
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.h b/src/plugins/platforms/cocoa/qcocoaintegration.h
index 30838ba254..664700cf51 100644
--- a/src/plugins/platforms/cocoa/qcocoaintegration.h
+++ b/src/plugins/platforms/cocoa/qcocoaintegration.h
@@ -1,47 +1,9 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QPLATFORMINTEGRATION_COCOA_H
#define QPLATFORMINTEGRATION_COCOA_H
-#include <AppKit/AppKit.h>
-
#include "qcocoacursor.h"
#include "qcocoawindow.h"
#include "qcocoanativeinterface.h"
@@ -50,18 +12,27 @@
#include "qcocoaclipboard.h"
#include "qcocoadrag.h"
#include "qcocoaservices.h"
-#include "qcocoakeymapper.h"
#if QT_CONFIG(vulkan)
#include "qcocoavulkaninstance.h"
#endif
+#include "qcocoawindowmanager.h"
#include <QtCore/QScopedPointer>
#include <qpa/qplatformintegration.h>
-#include <QtFontDatabaseSupport/private/qcoretextfontdatabase_p.h>
+#include <QtGui/private/qcoretextfontdatabase_p.h>
+#ifndef QT_NO_OPENGL
+# include <QtGui/private/qopenglcontext_p.h>
+#endif
+#include <QtGui/private/qapplekeymapper_p.h>
+
+Q_FORWARD_DECLARE_OBJC_CLASS(NSToolbar);
QT_BEGIN_NAMESPACE
class QCocoaIntegration : public QObject, public QPlatformIntegration
+#ifndef QT_NO_OPENGL
+ , public QNativeInterface::Private::QCocoaGLIntegration
+#endif
{
Q_OBJECT
public:
@@ -82,6 +53,7 @@ public:
QPlatformOffscreenSurface *createPlatformOffscreenSurface(QOffscreenSurface *surface) const override;
#ifndef QT_NO_OPENGL
QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const override;
+ QOpenGLContext *createOpenGLContext(NSOpenGLContext *, QOpenGLContext *shareContext) const override;
#endif
QPlatformBackingStore *createPlatformBackingStore(QWindow *widget) const override;
@@ -99,7 +71,7 @@ public:
QCoreTextFontDatabase *fontDatabase() const override;
QCocoaNativeInterface *nativeInterface() const override;
QPlatformInputContext *inputContext() const override;
-#ifndef QT_NO_ACCESSIBILITY
+#if QT_CONFIG(accessibility)
QCocoaAccessibility *accessibility() const override;
#endif
#ifndef QT_NO_CLIPBOARD
@@ -112,23 +84,13 @@ public:
QCocoaServices *services() const override;
QVariant styleHint(StyleHint hint) const override;
- Qt::KeyboardModifiers queryKeyboardModifiers() const override;
- QList<int> possibleKeys(const QKeyEvent *event) const override;
-
- void setToolbar(QWindow *window, NSToolbar *toolbar);
- NSToolbar *toolbar(QWindow *window) const;
- void clearToolbars();
-
- void pushPopupWindow(QCocoaWindow *window);
- QCocoaWindow *popPopupWindow();
- QCocoaWindow *activePopupWindow() const;
- QList<QCocoaWindow *> *popupWindowStack();
+ QPlatformKeyMapper *keyMapper() const override;
void setApplicationIcon(const QIcon &icon) const override;
+ void setApplicationBadge(qint64 number) override;
void beep() const override;
-
- void closePopups(QWindow *forWindow = nullptr);
+ void quit() const override;
private Q_SLOTS:
void focusWindowChanged(QWindow *);
@@ -140,7 +102,7 @@ private:
QScopedPointer<QCoreTextFontDatabase> mFontDb;
QScopedPointer<QPlatformInputContext> mInputContext;
-#ifndef QT_NO_ACCESSIBILITY
+#if QT_CONFIG(accessibility)
QScopedPointer<QCocoaAccessibility> mAccessibility;
#endif
QScopedPointer<QPlatformTheme> mPlatformTheme;
@@ -150,13 +112,13 @@ private:
QScopedPointer<QCocoaDrag> mCocoaDrag;
QScopedPointer<QCocoaNativeInterface> mNativeInterface;
QScopedPointer<QCocoaServices> mServices;
- QScopedPointer<QCocoaKeyMapper> mKeyboardMapper;
+ QScopedPointer<QAppleKeyMapper> mKeyboardMapper;
#if QT_CONFIG(vulkan)
mutable QCocoaVulkanInstance *mCocoaVulkanInstance = nullptr;
#endif
- QHash<QWindow *, NSToolbar *> mToolbars;
- QList<QCocoaWindow *> m_popupWindowStack;
+
+ QCocoaWindowManager m_windowManager;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QCocoaIntegration::Options)
diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.mm b/src/plugins/platforms/cocoa/qcocoaintegration.mm
index b2698b05fe..2ce39ff897 100644
--- a/src/plugins/platforms/cocoa/qcocoaintegration.mm
+++ b/src/plugins/platforms/cocoa/qcocoaintegration.mm
@@ -1,41 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <AppKit/AppKit.h>
#include "qcocoaintegration.h"
@@ -55,31 +21,28 @@
#if QT_CONFIG(sessionmanager)
# include "qcocoasessionmanager.h"
#endif
+#include "qcocoawindowmanager.h"
#include <qpa/qplatforminputcontextfactory_p.h>
#include <qpa/qplatformaccessibility.h>
#include <qpa/qplatforminputcontextfactory_p.h>
#include <qpa/qplatformoffscreensurface.h>
#include <QtCore/qcoreapplication.h>
+#include <QtGui/qpointingdevice.h>
-#include <QtPlatformHeaders/qcocoanativecontext.h>
-
+#include <QtCore/private/qcore_mac_p.h>
#include <QtGui/private/qcoregraphics_p.h>
-
-#include <QtFontDatabaseSupport/private/qfontengine_coretext_p.h>
-
-#if QT_CONFIG(opengl)
-#include <QtPlatformCompositorSupport/qpa/qplatformbackingstoreopenglsupport.h>
-#endif
-
-#ifdef QT_WIDGETS_LIB
-#include <QtWidgets/qtwidgetsglobal.h>
-#if QT_CONFIG(filedialog)
-#include "qcocoafiledialoghelper.h"
-#endif
+#include <QtGui/private/qmacmimeregistry_p.h>
+#ifndef QT_NO_OPENGL
+# include <QtGui/private/qopenglcontext_p.h>
#endif
+#include <QtGui/private/qrhibackingstore_p.h>
+#include <QtGui/private/qfontengine_coretext_p.h>
#include <IOKit/graphics/IOGraphicsLib.h>
+#include <UniformTypeIdentifiers/UTCoreTypes.h>
+
+#include <inttypes.h>
static void initResources()
{
@@ -88,6 +51,8 @@ static void initResources()
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
Q_LOGGING_CATEGORY(lcQpa, "qt.qpa", QtWarningMsg);
static void logVersionInformation()
@@ -120,9 +85,9 @@ class QFontEngineFT;
static QCocoaIntegration::Options parseOptions(const QStringList &paramList)
{
QCocoaIntegration::Options options;
- foreach (const QString &param, paramList) {
+ for (const QString &param : paramList) {
#ifndef QT_NO_FREETYPE
- if (param == QLatin1String("fontengine=freetype"))
+ if (param == "fontengine=freetype"_L1)
options |= QCocoaIntegration::UseFreeTypeFontEngine;
else
#endif
@@ -136,7 +101,7 @@ QCocoaIntegration *QCocoaIntegration::mInstance = nullptr;
QCocoaIntegration::QCocoaIntegration(const QStringList &paramList)
: mOptions(parseOptions(paramList))
, mFontDb(nullptr)
-#ifndef QT_NO_ACCESSIBILITY
+#if QT_CONFIG(accessibility)
, mAccessibility(new QCocoaAccessibility)
#endif
#ifndef QT_NO_CLIPBOARD
@@ -145,7 +110,7 @@ QCocoaIntegration::QCocoaIntegration(const QStringList &paramList)
, mCocoaDrag(new QCocoaDrag)
, mNativeInterface(new QCocoaNativeInterface)
, mServices(new QCocoaServices)
- , mKeyboardMapper(new QCocoaKeyMapper)
+ , mKeyboardMapper(new QAppleKeyMapper)
{
logVersionInformation();
@@ -160,9 +125,9 @@ QCocoaIntegration::QCocoaIntegration(const QStringList &paramList)
#endif
mFontDb.reset(new QCoreTextFontDatabaseEngineFactory<QCoreTextFontEngine>);
- QString icStr = QPlatformInputContextFactory::requested();
- icStr.isNull() ? mInputContext.reset(new QCocoaInputContext)
- : mInputContext.reset(QPlatformInputContextFactory::create(icStr));
+ auto icStrs = QPlatformInputContextFactory::requested();
+ icStrs.isEmpty() ? mInputContext.reset(new QCocoaInputContext)
+ : mInputContext.reset(QPlatformInputContextFactory::create(icStrs));
initResources();
QMacAutoReleasePool pool;
@@ -172,24 +137,13 @@ QCocoaIntegration::QCocoaIntegration(const QStringList &paramList)
if (qEnvironmentVariableIsEmpty("QT_MAC_DISABLE_FOREGROUND_APPLICATION_TRANSFORM")) {
// Applications launched from plain executables (without an app
- // bundle) are "background" applications that does not take keybaord
+ // bundle) are "background" applications that does not take keyboard
// focus or have a dock icon or task switcher entry. Qt Gui apps generally
// wants to be foreground applications so change the process type. (But
// see the function implementation for exceptions.)
qt_mac_transformProccessToForegroundApplication();
-
- // Move the application window to front to make it take focus, also when launching
- // from the terminal. On 10.12+ this call has been moved to applicationDidFinishLauching
- // to work around issues with loss of focus at startup.
- if (QOperatingSystemVersion::current() < QOperatingSystemVersion::MacOSSierra) {
- // Ignoring other apps is necessary (we must ignore the terminal), but makes
- // Qt apps play slightly less nice with other apps when lanching from Finder
- // (See the activateIgnoringOtherApps docs.)
- [cocoaApplication activateIgnoringOtherApps : YES];
- }
}
- // ### For AA_MacPluginApplication we don't want to load the menu nib.
// Qt 4 also does not set the application delegate, so that behavior
// is matched here.
if (!QCoreApplication::testAttribute(Qt::AA_PluginApplication)) {
@@ -206,9 +160,11 @@ QCocoaIntegration::QCocoaIntegration(const QStringList &paramList)
QCocoaScreen::initializeScreens();
- QMacInternalPasteboardMime::initializeMimeTypes();
+ QMacMimeRegistry::initializeMimeTypes();
QCocoaMimeTypes::initializeMimeTypes();
QWindowSystemInterfacePrivate::TabletEvent::setPlatformSynthesizesMouse(false);
+ QWindowSystemInterface::registerInputDevice(new QInputDevice(QString("keyboard"), 0,
+ QInputDevice::DeviceType::Keyboard, QString(), this));
connect(qGuiApp, &QGuiApplication::focusWindowChanged,
this, &QCocoaIntegration::focusWindowChanged);
@@ -229,17 +185,18 @@ QCocoaIntegration::~QCocoaIntegration()
[[NSApplication sharedApplication] setDelegate:nil];
}
+ // Stop global mouse event and app activation monitoring
+ QCocoaWindow::removePopupMonitor();
+
#ifndef QT_NO_CLIPBOARD
// Delete the clipboard integration and destroy mime type converters.
// Deleting the clipboard integration flushes promised pastes using
// the mime converters - the ordering here is important.
delete mCocoaClipboard;
- QMacInternalPasteboardMime::destroyMimeTypes();
+ QMacMimeRegistry::destroyMimeTypes();
#endif
QCocoaScreen::cleanupScreens();
-
- clearToolbars();
}
QCocoaIntegration *QCocoaIntegration::instance()
@@ -267,8 +224,8 @@ bool QCocoaIntegration::hasCapability(QPlatformIntegration::Capability cap) cons
// AppKit expects rendering to happen on the main thread, and we can
// easily end up in situations where rendering on secondary threads
// will result in visual artifacts, bugs, or even deadlocks, when
- // building with SDK 10.14 or higher which enbles view layer-backing.
- return QMacVersion::buildSDK() < QOperatingSystemVersion(QOperatingSystemVersion::MacOSMojave);
+ // layer-backed.
+ return false;
case OpenGL:
case BufferQueueingOpenGL:
#endif
@@ -279,6 +236,7 @@ bool QCocoaIntegration::hasCapability(QPlatformIntegration::Capability cap) cons
case RasterGLSurface:
case ApplicationState:
case ApplicationIcon:
+ case BackingStoreStaticContents:
return true;
default:
return QPlatformIntegration::hasCapability(cap);
@@ -318,6 +276,19 @@ QPlatformOpenGLContext *QCocoaIntegration::createPlatformOpenGLContext(QOpenGLCo
{
return new QCocoaGLContext(context);
}
+
+QOpenGLContext *QCocoaIntegration::createOpenGLContext(NSOpenGLContext *nativeContext, QOpenGLContext *shareContext) const
+{
+ if (!nativeContext)
+ return nullptr;
+
+ auto *context = new QOpenGLContext;
+ context->setShareContext(shareContext);
+ auto *contextPrivate = QOpenGLContextPrivate::get(context);
+ contextPrivate->adopt(new QCocoaGLContext(nativeContext));
+ return context;
+}
+
#endif
QPlatformBackingStore *QCocoaIntegration::createPlatformBackingStore(QWindow *window) const
@@ -328,16 +299,27 @@ QPlatformBackingStore *QCocoaIntegration::createPlatformBackingStore(QWindow *wi
return nullptr;
}
- QPlatformBackingStore *backingStore = nullptr;
- if (platformWindow->view().layer)
- backingStore = new QCALayerBackingStore(window);
- else
- backingStore = new QNSWindowBackingStore(window);
-
-#if QT_CONFIG(opengl)
- backingStore->setOpenGLSupport(new QPlatformBackingStoreOpenGLSupport(backingStore));
-#endif
- return backingStore;
+ switch (window->surfaceType()) {
+ case QSurface::RasterSurface:
+ return new QCALayerBackingStore(window);
+ case QSurface::MetalSurface:
+ case QSurface::OpenGLSurface:
+ case QSurface::VulkanSurface:
+ // If the window is a widget window, we know that the QWidgetRepaintManager
+ // will explicitly use rhiFlush() for the window owning the backingstore,
+ // and any child window with the same surface format. This means we can
+ // safely return a QCALayerBackingStore here, to ensure that any plain
+ // flush() for child windows that don't have a matching surface format
+ // will still work, by setting the layer's contents property.
+ if (window->inherits("QWidgetWindow"))
+ return new QCALayerBackingStore(window);
+
+ // Otherwise we return a QRhiBackingStore, that implements flush() in
+ // terms of rhiFlush().
+ return new QRhiBackingStore(window);
+ default:
+ return nullptr;
+ }
}
QAbstractEventDispatcher *QCocoaIntegration::createEventDispatcher() const
@@ -373,7 +355,7 @@ QPlatformInputContext *QCocoaIntegration::inputContext() const
return mInputContext.data();
}
-#ifndef QT_NO_ACCESSIBILITY
+#if QT_CONFIG(accessibility)
QCocoaAccessibility *QCocoaIntegration::accessibility() const
{
return mAccessibility.data();
@@ -394,12 +376,12 @@ QCocoaDrag *QCocoaIntegration::drag() const
QStringList QCocoaIntegration::themeNames() const
{
- return QStringList(QLatin1String(QCocoaTheme::name));
+ return QStringList(QLatin1StringView(QCocoaTheme::name));
}
QPlatformTheme *QCocoaIntegration::createPlatformTheme(const QString &name) const
{
- if (name == QLatin1String(QCocoaTheme::name))
+ if (name == QLatin1StringView(QCocoaTheme::name))
return new QCocoaTheme;
return QPlatformIntegration::createPlatformTheme(name);
}
@@ -416,80 +398,29 @@ QVariant QCocoaIntegration::styleHint(StyleHint hint) const
return QCoreTextFontEngine::fontSmoothingGamma();
case ShowShortcutsInContextMenus:
return QVariant(false);
+ case ReplayMousePressOutsidePopup:
+ return QVariant(false);
default: break;
}
return QPlatformIntegration::styleHint(hint);
}
-Qt::KeyboardModifiers QCocoaIntegration::queryKeyboardModifiers() const
+QPlatformKeyMapper *QCocoaIntegration::keyMapper() const
{
- return QCocoaKeyMapper::queryKeyboardModifiers();
+ return mKeyboardMapper.data();
}
-QList<int> QCocoaIntegration::possibleKeys(const QKeyEvent *event) const
-{
- return mKeyboardMapper->possibleKeys(event);
-}
-
-void QCocoaIntegration::setToolbar(QWindow *window, NSToolbar *toolbar)
-{
- if (NSToolbar *prevToolbar = mToolbars.value(window))
- [prevToolbar release];
-
- [toolbar retain];
- mToolbars.insert(window, toolbar);
-}
-
-NSToolbar *QCocoaIntegration::toolbar(QWindow *window) const
-{
- return mToolbars.value(window);
-}
-
-void QCocoaIntegration::clearToolbars()
-{
- QHash<QWindow *, NSToolbar *>::const_iterator it = mToolbars.constBegin();
- while (it != mToolbars.constEnd()) {
- [it.value() release];
- ++it;
- }
- 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()
+void QCocoaIntegration::setApplicationIcon(const QIcon &icon) const
{
- return &m_popupWindowStack;
+ // Fall back to a size that looks good on the highest resolution screen available
+ auto fallbackSize = NSApp.dockTile.size.width * qGuiApp->devicePixelRatio();
+ NSApp.applicationIconImage = [NSImage imageFromQIcon:icon withSize:fallbackSize];
}
-void QCocoaIntegration::setApplicationIcon(const QIcon &icon) const
+void QCocoaIntegration::setApplicationBadge(qint64 number)
{
- NSImage *image = nil;
- if (!icon.isNull()) {
- NSSize size = [[[NSApplication sharedApplication] dockTile] size];
- QPixmap pixmap = icon.pixmap(size.width, size.height);
- image = static_cast<NSImage *>(qt_mac_create_nsimage(pixmap));
- }
- [[NSApplication sharedApplication] setApplicationIconImage:image];
- [image release];
+ NSApp.dockTile.badgeLabel = number ? [NSString stringWithFormat:@"%" PRId64, number] : nil;
}
void QCocoaIntegration::beep() const
@@ -497,17 +428,10 @@ void QCocoaIntegration::beep() const
NSBeep();
}
-void QCocoaIntegration::closePopups(QWindow *forWindow)
+void QCocoaIntegration::quit() const
{
- 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;
- }
- }
+ qCDebug(lcQpaApplication) << "Terminating application";
+ [NSApp terminate:nil];
}
void QCocoaIntegration::focusWindowChanged(QWindow *focusWindow)
@@ -517,8 +441,8 @@ void QCocoaIntegration::focusWindowChanged(QWindow *focusWindow)
return;
static bool hasDefaultApplicationIcon = [](){
- NSImage *genericApplicationIcon = [[NSWorkspace sharedWorkspace]
- iconForFileType:NSFileTypeForHFSTypeCode(kGenericApplicationIcon)];
+ NSImage *genericApplicationIcon = [NSWorkspace.sharedWorkspace
+ iconForContentType:UTTypeApplicationBundle];
NSImage *applicationIcon = [NSImage imageNamed:NSImageNameApplicationIcon];
NSRect rect = NSMakeRect(0, 0, 32, 32);
@@ -537,6 +461,6 @@ void QCocoaIntegration::focusWindowChanged(QWindow *focusWindow)
setApplicationIcon(focusWindow->icon());
}
-#include "moc_qcocoaintegration.cpp"
-
QT_END_NAMESPACE
+
+#include "moc_qcocoaintegration.cpp"
diff --git a/src/plugins/platforms/cocoa/qcocoaintrospection.h b/src/plugins/platforms/cocoa/qcocoaintrospection.h
index 20001ac71d..c4956a9f62 100644
--- a/src/plugins/platforms/cocoa/qcocoaintrospection.h
+++ b/src/plugins/platforms/cocoa/qcocoaintrospection.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
/****************************************************************************
**
@@ -71,8 +35,11 @@
**
****************************************************************************/
+#ifndef QCOCOAINTROSPECTION_H
+#define QCOCOAINTROSPECTION_H
+
#include <qglobal.h>
-#import <objc/objc-class.h>
+#include <objc/objc-class.h>
QT_BEGIN_NAMESPACE
@@ -80,3 +47,5 @@ void qt_cocoa_change_implementation(Class baseClass, SEL originalSel, Class prox
void qt_cocoa_change_back_implementation(Class baseClass, SEL originalSel, SEL backupSel);
QT_END_NAMESPACE
+
+#endif // QCOCOAINTROSPECTION_H
diff --git a/src/plugins/platforms/cocoa/qcocoaintrospection.mm b/src/plugins/platforms/cocoa/qcocoaintrospection.mm
index 9d1e987176..2d769d4c6d 100644
--- a/src/plugins/platforms/cocoa/qcocoaintrospection.mm
+++ b/src/plugins/platforms/cocoa/qcocoaintrospection.mm
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
/****************************************************************************
**
diff --git a/src/plugins/platforms/cocoa/qcocoakeymapper.h b/src/plugins/platforms/cocoa/qcocoakeymapper.h
deleted file mode 100644
index 2624f19978..0000000000
--- a/src/plugins/platforms/cocoa/qcocoakeymapper.h
+++ /dev/null
@@ -1,104 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 QCOCOAKEYMAPPER_H
-#define QCOCOAKEYMAPPER_H
-
-#include "qcocoahelpers.h"
-
-#include <AppKit/AppKit.h>
-#include <Carbon/Carbon.h>
-
-#include <QtCore/QList>
-#include <QtGui/QKeyEvent>
-
-QT_BEGIN_NAMESPACE
-
-/*
- \internal
- A Mac KeyboardLayoutItem has 8 possible states:
- 1. Unmodified
- 2. Shift
- 3. Control
- 4. Control + Shift
- 5. Alt
- 6. Alt + Shift
- 7. Alt + Control
- 8. Alt + Control + Shift
- 9. Meta
- 10. Meta + Shift
- 11. Meta + Control
- 12. Meta + Control + Shift
- 13. Meta + Alt
- 14. Meta + Alt + Shift
- 15. Meta + Alt + Control
- 16. Meta + Alt + Control + Shift
-*/
-struct KeyboardLayoutItem {
- bool dirty;
- quint32 qtKey[16]; // Can by any Qt::Key_<foo>, or unicode character
-};
-
-
-class QCocoaKeyMapper
-{
-public:
- QCocoaKeyMapper();
- ~QCocoaKeyMapper();
- static Qt::KeyboardModifiers queryKeyboardModifiers();
- QList<int> possibleKeys(const QKeyEvent *event) const;
- bool updateKeyboard();
- void deleteLayouts();
- void updateKeyMap(unsigned short macVirtualKey, QChar unicodeKey);
- void clearMappings();
-
-private:
- QCFType<TISInputSourceRef> currentInputSource = nullptr;
-
- enum { NullMode, UnicodeMode, OtherMode } keyboard_mode = NullMode;
- const UCKeyboardLayout *keyboard_layout_format = nullptr;
- KeyboardLayoutKind keyboard_kind = kKLKCHRuchrKind;
- UInt32 keyboard_dead = 0;
- KeyboardLayoutItem *keyLayout[256];
-};
-
-QT_END_NAMESPACE
-
-#endif
-
diff --git a/src/plugins/platforms/cocoa/qcocoakeymapper.mm b/src/plugins/platforms/cocoa/qcocoakeymapper.mm
deleted file mode 100644
index 350ae4b9be..0000000000
--- a/src/plugins/platforms/cocoa/qcocoakeymapper.mm
+++ /dev/null
@@ -1,471 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 "qcocoakeymapper.h"
-
-#include <QtCore/QDebug>
-#include <QtGui/QGuiApplication>
-
-QT_BEGIN_NAMESPACE
-
-// QCocoaKeyMapper debug facilities
-//#define DEBUG_KEY_BINDINGS
-//#define DEBUG_KEY_BINDINGS_MODIFIERS
-//#define DEBUG_KEY_MAPS
-
-// Possible modifier states.
-// NOTE: The order of these states match the order in updatePossibleKeyCodes()!
-static const Qt::KeyboardModifiers ModsTbl[] = {
- Qt::NoModifier, // 0
- Qt::ShiftModifier, // 1
- Qt::ControlModifier, // 2
- Qt::ControlModifier | Qt::ShiftModifier, // 3
- Qt::AltModifier, // 4
- Qt::AltModifier | Qt::ShiftModifier, // 5
- Qt::AltModifier | Qt::ControlModifier, // 6
- Qt::AltModifier | Qt::ShiftModifier | Qt::ControlModifier, // 7
- Qt::MetaModifier, // 8
- Qt::MetaModifier | Qt::ShiftModifier, // 9
- Qt::MetaModifier | Qt::ControlModifier, // 10
- Qt::MetaModifier | Qt::ControlModifier | Qt::ShiftModifier,// 11
- Qt::MetaModifier | Qt::AltModifier, // 12
- Qt::MetaModifier | Qt::AltModifier | Qt::ShiftModifier, // 13
- Qt::MetaModifier | Qt::AltModifier | Qt::ControlModifier, // 14
- Qt::MetaModifier | Qt::AltModifier | Qt::ShiftModifier | Qt::ControlModifier, // 15
-};
-
-bool qt_mac_eat_unicode_key = false;
-
-
-/* key maps */
-struct qt_mac_enum_mapper
-{
- int mac_code;
- int qt_code;
-#if defined(DEBUG_KEY_BINDINGS)
-# define QT_MAC_MAP_ENUM(x) x, #x
- const char *desc;
-#else
-# define QT_MAC_MAP_ENUM(x) x
-#endif
-};
-
-//modifiers
-static qt_mac_enum_mapper qt_mac_modifier_symbols[] = {
- { shiftKey, QT_MAC_MAP_ENUM(Qt::ShiftModifier) },
- { rightShiftKey, QT_MAC_MAP_ENUM(Qt::ShiftModifier) },
- { controlKey, QT_MAC_MAP_ENUM(Qt::MetaModifier) },
- { rightControlKey, QT_MAC_MAP_ENUM(Qt::MetaModifier) },
- { cmdKey, QT_MAC_MAP_ENUM(Qt::ControlModifier) },
- { optionKey, QT_MAC_MAP_ENUM(Qt::AltModifier) },
- { rightOptionKey, QT_MAC_MAP_ENUM(Qt::AltModifier) },
- { kEventKeyModifierNumLockMask, QT_MAC_MAP_ENUM(Qt::KeypadModifier) },
- { 0, QT_MAC_MAP_ENUM(0) }
-};
-Qt::KeyboardModifiers qt_mac_get_modifiers(int keys)
-{
-#ifdef DEBUG_KEY_BINDINGS_MODIFIERS
- qDebug("Qt: internal: **Mapping modifiers: %d (0x%04x)", keys, keys);
-#endif
- Qt::KeyboardModifiers ret = Qt::NoModifier;
- for (int i = 0; qt_mac_modifier_symbols[i].qt_code; i++) {
- if (keys & qt_mac_modifier_symbols[i].mac_code) {
-#ifdef DEBUG_KEY_BINDINGS_MODIFIERS
- qDebug("Qt: internal: got modifier: %s", qt_mac_modifier_symbols[i].desc);
-#endif
- ret |= Qt::KeyboardModifier(qt_mac_modifier_symbols[i].qt_code);
- }
- }
- if (qApp->testAttribute(Qt::AA_MacDontSwapCtrlAndMeta)) {
- Qt::KeyboardModifiers oldModifiers = ret;
- ret &= ~(Qt::MetaModifier | Qt::ControlModifier);
- if (oldModifiers & Qt::ControlModifier)
- ret |= Qt::MetaModifier;
- if (oldModifiers & Qt::MetaModifier)
- ret |= Qt::ControlModifier;
- }
- return ret;
-}
-static int qt_mac_get_mac_modifiers(Qt::KeyboardModifiers keys)
-{
-#ifdef DEBUG_KEY_BINDINGS_MODIFIERS
- qDebug("Qt: internal: **Mapping modifiers: %d (0x%04x)", (int)keys, (int)keys);
-#endif
- int ret = 0;
- for (int i = 0; qt_mac_modifier_symbols[i].qt_code; i++) {
- if (keys & qt_mac_modifier_symbols[i].qt_code) {
-#ifdef DEBUG_KEY_BINDINGS_MODIFIERS
- qDebug("Qt: internal: got modifier: %s", qt_mac_modifier_symbols[i].desc);
-#endif
- ret |= qt_mac_modifier_symbols[i].mac_code;
- }
- }
-
- if (qApp->testAttribute(Qt::AA_MacDontSwapCtrlAndMeta)) {
- int oldModifiers = ret;
- ret &= ~(controlKeyBit | cmdKeyBit);
- if (oldModifiers & controlKeyBit)
- ret |= cmdKeyBit;
- if (oldModifiers & cmdKeyBit)
- ret |= controlKeyBit;
- }
- return ret;
-}
-
-//keyboard keys (non-modifiers)
-static qt_mac_enum_mapper qt_mac_keyboard_symbols[] = {
- { kHomeCharCode, QT_MAC_MAP_ENUM(Qt::Key_Home) },
- { kEnterCharCode, QT_MAC_MAP_ENUM(Qt::Key_Enter) },
- { kEndCharCode, QT_MAC_MAP_ENUM(Qt::Key_End) },
- { kBackspaceCharCode, QT_MAC_MAP_ENUM(Qt::Key_Backspace) },
- { kTabCharCode, QT_MAC_MAP_ENUM(Qt::Key_Tab) },
- { kPageUpCharCode, QT_MAC_MAP_ENUM(Qt::Key_PageUp) },
- { kPageDownCharCode, QT_MAC_MAP_ENUM(Qt::Key_PageDown) },
- { kReturnCharCode, QT_MAC_MAP_ENUM(Qt::Key_Return) },
- { kEscapeCharCode, QT_MAC_MAP_ENUM(Qt::Key_Escape) },
- { kLeftArrowCharCode, QT_MAC_MAP_ENUM(Qt::Key_Left) },
- { kRightArrowCharCode, QT_MAC_MAP_ENUM(Qt::Key_Right) },
- { kUpArrowCharCode, QT_MAC_MAP_ENUM(Qt::Key_Up) },
- { kDownArrowCharCode, QT_MAC_MAP_ENUM(Qt::Key_Down) },
- { kHelpCharCode, QT_MAC_MAP_ENUM(Qt::Key_Help) },
- { kDeleteCharCode, QT_MAC_MAP_ENUM(Qt::Key_Delete) },
-//ascii maps, for debug
- { ':', QT_MAC_MAP_ENUM(Qt::Key_Colon) },
- { ';', QT_MAC_MAP_ENUM(Qt::Key_Semicolon) },
- { '<', QT_MAC_MAP_ENUM(Qt::Key_Less) },
- { '=', QT_MAC_MAP_ENUM(Qt::Key_Equal) },
- { '>', QT_MAC_MAP_ENUM(Qt::Key_Greater) },
- { '?', QT_MAC_MAP_ENUM(Qt::Key_Question) },
- { '@', QT_MAC_MAP_ENUM(Qt::Key_At) },
- { ' ', QT_MAC_MAP_ENUM(Qt::Key_Space) },
- { '!', QT_MAC_MAP_ENUM(Qt::Key_Exclam) },
- { '"', QT_MAC_MAP_ENUM(Qt::Key_QuoteDbl) },
- { '#', QT_MAC_MAP_ENUM(Qt::Key_NumberSign) },
- { '$', QT_MAC_MAP_ENUM(Qt::Key_Dollar) },
- { '%', QT_MAC_MAP_ENUM(Qt::Key_Percent) },
- { '&', QT_MAC_MAP_ENUM(Qt::Key_Ampersand) },
- { '\'', QT_MAC_MAP_ENUM(Qt::Key_Apostrophe) },
- { '(', QT_MAC_MAP_ENUM(Qt::Key_ParenLeft) },
- { ')', QT_MAC_MAP_ENUM(Qt::Key_ParenRight) },
- { '*', QT_MAC_MAP_ENUM(Qt::Key_Asterisk) },
- { '+', QT_MAC_MAP_ENUM(Qt::Key_Plus) },
- { ',', QT_MAC_MAP_ENUM(Qt::Key_Comma) },
- { '-', QT_MAC_MAP_ENUM(Qt::Key_Minus) },
- { '.', QT_MAC_MAP_ENUM(Qt::Key_Period) },
- { '/', QT_MAC_MAP_ENUM(Qt::Key_Slash) },
- { '[', QT_MAC_MAP_ENUM(Qt::Key_BracketLeft) },
- { ']', QT_MAC_MAP_ENUM(Qt::Key_BracketRight) },
- { '\\', QT_MAC_MAP_ENUM(Qt::Key_Backslash) },
- { '_', QT_MAC_MAP_ENUM(Qt::Key_Underscore) },
- { '`', QT_MAC_MAP_ENUM(Qt::Key_QuoteLeft) },
- { '{', QT_MAC_MAP_ENUM(Qt::Key_BraceLeft) },
- { '}', QT_MAC_MAP_ENUM(Qt::Key_BraceRight) },
- { '|', QT_MAC_MAP_ENUM(Qt::Key_Bar) },
- { '~', QT_MAC_MAP_ENUM(Qt::Key_AsciiTilde) },
- { '^', QT_MAC_MAP_ENUM(Qt::Key_AsciiCircum) },
- { 0, QT_MAC_MAP_ENUM(0) }
-};
-
-static qt_mac_enum_mapper qt_mac_keyvkey_symbols[] = { //real scan codes
- { kVK_F1, QT_MAC_MAP_ENUM(Qt::Key_F1) },
- { kVK_F2, QT_MAC_MAP_ENUM(Qt::Key_F2) },
- { kVK_F3, QT_MAC_MAP_ENUM(Qt::Key_F3) },
- { kVK_F4, QT_MAC_MAP_ENUM(Qt::Key_F4) },
- { kVK_F5, QT_MAC_MAP_ENUM(Qt::Key_F5) },
- { kVK_F6, QT_MAC_MAP_ENUM(Qt::Key_F6) },
- { kVK_F7, QT_MAC_MAP_ENUM(Qt::Key_F7) },
- { kVK_F8, QT_MAC_MAP_ENUM(Qt::Key_F8) },
- { kVK_F9, QT_MAC_MAP_ENUM(Qt::Key_F9) },
- { kVK_F10, QT_MAC_MAP_ENUM(Qt::Key_F10) },
- { kVK_F11, QT_MAC_MAP_ENUM(Qt::Key_F11) },
- { kVK_F12, QT_MAC_MAP_ENUM(Qt::Key_F12) },
- { kVK_F13, QT_MAC_MAP_ENUM(Qt::Key_F13) },
- { kVK_F14, QT_MAC_MAP_ENUM(Qt::Key_F14) },
- { kVK_F15, QT_MAC_MAP_ENUM(Qt::Key_F15) },
- { kVK_F16, QT_MAC_MAP_ENUM(Qt::Key_F16) },
- { kVK_Return, QT_MAC_MAP_ENUM(Qt::Key_Return) },
- { kVK_Tab, QT_MAC_MAP_ENUM(Qt::Key_Tab) },
- { kVK_Escape, QT_MAC_MAP_ENUM(Qt::Key_Escape) },
- { kVK_Help, QT_MAC_MAP_ENUM(Qt::Key_Help) },
- { kVK_UpArrow, QT_MAC_MAP_ENUM(Qt::Key_Up) },
- { kVK_DownArrow, QT_MAC_MAP_ENUM(Qt::Key_Down) },
- { kVK_LeftArrow, QT_MAC_MAP_ENUM(Qt::Key_Left) },
- { kVK_RightArrow, QT_MAC_MAP_ENUM(Qt::Key_Right) },
- { kVK_PageUp, QT_MAC_MAP_ENUM(Qt::Key_PageUp) },
- { kVK_PageDown, QT_MAC_MAP_ENUM(Qt::Key_PageDown) },
- { 0, QT_MAC_MAP_ENUM(0) }
-};
-
-static qt_mac_enum_mapper qt_mac_private_unicode[] = {
- { 0xF700, QT_MAC_MAP_ENUM(Qt::Key_Up) }, //NSUpArrowFunctionKey
- { 0xF701, QT_MAC_MAP_ENUM(Qt::Key_Down) }, //NSDownArrowFunctionKey
- { 0xF702, QT_MAC_MAP_ENUM(Qt::Key_Left) }, //NSLeftArrowFunctionKey
- { 0xF703, QT_MAC_MAP_ENUM(Qt::Key_Right) }, //NSRightArrowFunctionKey
- { 0xF727, QT_MAC_MAP_ENUM(Qt::Key_Insert) }, //NSInsertFunctionKey
- { 0xF728, QT_MAC_MAP_ENUM(Qt::Key_Delete) }, //NSDeleteFunctionKey
- { 0xF729, QT_MAC_MAP_ENUM(Qt::Key_Home) }, //NSHomeFunctionKey
- { 0xF72B, QT_MAC_MAP_ENUM(Qt::Key_End) }, //NSEndFunctionKey
- { 0xF72C, QT_MAC_MAP_ENUM(Qt::Key_PageUp) }, //NSPageUpFunctionKey
- { 0xF72D, QT_MAC_MAP_ENUM(Qt::Key_PageDown) }, //NSPageDownFunctionKey
- { 0xF72E, QT_MAC_MAP_ENUM(Qt::Key_Print) }, //NSPrintScreenFunctionKey
- { 0xF72F, QT_MAC_MAP_ENUM(Qt::Key_ScrollLock) }, //NSScrollLockFunctionKey
- { 0xF730, QT_MAC_MAP_ENUM(Qt::Key_Pause) }, //NSPauseFunctionKey
- { 0xF731, QT_MAC_MAP_ENUM(Qt::Key_SysReq) }, //NSSysReqFunctionKey
- { 0xF735, QT_MAC_MAP_ENUM(Qt::Key_Menu) }, //NSMenuFunctionKey
- { 0xF738, QT_MAC_MAP_ENUM(Qt::Key_Printer) }, //NSPrintFunctionKey
- { 0xF73A, QT_MAC_MAP_ENUM(Qt::Key_Clear) }, //NSClearDisplayFunctionKey
- { 0xF73D, QT_MAC_MAP_ENUM(Qt::Key_Insert) }, //NSInsertCharFunctionKey
- { 0xF73E, QT_MAC_MAP_ENUM(Qt::Key_Delete) }, //NSDeleteCharFunctionKey
- { 0xF741, QT_MAC_MAP_ENUM(Qt::Key_Select) }, //NSSelectFunctionKey
- { 0xF742, QT_MAC_MAP_ENUM(Qt::Key_Execute) }, //NSExecuteFunctionKey
- { 0xF743, QT_MAC_MAP_ENUM(Qt::Key_Undo) }, //NSUndoFunctionKey
- { 0xF744, QT_MAC_MAP_ENUM(Qt::Key_Redo) }, //NSRedoFunctionKey
- { 0xF745, QT_MAC_MAP_ENUM(Qt::Key_Find) }, //NSFindFunctionKey
- { 0xF746, QT_MAC_MAP_ENUM(Qt::Key_Help) }, //NSHelpFunctionKey
- { 0xF747, QT_MAC_MAP_ENUM(Qt::Key_Mode_switch) }, //NSModeSwitchFunctionKey
- { 0, QT_MAC_MAP_ENUM(0) }
-};
-
-static int qt_mac_get_key(int modif, const QChar &key, int virtualKey)
-{
-#ifdef DEBUG_KEY_BINDINGS
- qDebug("**Mapping key: %d (0x%04x) - %d (0x%04x)", key.unicode(), key.unicode(), virtualKey, virtualKey);
-#endif
-
- if (key == kClearCharCode && virtualKey == 0x47)
- return Qt::Key_Clear;
-
- if (key.isDigit()) {
-#ifdef DEBUG_KEY_BINDINGS
- qDebug("%d: got key: %d", __LINE__, key.digitValue());
-#endif
- return key.digitValue() + Qt::Key_0;
- }
-
- if (key.isLetter()) {
-#ifdef DEBUG_KEY_BINDINGS
- qDebug("%d: got key: %d", __LINE__, (key.toUpper().unicode() - 'A'));
-#endif
- return (key.toUpper().unicode() - 'A') + Qt::Key_A;
- }
- if (key.isSymbol()) {
-#ifdef DEBUG_KEY_BINDINGS
- qDebug("%d: got key: %d", __LINE__, (key.unicode()));
-#endif
- return key.unicode();
- }
-
- for (int i = 0; qt_mac_keyboard_symbols[i].qt_code; i++) {
- if (qt_mac_keyboard_symbols[i].mac_code == key) {
- /* To work like Qt for X11 we issue Backtab when Shift + Tab are pressed */
- if (qt_mac_keyboard_symbols[i].qt_code == Qt::Key_Tab && (modif & Qt::ShiftModifier)) {
-#ifdef DEBUG_KEY_BINDINGS
- qDebug("%d: got key: Qt::Key_Backtab", __LINE__);
-#endif
- return Qt::Key_Backtab;
- }
-
-#ifdef DEBUG_KEY_BINDINGS
- qDebug("%d: got key: %s", __LINE__, qt_mac_keyboard_symbols[i].desc);
-#endif
- return qt_mac_keyboard_symbols[i].qt_code;
- }
- }
-
- //last ditch try to match the scan code
- for (int i = 0; qt_mac_keyvkey_symbols[i].qt_code; i++) {
- if (qt_mac_keyvkey_symbols[i].mac_code == virtualKey) {
-#ifdef DEBUG_KEY_BINDINGS
- qDebug("%d: got key: %s", __LINE__, qt_mac_keyvkey_symbols[i].desc);
-#endif
- return qt_mac_keyvkey_symbols[i].qt_code;
- }
- }
-
- // check if they belong to key codes in private unicode range
- if (key >= 0xf700 && key <= 0xf747) {
- if (key >= 0xf704 && key <= 0xf726) {
- return Qt::Key_F1 + (key.unicode() - 0xf704) ;
- }
- for (int i = 0; qt_mac_private_unicode[i].qt_code; i++) {
- if (qt_mac_private_unicode[i].mac_code == key) {
- return qt_mac_private_unicode[i].qt_code;
- }
- }
-
- }
-
- //oh well
-#ifdef DEBUG_KEY_BINDINGS
- qDebug("Unknown case.. %s:%d %d[%d] %d", __FILE__, __LINE__, key.unicode(), key.toLatin1(), virtualKey);
-#endif
- return Qt::Key_unknown;
-}
-
-QCocoaKeyMapper::QCocoaKeyMapper()
-{
- memset(keyLayout, 0, sizeof(keyLayout));
-}
-
-QCocoaKeyMapper::~QCocoaKeyMapper()
-{
- deleteLayouts();
-}
-
-Qt::KeyboardModifiers QCocoaKeyMapper::queryKeyboardModifiers()
-{
- return qt_mac_get_modifiers(GetCurrentKeyModifiers());
-}
-
-bool QCocoaKeyMapper::updateKeyboard()
-{
- const UCKeyboardLayout *uchrData = nullptr;
- QCFType<TISInputSourceRef> source = TISCopyInputMethodKeyboardLayoutOverride();
- if (!source)
- source = TISCopyCurrentKeyboardInputSource();
- if (keyboard_mode != NullMode && source == currentInputSource) {
- return false;
- }
- Q_ASSERT(source);
- CFDataRef data = static_cast<CFDataRef>(TISGetInputSourceProperty(source,
- kTISPropertyUnicodeKeyLayoutData));
- uchrData = data ? reinterpret_cast<const UCKeyboardLayout *>(CFDataGetBytePtr(data)) : nullptr;
-
- keyboard_kind = LMGetKbdType();
- if (uchrData) {
- keyboard_layout_format = uchrData;
- keyboard_mode = UnicodeMode;
- } else {
- keyboard_layout_format = nullptr;
- keyboard_mode = NullMode;
- }
- currentInputSource = source;
- keyboard_dead = 0;
-
- const auto newMode = keyboard_mode;
- deleteLayouts();
- keyboard_mode = newMode;
-
- return true;
-}
-
-void QCocoaKeyMapper::deleteLayouts()
-{
- keyboard_mode = NullMode;
- for (int i = 0; i < 255; ++i) {
- if (keyLayout[i]) {
- delete keyLayout[i];
- keyLayout[i] = nullptr;
- }
- }
-}
-
-void QCocoaKeyMapper::clearMappings()
-{
- deleteLayouts();
- updateKeyboard();
-}
-
-void QCocoaKeyMapper::updateKeyMap(unsigned short macVirtualKey, QChar unicodeKey)
-{
- updateKeyboard();
-
- if (keyLayout[macVirtualKey])
- return;
-
- UniCharCount buffer_size = 10;
- UniChar buffer[buffer_size];
- keyLayout[macVirtualKey] = new KeyboardLayoutItem;
- for (int i = 0; i < 16; ++i) {
- UniCharCount out_buffer_size = 0;
- keyLayout[macVirtualKey]->qtKey[i] = 0;
-
- const UInt32 keyModifier = ((qt_mac_get_mac_modifiers(ModsTbl[i]) >> 8) & 0xFF);
- OSStatus err = UCKeyTranslate(keyboard_layout_format, macVirtualKey, kUCKeyActionDown, keyModifier,
- keyboard_kind, 0, &keyboard_dead, buffer_size, &out_buffer_size, buffer);
- if (err == noErr && out_buffer_size) {
- const QChar unicode(buffer[0]);
- int qtkey = qt_mac_get_key(keyModifier, unicode, macVirtualKey);
- if (qtkey == Qt::Key_unknown)
- qtkey = unicode.unicode();
- keyLayout[macVirtualKey]->qtKey[i] = qtkey;
- } else {
- int qtkey = qt_mac_get_key(keyModifier, unicodeKey, macVirtualKey);
- if (qtkey == Qt::Key_unknown)
- qtkey = unicodeKey.unicode();
- keyLayout[macVirtualKey]->qtKey[i] = qtkey;
- }
- }
-#ifdef DEBUG_KEY_MAPS
- qDebug("updateKeyMap for virtual key = 0x%02x!", (uint)macVirtualKey);
- for (int i = 0; i < 16; ++i) {
- qDebug(" [%d] (%d,0x%02x,'%c')", i,
- keyLayout[macVirtualKey]->qtKey[i],
- keyLayout[macVirtualKey]->qtKey[i],
- keyLayout[macVirtualKey]->qtKey[i]);
- }
-#endif
-}
-
-QList<int> QCocoaKeyMapper::possibleKeys(const QKeyEvent *event) const
-{
- QList<int> ret;
- const_cast<QCocoaKeyMapper *>(this)->updateKeyMap(event->nativeVirtualKey(), QChar(event->key()));
-
- KeyboardLayoutItem *kbItem = keyLayout[event->nativeVirtualKey()];
-
- if (!kbItem) // Key is not in any keyboard layout (e.g. eisu-key on Japanese keyboard)
- return ret;
-
- int baseKey = kbItem->qtKey[0];
- Qt::KeyboardModifiers keyMods = event->modifiers();
-
- ret << int(baseKey + keyMods); // The base key is _always_ valid, of course
-
- for (int i = 1; i < 8; ++i) {
- Qt::KeyboardModifiers neededMods = ModsTbl[i];
- int key = kbItem->qtKey[i];
- if (key && key != baseKey && ((keyMods & neededMods) == neededMods)) {
- ret << int(key + (keyMods & ~neededMods));
- }
- }
- return ret;
-}
-
-QT_END_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/qcocoamenu.h b/src/plugins/platforms/cocoa/qcocoamenu.h
index 1dccf0621c..f53f1c3e74 100644
--- a/src/plugins/platforms/cocoa/qcocoamenu.h
+++ b/src/plugins/platforms/cocoa/qcocoamenu.h
@@ -1,48 +1,14 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Copyright (C) 2012 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author James Turner <james.turner@kdab.com>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// Copyright (C) 2012 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author James Turner <james.turner@kdab.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QCOCOAMENU_H
#define QCOCOAMENU_H
#include <QtCore/QList>
#include <qpa/qplatformmenu.h>
+#include <qpa/qplatformmenu_p.h>
+
#include "qcocoamenuitem.h"
#include "qcocoansmenu.h"
@@ -51,6 +17,7 @@ QT_BEGIN_NAMESPACE
class QCocoaMenuBar;
class QCocoaMenu : public QPlatformMenu, public QCocoaMenuObject
+ , public QNativeInterface::Private::QCocoaMenu
{
public:
QCocoaMenu();
@@ -69,13 +36,14 @@ public:
void propagateEnabledState(bool enabled);
- void setIcon(const QIcon &icon) override { Q_UNUSED(icon) }
+ void setIcon(const QIcon &) override {}
void setText(const QString &text) override;
void setMinimumWidth(int width) override;
void setFont(const QFont &font) override;
- NSMenu *nsMenu() const;
+ NSMenu *nsMenu() const override;
+ void setAsDockMenu() const override;
inline bool isVisible() const { return m_visible; }
diff --git a/src/plugins/platforms/cocoa/qcocoamenu.mm b/src/plugins/platforms/cocoa/qcocoamenu.mm
index 90d5180fed..7a6999c2cc 100644
--- a/src/plugins/platforms/cocoa/qcocoamenu.mm
+++ b/src/plugins/platforms/cocoa/qcocoamenu.mm
@@ -1,42 +1,8 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Copyright (C) 2012 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author James Turner <james.turner@kdab.com>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// Copyright (C) 2012 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author James Turner <james.turner@kdab.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <AppKit/AppKit.h>
#include "qcocoamenu.h"
#include "qcocoansmenu.h"
@@ -50,6 +16,10 @@
#include "qcocoamenubar.h"
#include "qcocoawindow.h"
#include "qcocoascreen.h"
+#include "qcocoaapplicationdelegate.h"
+
+#include <QtCore/private/qcore_mac_p.h>
+#include <QtCore/qpointer.h>
QT_BEGIN_NAMESPACE
@@ -68,11 +38,13 @@ QCocoaMenu::QCocoaMenu() :
QCocoaMenu::~QCocoaMenu()
{
- for (auto *item : qAsConst(m_menuItems)) {
+ for (auto *item : std::as_const(m_menuItems)) {
if (item->menuParent() == this)
item->setMenuParent(nullptr);
}
+ if (isOpen())
+ dismiss();
[m_nativeMenu release];
}
@@ -90,8 +62,8 @@ void QCocoaMenu::setMinimumWidth(int width)
void QCocoaMenu::setFont(const QFont &font)
{
- if (font.resolve()) {
- NSFont *customMenuFont = [NSFont fontWithName:font.family().toNSString()
+ if (font.resolveMask()) {
+ NSFont *customMenuFont = [NSFont fontWithName:font.families().constFirst().toNSString()
size:font.pointSize()];
m_nativeMenu.font = customMenuFont;
}
@@ -102,6 +74,12 @@ NSMenu *QCocoaMenu::nsMenu() const
return static_cast<NSMenu *>(m_nativeMenu);
}
+void QCocoaMenu::setAsDockMenu() const
+{
+ QMacAutoReleasePool pool;
+ QCocoaApplicationDelegate.sharedDelegate.dockMenu = m_nativeMenu;
+}
+
void QCocoaMenu::insertMenuItem(QPlatformMenuItem *menuItem, QPlatformMenuItem *before)
{
QMacAutoReleasePool pool;
@@ -113,7 +91,7 @@ void QCocoaMenu::insertMenuItem(QPlatformMenuItem *menuItem, QPlatformMenuItem *
int index = m_menuItems.indexOf(beforeItem);
// if a before item is supplied, it should be in the menu
if (index < 0) {
- qWarning("Before menu item not found");
+ qCWarning(lcQpaMenus) << beforeItem << "not in" << m_menuItems;
return;
}
m_menuItems.insert(index, cocoaItem);
@@ -151,13 +129,13 @@ void QCocoaMenu::insertNative(QCocoaMenuItem *item, QCocoaMenuItem *beforeItem)
}
if (nativeItem.menu) {
- qWarning() << "Menu item" << item->text() << "already in menu" << QString::fromNSString(nativeItem.menu.title);
+ qCWarning(lcQpaMenus) << "Menu item" << item->text() << "already in menu" << QString::fromNSString(nativeItem.menu.title);
return;
}
if (beforeItem) {
if (beforeItem->isMerged()) {
- qWarning("No non-merged before menu item found");
+ qCWarning(lcQpaMenus, "No non-merged before menu item found");
return;
}
const NSInteger nativeIndex = [m_nativeMenu indexOfItem:beforeItem->nsItem()];
@@ -193,7 +171,7 @@ void QCocoaMenu::removeMenuItem(QPlatformMenuItem *menuItem)
QMacAutoReleasePool pool;
QCocoaMenuItem *cocoaItem = static_cast<QCocoaMenuItem *>(menuItem);
if (!m_menuItems.contains(cocoaItem)) {
- qWarning("Menu does not contain the item to be removed");
+ qCWarning(lcQpaMenus) << m_menuItems << "does not contain" << cocoaItem;
return;
}
@@ -206,7 +184,7 @@ void QCocoaMenu::removeMenuItem(QPlatformMenuItem *menuItem)
m_menuItems.removeOne(cocoaItem);
if (!cocoaItem->isMerged()) {
if (m_nativeMenu != cocoaItem->nsItem().menu) {
- qWarning("Item to remove does not belong to this menu");
+ qCWarning(lcQpaMenus) << cocoaItem << "does not belong to" << m_nativeMenu;
return;
}
[m_nativeMenu removeItem:cocoaItem->nsItem()];
@@ -246,7 +224,7 @@ void QCocoaMenu::syncMenuItem_helper(QPlatformMenuItem *menuItem, bool menubarUp
QMacAutoReleasePool pool;
QCocoaMenuItem *cocoaItem = static_cast<QCocoaMenuItem *>(menuItem);
if (!m_menuItems.contains(cocoaItem)) {
- qWarning("Item does not belong to this menu");
+ qCWarning(lcQpaMenus) << cocoaItem << "does not belong to" << this;
return;
}
@@ -290,33 +268,32 @@ 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 hideItem = previousIsSeparator;
if (auto *cocoaItem = qt_objc_cast<QCocoaNSMenuItem *>(item).platformMenuItem)
- cocoaItem->setVisible(!previousIsSeparator);
- item.hidden = previousIsSeparator;
+ 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)) {
+ for (auto *item : std::as_const(m_menuItems)) {
if (!item->isSeparator())
continue;
- // sync the visiblity directly
+ // sync the visibility directly
item->sync();
}
}
@@ -346,11 +323,24 @@ void QCocoaMenu::showPopup(const QWindow *parentWindow, const QRect &targetRect,
{
QMacAutoReleasePool pool;
+ QPointer<QCocoaMenu> guard = this;
+
QPoint pos = QPoint(targetRect.left(), targetRect.top() + targetRect.height());
QCocoaWindow *cocoaWindow = parentWindow ? static_cast<QCocoaWindow *>(parentWindow->handle()) : nullptr;
NSView *view = cocoaWindow ? cocoaWindow->view() : nil;
NSMenuItem *nsItem = item ? ((QCocoaMenuItem *)item)->nsItem() : nil;
+ // store the window that this popup belongs to so that we can evaluate whether we are modally blocked
+ bool resetMenuParent = false;
+ if (!menuParent()) {
+ setMenuParent(cocoaWindow);
+ resetMenuParent = true;
+ }
+ auto menuParentGuard = qScopeGuard([&]{
+ if (resetMenuParent)
+ setMenuParent(nullptr);
+ });
+
QScreen *screen = nullptr;
if (parentWindow)
screen = parentWindow->screen();
@@ -377,7 +367,7 @@ void QCocoaMenu::showPopup(const QWindow *parentWindow, const QRect &targetRect,
QCocoaScreen *cocoaScreen = static_cast<QCocoaScreen *>(screen->handle());
int availableHeight = cocoaScreen->availableGeometry().height();
- const QPoint &globalPos = cocoaWindow->mapToGlobal(pos);
+ const QPoint globalPos = cocoaWindow ? cocoaWindow->mapToGlobal(pos) : pos;
int menuHeight = m_nativeMenu.size.height;
if (globalPos.y() + menuHeight > availableHeight) {
// Maybe we need to fix the vertical popup position but we don't know the
@@ -419,9 +409,14 @@ void QCocoaMenu::showPopup(const QWindow *parentWindow, const QRect &targetRect,
}
}
+ if (!guard) {
+ menuParentGuard.dismiss();
+ return;
+ }
+
// The calls above block, and also swallow any mouse release event,
// so we need to clear any mouse button that triggered the menu popup.
- if (!cocoaWindow->isForeignWindow())
+ if (cocoaWindow && !cocoaWindow->isForeignWindow())
[qnsview_cast(view) resetMouseButtons];
}
@@ -440,7 +435,7 @@ QPlatformMenuItem *QCocoaMenu::menuItemAt(int position) const
QPlatformMenuItem *QCocoaMenu::menuItemForTag(quintptr tag) const
{
- for (auto *item : qAsConst(m_menuItems)) {
+ for (auto *item : std::as_const(m_menuItems)) {
if (item->tag() == tag)
return item;
}
@@ -456,7 +451,7 @@ QList<QCocoaMenuItem *> QCocoaMenu::items() const
QList<QCocoaMenuItem *> QCocoaMenu::merged() const
{
QList<QCocoaMenuItem *> result;
- for (auto *item : qAsConst(m_menuItems)) {
+ for (auto *item : std::as_const(m_menuItems)) {
if (item->menu()) { // recurse into submenus
result.append(item->menu()->merged());
continue;
@@ -477,7 +472,7 @@ void QCocoaMenu::propagateEnabledState(bool enabled)
if (!m_enabled && enabled) // Some ancestor was enabled, but this menu is not
return;
- for (auto *item : qAsConst(m_menuItems)) {
+ for (auto *item : std::as_const(m_menuItems)) {
if (QCocoaMenu *menu = item->menu())
menu->propagateEnabledState(enabled);
else
@@ -498,6 +493,10 @@ void QCocoaMenu::setAttachedItem(NSMenuItem *item)
if (m_attachedItem)
m_attachedItem.submenu = m_nativeMenu;
+ // NSMenuItems with a submenu and submenuAction: as the item's action
+ // will not take part in NSMenuValidation, so explicitly enable/disable
+ // the item here. See also QCocoaMenuItem::resolveTargetAction()
+ m_attachedItem.enabled = m_attachedItem.hasSubmenu;
}
NSMenuItem *QCocoaMenu::attachedItem() const
diff --git a/src/plugins/platforms/cocoa/qcocoamenubar.h b/src/plugins/platforms/cocoa/qcocoamenubar.h
index 50b6e69720..785de9c0f6 100644
--- a/src/plugins/platforms/cocoa/qcocoamenubar.h
+++ b/src/plugins/platforms/cocoa/qcocoamenubar.h
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Copyright (C) 2012 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author James Turner <james.turner@kdab.com>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the plugins module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and 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$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// Copyright (C) 2012 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author James Turner <james.turner@kdab.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QCOCOAMENUBAR_H
#define QCOCOAMENUBAR_H
@@ -45,11 +9,14 @@
#include <qpa/qplatformmenu.h>
#include "qcocoamenu.h"
+#include <QtCore/qpointer.h>
+
QT_BEGIN_NAMESPACE
class QCocoaWindow;
class QCocoaMenuBar : public QPlatformMenuBar
+ , public QNativeInterface::Private::QCocoaMenuBar
{
Q_OBJECT
public:
@@ -63,10 +30,10 @@ public:
QWindow *parentWindow() const override;
QPlatformMenu *menuForTag(quintptr tag) const override;
- inline NSMenu *nsMenu() const
- { return m_nativeMenu; }
+ NSMenu *nsMenu() const override { return m_nativeMenu; }
static void updateMenuBarImmediately();
+ static void insertWindowMenu();
QList<QCocoaMenuItem*> merged() const;
NSMenuItem *itemForRole(QPlatformMenuItem::MenuRole role);
diff --git a/src/plugins/platforms/cocoa/qcocoamenubar.mm b/src/plugins/platforms/cocoa/qcocoamenubar.mm
index 363defdd28..2493d90724 100644
--- a/src/plugins/platforms/cocoa/qcocoamenubar.mm
+++ b/src/plugins/platforms/cocoa/qcocoamenubar.mm
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Copyright (C) 2012 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author James Turner <james.turner@kdab.com>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// Copyright (C) 2012 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author James Turner <james.turner@kdab.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <AppKit/AppKit.h>
@@ -45,10 +9,14 @@
#include "qcocoamenuloader.h"
#include "qcocoaapplication.h" // for custom application category
#include "qcocoaapplicationdelegate.h"
+#include "qcocoahelpers.h"
#include <QtGui/QGuiApplication>
#include <QtCore/QDebug>
+#include <QtCore/private/qcore_mac_p.h>
+#include <QtGui/private/qguiapplication_p.h>
+
QT_BEGIN_NAMESPACE
static QList<QCocoaMenuBar*> static_menubars;
@@ -57,18 +25,19 @@ QCocoaMenuBar::QCocoaMenuBar()
{
static_menubars.append(this);
+ // clicks into the menu bar should close all popup windows
+ static QMacNotificationObserver menuBarClickObserver(nil, NSMenuDidBeginTrackingNotification, ^{
+ QGuiApplicationPrivate::instance()->closeAllPopups();
+ });
+
m_nativeMenu = [[NSMenu alloc] init];
-#ifdef QT_COCOA_ENABLE_MENU_DEBUG
- qDebug() << "Construct QCocoaMenuBar" << this << m_nativeMenu;
-#endif
+ qCDebug(lcQpaMenus) << "Constructed" << this << "with" << m_nativeMenu;
}
QCocoaMenuBar::~QCocoaMenuBar()
{
-#ifdef QT_COCOA_ENABLE_MENU_DEBUG
- qDebug() << "~QCocoaMenuBar" << this;
-#endif
- for (auto menu : qAsConst(m_menus)) {
+ qCDebug(lcQpaMenus) << "Destructing" << this << "with" << m_nativeMenu;
+ for (auto menu : std::as_const(m_menus)) {
if (!menu)
continue;
NSMenuItem *item = nativeItemForMenu(menu);
@@ -121,17 +90,16 @@ void QCocoaMenuBar::insertMenu(QPlatformMenu *platformMenu, QPlatformMenu *befor
{
QCocoaMenu *menu = static_cast<QCocoaMenu *>(platformMenu);
QCocoaMenu *beforeMenu = static_cast<QCocoaMenu *>(before);
-#ifdef QT_COCOA_ENABLE_MENU_DEBUG
- qDebug() << "QCocoaMenuBar" << this << "insertMenu" << menu << "before" << before;
-#endif
+
+ qCDebug(lcQpaMenus) << "Inserting" << menu << "before" << before << "into" << this;
if (m_menus.contains(QPointer<QCocoaMenu>(menu))) {
- qWarning("This menu already belongs to the menubar, remove it first");
+ qCWarning(lcQpaMenus, "This menu already belongs to the menubar, remove it first");
return;
}
if (beforeMenu && !m_menus.contains(QPointer<QCocoaMenu>(beforeMenu))) {
- qWarning("The before menu does not belong to the menubar");
+ qCWarning(lcQpaMenus, "The before menu does not belong to the menubar");
return;
}
@@ -165,7 +133,7 @@ void QCocoaMenuBar::removeMenu(QPlatformMenu *platformMenu)
{
QCocoaMenu *menu = static_cast<QCocoaMenu *>(platformMenu);
if (!m_menus.contains(menu)) {
- qWarning("Trying to remove a menu that does not belong to the menubar");
+ qCWarning(lcQpaMenus) << "Trying to remove" << menu << "that does not belong to" << this;
return;
}
@@ -191,12 +159,12 @@ void QCocoaMenuBar::syncMenu_helper(QPlatformMenu *menu, bool menubarUpdate)
QMacAutoReleasePool pool;
QCocoaMenu *cocoaMenu = static_cast<QCocoaMenu *>(menu);
- Q_FOREACH (QCocoaMenuItem *item, cocoaMenu->items())
+ for (QCocoaMenuItem *item : cocoaMenu->items())
cocoaMenu->syncMenuItem_helper(item, menubarUpdate);
BOOL shouldHide = YES;
if (cocoaMenu->isVisible()) {
- // If the NSMenu has no visble items, or only separators, we should hide it
+ // If the NSMenu has no visible items, or only separators, we should hide it
// on the menubar. This can happen after syncing the menu items since they
// can be moved to other menus.
for (NSMenuItem *item in cocoaMenu->nsMenu().itemArray)
@@ -206,10 +174,44 @@ void QCocoaMenuBar::syncMenu_helper(QPlatformMenu *menu, bool menubarUpdate)
}
}
- if (NSMenuItem *attachedItem = cocoaMenu->attachedItem()) {
- // Non-nil attached item means the item's submenu is set
- attachedItem.title = cocoaMenu->nsMenu().title;
- attachedItem.hidden = shouldHide;
+ if (NSMenuItem *menuItem = cocoaMenu->attachedItem()) {
+ // Non-nil menu item means the item's sub menu is set
+
+ NSString *menuTitle = cocoaMenu->nsMenu().title;
+
+ // The NSMenu's title is what's visible to the user, and AppKit uses this
+ // for some of its heuristics of when to add special items to the menus,
+ // such as 'Enter Full Screen' in the View menu, the search bare in the
+ // Help menu, and the "Send App feedback to Apple" in the Help menu.
+ // This relies on the title matching AppKit's localized value from the
+ // MenuCommands table, which in turn depends on the preferredLocalizations
+ // of the AppKit bundle. We don't do any automatic translation of menu
+ // titles visible to the user, so this relies on the application developer
+ // having chosen translated titles that match AppKit's, and that the Qt
+ // preferred UI languages match AppKit's preferredLocalizations.
+
+ // In the case of the Edit menu, AppKit uses the NSMenuItem's title
+ // for its heuristics of when to add the dictation and emoji entries,
+ // and this title is not visible to the user. But like above, the
+ // heuristics are based on the localized title of the menu, so we need
+ // to ensure the title matches AppKit's localization.
+
+ // Unfortunately, the title we have at this point may have gone through
+ // Qt's i18n machinery already, via e.g. tr("Edit") in the application,
+ // in which case we don't know the context of the translation, and can't
+ // do a reverse lookup to go back to the untranslated title to pass to
+ // AppKit. As a workaround we translate the title via a our context,
+ // and document that the user needs to ensure their application matches
+ // this translation.
+ if ([menuTitle isEqual:@"Edit"] || [menuTitle isEqual:tr("Edit").toNSString()]) {
+ menuItem.title = qt_mac_AppKitString(@"InputManager", @"Edit");
+ } else {
+ // The Edit menu is the only case we know of so far, but to be on
+ // the safe side we always sync the menu title.
+ menuItem.title = menuTitle;
+ }
+
+ menuItem.hidden = shouldHide;
}
}
@@ -223,9 +225,7 @@ NSMenuItem *QCocoaMenuBar::nativeItemForMenu(QCocoaMenu *menu) const
void QCocoaMenuBar::handleReparent(QWindow *newParentWindow)
{
-#ifdef QT_COCOA_ENABLE_MENU_DEBUG
- qDebug() << "QCocoaMenuBar" << this << "handleReparent" << newParentWindow;
-#endif
+ qCDebug(lcQpaMenus) << "Reparenting" << this << "to" << newParentWindow;
if (!m_window.isNull())
m_window->setMenubar(nullptr);
@@ -257,7 +257,7 @@ QCocoaWindow *QCocoaMenuBar::findWindowForMenubar()
QCocoaMenuBar *QCocoaMenuBar::findGlobalMenubar()
{
- for (auto *menubar : qAsConst(static_menubars)) {
+ for (auto *menubar : std::as_const(static_menubars)) {
if (menubar->m_window.isNull())
return menubar;
}
@@ -293,12 +293,11 @@ void QCocoaMenuBar::updateMenuBarImmediately()
if (!mb)
return;
-#ifdef QT_COCOA_ENABLE_MENU_DEBUG
- qDebug() << "QCocoaMenuBar" << "updateMenuBarImmediately" << cw;
-#endif
+ qCDebug(lcQpaMenus) << "Updating" << mb << "immediately for" << cw;
+
bool disableForModal = mb->shouldDisable(cw);
- for (auto menu : qAsConst(mb->m_menus)) {
+ for (auto menu : std::as_const(mb->m_menus)) {
if (!menu)
continue;
NSMenuItem *item = mb->nativeItemForMenu(menu);
@@ -327,15 +326,74 @@ void QCocoaMenuBar::updateMenuBarImmediately()
}
[mergedItems release];
- [NSApp setMainMenu:mb->nsMenu()];
+
+ NSMenu *newMainMenu = mb->nsMenu();
+ if (NSApp.mainMenu == newMainMenu) {
+ // NSApplication triggers _customizeMainMenu when the menu
+ // changes, which takes care of adding text input items to
+ // the edit menu e.g., but this doesn't happen if the menu
+ // is the same. In our case we might be re-using an existing
+ // menu, but the menu might have new sub menus that need to
+ // be customized. To ensure NSApplication does the right
+ // thing we reset the main menu first.
+ qCDebug(lcQpaMenus) << "Clearing main menu temporarily";
+ NSApp.mainMenu = nil;
+ }
+ NSApp.mainMenu = newMainMenu;
+
+ insertWindowMenu();
[loader qtTranslateApplicationMenu];
}
+void QCocoaMenuBar::insertWindowMenu()
+{
+ // For such an item/menu we get for 'free' an additional feature -
+ // a list of windows the application has created in the Dock's menu.
+
+ NSApplication *app = NSApplication.sharedApplication;
+ if (app.windowsMenu)
+ return;
+
+ NSMenu *mainMenu = app.mainMenu;
+ NSMenuItem *winMenuItem = [[[NSMenuItem alloc] initWithTitle:@"QtWindowMenu"
+ action:nil keyEquivalent:@""] autorelease];
+ // We don't want to show this menu, nobody asked us to do so:
+ winMenuItem.hidden = YES;
+
+ winMenuItem.submenu = [[[NSMenu alloc] initWithTitle:@"QtWindowMenu"] autorelease];
+
+ // AppKit has a bug in [NSApplication setWindowsMenu:] where it will resolve
+ // the last item of the window menu's itemArray, but not account for the array
+ // being empty, resulting in a lookup of itemAtIndex:-1. To work around this,
+ // we insert a hidden dummy item into the menu. See FB13369198.
+ auto *dummyItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""];
+ dummyItem.hidden = YES;
+ [winMenuItem.submenu addItem:[dummyItem autorelease]];
+
+ [mainMenu insertItem:winMenuItem atIndex:mainMenu.itemArray.count];
+ app.windowsMenu = winMenuItem.submenu;
+
+ // Windows that have already been ordered in at this point have already been
+ // evaluated by AppKit via _addToWindowsMenuIfNecessary and added to the menu,
+ // but since the menu didn't exist at that point the addition was a noop.
+ // Instead of trying to duplicate the logic AppKit uses for deciding if
+ // a window should be part of the Window menu we toggle one of the settings
+ // that definitely will affect this, which results in AppKit reevaluating the
+ // situation and adding the window to the menu if necessary.
+ for (NSWindow *win in app.windows) {
+ win.excludedFromWindowsMenu = !win.excludedFromWindowsMenu;
+ win.excludedFromWindowsMenu = !win.excludedFromWindowsMenu;
+ }
+}
+
QList<QCocoaMenuItem*> QCocoaMenuBar::merged() const
{
QList<QCocoaMenuItem*> r;
- for (auto menu : qAsConst(m_menus))
+ for (auto menu : std::as_const(m_menus)) {
+ if (!menu)
+ continue;
r.append(menu->merged());
+ }
return r;
}
@@ -354,10 +412,10 @@ bool QCocoaMenuBar::shouldDisable(QCocoaWindow *active) const
// When there is an application modal window on screen, the entries of
// the menubar should be disabled. The exception in Qt is that if the
// modal window is the only window on screen, then we enable the menu bar.
- for (auto *window : qAsConst(topWindows)) {
+ for (auto *window : std::as_const(topWindows)) {
if (window->isVisible() && window->modality() == Qt::ApplicationModal) {
// check for other visible windows
- for (auto *other : qAsConst(topWindows)) {
+ for (auto *other : std::as_const(topWindows)) {
if ((window != other) && (other->isVisible())) {
// INVARIANT: we found another visible window
// on screen other than our modalWidget. We therefore
@@ -378,8 +436,8 @@ bool QCocoaMenuBar::shouldDisable(QCocoaWindow *active) const
QPlatformMenu *QCocoaMenuBar::menuForTag(quintptr tag) const
{
- for (auto menu : qAsConst(m_menus))
- if (menu->tag() == tag)
+ for (auto menu : std::as_const(m_menus))
+ if (menu && menu->tag() == tag)
return menu;
return nullptr;
@@ -387,10 +445,13 @@ QPlatformMenu *QCocoaMenuBar::menuForTag(quintptr tag) const
NSMenuItem *QCocoaMenuBar::itemForRole(QPlatformMenuItem::MenuRole role)
{
- for (auto menu : qAsConst(m_menus))
- for (auto *item : menu->items())
- if (item->effectiveRole() == role)
- return item->nsItem();
+ for (auto menu : std::as_const(m_menus)) {
+ if (menu) {
+ for (auto *item : menu->items())
+ if (item->effectiveRole() == role)
+ return item->nsItem();
+ }
+ }
return nil;
}
diff --git a/src/plugins/platforms/cocoa/qcocoamenuitem.h b/src/plugins/platforms/cocoa/qcocoamenuitem.h
index c842b08d52..f677ffb7a7 100644
--- a/src/plugins/platforms/cocoa/qcocoamenuitem.h
+++ b/src/plugins/platforms/cocoa/qcocoamenuitem.h
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Copyright (C) 2012 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author James Turner <james.turner@kdab.com>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// Copyright (C) 2012 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author James Turner <james.turner@kdab.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QCOCOAMENUITEM_H
#define QCOCOAMENUITEM_H
@@ -44,7 +8,7 @@
#include <qpa/qplatformmenu.h>
#include <QtGui/QImage>
-//#define QT_COCOA_ENABLE_MENU_DEBUG
+#include <QtCore/qpointer.h>
Q_FORWARD_DECLARE_OBJC_CLASS(NSMenuItem);
Q_FORWARD_DECLARE_OBJC_CLASS(NSMenu);
@@ -53,6 +17,18 @@ Q_FORWARD_DECLARE_OBJC_CLASS(NSView);
QT_BEGIN_NAMESPACE
+enum {
+ AboutAppMenuItem = 0,
+ PreferencesAppMenuItem,
+ ServicesAppMenuItem,
+ HideAppMenuItem,
+ HideOthersAppMenuItem,
+ ShowAllAppMenuItem,
+ QuitAppMenuItem
+};
+
+QString qt_mac_applicationmenu_string(int type);
+
class QCocoaMenu;
class QCocoaMenuObject
@@ -88,7 +64,7 @@ public:
#ifndef QT_NO_SHORTCUT
void setShortcut(const QKeySequence& shortcut) override;
#endif
- void setCheckable(bool checkable) override { Q_UNUSED(checkable) }
+ void setCheckable(bool) override {}
void setChecked(bool isChecked) override;
void setEnabled(bool isEnabled) override;
void setIconSize(int size) override;
@@ -105,6 +81,7 @@ public:
inline bool isMerged() const { return m_merged; }
inline bool isEnabled() const { return m_enabled && m_parentEnabled; }
inline bool isSeparator() const { return m_isSeparator; }
+ inline bool isVisible() const { return m_isVisible; }
QCocoaMenu *menu() const { return m_menu; }
MenuRole effectiveRole() const;
diff --git a/src/plugins/platforms/cocoa/qcocoamenuitem.mm b/src/plugins/platforms/cocoa/qcocoamenuitem.mm
index c35cf6d799..3a0f71bc50 100644
--- a/src/plugins/platforms/cocoa/qcocoamenuitem.mm
+++ b/src/plugins/platforms/cocoa/qcocoamenuitem.mm
@@ -1,42 +1,8 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Copyright (C) 2012 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author James Turner <james.turner@kdab.com>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// Copyright (C) 2012 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author James Turner <james.turner@kdab.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <AppKit/AppKit.h>
#include <qpa/qplatformtheme.h>
@@ -45,53 +11,41 @@
#include "qcocoansmenu.h"
#include "qcocoamenu.h"
#include "qcocoamenubar.h"
-#include "messages.h"
#include "qcocoahelpers.h"
-#include "qt_mac_p.h"
#include "qcocoaapplication.h" // for custom application category
#include "qcocoamenuloader.h"
#include <QtGui/private/qcoregraphics_p.h>
+#include <QtCore/qregularexpression.h>
+#include <QtCore/private/qcore_mac_p.h>
+#include <QtGui/private/qapplekeymapper_p.h>
#include <QtCore/QDebug>
-#include <QtCore/QRegExp>
QT_BEGIN_NAMESPACE
-static quint32 constructModifierMask(quint32 accel_key)
-{
- quint32 ret = 0;
- const bool dontSwap = qApp->testAttribute(Qt::AA_MacDontSwapCtrlAndMeta);
- if ((accel_key & Qt::CTRL) == Qt::CTRL)
- ret |= (dontSwap ? NSEventModifierFlagControl : NSEventModifierFlagCommand);
- if ((accel_key & Qt::META) == Qt::META)
- ret |= (dontSwap ? NSEventModifierFlagCommand : NSEventModifierFlagControl);
- if ((accel_key & Qt::ALT) == Qt::ALT)
- ret |= NSEventModifierFlagOption;
- if ((accel_key & Qt::SHIFT) == Qt::SHIFT)
- ret |= NSEventModifierFlagShift;
- return ret;
-}
+using namespace Qt::StringLiterals;
-#ifndef QT_NO_SHORTCUT
-// return an autoreleased string given a QKeySequence (currently only looks at the first one).
-NSString *keySequenceToKeyEqivalent(const QKeySequence &accel)
+static const char *application_menu_strings[] =
{
- quint32 accel_key = (accel[0] & ~(Qt::MODIFIER_MASK | Qt::UNICODE_ACCEL));
- QChar cocoa_key = qt_mac_qtKey2CocoaKey(Qt::Key(accel_key));
- if (cocoa_key.isNull())
- cocoa_key = QChar(accel_key).toLower().unicode();
- // Similar to qt_mac_removePrivateUnicode change the delete key so the symbol is correctly seen in native menubar
- if (cocoa_key.unicode() == NSDeleteFunctionKey)
- cocoa_key = NSDeleteCharacter;
- return [NSString stringWithCharacters:&cocoa_key.unicode() length:1];
-}
-
-// return the cocoa modifier mask for the QKeySequence (currently only looks at the first one).
-NSUInteger keySequenceModifierMask(const QKeySequence &accel)
+ QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU","About %1"),
+ QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU","Preferences..."),
+ QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU","Services"),
+ QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU","Hide %1"),
+ QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU","Hide Others"),
+ QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU","Show All"),
+ QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU","Quit %1")
+};
+
+QString qt_mac_applicationmenu_string(int type)
{
- return constructModifierMask(accel[0]);
+ QString menuString = QString::fromLatin1(application_menu_strings[type]);
+ const QString translated = QCoreApplication::translate("QMenuBar", application_menu_strings[type]);
+ if (translated != menuString) {
+ return translated;
+ } else {
+ return QCoreApplication::translate("MAC_APPLICATION_MENU", application_menu_strings[type]);
+ }
}
-#endif
QCocoaMenuItem::QCocoaMenuItem() :
m_native(nil),
@@ -182,7 +136,7 @@ void QCocoaMenuItem::setIsSeparator(bool isSeparator)
void QCocoaMenuItem::setFont(const QFont &font)
{
- Q_UNUSED(font)
+ Q_UNUSED(font);
}
void QCocoaMenuItem::setRole(MenuRole role)
@@ -226,6 +180,73 @@ void QCocoaMenuItem::setNativeContents(WId item)
m_itemView.needsDisplay = YES;
}
+static QPlatformMenuItem::MenuRole detectMenuRole(const QString &captionWithPossibleMnemonic)
+{
+ QString itemCaption(captionWithPossibleMnemonic);
+ itemCaption.remove(u'&');
+
+ static const std::tuple<QPlatformMenuItem::MenuRole, std::vector<std::tuple<Qt::MatchFlags, const char *>>> roleMap[] = {
+ { QPlatformMenuItem::AboutRole, {
+ { Qt::MatchStartsWith | Qt::MatchEndsWith, QT_TRANSLATE_NOOP("QCocoaMenuItem", "About") }
+ }},
+ { QPlatformMenuItem::PreferencesRole, {
+ { Qt::MatchStartsWith, QT_TRANSLATE_NOOP("QCocoaMenuItem", "Config") },
+ { Qt::MatchStartsWith, QT_TRANSLATE_NOOP("QCocoaMenuItem", "Preference") },
+ { Qt::MatchStartsWith, QT_TRANSLATE_NOOP("QCocoaMenuItem", "Options") },
+ { Qt::MatchStartsWith, QT_TRANSLATE_NOOP("QCocoaMenuItem", "Setting") },
+ { Qt::MatchStartsWith, QT_TRANSLATE_NOOP("QCocoaMenuItem", "Setup") },
+ }},
+ { QPlatformMenuItem::QuitRole, {
+ { Qt::MatchStartsWith, QT_TRANSLATE_NOOP("QCocoaMenuItem", "Quit") },
+ { Qt::MatchStartsWith, QT_TRANSLATE_NOOP("QCocoaMenuItem", "Exit") },
+ }},
+ { QPlatformMenuItem::CutRole, {
+ { Qt::MatchExactly, QT_TRANSLATE_NOOP("QCocoaMenuItem", "Cut") }
+ }},
+ { QPlatformMenuItem::CopyRole, {
+ { Qt::MatchExactly, QT_TRANSLATE_NOOP("QCocoaMenuItem", "Copy") }
+ }},
+ { QPlatformMenuItem::PasteRole, {
+ { Qt::MatchExactly, QT_TRANSLATE_NOOP("QCocoaMenuItem", "Paste") }
+ }},
+ { QPlatformMenuItem::SelectAllRole, {
+ { Qt::MatchExactly, QT_TRANSLATE_NOOP("QCocoaMenuItem", "Select All") }
+ }},
+ };
+
+ auto match = [](const QString &caption, const QString &itemCaption, Qt::MatchFlags matchFlags) {
+ if (matchFlags.testFlag(Qt::MatchExactly))
+ return !itemCaption.compare(caption, Qt::CaseInsensitive);
+ if (matchFlags.testFlag(Qt::MatchStartsWith) && itemCaption.startsWith(caption, Qt::CaseInsensitive))
+ return true;
+ if (matchFlags.testFlag(Qt::MatchEndsWith) && itemCaption.endsWith(caption, Qt::CaseInsensitive))
+ return true;
+ return false;
+ };
+
+ QPlatformMenuItem::MenuRole detectedRole = [&]{
+ for (const auto &[role, captions] : roleMap) {
+ for (const auto &[matchFlags, caption] : captions) {
+ // Check for untranslated match
+ if (match(caption, itemCaption, matchFlags))
+ return role;
+ // Then translated with the current Qt translation
+ if (match(QCoreApplication::translate("QCocoaMenuItem", caption), itemCaption, matchFlags))
+ return role;
+ }
+ }
+ return QPlatformMenuItem::NoRole;
+ }();
+
+ if (detectedRole == QPlatformMenuItem::AboutRole) {
+ static const QRegularExpression qtRegExp("qt$"_L1, QRegularExpression::CaseInsensitiveOption);
+ if (itemCaption.contains(qtRegExp))
+ detectedRole = QPlatformMenuItem::AboutQtRole;
+ }
+
+ return detectedRole;
+}
+
NSMenuItem *QCocoaMenuItem::sync()
{
if (m_isSeparator != m_native.separatorItem) {
@@ -245,8 +266,7 @@ NSMenuItem *QCocoaMenuItem::sync()
while (depth < 3 && p && !(menubar = qobject_cast<QCocoaMenuBar *>(p))) {
++depth;
QCocoaMenuObject *menuObject = dynamic_cast<QCocoaMenuObject *>(p);
- Q_ASSERT(menuObject);
- p = menuObject->menuParent();
+ p = menuObject ? menuObject->menuParent() : nullptr;
}
if (menubar && depth < 3)
@@ -325,15 +345,26 @@ NSMenuItem *QCocoaMenuItem::sync()
// Show multiple key sequences as part of the menu text.
if (accel.count() > 1)
- text += QLatin1String(" (") + accel.toString(QKeySequence::NativeText) + QLatin1String(")");
+ text += " ("_L1 + accel.toString(QKeySequence::NativeText) + ")"_L1;
#endif
m_native.title = QPlatformTheme::removeMnemonics(text).toNSString();
#ifndef QT_NO_SHORTCUT
if (accel.count() == 1) {
- m_native.keyEquivalent = keySequenceToKeyEqivalent(accel);
- m_native.keyEquivalentModifierMask = keySequenceModifierMask(accel);
+ auto key = accel[0].key();
+ auto modifiers = accel[0].keyboardModifiers();
+
+ QChar cocoaKey = QAppleKeyMapper::toCocoaKey(key);
+ if (cocoaKey.isNull())
+ cocoaKey = QChar(key).toLower().unicode();
+ // Similar to qt_mac_removePrivateUnicode change the delete key,
+ // so the symbol is correctly seen in native menu bar.
+ if (cocoaKey.unicode() == NSDeleteFunctionKey)
+ cocoaKey = QChar(NSDeleteCharacter);
+
+ m_native.keyEquivalent = QStringView(&cocoaKey, 1).toNSString();
+ m_native.keyEquivalentModifierMask = QAppleKeyMapper::toCocoaModifiers(modifiers);
} else
#endif
{
@@ -341,15 +372,9 @@ NSMenuItem *QCocoaMenuItem::sync()
m_native.keyEquivalentModifierMask = NSEventModifierFlagCommand;
}
- NSImage *img = nil;
- if (!m_icon.isNull()) {
- img = qt_mac_create_nsimage(m_icon, m_iconSize);
- img.size = CGSizeMake(m_iconSize, m_iconSize);
- }
- m_native.image = img;
- [img release];
+ m_native.image = [NSImage imageFromQIcon:m_icon withSize:m_iconSize];
- m_native.state = m_checked ? NSOnState : NSOffState;
+ m_native.state = m_checked ? NSControlStateValueOn : NSControlStateValueOff;
return m_native;
}
@@ -360,7 +385,7 @@ QString QCocoaMenuItem::mergeText()
return qt_mac_applicationmenu_string(AboutAppMenuItem).arg(qt_mac_applicationName());
} else if (m_native== [loader aboutQtMenuItem]) {
if (m_text == QString("About Qt"))
- return msgAboutQt();
+ return QCoreApplication::translate("QCocoaMenuItem", "About Qt");
else
return m_text;
} else if (m_native == [loader preferencesMenuItem]) {
@@ -391,7 +416,7 @@ QKeySequence QCocoaMenuItem::mergeAccel()
void QCocoaMenuItem::syncMerged()
{
if (!m_merged) {
- qWarning("Trying to sync a non-merged item");
+ qCWarning(lcQpaMenus) << "Trying to sync non-merged" << this;
return;
}
@@ -448,7 +473,20 @@ void QCocoaMenuItem::resolveTargetAction()
roleAction = @selector(selectAll:);
break;
default:
- roleAction = @selector(qt_itemFired:);
+ if (m_menu) {
+ // Menu items that represent sub menus should have submenuAction: as their
+ // action, so that clicking the menu item opens the sub menu without closing
+ // the entire menu hierarchy. A menu item with this action and a valid submenu
+ // will disable NSMenuValidation for the item, which is normally not an issue
+ // as NSMenuItems are enabled by default. But in our case, we haven't attached
+ // the submenu yet, which results in AppKit concluding that there's no validator
+ // for the item (the target is nil, and nothing responds to submenuAction:), and
+ // will in response disable the menu item. To work around this we explicitly
+ // enable the menu item in QCocoaMenu::setAttachedItem() once we have a submenu.
+ roleAction = @selector(submenuAction:);
+ } else {
+ roleAction = @selector(qt_itemFired:);
+ }
}
m_native.action = roleAction;
diff --git a/src/plugins/platforms/cocoa/qcocoamenuloader.h b/src/plugins/platforms/cocoa/qcocoamenuloader.h
index 5e83327854..9c2fc84239 100644
--- a/src/plugins/platforms/cocoa/qcocoamenuloader.h
+++ b/src/plugins/platforms/cocoa/qcocoamenuloader.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 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$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QCOCOAMENULOADER_P_H
#define QCOCOAMENULOADER_P_H
@@ -51,12 +15,11 @@
// We mean it.
//
-#import <AppKit/AppKit.h>
#include <QtCore/private/qcore_mac_p.h>
QT_FORWARD_DECLARE_CLASS(QCocoaMenuItem);
-@interface QT_MANGLE_NAMESPACE(QCocoaMenuLoader) : NSObject
+QT_DECLARE_NAMESPACED_OBJC_INTERFACE(QCocoaMenuLoader, NSObject
+ (instancetype)sharedMenuLoader;
- (NSMenu *)menu;
- (void)ensureAppMenuInMenu:(NSMenu *)menu;
@@ -68,8 +31,6 @@ QT_FORWARD_DECLARE_CLASS(QCocoaMenuItem);
- (NSMenuItem *)appSpecificMenuItem:(QCocoaMenuItem *)platformItem;
- (void)qtTranslateApplicationMenu;
- (NSArray<NSMenuItem *> *)mergeable;
-@end
-
-QT_NAMESPACE_ALIAS_OBJC_CLASS(QCocoaMenuLoader);
+)
#endif // QCOCOAMENULOADER_P_H
diff --git a/src/plugins/platforms/cocoa/qcocoamenuloader.mm b/src/plugins/platforms/cocoa/qcocoamenuloader.mm
index d384078e91..b5ee3479aa 100644
--- a/src/plugins/platforms/cocoa/qcocoamenuloader.mm
+++ b/src/plugins/platforms/cocoa/qcocoamenuloader.mm
@@ -1,45 +1,10 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 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$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <AppKit/AppKit.h>
#include "qcocoamenuloader.h"
-#include "messages.h"
#include "qcocoahelpers.h"
#include "qcocoansmenu.h"
#include "qcocoamenubar.h"
@@ -91,7 +56,7 @@
NSMenuItem *appItem = [[[NSMenuItem alloc] init] autorelease];
appItem.title = appName;
[theMenu addItem:appItem];
- appMenu = [[NSMenu alloc] initWithTitle:appName];
+ appMenu = [[QCocoaNSMenu alloc] initWithoutPlatformMenu:appName];
appItem.submenu = appMenu;
// About Application
@@ -221,8 +186,8 @@
if (appMenu.supermenu)
unparentAppMenu(appMenu.supermenu);
- NSMenuItem *appMenuItem = [[NSMenuItem alloc] initWithTitle:@"Apple"
- action:nil keyEquivalent:@""];
+ NSMenuItem *appMenuItem = [[[NSMenuItem alloc] initWithTitle:@"Apple"
+ action:nil keyEquivalent:@""] autorelease];
appMenuItem.submenu = appMenu;
[menu insertItem:appMenuItem atIndex:0];
}
@@ -319,12 +284,8 @@
- (BOOL)validateMenuItem:(NSMenuItem*)menuItem
{
if (menuItem.action == @selector(hideOtherApplications:)
- || menuItem.action == @selector(unhideAllApplications:))
- return [NSApp validateMenuItem:menuItem];
-
- if (menuItem.action == @selector(hide:)) {
- if (QCocoaIntegration::instance()->activePopupWindow())
- return NO;
+ || menuItem.action == @selector(unhideAllApplications:)
+ || menuItem.action == @selector(hide:)) {
return [NSApp validateMenuItem:menuItem];
}
diff --git a/src/plugins/platforms/cocoa/qcocoamessagedialog.h b/src/plugins/platforms/cocoa/qcocoamessagedialog.h
new file mode 100644
index 0000000000..b8c273469a
--- /dev/null
+++ b/src/plugins/platforms/cocoa/qcocoamessagedialog.h
@@ -0,0 +1,38 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QCOCOAMESSAGEDIALOG_H
+#define QCOCOAMESSAGEDIALOG_H
+
+#include <qpa/qplatformdialoghelper.h>
+
+Q_FORWARD_DECLARE_OBJC_CLASS(NSAlert);
+typedef long NSInteger;
+typedef NSInteger NSModalResponse;
+
+QT_BEGIN_NAMESPACE
+
+class QEventLoop;
+
+class QCocoaMessageDialog : public QPlatformMessageDialogHelper
+{
+public:
+ QCocoaMessageDialog() = default;
+ ~QCocoaMessageDialog();
+
+ void exec() override;
+ bool show(Qt::WindowFlags windowFlags, Qt::WindowModality windowModality, QWindow *parent) override;
+ void hide() override;
+
+private:
+ Qt::WindowModality modality() const;
+ NSAlert *m_alert = nullptr;
+ QEventLoop *m_eventLoop = nullptr;
+ NSModalResponse runModal() const;
+ void processResponse(NSModalResponse response);
+};
+
+QT_END_NAMESPACE
+
+#endif // QCOCOAMESSAGEDIALOG_H
+
diff --git a/src/plugins/platforms/cocoa/qcocoamessagedialog.mm b/src/plugins/platforms/cocoa/qcocoamessagedialog.mm
new file mode 100644
index 0000000000..84525099c9
--- /dev/null
+++ b/src/plugins/platforms/cocoa/qcocoamessagedialog.mm
@@ -0,0 +1,425 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qcocoamessagedialog.h"
+
+#include "qcocoawindow.h"
+#include "qcocoahelpers.h"
+#include "qcocoaeventdispatcher.h"
+
+#include <QtCore/qmetaobject.h>
+#include <QtCore/qscopedvaluerollback.h>
+#include <QtCore/qtimer.h>
+
+#include <QtGui/qtextdocument.h>
+#include <QtGui/private/qguiapplication_p.h>
+#include <QtGui/private/qcoregraphics_p.h>
+#include <QtGui/qpa/qplatformtheme.h>
+
+#include <AppKit/NSAlert.h>
+#include <AppKit/NSButton.h>
+
+QT_USE_NAMESPACE
+
+using namespace Qt::StringLiterals;
+
+QT_BEGIN_NAMESPACE
+
+QCocoaMessageDialog::~QCocoaMessageDialog()
+{
+ hide();
+ [m_alert release];
+}
+
+static QString toPlainText(const QString &text)
+{
+ // FIXME: QMessageDialog supports Qt::TextFormat, which
+ // nowadays includes Qt::MarkdownText, but we don't have
+ // the machinery to deal with that yet. We should as a
+ // start plumb the dialog's text format to the platform
+ // via the dialog options.
+
+ if (!Qt::mightBeRichText(text))
+ return text;
+
+ QTextDocument textDocument;
+ textDocument.setHtml(text);
+ return textDocument.toPlainText();
+}
+
+static NSControlStateValue controlStateFor(Qt::CheckState state)
+{
+ switch (state) {
+ case Qt::Checked: return NSControlStateValueOn;
+ case Qt::Unchecked: return NSControlStateValueOff;
+ case Qt::PartiallyChecked: return NSControlStateValueMixed;
+ }
+ Q_UNREACHABLE();
+}
+
+/*
+ Called from QDialogPrivate::setNativeDialogVisible() when the message box
+ is ready to be shown.
+
+ At this point the options() will reflect the specific dialog shown.
+
+ Returns true if the helper could successfully show the dialog, or
+ false if the cross platform fallback dialog should be used instead.
+*/
+bool QCocoaMessageDialog::show(Qt::WindowFlags windowFlags, Qt::WindowModality windowModality, QWindow *parent)
+{
+ Q_UNUSED(windowFlags);
+
+ qCDebug(lcQpaDialogs) << "Asked to show" << windowModality << "dialog with parent" << parent;
+
+ if (m_alert.window.visible) {
+ qCDebug(lcQpaDialogs) << "Dialog already visible, ignoring request to show";
+ return true; // But we don't want to show the fallback dialog instead
+ }
+
+ // We can only do application and window modal dialogs
+ if (windowModality == Qt::NonModal)
+ return false;
+
+ // And only window modal if we have a parent
+ if (windowModality == Qt::WindowModal && (!parent || !parent->handle())) {
+ qCWarning(lcQpaDialogs, "Cannot run window modal dialog without parent window");
+ return false;
+ }
+
+ // And without options we don't know what to show
+ if (!options())
+ return false;
+
+ // NSAlert doesn't have a section for detailed text
+ if (!options()->detailedText().isEmpty()) {
+ qCWarning(lcQpaDialogs, "Message box contains detailed text");
+ return false;
+ }
+
+ if (Qt::mightBeRichText(options()->text()) ||
+ Qt::mightBeRichText(options()->informativeText())) {
+ // Let's fallback to non-native message box,
+ // we only have plain NSString/text in NSAlert.
+ qCDebug(lcQpaDialogs, "Message box contains text in rich text format");
+ return false;
+ }
+
+ Q_ASSERT(!m_alert);
+ m_alert = [NSAlert new];
+ m_alert.window.title = options()->windowTitle().toNSString();
+
+ const QString text = toPlainText(options()->text());
+ m_alert.messageText = text.toNSString();
+ m_alert.informativeText = toPlainText(options()->informativeText()).toNSString();
+
+ switch (options()->standardIcon()) {
+ case QMessageDialogOptions::NoIcon: {
+ // We only reflect the pixmap icon if the standard icon is unset,
+ // as setting a standard icon will also set a corresponding pixmap
+ // icon, which we don't want since it conflicts with the platform.
+ // If the user has set an explicit pixmap icon however, the standard
+ // icon will be NoIcon, so we're good.
+ QPixmap iconPixmap = options()->iconPixmap();
+ if (!iconPixmap.isNull())
+ m_alert.icon = [NSImage imageFromQImage:iconPixmap.toImage()];
+ break;
+ }
+ case QMessageDialogOptions::Information:
+ case QMessageDialogOptions::Question:
+ [m_alert setAlertStyle:NSAlertStyleInformational];
+ break;
+ case QMessageDialogOptions::Warning:
+ [m_alert setAlertStyle:NSAlertStyleWarning];
+ break;
+ case QMessageDialogOptions::Critical:
+ [m_alert setAlertStyle:NSAlertStyleCritical];
+ break;
+ }
+
+ auto defaultButton = options()->defaultButton();
+ auto escapeButton = options()->escapeButton();
+
+ const auto addButton = [&](auto title, auto tag, auto role) {
+ title = QPlatformTheme::removeMnemonics(title);
+ NSButton *button = [m_alert addButtonWithTitle:title.toNSString()];
+
+ // Calling addButtonWithTitle places buttons starting at the right side/top of the alert
+ // and going toward the left/bottom. By default, the first button has a key equivalent of
+ // Return, any button with a title of "Cancel" has a key equivalent of Escape, and any button
+ // with the title "Don't Save" has a key equivalent of Command-D (but only if it's not the first
+ // button). If an explicit default or escape button has been set, we respect these,
+ // and otherwise we fall back to role-based default and escape buttons.
+
+ qCDebug(lcQpaDialogs).verbosity(0) << "Adding button" << title << "with" << role;
+
+ if (!defaultButton && role == AcceptRole)
+ defaultButton = tag;
+
+ if (tag == defaultButton)
+ button.keyEquivalent = @"\r";
+ else if ([button.keyEquivalent isEqualToString:@"\r"])
+ button.keyEquivalent = @"";
+
+ if (!escapeButton && role == RejectRole)
+ escapeButton = tag;
+
+ // Don't override default button with escape button, to match AppKit default
+ if (tag == escapeButton && ![button.keyEquivalent isEqualToString:@"\r"])
+ button.keyEquivalent = @"\e";
+ else if ([button.keyEquivalent isEqualToString:@"\e"])
+ button.keyEquivalent = @"";
+
+ if (@available(macOS 11, *))
+ button.hasDestructiveAction = role == DestructiveRole;
+
+ // The NSModalResponse of showing an NSAlert normally depends on the order of the
+ // button that was clicked, starting from the right with NSAlertFirstButtonReturn (1000),
+ // NSAlertSecondButtonReturn (1001), NSAlertThirdButtonReturn (1002), and after that
+ // NSAlertThirdButtonReturn + n. The response can also be customized per button via its
+ // tag, which, following the above logic, can include any positive value from 1000 and up.
+ // In addition the system reserves the values from -1000 and down for its own modal responses,
+ // such as NSModalResponseStop, NSModalResponseAbort, and NSModalResponseContinue.
+ // Luckily for us, the QPlatformDialogHelper::StandardButton enum values all fall within
+ // the positive range, so we can use the standard button value as the tag directly.
+ // The same applies to the custom button IDs, as these are generated in sequence after
+ // the QPlatformDialogHelper::LastButton.
+ Q_ASSERT(tag >= NSAlertFirstButtonReturn);
+ button.tag = tag;
+ };
+
+ // Resolve all dialog buttons from the options, both standard and custom
+
+ struct Button { QString title; int identifier; ButtonRole role; };
+ std::vector<Button> buttons;
+
+ const auto *platformTheme = QGuiApplicationPrivate::platformTheme();
+ if (auto standardButtons = options()->standardButtons()) {
+ for (int standardButton = FirstButton; standardButton <= LastButton; standardButton <<= 1) {
+ if (standardButtons & standardButton) {
+ auto title = platformTheme->standardButtonText(standardButton);
+ buttons.push_back({
+ title, standardButton, buttonRole(StandardButton(standardButton))
+ });
+ }
+ }
+ }
+ const auto customButtons = options()->customButtons();
+ for (auto customButton : customButtons)
+ buttons.push_back({customButton.label, customButton.id, customButton.role});
+
+ // Sort them according to the QPlatformDialogHelper::ButtonLayout for macOS
+
+ // The ButtonLayout adds one additional role, AlternateRole, which is used
+ // for any AcceptRole beyond the first one, and should be ordered before the
+ // AcceptRole. Set this up by fixing the roles up front.
+ bool seenAccept = false;
+ for (auto &button : buttons) {
+ if (button.role == AcceptRole) {
+ if (!seenAccept)
+ seenAccept = true;
+ else
+ button.role = AlternateRole;
+ }
+ }
+
+ std::vector<Button> orderedButtons;
+ const int *layoutEntry = buttonLayout(Qt::Horizontal, ButtonLayout::MacLayout);
+ while (*layoutEntry != QPlatformDialogHelper::EOL) {
+ const auto role = ButtonRole(*layoutEntry & ~ButtonRole::Reverse);
+ const bool reverse = *layoutEntry & ButtonRole::Reverse;
+
+ auto addButton = [&](const Button &button) {
+ if (button.role == role)
+ orderedButtons.push_back(button);
+ };
+
+ if (reverse)
+ std::for_each(std::crbegin(buttons), std::crend(buttons), addButton);
+ else
+ std::for_each(std::cbegin(buttons), std::cend(buttons), addButton);
+
+ ++layoutEntry;
+ }
+
+ // Add them to the alert in reverse order, since buttons are added right to left
+ for (auto button = orderedButtons.crbegin(); button != orderedButtons.crend(); ++button)
+ addButton(button->title, button->identifier, button->role);
+
+ // If we didn't find a an explicit or implicit default button above
+ // we restore the AppKit behavior of making the first button default.
+ if (!defaultButton)
+ m_alert.buttons.firstObject.keyEquivalent = @"\r";
+
+ if (auto checkBoxLabel = options()->checkBoxLabel(); !checkBoxLabel.isNull()) {
+ checkBoxLabel = QPlatformTheme::removeMnemonics(checkBoxLabel);
+ m_alert.suppressionButton.title = checkBoxLabel.toNSString();
+ auto state = options()->checkBoxState();
+ m_alert.suppressionButton.allowsMixedState = state == Qt::PartiallyChecked;
+ m_alert.suppressionButton.state = controlStateFor(state);
+ m_alert.showsSuppressionButton = YES;
+ }
+
+ qCDebug(lcQpaDialogs) << "Showing" << m_alert;
+
+ if (windowModality == Qt::WindowModal) {
+ auto *cocoaWindow = static_cast<QCocoaWindow*>(parent->handle());
+ [m_alert beginSheetModalForWindow:cocoaWindow->nativeWindow()
+ completionHandler:^(NSModalResponse response) {
+ processResponse(response);
+ }
+ ];
+ } else {
+ // The dialog is application modal, so we need to call runModal,
+ // but we can't call it here as the nativeDialogInUse state of QDialog
+ // depends on the result of show(), and we can't rely on doing it
+ // in exec(), as we can't guarantee that the user will call exec()
+ // after showing the dialog. As a workaround, we call it from exec(),
+ // but also make sure that if the user returns to the main runloop
+ // we'll run the modal dialog from there.
+ QTimer::singleShot(0, this, [this]{
+ if (m_alert && !m_alert.window.visible) {
+ qCDebug(lcQpaDialogs) << "Running deferred modal" << m_alert;
+ QCocoaEventDispatcher::clearCurrentThreadCocoaEventDispatcherInterruptFlag();
+ processResponse(runModal());
+ }
+ });
+ }
+
+ return true;
+}
+
+// We shouldn't get NSModalResponseContinue as a response from NSAlert::runModal,
+// and processResponse must not be called with that value (if we are there, it's
+// too late to do anything about it.
+// However, as QTBUG-114546 shows, there are scenarios where we might get that
+// response anyway. We interpret it to keep the modal loop running, and we only
+// return if we got something else to pass to processResponse.
+NSModalResponse QCocoaMessageDialog::runModal() const
+{
+ NSModalResponse response = NSModalResponseContinue;
+ while (response == NSModalResponseContinue)
+ response = [m_alert runModal];
+ return response;
+}
+
+void QCocoaMessageDialog::exec()
+{
+ Q_ASSERT(m_alert);
+
+ if (modality() == Qt::WindowModal) {
+ qCDebug(lcQpaDialogs) << "Running local event loop for window modal" << m_alert;
+ QEventLoop eventLoop;
+ QScopedValueRollback updateGuard(m_eventLoop, &eventLoop);
+ m_eventLoop->exec(QEventLoop::DialogExec);
+ } else {
+ qCDebug(lcQpaDialogs) << "Running modal" << m_alert;
+ QCocoaEventDispatcher::clearCurrentThreadCocoaEventDispatcherInterruptFlag();
+ processResponse(runModal());
+ }
+}
+
+// Custom modal response code to record that the dialog was hidden by us
+static const NSInteger kModalResponseDialogHidden = NSAlertThirdButtonReturn + 1;
+
+static Qt::CheckState checkStateFor(NSControlStateValue state)
+{
+ switch (state) {
+ case NSControlStateValueOn: return Qt::Checked;
+ case NSControlStateValueOff: return Qt::Unchecked;
+ case NSControlStateValueMixed: return Qt::PartiallyChecked;
+ }
+ Q_UNREACHABLE();
+}
+
+void QCocoaMessageDialog::processResponse(NSModalResponse response)
+{
+ qCDebug(lcQpaDialogs) << "Processing response" << response << "for" << m_alert;
+
+ // We can't re-use the same dialog for the next show() anyways,
+ // since the options may have changed, so get rid of it now,
+ // before we emit anything that might recurse back to hide/show/etc.
+ auto alert = std::exchange(m_alert, nil);
+ [alert autorelease];
+
+ if (alert.showsSuppressionButton)
+ emit checkBoxStateChanged(checkStateFor(alert.suppressionButton.state));
+
+ if (response >= NSAlertFirstButtonReturn) {
+ // Safe range for user-defined modal responses
+ if (response == kModalResponseDialogHidden) {
+ // Dialog was explicitly hidden by us, so nothing to report
+ qCDebug(lcQpaDialogs) << "Dialog was hidden; ignoring response";
+ } else {
+ // Dialog buttons
+ if (response <= StandardButton::LastButton) {
+ Q_ASSERT(response >= StandardButton::FirstButton);
+ auto standardButton = StandardButton(response);
+ emit clicked(standardButton, buttonRole(standardButton));
+ } else {
+ auto *customButton = options()->customButton(response);
+ Q_ASSERT(customButton);
+ emit clicked(StandardButton(customButton->id), customButton->role);
+ }
+ }
+ } else {
+ // We have to consider NSModalResponses beyond the ones specific to
+ // the alert buttons as the alert may be canceled programmatically.
+
+ switch (response) {
+ case NSModalResponseContinue:
+ // Modal session is continuing (returned by runModalSession: only)
+ Q_UNREACHABLE();
+ case NSModalResponseOK:
+ emit accept();
+ break;
+ case NSModalResponseCancel:
+ case NSModalResponseStop: // Modal session was broken with stopModal
+ case NSModalResponseAbort: // Modal session was broken with abortModal
+ emit reject();
+ break;
+ default:
+ qCWarning(lcQpaDialogs) << "Unrecognized modal response" << response;
+ }
+ }
+
+ if (m_eventLoop)
+ m_eventLoop->exit(response);
+}
+
+void QCocoaMessageDialog::hide()
+{
+ if (!m_alert)
+ return;
+
+ if (m_alert.window.visible) {
+ qCDebug(lcQpaDialogs) << "Hiding" << modality() << m_alert;
+
+ // Note: Just hiding or closing the NSAlert's NWindow here is not sufficient,
+ // as the dialog is running a modal event loop as well, which we need to end.
+
+ if (modality() == Qt::WindowModal) {
+ // Will call processResponse() synchronously
+ [m_alert.window.sheetParent endSheet:m_alert.window returnCode:kModalResponseDialogHidden];
+ } else {
+ if (NSApp.modalWindow == m_alert.window) {
+ // Will call processResponse() asynchronously
+ [NSApp stopModalWithCode:kModalResponseDialogHidden];
+ } else {
+ qCWarning(lcQpaDialogs, "Dialog is not top level modal window. Cannot hide.");
+ }
+ }
+ } else {
+ qCDebug(lcQpaDialogs) << "No need to hide already hidden" << m_alert;
+ auto alert = std::exchange(m_alert, nil);
+ [alert autorelease];
+ }
+}
+
+Qt::WindowModality QCocoaMessageDialog::modality() const
+{
+ Q_ASSERT(m_alert && m_alert.window);
+ return m_alert.window.sheetParent ? Qt::WindowModal : Qt::ApplicationModal;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/qcocoamimetypes.h b/src/plugins/platforms/cocoa/qcocoamimetypes.h
index a00e25bc93..fd075d35bd 100644
--- a/src/plugins/platforms/cocoa/qcocoamimetypes.h
+++ b/src/plugins/platforms/cocoa/qcocoamimetypes.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QCOCOAMIMETYPES_H
#define QCOCOAMIMETYPES_H
diff --git a/src/plugins/platforms/cocoa/qcocoamimetypes.mm b/src/plugins/platforms/cocoa/qcocoamimetypes.mm
index f7662a92a4..52e5c64538 100644
--- a/src/plugins/platforms/cocoa/qcocoamimetypes.mm
+++ b/src/plugins/platforms/cocoa/qcocoamimetypes.mm
@@ -1,92 +1,51 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <AppKit/AppKit.h>
#include "qcocoamimetypes.h"
-#include <QtClipboardSupport/private/qmacmime_p.h>
+#include <QtGui/qutimimeconverter.h>
#include "qcocoahelpers.h"
#include <QtGui/private/qcoregraphics_p.h>
QT_BEGIN_NAMESPACE
-class QMacPasteboardMimeTraditionalMacPlainText : public QMacInternalPasteboardMime {
-public:
- QMacPasteboardMimeTraditionalMacPlainText() : QMacInternalPasteboardMime(MIME_ALL) { }
- QString convertorName();
+using namespace Qt::StringLiterals;
- QString flavorFor(const QString &mime);
- QString mimeFor(QString flav);
- bool canConvert(const QString &mime, QString flav);
- QVariant convertToMime(const QString &mime, QList<QByteArray> data, QString flav);
- QList<QByteArray> convertFromMime(const QString &mime, QVariant data, QString flav);
+class QMacMimeTraditionalMacPlainText : public QUtiMimeConverter {
+public:
+ QString utiForMime(const QString &mime) const override;
+ QString mimeForUti(const QString &uti) const override;
+ QVariant convertToMime(const QString &mime, const QList<QByteArray> &data,
+ const QString &uti) const override;
+ QList<QByteArray> convertFromMime(const QString &mime, const QVariant &data,
+ const QString &uti) const override;
};
-QString QMacPasteboardMimeTraditionalMacPlainText::convertorName()
+QString QMacMimeTraditionalMacPlainText::utiForMime(const QString &mime) const
{
- return QLatin1String("PlainText (traditional-mac-plain-text)");
-}
-
-QString QMacPasteboardMimeTraditionalMacPlainText::flavorFor(const QString &mime)
-{
- if (mime == QLatin1String("text/plain"))
- return QLatin1String("com.apple.traditional-mac-plain-text");
+ if (mime == "text/plain"_L1)
+ return "com.apple.traditional-mac-plain-text"_L1;
return QString();
}
-QString QMacPasteboardMimeTraditionalMacPlainText::mimeFor(QString flav)
+QString QMacMimeTraditionalMacPlainText::mimeForUti(const QString &uti) const
{
- if (flav == QLatin1String("com.apple.traditional-mac-plain-text"))
- return QLatin1String("text/plain");
+ if (uti == "com.apple.traditional-mac-plain-text"_L1)
+ return "text/plain"_L1;
return QString();
}
-bool QMacPasteboardMimeTraditionalMacPlainText::canConvert(const QString &mime, QString flav)
-{
- return flavorFor(mime) == flav;
-}
-
-QVariant QMacPasteboardMimeTraditionalMacPlainText::convertToMime(const QString &mimetype, QList<QByteArray> data, QString flavor)
+QVariant
+QMacMimeTraditionalMacPlainText::convertToMime(const QString &mimetype,
+ const QList<QByteArray> &data,
+ const QString &uti) const
{
if (data.count() > 1)
- qWarning("QMacPasteboardMimeTraditionalMacPlainText: Cannot handle multiple member data");
+ qWarning("QMacMimeTraditionalMacPlainText: Cannot handle multiple member data");
const QByteArray &firstData = data.first();
QVariant ret;
- if (flavor == QLatin1String("com.apple.traditional-mac-plain-text")) {
+ if (uti == "com.apple.traditional-mac-plain-text"_L1) {
return QString(QCFString(CFStringCreateWithBytes(kCFAllocatorDefault,
reinterpret_cast<const UInt8 *>(firstData.constData()),
firstData.size(), CFStringGetSystemEncoding(), false)));
@@ -96,18 +55,21 @@ QVariant QMacPasteboardMimeTraditionalMacPlainText::convertToMime(const QString
return ret;
}
-QList<QByteArray> QMacPasteboardMimeTraditionalMacPlainText::convertFromMime(const QString &, QVariant data, QString flavor)
+QList<QByteArray>
+QMacMimeTraditionalMacPlainText::convertFromMime(const QString &,
+ const QVariant &data,
+ const QString &uti) const
{
QList<QByteArray> ret;
QString string = data.toString();
- if (flavor == QLatin1String("com.apple.traditional-mac-plain-text"))
+ if (uti == "com.apple.traditional-mac-plain-text"_L1)
ret.append(string.toLatin1());
return ret;
}
void QCocoaMimeTypes::initializeMimeTypes()
{
- new QMacPasteboardMimeTraditionalMacPlainText;
+ new QMacMimeTraditionalMacPlainText;
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/qcocoanativeinterface.h b/src/plugins/platforms/cocoa/qcocoanativeinterface.h
index c78f1d5a7f..a406cae366 100644
--- a/src/plugins/platforms/cocoa/qcocoanativeinterface.h
+++ b/src/plugins/platforms/cocoa/qcocoanativeinterface.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QCOCOANATIVEINTERFACE_H
#define QCOCOANATIVEINTERFACE_H
@@ -44,11 +8,11 @@
#include <qpa/qplatformnativeinterface.h>
#include <QtGui/qpixmap.h>
+Q_MOC_INCLUDE(<QWindow>)
QT_BEGIN_NAMESPACE
class QWidget;
-class QPlatformPrinterSupport;
class QPrintEngine;
class QPlatformMenu;
class QPlatformMenuBar;
@@ -59,69 +23,18 @@ class QCocoaNativeInterface : public QPlatformNativeInterface
public:
QCocoaNativeInterface();
-#ifndef QT_NO_OPENGL
- void *nativeResourceForContext(const QByteArray &resourceString, QOpenGLContext *context) override;
-#endif
void *nativeResourceForWindow(const QByteArray &resourceString, QWindow *window) override;
NativeResourceForIntegrationFunction nativeResourceFunctionForIntegration(const QByteArray &resource) override;
-#ifndef QT_NO_OPENGL
- static void *cglContextForContext(QOpenGLContext *context);
- static void *nsOpenGLContextForContext(QOpenGLContext* context);
-#endif
-
- QFunctionPointer platformFunction(const QByteArray &function) const override;
-
public Q_SLOTS:
void onAppFocusWindowChanged(QWindow *window);
private:
- /*
- "Virtual" function to create the platform printer support
- implementation.
-
- We use an invokable function instead of a virtual one, we do not want
- this in the QPlatform* API yet.
-
- This was added here only because QPlatformNativeInterface is a QObject
- and allow us to use QMetaObject::indexOfMethod() from the printsupport
- plugin.
- */
- Q_INVOKABLE QPlatformPrinterSupport *createPlatformPrinterSupport();
- /*
- Function to return the NSPrintInfo * from QMacPaintEnginePrivate.
- Needed by the native print dialog in the Qt Print Support module.
- */
- Q_INVOKABLE void *NSPrintInfoForPrintEngine(QPrintEngine *printEngine);
- /*
- Function to return the default background pixmap.
- Needed by QWizard in the Qt widget module.
- */
- Q_INVOKABLE QPixmap defaultBackgroundPixmapForQWizard();
-
Q_INVOKABLE void clearCurrentThreadCocoaEventDispatcherInterruptFlag();
- // QMacPastebardMime support. The mac pasteboard void pointers are
- // QMacPastebardMime instances from the cocoa plugin or qtmacextras
- // These two classes are kept in sync and can be casted between.
- static void addToMimeList(void *macPasteboardMime);
- static void removeFromMimeList(void *macPasteboardMime);
static void registerDraggedTypes(const QStringList &types);
- // Dock menu support
- static void setDockMenu(QPlatformMenu *platformMenu);
-
- // Function to return NSMenu * from QPlatformMenu
- static void *qMenuToNSMenu(QPlatformMenu *platformMenu);
-
- // Function to return NSMenu * from QPlatformMenuBar
- static void *qMenuBarToNSMenu(QPlatformMenuBar *platformMenuBar);
-
- // QImage <-> CGImage conversion functions
- static CGImageRef qImageToCGImage(const QImage &image);
- static QImage cgImageToQImage(CGImageRef image);
-
// Set a QWindow as a "guest" (subwindow) of a non-QWindow
static void setEmbeddedInForeignView(QPlatformWindow *window, bool embedded);
@@ -134,12 +47,6 @@ private:
// deregisters.
static void registerTouchWindow(QWindow *window, bool enable);
- // Enable the unified title and toolbar area for a window.
- static void setContentBorderEnabled(QWindow *window, bool enable);
-
- // Set the size of the unified title and toolbar area.
- static void setContentBorderThickness(QWindow *window, int topThickness, int bottomThickness);
-
// Set the size for a unified toolbar content border area.
// Multiple callers can register areas and the platform plugin
// will extend the "unified" area to cover them.
@@ -151,12 +58,6 @@ private:
// Returns true if the given coordinate is inside the current
// content border.
static bool testContentBorderPosition(QWindow *window, int position);
-
- // Sets a NSToolbar instance for the given QWindow. The
- // toolbar will be attached to the native NSWindow when
- // that is created;
- static void setNSToolbar(QWindow *window, void *nsToolbar);
-
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/qcocoanativeinterface.mm b/src/plugins/platforms/cocoa/qcocoanativeinterface.mm
index d0e69bdca5..58bda2706a 100644
--- a/src/plugins/platforms/cocoa/qcocoanativeinterface.mm
+++ b/src/plugins/platforms/cocoa/qcocoanativeinterface.mm
@@ -1,45 +1,12 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <AppKit/AppKit.h>
#include "qcocoanativeinterface.h"
#include "qcocoawindow.h"
#include "qcocoamenu.h"
+#include "qcocoansmenu.h"
#include "qcocoamenubar.h"
#include "qcocoahelpers.h"
#include "qcocoaapplicationdelegate.h"
@@ -50,27 +17,18 @@
#include <qwindow.h>
#include <qpixmap.h>
#include <qpa/qplatformwindow.h>
-#include "qsurfaceformat.h"
+#include <QtGui/qsurfaceformat.h>
#ifndef QT_NO_OPENGL
#include <qpa/qplatformopenglcontext.h>
-#include "qopenglcontext.h"
+#include <QtGui/qopenglcontext.h>
#include "qcocoaglcontext.h"
#endif
-#include "qguiapplication.h"
+#include <QtGui/qguiapplication.h>
#include <qdebug.h>
-#if !defined(QT_NO_WIDGETS) && defined(QT_PRINTSUPPORT_LIB)
-#include "qcocoaprintersupport.h"
-#include "qprintengine_mac_p.h"
-#include <qpa/qplatformprintersupport.h>
-#endif
-
+#include <QtGui/private/qmacmimeregistry_p.h>
#include <QtGui/private/qcoregraphics_p.h>
-#include <QtPlatformHeaders/qcocoawindowfunctions.h>
-
-#include <AppKit/AppKit.h>
-
#if QT_CONFIG(vulkan)
#include <MoltenVK/mvk_vulkan.h>
#endif
@@ -81,20 +39,6 @@ QCocoaNativeInterface::QCocoaNativeInterface()
{
}
-#ifndef QT_NO_OPENGL
-void *QCocoaNativeInterface::nativeResourceForContext(const QByteArray &resourceString, QOpenGLContext *context)
-{
- if (!context)
- return nullptr;
- if (resourceString.toLower() == "nsopenglcontext")
- return nsOpenGLContextForContext(context);
- if (resourceString.toLower() == "cglcontextobj")
- return cglContextForContext(context);
-
- return nullptr;
-}
-#endif
-
void *QCocoaNativeInterface::nativeResourceForWindow(const QByteArray &resourceString, QWindow *window)
{
if (!window->handle())
@@ -107,7 +51,7 @@ void *QCocoaNativeInterface::nativeResourceForWindow(const QByteArray &resourceS
#if QT_CONFIG(vulkan)
} else if (resourceString == "vkSurface") {
if (QVulkanInstance *instance = window->vulkanInstance())
- return static_cast<QCocoaVulkanInstance *>(instance->handle())->createSurface(window);
+ return static_cast<QCocoaVulkanInstance *>(instance->handle())->surface(window);
#endif
}
return nullptr;
@@ -115,95 +59,22 @@ void *QCocoaNativeInterface::nativeResourceForWindow(const QByteArray &resourceS
QPlatformNativeInterface::NativeResourceForIntegrationFunction QCocoaNativeInterface::nativeResourceFunctionForIntegration(const QByteArray &resource)
{
- if (resource.toLower() == "addtomimelist")
- return NativeResourceForIntegrationFunction(QCocoaNativeInterface::addToMimeList);
- if (resource.toLower() == "removefrommimelist")
- return NativeResourceForIntegrationFunction(QCocoaNativeInterface::removeFromMimeList);
if (resource.toLower() == "registerdraggedtypes")
return NativeResourceForIntegrationFunction(QCocoaNativeInterface::registerDraggedTypes);
- if (resource.toLower() == "setdockmenu")
- return NativeResourceForIntegrationFunction(QCocoaNativeInterface::setDockMenu);
- if (resource.toLower() == "qmenutonsmenu")
- return NativeResourceForIntegrationFunction(QCocoaNativeInterface::qMenuToNSMenu);
- if (resource.toLower() == "qmenubartonsmenu")
- return NativeResourceForIntegrationFunction(QCocoaNativeInterface::qMenuBarToNSMenu);
- if (resource.toLower() == "qimagetocgimage")
- return NativeResourceForIntegrationFunction(QCocoaNativeInterface::qImageToCGImage);
- if (resource.toLower() == "cgimagetoqimage")
- return NativeResourceForIntegrationFunction(QCocoaNativeInterface::cgImageToQImage);
if (resource.toLower() == "registertouchwindow")
return NativeResourceForIntegrationFunction(QCocoaNativeInterface::registerTouchWindow);
if (resource.toLower() == "setembeddedinforeignview")
return NativeResourceForIntegrationFunction(QCocoaNativeInterface::setEmbeddedInForeignView);
- if (resource.toLower() == "setcontentborderthickness")
- return NativeResourceForIntegrationFunction(QCocoaNativeInterface::setContentBorderThickness);
if (resource.toLower() == "registercontentborderarea")
return NativeResourceForIntegrationFunction(QCocoaNativeInterface::registerContentBorderArea);
if (resource.toLower() == "setcontentborderareaenabled")
return NativeResourceForIntegrationFunction(QCocoaNativeInterface::setContentBorderAreaEnabled);
- if (resource.toLower() == "setcontentborderenabled")
- return NativeResourceForIntegrationFunction(QCocoaNativeInterface::setContentBorderEnabled);
- if (resource.toLower() == "setnstoolbar")
- return NativeResourceForIntegrationFunction(QCocoaNativeInterface::setNSToolbar);
if (resource.toLower() == "testcontentborderposition")
return NativeResourceForIntegrationFunction(QCocoaNativeInterface::testContentBorderPosition);
return nullptr;
}
-QPlatformPrinterSupport *QCocoaNativeInterface::createPlatformPrinterSupport()
-{
-#if !defined(QT_NO_WIDGETS) && !defined(QT_NO_PRINTER) && defined(QT_PRINTSUPPORT_LIB)
- return new QCocoaPrinterSupport();
-#else
- qFatal("Printing is not supported when Qt is configured with -no-widgets or -no-feature-printer");
- return nullptr;
-#endif
-}
-
-void *QCocoaNativeInterface::NSPrintInfoForPrintEngine(QPrintEngine *printEngine)
-{
-#if !defined(QT_NO_WIDGETS) && !defined(QT_NO_PRINTER) && defined(QT_PRINTSUPPORT_LIB)
- QMacPrintEnginePrivate *macPrintEnginePriv = static_cast<QMacPrintEngine *>(printEngine)->d_func();
- if (macPrintEnginePriv->state == QPrinter::Idle && !macPrintEnginePriv->isPrintSessionInitialized())
- macPrintEnginePriv->initialize();
- return macPrintEnginePriv->printInfo;
-#else
- Q_UNUSED(printEngine);
- qFatal("Printing is not supported when Qt is configured with -no-widgets or -no-feature-printer");
- return nullptr;
-#endif
-}
-
-QPixmap QCocoaNativeInterface::defaultBackgroundPixmapForQWizard()
-{
- // Note: starting with macOS 10.14, the KeyboardSetupAssistant app bundle no
- // longer contains the "Background.png" image. This function then returns a
- // null pixmap.
- const int ExpectedImageWidth = 242;
- const int ExpectedImageHeight = 414;
- QCFType<CFArrayRef> urls = LSCopyApplicationURLsForBundleIdentifier(
- CFSTR("com.apple.KeyboardSetupAssistant"), nullptr);
- if (urls && CFArrayGetCount(urls) > 0) {
- CFURLRef url = (CFURLRef)CFArrayGetValueAtIndex(urls, 0);
- QCFType<CFBundleRef> bundle = CFBundleCreate(kCFAllocatorDefault, url);
- if (bundle) {
- url = CFBundleCopyResourceURL(bundle, CFSTR("Background"), CFSTR("png"), nullptr);
- if (url) {
- QCFType<CGImageSourceRef> imageSource = CGImageSourceCreateWithURL(url, nullptr);
- QCFType<CGImageRef> image = CGImageSourceCreateImageAtIndex(imageSource, 0, nullptr);
- if (image) {
- int width = CGImageGetWidth(image);
- int height = CGImageGetHeight(image);
- if (width == ExpectedImageWidth && height == ExpectedImageHeight)
- return QPixmap::fromImage(qt_mac_toQImage(image));
- }
- }
- }
- }
- return QPixmap();
-}
-
void QCocoaNativeInterface::clearCurrentThreadCocoaEventDispatcherInterruptFlag()
{
QCocoaEventDispatcher::clearCurrentThreadCocoaEventDispatcherInterruptFlag();
@@ -215,78 +86,9 @@ void QCocoaNativeInterface::onAppFocusWindowChanged(QWindow *window)
QCocoaMenuBar::updateMenuBarImmediately();
}
-#ifndef QT_NO_OPENGL
-void *QCocoaNativeInterface::cglContextForContext(QOpenGLContext* context)
-{
- NSOpenGLContext *nsOpenGLContext = static_cast<NSOpenGLContext*>(nsOpenGLContextForContext(context));
- if (nsOpenGLContext)
- return [nsOpenGLContext CGLContextObj];
- return nullptr;
-}
-
-void *QCocoaNativeInterface::nsOpenGLContextForContext(QOpenGLContext* context)
-{
- if (context) {
- if (QCocoaGLContext *cocoaGLContext = static_cast<QCocoaGLContext *>(context->handle()))
- return cocoaGLContext->nativeContext();
- }
- return nullptr;
-}
-#endif
-
-QFunctionPointer QCocoaNativeInterface::platformFunction(const QByteArray &function) const
-{
- if (function == QCocoaWindowFunctions::bottomLeftClippedByNSWindowOffsetIdentifier())
- return QFunctionPointer(QCocoaWindowFunctions::BottomLeftClippedByNSWindowOffset(QCocoaWindow::bottomLeftClippedByNSWindowOffsetStatic));
-
- return nullptr;
-}
-
-void QCocoaNativeInterface::addToMimeList(void *macPasteboardMime)
-{
- qt_mac_addToGlobalMimeList(reinterpret_cast<QMacInternalPasteboardMime *>(macPasteboardMime));
-}
-
-void QCocoaNativeInterface::removeFromMimeList(void *macPasteboardMime)
-{
- qt_mac_removeFromGlobalMimeList(reinterpret_cast<QMacInternalPasteboardMime *>(macPasteboardMime));
-}
-
void QCocoaNativeInterface::registerDraggedTypes(const QStringList &types)
{
- qt_mac_registerDraggedTypes(types);
-}
-
-void QCocoaNativeInterface::setDockMenu(QPlatformMenu *platformMenu)
-{
- QMacAutoReleasePool pool;
- QCocoaMenu *cocoaPlatformMenu = static_cast<QCocoaMenu *>(platformMenu);
- NSMenu *menu = cocoaPlatformMenu->nsMenu();
- [QCocoaApplicationDelegate sharedDelegate].dockMenu = menu;
-}
-
-void *QCocoaNativeInterface::qMenuToNSMenu(QPlatformMenu *platformMenu)
-{
- QCocoaMenu *cocoaPlatformMenu = static_cast<QCocoaMenu *>(platformMenu);
- NSMenu *menu = cocoaPlatformMenu->nsMenu();
- return reinterpret_cast<void *>(menu);
-}
-
-void *QCocoaNativeInterface::qMenuBarToNSMenu(QPlatformMenuBar *platformMenuBar)
-{
- QCocoaMenuBar *cocoaPlatformMenuBar = static_cast<QCocoaMenuBar *>(platformMenuBar);
- NSMenu *menu = cocoaPlatformMenuBar->nsMenu();
- return reinterpret_cast<void *>(menu);
-}
-
-CGImageRef QCocoaNativeInterface::qImageToCGImage(const QImage &image)
-{
- return qt_mac_toCGImage(image);
-}
-
-QImage QCocoaNativeInterface::cgImageToQImage(CGImageRef image)
-{
- return qt_mac_toQImage(image);
+ QMacMimeRegistry::registerDraggedTypes(types);
}
void QCocoaNativeInterface::setEmbeddedInForeignView(QPlatformWindow *window, bool embedded)
@@ -306,16 +108,6 @@ void QCocoaNativeInterface::registerTouchWindow(QWindow *window, bool enable)
cocoaWindow->registerTouch(enable);
}
-void QCocoaNativeInterface::setContentBorderThickness(QWindow *window, int topThickness, int bottomThickness)
-{
- if (!window)
- return;
-
- QCocoaWindow *cocoaWindow = static_cast<QCocoaWindow *>(window->handle());
- if (cocoaWindow)
- cocoaWindow->setContentBorderThickness(topThickness, bottomThickness);
-}
-
void QCocoaNativeInterface::registerContentBorderArea(QWindow *window, quintptr identifier, int upper, int lower)
{
if (!window)
@@ -336,25 +128,6 @@ void QCocoaNativeInterface::setContentBorderAreaEnabled(QWindow *window, quintpt
cocoaWindow->setContentBorderAreaEnabled(identifier, enable);
}
-void QCocoaNativeInterface::setContentBorderEnabled(QWindow *window, bool enable)
-{
- if (!window)
- return;
-
- QCocoaWindow *cocoaWindow = static_cast<QCocoaWindow *>(window->handle());
- if (cocoaWindow)
- cocoaWindow->setContentBorderEnabled(enable);
-}
-
-void QCocoaNativeInterface::setNSToolbar(QWindow *window, void *nsToolbar)
-{
- QCocoaIntegration::instance()->setToolbar(window, static_cast<NSToolbar *>(nsToolbar));
-
- QCocoaWindow *cocoaWindow = static_cast<QCocoaWindow *>(window->handle());
- if (cocoaWindow)
- cocoaWindow->updateNSToolbar();
-}
-
bool QCocoaNativeInterface::testContentBorderPosition(QWindow *window, int position)
{
if (!window)
diff --git a/src/plugins/platforms/cocoa/qcocoansmenu.h b/src/plugins/platforms/cocoa/qcocoansmenu.h
index 0c77e2f1aa..533aba1a21 100644
--- a/src/plugins/platforms/cocoa/qcocoansmenu.h
+++ b/src/plugins/platforms/cocoa/qcocoansmenu.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 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$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QCOCOANSMENU_H
#define QCOCOANSMENU_H
@@ -51,32 +15,27 @@
// We mean it.
//
-#import <AppKit/AppKit.h>
-
-#include <qcocoahelpers.h>
+#include <QtCore/private/qcore_mac_p.h>
QT_FORWARD_DECLARE_CLASS(QCocoaMenu);
QT_FORWARD_DECLARE_CLASS(QCocoaMenuItem);
-@interface QT_MANGLE_NAMESPACE(QCocoaNSMenuDelegate) : NSObject <NSMenuDelegate>
+QT_DECLARE_NAMESPACED_OBJC_INTERFACE(QCocoaNSMenuDelegate, NSObject <NSMenuDelegate>
+ (instancetype)sharedMenuDelegate;
- (NSMenuItem *)findItemInMenu:(NSMenu *)menu forKey:(NSString *)key modifiers:(NSUInteger)modifiers;
-@end
+)
-@interface QT_MANGLE_NAMESPACE(QCocoaNSMenu) : NSMenu
+QT_DECLARE_NAMESPACED_OBJC_INTERFACE(QCocoaNSMenu, NSMenu
@property (readonly, nonatomic) QCocoaMenu *platformMenu;
- (instancetype)initWithPlatformMenu:(QCocoaMenu *)menu;
-@end
+- (instancetype)initWithoutPlatformMenu:(NSString *)menu;
+)
-@interface QT_MANGLE_NAMESPACE(QCocoaNSMenuItem) : NSMenuItem
+QT_DECLARE_NAMESPACED_OBJC_INTERFACE(QCocoaNSMenuItem, NSMenuItem
@property (nonatomic) QCocoaMenuItem *platformMenuItem;
+ (instancetype)separatorItemWithPlatformMenuItem:(QCocoaMenuItem *)menuItem;
- (instancetype)initWithPlatformMenuItem:(QCocoaMenuItem *)menuItem;
- (instancetype)init;
-@end
-
-QT_NAMESPACE_ALIAS_OBJC_CLASS(QCocoaNSMenu);
-QT_NAMESPACE_ALIAS_OBJC_CLASS(QCocoaNSMenuItem);
-QT_NAMESPACE_ALIAS_OBJC_CLASS(QCocoaNSMenuDelegate);
+)
#endif // QCOCOANSMENU_H
diff --git a/src/plugins/platforms/cocoa/qcocoansmenu.mm b/src/plugins/platforms/cocoa/qcocoansmenu.mm
index c51460282a..ba222a3ef4 100644
--- a/src/plugins/platforms/cocoa/qcocoansmenu.mm
+++ b/src/plugins/platforms/cocoa/qcocoansmenu.mm
@@ -1,51 +1,22 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 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$
-**
-****************************************************************************/
-
-#import "qcocoansmenu.h"
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <AppKit/AppKit.h>
+
+#include "qcocoansmenu.h"
#include "qcocoamenu.h"
#include "qcocoamenuitem.h"
#include "qcocoamenubar.h"
#include "qcocoawindow.h"
-#import "qnsview.h"
+#include "qnsview.h"
+#include "qcocoahelpers.h"
#include <QtCore/qcoreapplication.h>
#include <QtCore/qcoreevent.h>
+#include <QtCore/qvarlengtharray.h>
+#include <QtGui/private/qapplekeymapper_p.h>
+
+#include <QtCore/qpointer.h>
static NSString *qt_mac_removePrivateUnicode(NSString *string)
{
@@ -83,6 +54,13 @@ static NSString *qt_mac_removePrivateUnicode(NSString *string)
return self;
}
+- (instancetype)initWithoutPlatformMenu:(NSString *)title
+{
+ if (self = [super initWithTitle:title])
+ self.delegate = [QCocoaNSMenuDelegate sharedMenuDelegate];
+ return self;
+}
+
- (QCocoaMenu *)platformMenu
{
return _platformMenu.data();
@@ -250,7 +228,7 @@ static NSString *qt_mac_removePrivateUnicode(NSString *string)
QChar ch;
int keyCode;
ulong nativeModifiers = event.modifierFlags;
- Qt::KeyboardModifiers modifiers = [QNSView convertKeyModifiers:nativeModifiers];
+ Qt::KeyboardModifiers modifiers = QAppleKeyMapper::fromCocoaModifiers(nativeModifiers);
NSString *charactersIgnoringModifiers = event.charactersIgnoringModifiers;
NSString *characters = event.characters;
@@ -260,7 +238,7 @@ static NSString *qt_mac_removePrivateUnicode(NSString *string)
} else {
ch = QChar([charactersIgnoringModifiers characterAtIndex:0]);
}
- keyCode = qt_mac_cocoaKey2QtKey(ch);
+ keyCode = QAppleKeyMapper::fromCocoaKey(ch);
} else {
// might be a dead key
ch = QChar::ReplacementCharacter;
diff --git a/src/plugins/platforms/cocoa/qcocoaprintdevice.h b/src/plugins/platforms/cocoa/qcocoaprintdevice.h
deleted file mode 100644
index d267343b0e..0000000000
--- a/src/plugins/platforms/cocoa/qcocoaprintdevice.h
+++ /dev/null
@@ -1,124 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 John Layt <jlayt@kde.org>
-** 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 QCOCOAPRINTDEVICE_H
-#define QCOCOAPRINTDEVICE_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists for the convenience
-// of internal files. This header file may change from version to version
-// without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <qpa/qplatformprintdevice.h>
-
-#ifndef QT_NO_PRINTER
-
-#include "qt_mac_p.h"
-
-#include <cups/ppd.h>
-
-QT_BEGIN_NAMESPACE
-
-class QCocoaPrintDevice : public QPlatformPrintDevice
-{
-public:
- QCocoaPrintDevice();
- explicit QCocoaPrintDevice(const QString &id);
- virtual ~QCocoaPrintDevice();
-
- bool isValid() const override;
- bool isDefault() const override;
-
- QPrint::DeviceState state() const override;
-
- QPageSize defaultPageSize() const override;
-
- QMarginsF printableMargins(const QPageSize &pageSize, QPageLayout::Orientation orientation,
- int resolution) const override;
-
- int defaultResolution() const override;
-
- QPrint::InputSlot defaultInputSlot() const override;
-
- QPrint::OutputBin defaultOutputBin() const override;
-
- QPrint::DuplexMode defaultDuplexMode() const override;
-
- QPrint::ColorMode defaultColorMode() const override;
-
- PMPrinter macPrinter() const;
- PMPaper macPaper(const QPageSize &pageSize) const;
-
-protected:
- void loadPageSizes() const override;
- void loadResolutions() const override;
- void loadInputSlots() const override;
- void loadOutputBins() const override;
- void loadDuplexModes() const override;
- void loadColorModes() const override;
-#if QT_CONFIG(mimetype)
- void loadMimeTypes() const override;
-#endif
-
-private:
- QPageSize createPageSize(const PMPaper &paper) const;
- bool openPpdFile();
-
- // Mac Core Printing
- PMPrinter m_printer;
- PMPrintSession m_session;
- mutable QHash<QString, PMPaper> m_macPapers;
-
- // PPD File
- ppd_file_t *m_ppd;
-
- QMarginsF m_customMargins;
- mutable QHash<QString, QMarginsF> m_printableMargins;
-};
-
-QT_END_NAMESPACE
-
-#endif // QT_NO_PRINTER
-#endif // QCOCOAPRINTDEVICE_H
diff --git a/src/plugins/platforms/cocoa/qcocoaprintdevice.mm b/src/plugins/platforms/cocoa/qcocoaprintdevice.mm
deleted file mode 100644
index 7605dc9d1a..0000000000
--- a/src/plugins/platforms/cocoa/qcocoaprintdevice.mm
+++ /dev/null
@@ -1,494 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 John Layt <jlayt@kde.org>
-** 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 "qcocoaprintdevice.h"
-
-#if QT_CONFIG(mimetype)
-#include <QtCore/qmimedatabase.h>
-#endif
-#include <qdebug.h>
-
-QT_BEGIN_NAMESPACE
-
-#ifndef QT_NO_PRINTER
-
-// The CUPS PPD APIs were deprecated in CUPS 1.6/macOS 10.8, but
-// as long as we're supporting RHEL 6, which still ships CUPS 1.4
-// we're not going to rewrite this, as we want to share the code
-// between macOS and Linux for the CUPS-bits. See discussion in
-// https://bugreports.qt.io/browse/QTBUG-56545
-#pragma message "Disabling CUPS PPD deprecation warnings. This should be fixed once we drop support for RHEL6 (QTBUG-56545)"
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wdeprecated-declarations"
-
-static QPrint::DuplexMode macToDuplexMode(const PMDuplexMode &mode)
-{
- if (mode == kPMDuplexTumble)
- return QPrint::DuplexShortSide;
- else if (mode == kPMDuplexNoTumble)
- return QPrint::DuplexLongSide;
- else // kPMDuplexNone or kPMSimplexTumble
- return QPrint::DuplexNone;
-}
-
-QCocoaPrintDevice::QCocoaPrintDevice()
- : QPlatformPrintDevice(),
- m_printer(nullptr),
- m_session(nullptr),
- m_ppd(nullptr)
-{
-}
-
-QCocoaPrintDevice::QCocoaPrintDevice(const QString &id)
- : QPlatformPrintDevice(id),
- m_printer(nullptr),
- m_session(nullptr),
- m_ppd(nullptr)
-{
- if (!id.isEmpty()) {
- m_printer = PMPrinterCreateFromPrinterID(id.toCFString());
- if (m_printer) {
- m_name = QString::fromCFString(PMPrinterGetName(m_printer));
- m_location = QString::fromCFString(PMPrinterGetLocation(m_printer));
- CFStringRef cfMakeAndModel;
- if (PMPrinterGetMakeAndModelName(m_printer, &cfMakeAndModel) == noErr)
- m_makeAndModel = QString::fromCFString(cfMakeAndModel);
- Boolean isRemote;
- if (PMPrinterIsRemote(m_printer, &isRemote) == noErr)
- m_isRemote = isRemote;
- if (PMCreateSession(&m_session) == noErr)
- PMSessionSetCurrentPMPrinter(m_session, m_printer);
-
- // No native api to query these options, need to use PPD directly, note is deprecated from 1.6 onwards
- if (openPpdFile()) {
- // Note this is if the hardware does multiple copies, not if Cups can
- m_supportsMultipleCopies = !m_ppd->manual_copies;
- // Note this is if the hardware does collation, not if Cups can
- ppd_option_t *collate = ppdFindOption(m_ppd, "Collate");
- if (collate)
- m_supportsCollateCopies = true;
- m_supportsCustomPageSizes = m_ppd->custom_max[0] > 0 && m_ppd->custom_max[1] > 0;
- m_minimumPhysicalPageSize = QSize(m_ppd->custom_min[0], m_ppd->custom_min[1]);
- m_maximumPhysicalPageSize = QSize(m_ppd->custom_max[0], m_ppd->custom_max[1]);
- m_customMargins = QMarginsF(m_ppd->custom_margins[0], m_ppd->custom_margins[3],
- m_ppd->custom_margins[2], m_ppd->custom_margins[1]);
- }
- }
- }
-}
-
-QCocoaPrintDevice::~QCocoaPrintDevice()
-{
- if (m_ppd)
- ppdClose(m_ppd);
- foreach (PMPaper paper, m_macPapers)
- PMRelease(paper);
- // Releasing the session appears to also release the printer
- if (m_session)
- PMRelease(m_session);
- else if (m_printer)
- PMRelease(m_printer);
-}
-
-bool QCocoaPrintDevice::isValid() const
-{
- return m_printer ? true : false;
-}
-
-bool QCocoaPrintDevice::isDefault() const
-{
- return PMPrinterIsDefault(m_printer);
-}
-
-QPrint::DeviceState QCocoaPrintDevice::state() const
-{
- PMPrinterState state;
- if (PMPrinterGetState(m_printer, &state) == noErr) {
- if (state == kPMPrinterIdle)
- return QPrint::Idle;
- else if (state == kPMPrinterProcessing)
- return QPrint::Active;
- else if (state == kPMPrinterStopped)
- return QPrint::Error;
- }
- return QPrint::Error;
-}
-
-QPageSize QCocoaPrintDevice::createPageSize(const PMPaper &paper) const
-{
- CFStringRef key;
- double width;
- double height;
- CFStringRef localizedName;
- if (PMPaperGetPPDPaperName(paper, &key) == noErr
- && PMPaperGetWidth(paper, &width) == noErr
- && PMPaperGetHeight(paper, &height) == noErr
- && PMPaperCreateLocalizedName(paper, m_printer, &localizedName) == noErr) {
- QPageSize pageSize = QPlatformPrintDevice::createPageSize(QString::fromCFString(key),QSize(width, height),
- QString::fromCFString(localizedName));
- CFRelease(localizedName);
- return pageSize;
- }
- return QPageSize();
-}
-
-void QCocoaPrintDevice::loadPageSizes() const
-{
- m_pageSizes.clear();
- foreach (PMPaper paper, m_macPapers)
- PMRelease(paper);
- m_macPapers.clear();
- m_printableMargins.clear();
- CFArrayRef paperSizes;
- if (PMPrinterGetPaperList(m_printer, &paperSizes) == noErr) {
- int count = CFArrayGetCount(paperSizes);
- for (int i = 0; i < count; ++i) {
- PMPaper paper = static_cast<PMPaper>(const_cast<void *>(CFArrayGetValueAtIndex(paperSizes, i)));
- QPageSize pageSize = createPageSize(paper);
- if (pageSize.isValid()) {
- m_pageSizes.append(pageSize);
- PMRetain(paper);
- m_macPapers.insert(pageSize.key(), paper);
- PMPaperMargins printMargins;
- PMPaperGetMargins(paper, &printMargins);
- m_printableMargins.insert(pageSize.key(), QMarginsF(printMargins.left, printMargins.top,
- printMargins.right, printMargins.bottom));
- }
- }
- }
- m_havePageSizes = true;
-}
-
-QPageSize QCocoaPrintDevice::defaultPageSize() const
-{
- QPageSize pageSize;
- PMPageFormat pageFormat;
- PMPaper paper;
- if (PMCreatePageFormat(&pageFormat) == noErr) {
- if (PMSessionDefaultPageFormat(m_session, pageFormat) == noErr
- && PMGetPageFormatPaper(pageFormat, &paper) == noErr) {
- pageSize = createPageSize(paper);
- }
- PMRelease(pageFormat);
- }
- return pageSize;
-}
-
-QMarginsF QCocoaPrintDevice::printableMargins(const QPageSize &pageSize,
- QPageLayout::Orientation orientation,
- int resolution) const
-{
- Q_UNUSED(orientation)
- Q_UNUSED(resolution)
- if (!m_havePageSizes)
- loadPageSizes();
- if (m_printableMargins.contains(pageSize.key()))
- return m_printableMargins.value(pageSize.key());
- return m_customMargins;
-}
-
-void QCocoaPrintDevice::loadResolutions() const
-{
- m_resolutions.clear();
- UInt32 count;
- if (PMPrinterGetPrinterResolutionCount(m_printer, &count) == noErr) {
- // 1-based index
- for (UInt32 i = 1; i <= count; ++i) {
- PMResolution resolution;
- if (PMPrinterGetIndexedPrinterResolution(m_printer, i, &resolution) == noErr)
- m_resolutions.append(int(resolution.hRes));
- }
- }
- m_haveResolutions = true;
-}
-
-int QCocoaPrintDevice::defaultResolution() const
-{
- int defaultResolution = 72;
- PMPrintSettings settings;
- if (PMCreatePrintSettings(&settings) == noErr) {
- PMResolution resolution;
- if (PMSessionDefaultPrintSettings(m_session, settings) == noErr
- && PMPrinterGetOutputResolution(m_printer, settings, &resolution) == noErr) {
- // PMPrinterGetOutputResolution usually fails with -9589 kPMKeyNotFound as not set in PPD
- defaultResolution = int(resolution.hRes);
- }
- PMRelease(settings);
- }
- // If no value returned (usually means not set in PPD) then use supported resolutions which
- // OSX will have populated with at least one default value (but why not returned by call?)
- if (defaultResolution <= 0) {
- if (!m_haveResolutions)
- loadResolutions();
- if (m_resolutions.count() > 0)
- return m_resolutions.at(0); // First value or highest? Only likely to be one anyway.
- return 72; // TDOD More sensible default value???
- }
- return defaultResolution;
-}
-
-void QCocoaPrintDevice::loadInputSlots() const
-{
- // NOTE: Implemented in both CUPS and Mac plugins, please keep in sync
- // TODO Deal with concatenated names like Tray1Manual or Tray1_Man,
- // will currently show as CustomInputSlot
- // TODO Deal with separate ManualFeed key
- // Try load standard PPD options first
- m_inputSlots.clear();
- if (m_ppd) {
- ppd_option_t *inputSlots = ppdFindOption(m_ppd, "InputSlot");
- if (inputSlots) {
- for (int i = 0; i < inputSlots->num_choices; ++i)
- m_inputSlots.append(QPrintUtils::ppdChoiceToInputSlot(inputSlots->choices[i]));
- }
- // If no result, try just the default
- if (m_inputSlots.size() == 0) {
- inputSlots = ppdFindOption(m_ppd, "DefaultInputSlot");
- if (inputSlots)
- m_inputSlots.append(QPrintUtils::ppdChoiceToInputSlot(inputSlots->choices[0]));
- }
- }
- // If still no result, just use Auto
- if (m_inputSlots.size() == 0)
- m_inputSlots.append(QPlatformPrintDevice::defaultInputSlot());
- m_haveInputSlots = true;
-}
-
-QPrint::InputSlot QCocoaPrintDevice::defaultInputSlot() const
-{
- // No native api to query, use PPD directly
- // NOTE: Implemented in both CUPS and Mac plugins, please keep in sync
- // Try load standard PPD option first
- if (m_ppd) {
- ppd_option_t *inputSlot = ppdFindOption(m_ppd, "DefaultInputSlot");
- if (inputSlot)
- return QPrintUtils::ppdChoiceToInputSlot(inputSlot->choices[0]);
- // If no result, then try a marked option
- ppd_choice_t *defaultChoice = ppdFindMarkedChoice(m_ppd, "InputSlot");
- if (defaultChoice)
- return QPrintUtils::ppdChoiceToInputSlot(*defaultChoice);
- }
- // Otherwise return Auto
- return QPlatformPrintDevice::defaultInputSlot();
-}
-
-void QCocoaPrintDevice::loadOutputBins() const
-{
- // No native api to query, use PPD directly
- // NOTE: Implemented in both CUPS and Mac plugins, please keep in sync
- m_outputBins.clear();
- if (m_ppd) {
- ppd_option_t *outputBins = ppdFindOption(m_ppd, "OutputBin");
- if (outputBins) {
- for (int i = 0; i < outputBins->num_choices; ++i)
- m_outputBins.append(QPrintUtils::ppdChoiceToOutputBin(outputBins->choices[i]));
- }
- // If no result, try just the default
- if (m_outputBins.size() == 0) {
- outputBins = ppdFindOption(m_ppd, "DefaultOutputBin");
- if (outputBins)
- m_outputBins.append(QPrintUtils::ppdChoiceToOutputBin(outputBins->choices[0]));
- }
- }
- // If still no result, just use Auto
- if (m_outputBins.size() == 0)
- m_outputBins.append(QPlatformPrintDevice::defaultOutputBin());
- m_haveOutputBins = true;
-}
-
-QPrint::OutputBin QCocoaPrintDevice::defaultOutputBin() const
-{
- // No native api to query, use PPD directly
- // NOTE: Implemented in both CUPS and Mac plugins, please keep in sync
- // Try load standard PPD option first
- if (m_ppd) {
- ppd_option_t *outputBin = ppdFindOption(m_ppd, "DefaultOutputBin");
- if (outputBin)
- return QPrintUtils::ppdChoiceToOutputBin(outputBin->choices[0]);
- // If no result, then try a marked option
- ppd_choice_t *defaultChoice = ppdFindMarkedChoice(m_ppd, "OutputBin");
- if (defaultChoice)
- return QPrintUtils::ppdChoiceToOutputBin(*defaultChoice);
- }
- // Otherwise return AutoBin
- return QPlatformPrintDevice::defaultOutputBin();
-}
-
-void QCocoaPrintDevice::loadDuplexModes() const
-{
- // No native api to query, use PPD directly
- // NOTE: Implemented in both CUPS and Mac plugins, please keep in sync
- // Try load standard PPD options first
- m_duplexModes.clear();
- if (m_ppd) {
- ppd_option_t *duplexModes = ppdFindOption(m_ppd, "Duplex");
- if (duplexModes) {
- for (int i = 0; i < duplexModes->num_choices; ++i)
- m_duplexModes.append(QPrintUtils::ppdChoiceToDuplexMode(duplexModes->choices[i].choice));
- }
- // If no result, try just the default
- if (m_duplexModes.size() == 0) {
- duplexModes = ppdFindOption(m_ppd, "DefaultDuplex");
- if (duplexModes)
- m_duplexModes.append(QPrintUtils::ppdChoiceToDuplexMode(duplexModes->choices[0].choice));
- }
- }
- // If still no result, or not added in PPD, then add None
- if (m_duplexModes.size() == 0 || !m_duplexModes.contains(QPrint::DuplexNone))
- m_duplexModes.append(QPrint::DuplexNone);
- // If have both modes, then can support DuplexAuto
- if (m_duplexModes.contains(QPrint::DuplexLongSide) && m_duplexModes.contains(QPrint::DuplexShortSide))
- m_duplexModes.append(QPrint::DuplexAuto);
- m_haveDuplexModes = true;
-}
-
-QPrint::DuplexMode QCocoaPrintDevice::defaultDuplexMode() const
-{
- QPrint::DuplexMode defaultMode = QPrint::DuplexNone;
- PMPrintSettings settings;
- if (PMCreatePrintSettings(&settings) == noErr) {
- PMDuplexMode duplexMode;
- if (PMSessionDefaultPrintSettings(m_session, settings) == noErr
- && PMGetDuplex(settings, &duplexMode) == noErr) {
- defaultMode = macToDuplexMode(duplexMode);
- }
- PMRelease(settings);
- }
- return defaultMode;
-}
-
-void QCocoaPrintDevice::loadColorModes() const
-{
- // No native api to query, use PPD directly
- m_colorModes.clear();
- m_colorModes.append(QPrint::GrayScale);
- if (!m_ppd || (m_ppd && m_ppd->color_device))
- m_colorModes.append(QPrint::Color);
- m_haveColorModes = true;
-}
-
-QPrint::ColorMode QCocoaPrintDevice::defaultColorMode() const
-{
- // No native api to query, use PPD directly
- // NOTE: Implemented in both CUPS and Mac plugins, please keep in sync
- // Not a proper option, usually only know if supports color or not, but some
- // users known to abuse ColorModel to always force GrayScale.
- if (m_ppd && supportedColorModes().contains(QPrint::Color)) {
- ppd_option_t *colorModel = ppdFindOption(m_ppd, "DefaultColorModel");
- if (!colorModel)
- colorModel = ppdFindOption(m_ppd, "ColorModel");
- if (!colorModel || qstrcmp(colorModel->defchoice, "Gray") != 0)
- return QPrint::Color;
- }
- return QPrint::GrayScale;
-}
-
-#if QT_CONFIG(mimetype)
-void QCocoaPrintDevice::loadMimeTypes() const
-{
- // TODO Check how settings affect returned list
- m_mimeTypes.clear();
- QMimeDatabase db;
- PMPrintSettings settings;
- if (PMCreatePrintSettings(&settings) == noErr) {
- CFArrayRef mimeTypes;
- if (PMPrinterGetMimeTypes(m_printer, settings, &mimeTypes) == noErr) {
- int count = CFArrayGetCount(mimeTypes);
- for (int i = 0; i < count; ++i) {
- CFStringRef mimeName = static_cast<CFStringRef>(const_cast<void *>(CFArrayGetValueAtIndex(mimeTypes, i)));
- QMimeType mimeType = db.mimeTypeForName(QString::fromCFString(mimeName));
- if (mimeType.isValid())
- m_mimeTypes.append(mimeType);
- }
- }
- PMRelease(settings);
- }
- m_haveMimeTypes = true;
-}
-#endif // mimetype
-
-bool QCocoaPrintDevice::openPpdFile()
-{
- if (m_ppd)
- ppdClose(m_ppd);
- m_ppd = nullptr;
- CFURLRef ppdURL = nullptr;
- char ppdPath[MAXPATHLEN];
- if (PMPrinterCopyDescriptionURL(m_printer, kPMPPDDescriptionType, &ppdURL) == noErr
- && ppdURL) {
- if (CFURLGetFileSystemRepresentation(ppdURL, true, (UInt8*)ppdPath, sizeof(ppdPath)))
- m_ppd = ppdOpenFile(ppdPath);
- CFRelease(ppdURL);
- }
- return m_ppd ? true : false;
-}
-
-PMPrinter QCocoaPrintDevice::macPrinter() const
-{
- return m_printer;
-}
-
-// Returns a cached printer PMPaper, or creates and caches a new custom PMPaper
-// Caller should never release a cached PMPaper!
-PMPaper QCocoaPrintDevice::macPaper(const QPageSize &pageSize) const
-{
- if (!m_havePageSizes)
- loadPageSizes();
- // If keys match, then is a supported size or an existing custom size
- if (m_macPapers.contains(pageSize.key()))
- return m_macPapers.value(pageSize.key());
- // For any other page size, whether custom or just unsupported, needs to be a custom PMPaper
- PMPaper paper = nullptr;
- PMPaperMargins paperMargins;
- paperMargins.left = m_customMargins.left();
- paperMargins.right = m_customMargins.right();
- paperMargins.top = m_customMargins.top();
- paperMargins.bottom = m_customMargins.bottom();
- PMPaperCreateCustom(m_printer, QCFString(pageSize.key()), QCFString(pageSize.name()),
- pageSize.sizePoints().width(), pageSize.sizePoints().height(),
- &paperMargins, &paper);
- m_macPapers.insert(pageSize.key(), paper);
- return paper;
-}
-
-#pragma clang diagnostic pop
-
-#endif // QT_NO_PRINTER
-
-QT_END_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/qcocoaprintersupport.h b/src/plugins/platforms/cocoa/qcocoaprintersupport.h
deleted file mode 100644
index 40a638207a..0000000000
--- a/src/plugins/platforms/cocoa/qcocoaprintersupport.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtPrintSupport module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and 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 QCOCOAPRINTERSUPPORT_H
-#define QCOCOAPRINTERSUPPORT_H
-
-#include <qpa/qplatformprintersupport.h>
-#ifndef QT_NO_PRINTER
-
-#include "qt_mac_p.h"
-
-QT_BEGIN_NAMESPACE
-
-class QCocoaPrinterSupport : public QPlatformPrinterSupport
-{
-public:
- QCocoaPrinterSupport();
- ~QCocoaPrinterSupport();
-
- QPrintEngine *createNativePrintEngine(QPrinter::PrinterMode printerMode, const QString &deviceId = QString()) override;
- QPaintEngine *createPaintEngine(QPrintEngine *, QPrinter::PrinterMode printerMode) override;
-
- QPrintDevice createPrintDevice(const QString &id) override;
- QStringList availablePrintDeviceIds() const override;
- QString defaultPrintDeviceId() const override;
-};
-
-QT_END_NAMESPACE
-
-#endif // QT_NO_PRINTER
-#endif // QCOCOAPRINTERSUPPORT_H
diff --git a/src/plugins/platforms/cocoa/qcocoaprintersupport.mm b/src/plugins/platforms/cocoa/qcocoaprintersupport.mm
deleted file mode 100644
index d7eaa469fb..0000000000
--- a/src/plugins/platforms/cocoa/qcocoaprintersupport.mm
+++ /dev/null
@@ -1,107 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtPrintSupport module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and 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 "qcocoaprintersupport.h"
-
-#ifndef QT_NO_PRINTER
-
-#include "qcocoaprintdevice.h"
-#include "qprintengine_mac_p.h"
-
-#include <private/qprinterinfo_p.h>
-
-QT_BEGIN_NAMESPACE
-
-QCocoaPrinterSupport::QCocoaPrinterSupport()
-{ }
-
-QCocoaPrinterSupport::~QCocoaPrinterSupport()
-{ }
-
-QPrintEngine *QCocoaPrinterSupport::createNativePrintEngine(QPrinter::PrinterMode printerMode, const QString &deviceId)
-{
- return new QMacPrintEngine(printerMode, deviceId);
-}
-
-QPaintEngine *QCocoaPrinterSupport::createPaintEngine(QPrintEngine *printEngine, QPrinter::PrinterMode printerMode)
-{
- Q_UNUSED(printerMode);
- /*
- QMacPrintEngine multiply inherits from QPrintEngine and QPaintEngine,
- the cast here allows conversion of QMacPrintEngine* to QPaintEngine*
- */
- return static_cast<QMacPrintEngine *>(printEngine);
-}
-
-QPrintDevice QCocoaPrinterSupport::createPrintDevice(const QString &id)
-{
- return QPlatformPrinterSupport::createPrintDevice(new QCocoaPrintDevice(id));
-}
-
-QStringList QCocoaPrinterSupport::availablePrintDeviceIds() const
-{
- QStringList list;
- QCFType<CFArrayRef> printerList;
- if (PMServerCreatePrinterList(kPMServerLocal, &printerList) == noErr) {
- CFIndex count = CFArrayGetCount(printerList);
- for (CFIndex i = 0; i < count; ++i) {
- PMPrinter printer = static_cast<PMPrinter>(const_cast<void *>(CFArrayGetValueAtIndex(printerList, i)));
- list.append(QString::fromCFString(PMPrinterGetID(printer)));
- }
- }
- return list;
-}
-
-QString QCocoaPrinterSupport::defaultPrintDeviceId() const
-{
- QCFType<CFArrayRef> printerList;
- if (PMServerCreatePrinterList(kPMServerLocal, &printerList) == noErr) {
- CFIndex count = CFArrayGetCount(printerList);
- for (CFIndex i = 0; i < count; ++i) {
- PMPrinter printer = static_cast<PMPrinter>(const_cast<void *>(CFArrayGetValueAtIndex(printerList, i)));
- if (PMPrinterIsDefault(printer))
- return QString::fromCFString(PMPrinterGetID(printer));
- }
- }
- return QString();
-}
-
-QT_END_NAMESPACE
-
-#endif //QT_NO_PRINTER
diff --git a/src/plugins/platforms/cocoa/qcocoaresources.qrc b/src/plugins/platforms/cocoa/qcocoaresources.qrc
deleted file mode 100644
index 1c4b941b9b..0000000000
--- a/src/plugins/platforms/cocoa/qcocoaresources.qrc
+++ /dev/null
@@ -1,7 +0,0 @@
-<RCC>
- <qresource prefix="/qt-project.org/mac/cursors">
- <file>images/spincursor.png</file>
- <file>images/waitcursor.png</file>
- <file>images/sizeallcursor.png</file>
- </qresource>
-</RCC>
diff --git a/src/plugins/platforms/cocoa/qcocoascreen.h b/src/plugins/platforms/cocoa/qcocoascreen.h
index dcf6f1c753..7708dc1968 100644
--- a/src/plugins/platforms/cocoa/qcocoascreen.h
+++ b/src/plugins/platforms/cocoa/qcocoascreen.h
@@ -1,50 +1,19 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QCOCOASCREEN_H
#define QCOCOASCREEN_H
-#include <AppKit/AppKit.h>
-
#include "qcocoacursor.h"
#include <qpa/qplatformintegration.h>
+#include <QtCore/private/qcore_mac_p.h>
+
+#include <CoreGraphics/CoreGraphics.h>
+#include <CoreVideo/CoreVideo.h>
+
+Q_FORWARD_DECLARE_OBJC_CLASS(NSScreen);
+Q_FORWARD_DECLARE_OBJC_CLASS(NSArray);
QT_BEGIN_NAMESPACE
@@ -62,22 +31,24 @@ public:
QRect availableGeometry() const override { return m_availableGeometry; }
int depth() const override { return m_depth; }
QImage::Format format() const override { return m_format; }
+ QColorSpace colorSpace() const override { return m_colorSpace; }
qreal devicePixelRatio() const override { return m_devicePixelRatio; }
QSizeF physicalSize() const override { return m_physicalSize; }
- QDpi logicalDpi() const override { return m_logicalDpi; }
- QDpi logicalBaseDpi() const override { return m_logicalDpi; }
+ QDpi logicalBaseDpi() const override { return QDpi(72, 72); }
qreal refreshRate() const override { return m_refreshRate; }
QString name() const override { return m_name; }
QPlatformCursor *cursor() const override { return m_cursor; }
QWindow *topLevelAt(const QPoint &point) const override;
QList<QPlatformScreen *> virtualSiblings() const override;
QPlatformScreen::SubpixelAntialiasingType subpixelAntialiasingTypeHint() const override;
+ Qt::ScreenOrientation orientation() const override;
// ----------------------------------------------------
+ static NSScreen *nativeScreenForDisplayId(CGDirectDisplayID displayId);
NSScreen *nativeScreen() const;
- void requestUpdate();
+ bool requestUpdate();
void deliverUpdateRequests();
bool isRunningDisplayLink() const;
@@ -96,8 +67,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);
@@ -112,14 +83,15 @@ private:
QRect m_geometry;
QRect m_availableGeometry;
- QDpi m_logicalDpi;
qreal m_refreshRate = 0;
int m_depth = 0;
QString m_name;
QImage::Format m_format;
+ QColorSpace m_colorSpace;
QSizeF m_physicalSize;
QCocoaCursor *m_cursor;
qreal m_devicePixelRatio = 0;
+ qreal m_rotation = 0;
CVDisplayLinkRef m_displayLink = nullptr;
dispatch_source_t m_displayLinkSource = nullptr;
@@ -136,8 +108,14 @@ QDebug operator<<(QDebug debug, const QCocoaScreen *screen);
QT_END_NAMESPACE
+#if defined(__OBJC__)
+
+// @compatibility_alias doesn't work with categories or their methods
+#define qt_displayId QT_MANGLE_NAMESPACE(qt_displayId)
+
@interface NSScreen (QtExtras)
@property(readonly) CGDirectDisplayID qt_displayId;
@end
+#endif
#endif // QCOCOASCREEN_H
diff --git a/src/plugins/platforms/cocoa/qcocoascreen.mm b/src/plugins/platforms/cocoa/qcocoascreen.mm
index e4dd4cf6c6..be562e5455 100644
--- a/src/plugins/platforms/cocoa/qcocoascreen.mm
+++ b/src/plugins/platforms/cocoa/qcocoascreen.mm
@@ -1,41 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <AppKit/AppKit.h>
#include "qcocoascreen.h"
@@ -49,7 +15,9 @@
#include <IOKit/graphics/IOGraphicsLib.h>
#include <QtGui/private/qwindow_p.h>
+#include <QtGui/private/qhighdpiscaling_p.h>
+#include <QtCore/private/qcore_mac_p.h>
#include <QtCore/private/qeventdispatcher_cf_p.h>
QT_BEGIN_NAMESPACE
@@ -72,91 +40,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.
@@ -164,6 +74,18 @@ bool QCocoaScreen::updateScreensIfNeeded()
*/
void QCocoaScreen::updateScreens()
{
+ // Adding, updating, or removing a screen below might trigger
+ // Qt or the application to move a window to a different screen,
+ // recursing back here via QCocoaWindow::windowDidChangeScreen.
+ // The update code is not re-entrant, so bail out if we end up
+ // in this situation. The screens will stabilize eventually.
+ static bool updatingScreens = false;
+ if (updatingScreens) {
+ qCInfo(lcQpaScreen) << "Skipping screen update, already updating";
+ return;
+ }
+ QBoolBlocker recursionGuard(updatingScreens);
+
uint32_t displayCount = 0;
if (CGGetOnlineDisplayList(0, nullptr, &displayCount) != kCGErrorSuccess)
qFatal("Failed to get number of online displays");
@@ -239,6 +161,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()
@@ -272,7 +200,7 @@ QCocoaScreen::~QCocoaScreen()
static QString displayName(CGDirectDisplayID displayID)
{
QIOType<io_iterator_t> iterator;
- if (IOServiceGetMatchingServices(kIOMasterPortDefault,
+ if (IOServiceGetMatchingServices(kIOMainPortDefault,
IOServiceMatching("IODisplayConnect"), &iterator))
return QString();
@@ -282,13 +210,13 @@ static QString displayName(CGDirectDisplayID displayID)
NSDictionary *info = [(__bridge NSDictionary*)IODisplayCreateInfoDictionary(
display, kIODisplayOnlyPreferredName) autorelease];
- if ([[info objectForKey:@kDisplayVendorID] longValue] != CGDisplayVendorNumber(displayID))
+ if ([[info objectForKey:@kDisplayVendorID] unsignedIntValue] != CGDisplayVendorNumber(displayID))
continue;
- if ([[info objectForKey:@kDisplayProductID] longValue] != CGDisplayModelNumber(displayID))
+ if ([[info objectForKey:@kDisplayProductID] unsignedIntValue] != CGDisplayModelNumber(displayID))
continue;
- if ([[info objectForKey:@kDisplaySerialNumber] longValue] != CGDisplaySerialNumber(displayID))
+ if ([[info objectForKey:@kDisplaySerialNumber] unsignedIntValue] != CGDisplaySerialNumber(displayID))
continue;
NSDictionary *localizedNames = [info objectForKey:@kDisplayProductName];
@@ -310,14 +238,17 @@ 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);
+ const double previousRotation = m_rotation;
// The reference screen for the geometry is always the primary screen
QRectF primaryScreenGeometry = QRectF::fromCGRect(CGDisplayBounds(CGMainDisplayID()));
@@ -328,24 +259,34 @@ void QCocoaScreen::update(CGDirectDisplayID displayId)
m_format = QImage::Format_RGB32;
m_depth = NSBitsPerPixelFromDepth(nsScreen.depth);
+ m_colorSpace = QColorSpace::fromIccProfile(QByteArray::fromNSData(nsScreen.colorSpace.ICCProfileData));
+ if (!m_colorSpace.isValid()) {
+ qCWarning(lcQpaScreen) << "Failed to parse ICC profile for" << nsScreen.colorSpace
+ << "with ICC data" << nsScreen.colorSpace.ICCProfileData
+ << "- Falling back to sRGB";
+ m_colorSpace = QColorSpace::SRgb;
+ }
CGSize size = CGDisplayScreenSize(m_displayId);
m_physicalSize = QSizeF(size.width, size.height);
- m_logicalDpi.first = 72;
- m_logicalDpi.second = 72;
QCFType<CGDisplayModeRef> displayMode = CGDisplayCopyDisplayMode(m_displayId);
float refresh = CGDisplayModeGetRefreshRate(displayMode);
m_refreshRate = refresh > 0 ? refresh : 60.0;
+ m_rotation = CGDisplayRotation(displayId);
- m_name = displayName(m_displayId);
+ if (@available(macOS 10.15, *))
+ m_name = QString::fromNSString(nsScreen.localizedName);
+ else
+ m_name = displayName(m_displayId);
const bool didChangeGeometry = m_geometry != previousGeometry || m_availableGeometry != previousAvailableGeometry;
+ if (m_rotation != previousRotation)
+ QWindowSystemInterface::handleScreenOrientationChange(screen(), orientation());
+
if (didChangeGeometry)
QWindowSystemInterface::handleScreenGeometryChange(screen(), geometry(), availableGeometry());
- if (m_logicalDpi != previousLogicalDpi)
- QWindowSystemInterface::handleScreenLogicalDotsPerInchChange(screen(), m_logicalDpi.first, m_logicalDpi.second);
if (m_refreshRate != previousRefreshRate)
QWindowSystemInterface::handleScreenRefreshRateChange(screen(), m_refreshRate);
}
@@ -354,19 +295,33 @@ void QCocoaScreen::update(CGDirectDisplayID displayId)
Q_LOGGING_CATEGORY(lcQpaScreenUpdates, "qt.qpa.screen.updates", QtCriticalMsg);
-void QCocoaScreen::requestUpdate()
+bool QCocoaScreen::requestUpdate()
{
Q_ASSERT(m_displayId);
+ if (!isOnline()) {
+ qCDebug(lcQpaScreenUpdates) << this << "is not online. Ignoring update request";
+ return false;
+ }
+
if (!m_displayLink) {
- CVDisplayLinkCreateWithCGDisplay(m_displayId, &m_displayLink);
+ qCDebug(lcQpaScreenUpdates) << "Creating display link for" << this;
+ if (CVDisplayLinkCreateWithCGDisplay(m_displayId, &m_displayLink) != kCVReturnSuccess) {
+ qCWarning(lcQpaScreenUpdates) << "Failed to create display link for" << this;
+ return false;
+ }
+ if (auto displayId = CVDisplayLinkGetCurrentCGDisplay(m_displayLink); displayId != m_displayId) {
+ qCWarning(lcQpaScreenUpdates) << "Unexpected display" << displayId << "for display link";
+ CVDisplayLinkRelease(m_displayLink);
+ m_displayLink = nullptr;
+ return false;
+ }
CVDisplayLinkSetOutputCallback(m_displayLink, [](CVDisplayLinkRef, const CVTimeStamp*,
const CVTimeStamp*, CVOptionFlags, CVOptionFlags*, void* displayLinkContext) -> int {
// FIXME: It would be nice if update requests would include timing info
static_cast<QCocoaScreen*>(displayLinkContext)->deliverUpdateRequests();
return kCVReturnSuccess;
}, this);
- qCDebug(lcQpaScreenUpdates) << "Display link created for" << this;
// During live window resizing -[NSWindow _resizeWithEvent:] will spin a local event loop
// in event-tracking mode, dequeuing only the mouse drag events needed to update the window's
@@ -421,6 +376,8 @@ void QCocoaScreen::requestUpdate()
qCDebug(lcQpaScreenUpdates) << "Starting display link for" << this;
CVDisplayLinkStart(m_displayLink);
}
+
+ return true;
}
// Helper to allow building up debug output in multiple steps
@@ -514,6 +471,25 @@ void QCocoaScreen::deliverUpdateRequests()
if (!platformWindow->updatesWithDisplayLink())
continue;
+ // QTBUG-107198: Skip updates in a live resize for a better resize experience.
+ if (platformWindow->isContentView() && platformWindow->view().inLiveResize) {
+ const QSurface::SurfaceType surfaceType = window->surfaceType();
+ const bool usesMetalLayer = surfaceType == QWindow::MetalSurface || surfaceType == QWindow::VulkanSurface;
+ const bool usesNonDefaultContentsPlacement = [platformWindow->view() layerContentsPlacement]
+ != NSViewLayerContentsPlacementScaleAxesIndependently;
+ if (usesMetalLayer && usesNonDefaultContentsPlacement) {
+ static bool deliverDisplayLinkUpdatesDuringLiveResize =
+ qEnvironmentVariableIsSet("QT_MAC_DISPLAY_LINK_UPDATE_IN_RESIZE");
+ if (!deliverDisplayLinkUpdatesDuringLiveResize) {
+ // Must keep the link running, we do not know what the event
+ // handlers for UpdateRequest (which is not sent now) would do,
+ // would they trigger a new requestUpdate() or not.
+ pauseUpdates = false;
+ continue;
+ }
+ }
+ }
+
platformWindow->deliverUpdateRequest();
// Another update request was triggered, keep the display link running
@@ -551,100 +527,153 @@ QPlatformScreen::SubpixelAntialiasingType QCocoaScreen::subpixelAntialiasingType
return type;
}
+Qt::ScreenOrientation QCocoaScreen::orientation() const
+{
+ if (m_rotation == 0)
+ return Qt::LandscapeOrientation;
+ if (m_rotation == 90)
+ return Qt::PortraitOrientation;
+ if (m_rotation == 180)
+ return Qt::InvertedLandscapeOrientation;
+ if (m_rotation == 270)
+ return Qt::InvertedPortraitOrientation;
+ return QPlatformScreen::orientation();
+}
+
QWindow *QCocoaScreen::topLevelAt(const QPoint &point) const
{
- NSPoint screenPoint = mapToNative(point);
-
- // Search (hit test) for the top-level window. [NSWidow windowNumberAtPoint:
- // belowWindowWithWindowNumber] may return windows that are not interesting
- // to Qt. The search iterates until a suitable window or no window is found.
- NSInteger topWindowNumber = 0;
- QWindow *window = nullptr;
- do {
- // Get the top-most window, below any previously rejected window.
- topWindowNumber = [NSWindow windowNumberAtPoint:screenPoint
- belowWindowWithWindowNumber:topWindowNumber];
-
- // Continue the search if the window does not belong to this process.
- NSWindow *nsWindow = [NSApp windowWithWindowNumber:topWindowNumber];
- if (!nsWindow)
- continue;
+ __block QWindow *window = nullptr;
+ [NSApp enumerateWindowsWithOptions:NSWindowListOrderedFrontToBack
+ usingBlock:^(NSWindow *nsWindow, BOOL *stop) {
+ if (!nsWindow)
+ return;
- // Continue the search if the window does not belong to Qt.
- if (![nsWindow conformsToProtocol:@protocol(QNSWindowProtocol)])
- continue;
+ // Continue the search if the window does not belong to Qt
+ if (![nsWindow conformsToProtocol:@protocol(QNSWindowProtocol)])
+ return;
- QCocoaWindow *cocoaWindow = qnsview_cast(nsWindow.contentView).platformWindow;
- if (!cocoaWindow)
- continue;
- window = cocoaWindow->window();
+ QCocoaWindow *cocoaWindow = qnsview_cast(nsWindow.contentView).platformWindow;
+ if (!cocoaWindow)
+ return;
- // Continue the search if the window is not a top-level window.
- if (!window->isTopLevel())
- continue;
+ QWindow *w = cocoaWindow->window();
+ if (!w->isVisible())
+ return;
- // Stop searching. The current window is the correct window.
- break;
- } while (topWindowNumber > 0);
+ auto nativeGeometry = QHighDpi::toNativePixels(w->geometry(), w);
+ if (!nativeGeometry.contains(point))
+ return;
+
+ QRegion mask = QHighDpi::toNativeLocalPosition(w->mask(), w);
+ if (!mask.isEmpty() && !mask.contains(point - nativeGeometry.topLeft()))
+ return;
+
+ window = w;
+
+ // Continue the search if the window is not a top-level window
+ if (!window->isTopLevel())
+ return;
+
+ *stop = true;
+ }
+ ];
return window;
}
+/*!
+ \internal
+
+ Coordinates are in screen coordinates if \a view is 0, otherwise they are in view
+ coordinates.
+*/
QPixmap QCocoaScreen::grabWindow(WId view, int x, int y, int width, int height) const
{
- // Determine the grab rect. FIXME: The rect should be bounded by the view's
- // geometry, but note that for the pixeltool use case that window will be the
- // desktop widget's view, which currently gets resized to fit one screen
- // only, since its NSWindow has the NSWindowStyleMaskTitled flag set.
- Q_UNUSED(view);
+ /*
+ Grab the grabRect section of the specified display into a pixmap that has
+ sRGB color spec. Once Qt supports a fully color-managed flow and conversions
+ that don't lose the colorspec information, we would want the image to maintain
+ the color spec of the display from which it was grabbed. Ultimately, rendering
+ the returned pixmap on the same display from which it was grabbed should produce
+ identical visual results.
+ */
+ auto grabFromDisplay = [](CGDirectDisplayID displayId, const QRect &grabRect) -> QPixmap {
+ QCFType<CGImageRef> image = CGDisplayCreateImageForRect(displayId, grabRect.toCGRect());
+ const QCFType<CGColorSpaceRef> sRGBcolorSpace = CGColorSpaceCreateWithName(kCGColorSpaceSRGB);
+ if (CGImageGetColorSpace(image) != sRGBcolorSpace) {
+ qCDebug(lcQpaScreen) << "applying color correction for display" << displayId;
+ image = CGImageCreateCopyWithColorSpace(image, sRGBcolorSpace);
+ }
+ QPixmap pixmap = QPixmap::fromImage(qt_mac_toQImage(image));
+ pixmap.setDevicePixelRatio(nativeScreenForDisplayId(displayId).backingScaleFactor);
+ return pixmap;
+ };
+
QRect grabRect = QRect(x, y, width, height);
qCDebug(lcQpaScreen) << "input grab rect" << grabRect;
- // Find which displays to grab from, or all of them if the grab size is unspecified
+ if (!view) {
+ // coordinates are relative to the screen
+ if (!grabRect.isValid()) // entire screen
+ grabRect = QRect(QPoint(0, 0), geometry().size());
+ else
+ grabRect.translate(-geometry().topLeft());
+ return grabFromDisplay(displayId(), grabRect);
+ }
+
+ // grab the window; grab rect in window coordinates might span multiple screens
+ NSView *nsView = reinterpret_cast<NSView*>(view);
+ NSPoint windowPoint = [nsView convertPoint:NSMakePoint(0, 0) toView:nil];
+ NSRect screenRect = [nsView.window convertRectToScreen:NSMakeRect(windowPoint.x, windowPoint.y, 1, 1)];
+ QPoint position = mapFromNative(screenRect.origin).toPoint();
+ QSize size = QRectF::fromCGRect(NSRectToCGRect(nsView.bounds)).toRect().size();
+ QRect windowRect = QRect(position, size);
+ if (!grabRect.isValid())
+ grabRect = windowRect;
+ else
+ grabRect.translate(windowRect.topLeft());
+
+ // Find which displays to grab from
const int maxDisplays = 128;
CGDirectDisplayID displays[maxDisplays];
CGDisplayCount displayCount;
- CGRect cgRect = (width < 0 || height < 0) ? CGRectInfinite : grabRect.toCGRect();
+ CGRect cgRect = grabRect.isValid() ? grabRect.toCGRect() : CGRectInfinite;
const CGDisplayErr err = CGGetDisplaysWithRect(cgRect, maxDisplays, displays, &displayCount);
if (err || displayCount == 0)
return QPixmap();
- // If the grab size is not specified, set it to be the bounding box of all screens,
- if (width < 0 || height < 0) {
- QRect windowRect;
- for (uint i = 0; i < displayCount; ++i) {
- QRect displayBounds = QRectF::fromCGRect(CGDisplayBounds(displays[i])).toRect();
- windowRect = windowRect.united(displayBounds);
- }
- if (grabRect.width() < 0)
- grabRect.setWidth(windowRect.width());
- if (grabRect.height() < 0)
- grabRect.setHeight(windowRect.height());
- }
-
qCDebug(lcQpaScreen) << "final grab rect" << grabRect << "from" << displayCount << "displays";
// Grab images from each display
- QVector<QImage> images;
+ QVector<QPixmap> pixmaps;
QVector<QRect> destinations;
for (uint i = 0; i < displayCount; ++i) {
auto display = displays[i];
- QRect displayBounds = QRectF::fromCGRect(CGDisplayBounds(display)).toRect();
- QRect grabBounds = displayBounds.intersected(grabRect);
- QRect displayLocalGrabBounds = QRect(QPoint(grabBounds.topLeft() - displayBounds.topLeft()), grabBounds.size());
- QImage displayImage = qt_mac_toQImage(QCFType<CGImageRef>(CGDisplayCreateImageForRect(display, displayLocalGrabBounds.toCGRect())));
- displayImage.setDevicePixelRatio(displayImage.size().width() / displayLocalGrabBounds.size().width());
- images.append(displayImage);
- QRect destBounds = QRect(QPoint(grabBounds.topLeft() - grabRect.topLeft()), grabBounds.size());
+ const QRect displayBounds = QRectF::fromCGRect(CGDisplayBounds(display)).toRect();
+ const QRect grabBounds = displayBounds.intersected(grabRect);
+ if (grabBounds.isNull()) {
+ destinations.append(QRect());
+ pixmaps.append(QPixmap());
+ continue;
+ }
+ const QRect displayLocalGrabBounds = QRect(QPoint(grabBounds.topLeft() - displayBounds.topLeft()), grabBounds.size());
+
+ qCDebug(lcQpaScreen) << "grab display" << i << "global" << grabBounds << "local" << displayLocalGrabBounds;
+ QPixmap displayPixmap = grabFromDisplay(display, displayLocalGrabBounds);
+ // Fast path for when grabbing from a single screen only
+ if (displayCount == 1)
+ return displayPixmap;
+
+ qCDebug(lcQpaScreen) << "grab sub-image size" << displayPixmap.size() << "devicePixelRatio" << displayPixmap.devicePixelRatio();
+ pixmaps.append(displayPixmap);
+ const QRect destBounds = QRect(QPoint(grabBounds.topLeft() - grabRect.topLeft()), grabBounds.size());
destinations.append(destBounds);
- qCDebug(lcQpaScreen) << "grab display" << i << "global" << grabBounds << "local" << displayLocalGrabBounds
- << "grab image size" << displayImage.size() << "devicePixelRatio" << displayImage.devicePixelRatio();
}
// Determine the highest dpr, which becomes the dpr for the returned pixmap.
qreal dpr = 1.0;
for (uint i = 0; i < displayCount; ++i)
- dpr = qMax(dpr, images.at(i).devicePixelRatio());
+ dpr = qMax(dpr, pixmaps.at(i).devicePixelRatio());
// Allocate target pixmap and draw each screen's content
qCDebug(lcQpaScreen) << "Create grap pixmap" << grabRect.size() << "at devicePixelRatio" << dpr;
@@ -653,7 +682,7 @@ QPixmap QCocoaScreen::grabWindow(WId view, int x, int y, int width, int height)
windowPixmap.fill(Qt::transparent);
QPainter painter(&windowPixmap);
for (uint i = 0; i < displayCount; ++i)
- painter.drawImage(destinations.at(i), images.at(i));
+ painter.drawPixmap(destinations.at(i), pixmaps.at(i));
return windowPixmap;
}
@@ -665,8 +694,8 @@ bool QCocoaScreen::isOnline() const
// returning -1 to signal that the displayId is invalid. Some functions
// will also assert or even crash in this case, so it's important that
// we double check if a display is online before calling other functions.
- auto isOnline = CGDisplayIsOnline(m_displayId);
- static const uint32_t kCGDisplayIsDisconnected = int32_t(-1);
+ int isOnline = CGDisplayIsOnline(m_displayId);
+ static const int kCGDisplayIsDisconnected = 0xffffffff;
return isOnline != kCGDisplayIsDisconnected && isOnline;
}
@@ -705,13 +734,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)
@@ -743,19 +776,23 @@ QCocoaScreen *QCocoaScreen::get(CFUUIDRef uuid)
return nullptr;
}
-NSScreen *QCocoaScreen::nativeScreen() const
+NSScreen *QCocoaScreen::nativeScreenForDisplayId(CGDirectDisplayID displayId)
{
- if (!m_displayId)
- return nil; // The display has been disconnected
-
for (NSScreen *screen in NSScreen.screens) {
- if (screen.qt_displayId == m_displayId)
+ if (screen.qt_displayId == displayId)
return screen;
}
-
return nil;
}
+NSScreen *QCocoaScreen::nativeScreen() const
+{
+ if (!m_displayId)
+ return nil; // The display has been disconnected
+
+ return nativeScreenForDisplayId(m_displayId);
+}
+
CGPoint QCocoaScreen::mapToNative(const QPointF &pos, QCocoaScreen *screen)
{
Q_ASSERT(screen);
@@ -808,10 +845,10 @@ QDebug operator<<(QDebug debug, const QCocoaScreen *screen)
}
#endif // !QT_NO_DEBUG_STREAM
-#include "qcocoascreen.moc"
-
QT_END_NAMESPACE
+#include "qcocoascreen.moc"
+
@implementation NSScreen (QtExtras)
- (CGDirectDisplayID)qt_displayId
diff --git a/src/plugins/platforms/cocoa/qcocoaservices.h b/src/plugins/platforms/cocoa/qcocoaservices.h
index 62a8891f96..a0aec6f16b 100644
--- a/src/plugins/platforms/cocoa/qcocoaservices.h
+++ b/src/plugins/platforms/cocoa/qcocoaservices.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QCOCOADESKTOPSERVICES_H
#define QCOCOADESKTOPSERVICES_H
@@ -47,8 +11,12 @@ QT_BEGIN_NAMESPACE
class QCocoaServices : public QPlatformServices
{
public:
+ bool hasCapability(Capability capability) const override;
+
bool openUrl(const QUrl &url) override;
bool openDocument(const QUrl &url) override;
+
+ QPlatformServiceColorPicker *colorPicker(QWindow *parent) override;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/qcocoaservices.mm b/src/plugins/platforms/cocoa/qcocoaservices.mm
index 1d05db5cdc..4566cbb8f7 100644
--- a/src/plugins/platforms/cocoa/qcocoaservices.mm
+++ b/src/plugins/platforms/cocoa/qcocoaservices.mm
@@ -1,65 +1,56 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qcocoaservices.h"
#include <AppKit/NSWorkspace.h>
+#include <AppKit/NSColorSampler.h>
#include <Foundation/NSURL.h>
#include <QtCore/QUrl>
+#include <QtGui/private/qcoregraphics_p.h>
QT_BEGIN_NAMESPACE
bool QCocoaServices::openUrl(const QUrl &url)
{
- const QString scheme = url.scheme();
- if (scheme.isEmpty())
- return openDocument(url);
return [[NSWorkspace sharedWorkspace] openURL:url.toNSURL()];
}
bool QCocoaServices::openDocument(const QUrl &url)
{
- if (!url.isValid())
- return false;
+ return openUrl(url);
+}
+
+class QCocoaColorPicker : public QPlatformServiceColorPicker
+{
+public:
+ QCocoaColorPicker() : m_colorSampler([NSColorSampler new]) {}
+ ~QCocoaColorPicker() { [m_colorSampler release]; }
+
+ void pickColor() override
+ {
+ [m_colorSampler showSamplerWithSelectionHandler:^(NSColor *selectedColor) {
+ emit colorPicked(qt_mac_toQColor(selectedColor));
+ }];
+ }
+private:
+ NSColorSampler *m_colorSampler = nullptr;
+};
+
+
+QPlatformServiceColorPicker *QCocoaServices::colorPicker(QWindow *parent)
+{
+ Q_UNUSED(parent);
+ return new QCocoaColorPicker;
+}
- return [[NSWorkspace sharedWorkspace] openFile:url.toLocalFile().toNSString()];
+bool QCocoaServices::hasCapability(Capability capability) const
+{
+ switch (capability) {
+ case ColorPicking: return true;
+ default: return false;
+ }
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/qcocoasessionmanager.cpp b/src/plugins/platforms/cocoa/qcocoasessionmanager.cpp
index 74e318b5be..1f44c74aa9 100644
--- a/src/plugins/platforms/cocoa/qcocoasessionmanager.cpp
+++ b/src/plugins/platforms/cocoa/qcocoasessionmanager.cpp
@@ -1,47 +1,11 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 Samuel Gaist <samuel.gaist@idiap.ch>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2019 Samuel Gaist <samuel.gaist@idiap.ch>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QT_NO_SESSIONMANAGER
#include <private/qsessionmanager_p.h>
#include <private/qguiapplication_p.h>
-#include <qcocoasessionmanager.h>
+#include "qcocoasessionmanager.h"
#include <qstring.h>
QT_BEGIN_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/qcocoasessionmanager.h b/src/plugins/platforms/cocoa/qcocoasessionmanager.h
index 89ab7bd157..8b6021c2b5 100644
--- a/src/plugins/platforms/cocoa/qcocoasessionmanager.h
+++ b/src/plugins/platforms/cocoa/qcocoasessionmanager.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 Samuel Gaist <samuel.gaist@idiap.ch>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2019 Samuel Gaist <samuel.gaist@idiap.ch>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QCOCOASESSIONMANAGER_H
#define QCOCOASESSIONMANAGER_H
diff --git a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.h b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.h
index 738c40aba6..75c33cc5a3 100644
--- a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.h
+++ b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.h
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2012 Klaralvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Christoph Schleifenbaum <christoph.schleifenbaum@kdab.com>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2012 Klaralvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Christoph Schleifenbaum <christoph.schleifenbaum@kdab.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QCOCOASYSTEMTRAYICON_P_H
#define QCOCOASYSTEMTRAYICON_P_H
@@ -46,17 +10,28 @@
#if QT_CONFIG(systemtrayicon)
-#include "QtCore/qstring.h"
-#include "QtGui/qpa/qplatformsystemtrayicon.h"
+#include <QtCore/qstring.h>
+#include <QtCore/private/qcore_mac_p.h>
-QT_BEGIN_NAMESPACE
+#include <QtGui/qpa/qplatformsystemtrayicon.h>
+
+#include "qcocoamenu.h"
+
+QT_FORWARD_DECLARE_CLASS(QCocoaSystemTrayIcon);
+
+QT_DECLARE_NAMESPACED_OBJC_INTERFACE(QStatusItemDelegate, NSObject <NSUserNotificationCenterDelegate>
+- (instancetype)initWithSysTray:(QCocoaSystemTrayIcon *)platformSystemTray;
+@property (nonatomic, assign) QCocoaSystemTrayIcon *platformSystemTray;
+)
-class QSystemTrayIconSys;
+Q_FORWARD_DECLARE_OBJC_CLASS(NSStatusItem);
+
+QT_BEGIN_NAMESPACE
class Q_GUI_EXPORT QCocoaSystemTrayIcon : public QPlatformSystemTrayIcon
{
public:
- QCocoaSystemTrayIcon() : m_sys(nullptr) {}
+ QCocoaSystemTrayIcon() {}
void init() override;
void cleanup() override;
@@ -70,8 +45,11 @@ public:
bool isSystemTrayAvailable() const override;
bool supportsMessages() const override;
+ void emitActivated();
+
private:
- QSystemTrayIconSys *m_sys;
+ NSStatusItem *m_statusItem = nullptr;
+ QStatusItemDelegate *m_delegate = nullptr;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
index 559188aa5f..cec8301cf6 100644
--- a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
+++ b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2012 Klaralvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Christoph Schleifenbaum <christoph.schleifenbaum@kdab.com>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2012 Klaralvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Christoph Schleifenbaum <christoph.schleifenbaum@kdab.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
/****************************************************************************
**
@@ -72,6 +36,8 @@
**
****************************************************************************/
+#include <AppKit/AppKit.h>
+
#include "qcocoasystemtrayicon.h"
#ifndef QT_NO_SYSTEMTRAYICON
@@ -83,76 +49,59 @@
#include <QtCore/private/qcore_mac_p.h>
#include "qcocoamenu.h"
+#include "qcocoansmenu.h"
-#include "qt_mac_p.h"
#include "qcocoahelpers.h"
#include "qcocoaintegration.h"
#include "qcocoascreen.h"
#include <QtGui/private/qcoregraphics_p.h>
-#import <AppKit/AppKit.h>
-
-QT_USE_NAMESPACE
+#warning NSUserNotification was deprecated in macOS 11. \
+We should be using UserNotifications.framework instead. \
+See QTBUG-110998 for more information.
+#define NSUserNotificationCenter QT_IGNORE_DEPRECATIONS(NSUserNotificationCenter)
+#define NSUserNotification QT_IGNORE_DEPRECATIONS(NSUserNotification)
-@interface QT_MANGLE_NAMESPACE(QNSStatusItem) : NSObject <NSUserNotificationCenterDelegate>
-@property (nonatomic, assign) QCocoaMenu *menu;
-@property (nonatomic, assign) QIcon icon;
-@property (nonatomic, readonly) NSStatusItem *item;
-@property (nonatomic, readonly) QRectF geometry;
-- (instancetype)initWithSysTray:(QCocoaSystemTrayIcon *)systray;
-- (void)triggerSelector:(id)sender button:(Qt::MouseButton)mouseButton;
-- (void)doubleClickSelector:(id)sender;
-@end
+QT_BEGIN_NAMESPACE
-QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSStatusItem);
+void QCocoaSystemTrayIcon::init()
+{
+ m_statusItem = [[NSStatusBar.systemStatusBar statusItemWithLength:NSSquareStatusItemLength] retain];
-@interface QT_MANGLE_NAMESPACE(QNSImageView) : NSImageView
-@property (nonatomic, assign) BOOL down;
-@property (nonatomic, assign) QNSStatusItem *parent;
-@end
+ m_delegate = [[QStatusItemDelegate alloc] initWithSysTray:this];
-QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSImageView);
+ // In case the status item does not have a menu assigned to it
+ // we fall back to the item's button to detect activation.
+ m_statusItem.button.target = m_delegate;
+ m_statusItem.button.action = @selector(statusItemClicked);
+ [m_statusItem.button sendActionOn:NSEventMaskLeftMouseDown | NSEventMaskRightMouseDown | NSEventMaskOtherMouseDown];
+}
-QT_BEGIN_NAMESPACE
-class QSystemTrayIconSys
+void QCocoaSystemTrayIcon::cleanup()
{
-public:
- QSystemTrayIconSys(QCocoaSystemTrayIcon *sys) {
- item = [[QNSStatusItem alloc] initWithSysTray:sys];
- NSUserNotificationCenter.defaultUserNotificationCenter.delegate = item;
- }
- ~QSystemTrayIconSys() {
- [[[item item] view] setHidden: YES];
- NSUserNotificationCenter *center = NSUserNotificationCenter.defaultUserNotificationCenter;
- if (center.delegate == item)
- center.delegate = nil;
- [item release];
- }
- QNSStatusItem *item;
-};
+ NSUserNotificationCenter *center = NSUserNotificationCenter.defaultUserNotificationCenter;
+ if (center.delegate == m_delegate)
+ center.delegate = nil;
-void QCocoaSystemTrayIcon::init()
-{
- if (!m_sys)
- m_sys = new QSystemTrayIconSys(this);
+ [NSStatusBar.systemStatusBar removeStatusItem:m_statusItem];
+ [m_statusItem release];
+ m_statusItem = nil;
+
+ [m_delegate release];
+ m_delegate = nil;
}
QRect QCocoaSystemTrayIcon::geometry() const
{
- if (!m_sys)
+ if (!m_statusItem)
return QRect();
- const QRectF geom = [m_sys->item geometry];
- if (!geom.isNull())
- return geom.toRect();
- else
- return QRect();
-}
+ if (NSWindow *window = m_statusItem.button.window) {
+ if (QCocoaScreen *screen = QCocoaScreen::get(window.screen))
+ return screen->mapFromNative(window.frame).toRect();
+ }
-void QCocoaSystemTrayIcon::cleanup()
-{
- delete m_sys;
- m_sys = nullptr;
+ return QRect();
}
static bool heightCompareFunction (QSize a, QSize b) { return (a.height() < b.height()); }
@@ -165,17 +114,15 @@ static QList<QSize> sortByHeight(const QList<QSize> &sizes)
void QCocoaSystemTrayIcon::updateIcon(const QIcon &icon)
{
- if (!m_sys)
+ if (!m_statusItem)
return;
- m_sys->item.icon = icon;
-
- // The reccomended maximum title bar icon height is 18 points
+ // The recommended maximum title bar icon height is 18 points
// (device independent pixels). The menu height on past and
// current OS X versions is 22 points. Provide some future-proofing
// by deriving the icon height from the menu height.
const int padding = 4;
- const int menuHeight = [[NSStatusBar systemStatusBar] thickness];
+ const int menuHeight = NSStatusBar.systemStatusBar.thickness;
const int maxImageHeight = menuHeight - padding;
// Select pixmap based on the device pixel height. Ideally we would use
@@ -185,7 +132,7 @@ void QCocoaSystemTrayIcon::updateIcon(const QIcon &icon)
qreal devicePixelRatio = qApp->devicePixelRatio();
const int maxPixmapHeight = maxImageHeight * devicePixelRatio;
QSize selectedSize;
- Q_FOREACH (const QSize& size, sortByHeight(icon.availableSizes())) {
+ for (const QSize& size : sortByHeight(icon.availableSizes())) {
// Select a pixmap based on the height. We want the largest pixmap
// with a height smaller or equal to maxPixmapHeight. The pixmap
// may rectangular; assume it has a reasonable size. If there is
@@ -227,31 +174,49 @@ void QCocoaSystemTrayIcon::updateIcon(const QIcon &icon)
r.moveCenter(fullHeightPixmap.rect().center());
p.drawPixmap(r, pixmap);
}
+ fullHeightPixmap.setDevicePixelRatio(devicePixelRatio);
- NSImage *nsimage = static_cast<NSImage *>(qt_mac_create_nsimage(fullHeightPixmap));
+ auto *nsimage = [NSImage imageFromQImage:fullHeightPixmap.toImage()];
[nsimage setTemplate:icon.isMask()];
- [(NSImageView*)[[m_sys->item item] view] setImage: nsimage];
- [nsimage release];
+ m_statusItem.button.image = nsimage;
+ m_statusItem.button.imageScaling = NSImageScaleProportionallyDown;
}
void QCocoaSystemTrayIcon::updateMenu(QPlatformMenu *menu)
{
- if (!m_sys)
+ auto *nsMenu = menu ? static_cast<QCocoaMenu *>(menu)->nsMenu() : nil;
+ if (m_statusItem.menu == nsMenu)
return;
- m_sys->item.menu = static_cast<QCocoaMenu *>(menu);
- if (menu && [m_sys->item.menu->nsMenu() numberOfItems] > 0) {
- [[m_sys->item item] setHighlightMode:YES];
- } else {
- [[m_sys->item item] setHighlightMode:NO];
+ if (m_statusItem.menu) {
+ [NSNotificationCenter.defaultCenter removeObserver:m_delegate
+ name:NSMenuDidBeginTrackingNotification
+ object:m_statusItem.menu
+ ];
+ }
+
+ m_statusItem.menu = nsMenu;
+
+ if (m_statusItem.menu) {
+ // When a menu is assigned, NSStatusBarButtonCell will intercept the mouse
+ // down to pop up the menu, and we never see the NSStatusBarButton action.
+ // To ensure we emit the 'activated' signal in both cases we detect when
+ // menu starts tracking, which happens before the menu delegate is sent
+ // the menuWillOpen callback we use to emit aboutToShow for the menu.
+ [NSNotificationCenter.defaultCenter addObserver:m_delegate
+ selector:@selector(statusItemMenuBeganTracking:)
+ name:NSMenuDidBeginTrackingNotification
+ object:m_statusItem.menu
+ ];
}
}
void QCocoaSystemTrayIcon::updateToolTip(const QString &toolTip)
{
- if (!m_sys)
+ if (!m_statusItem)
return;
- [[[m_sys->item item] view] setToolTip:toolTip.toNSString()];
+
+ m_statusItem.button.toolTip = toolTip.toNSString();
}
bool QCocoaSystemTrayIcon::isSystemTrayAvailable() const
@@ -267,180 +232,85 @@ bool QCocoaSystemTrayIcon::supportsMessages() const
void QCocoaSystemTrayIcon::showMessage(const QString &title, const QString &message,
const QIcon& icon, MessageIcon, int msecs)
{
- if (!m_sys)
+ if (!m_statusItem)
return;
- NSUserNotification *notification = [[NSUserNotification alloc] init];
- notification.title = [NSString stringWithUTF8String:title.toUtf8().data()];
- notification.informativeText = [NSString stringWithUTF8String:message.toUtf8().data()];
-
- if (!icon.isNull()) {
- auto *nsimage = qt_mac_create_nsimage(icon);
- [nsimage setTemplate:icon.isMask()];
- notification.contentImage = [nsimage autorelease];
- }
+ auto *notification = [[NSUserNotification alloc] init];
+ notification.title = title.toNSString();
+ notification.informativeText = message.toNSString();
+ notification.contentImage = [NSImage imageFromQIcon:icon];
NSUserNotificationCenter *center = NSUserNotificationCenter.defaultUserNotificationCenter;
- center.delegate = m_sys->item;
- [center deliverNotification:notification];
+ center.delegate = m_delegate;
+
+ [center deliverNotification:[notification autorelease]];
+
if (msecs) {
NSTimeInterval timeout = msecs / 1000.0;
[center performSelector:@selector(removeDeliveredNotification:) withObject:notification afterDelay:timeout];
}
- [notification release];
-}
-QT_END_NAMESPACE
-
-@implementation NSStatusItem (Qt)
-@end
-
-@implementation QNSImageView
-- (instancetype)initWithParent:(QNSStatusItem *)myParent {
- self = [super init];
- self.parent = myParent;
- self.down = NO;
- return self;
}
-- (void)menuTrackingDone:(NSNotification *)__unused notification
+void QCocoaSystemTrayIcon::emitActivated()
{
- self.down = NO;
+ auto *mouseEvent = NSApp.currentEvent;
- [self setNeedsDisplay:YES];
-}
-
-- (void)mousePressed:(NSEvent *)mouseEvent
-{
- self.down = YES;
- int clickCount = [mouseEvent clickCount];
- [self setNeedsDisplay:YES];
+ auto activationReason = QPlatformSystemTrayIcon::Unknown;
- if (clickCount == 2) {
- [self menuTrackingDone:nil];
- [self.parent doubleClickSelector:self];
+ if (mouseEvent.clickCount == 2) {
+ activationReason = QPlatformSystemTrayIcon::DoubleClick;
} else {
- [self.parent triggerSelector:self button:cocoaButton2QtButton(mouseEvent)];
+ auto mouseButton = cocoaButton2QtButton(mouseEvent);
+ if (mouseButton == Qt::MiddleButton)
+ activationReason = QPlatformSystemTrayIcon::MiddleClick;
+ else if (mouseButton == Qt::RightButton)
+ activationReason = QPlatformSystemTrayIcon::Context;
+ else
+ activationReason = QPlatformSystemTrayIcon::Trigger;
}
-}
-
-- (void)mouseDown:(NSEvent *)mouseEvent
-{
- [self mousePressed:mouseEvent];
-}
-
-- (void)mouseUp:(NSEvent *)mouseEvent
-{
- Q_UNUSED(mouseEvent);
- [self menuTrackingDone:nil];
-}
-- (void)rightMouseDown:(NSEvent *)mouseEvent
-{
- [self mousePressed:mouseEvent];
+ emit activated(activationReason);
}
-- (void)rightMouseUp:(NSEvent *)mouseEvent
-{
- Q_UNUSED(mouseEvent);
- [self menuTrackingDone:nil];
-}
+QT_END_NAMESPACE
-- (void)otherMouseDown:(NSEvent *)mouseEvent
-{
- [self mousePressed:mouseEvent];
-}
+@implementation QStatusItemDelegate
-- (void)otherMouseUp:(NSEvent *)mouseEvent
+- (instancetype)initWithSysTray:(QCocoaSystemTrayIcon *)platformSystemTray
{
- Q_UNUSED(mouseEvent);
- [self menuTrackingDone:nil];
-}
+ if ((self = [super init]))
+ self.platformSystemTray = platformSystemTray;
-- (void)drawRect:(NSRect)rect {
- [[self.parent item] drawStatusBarBackgroundInRect:rect withHighlight:self.down];
- [super drawRect:rect];
-}
-@end
-
-@implementation QNSStatusItem {
- QCocoaSystemTrayIcon *systray;
- NSStatusItem *item;
- QNSImageView *imageCell;
-}
-
-@synthesize menu = menu;
-@synthesize icon = icon;
-
-- (instancetype)initWithSysTray:(QCocoaSystemTrayIcon *)sys
-{
- self = [super init];
- if (self) {
- item = [[[NSStatusBar systemStatusBar] statusItemWithLength:NSSquareStatusItemLength] retain];
- menu = nullptr;
- systray = sys;
- imageCell = [[QNSImageView alloc] initWithParent:self];
- [item setView: imageCell];
- }
return self;
}
-- (void)dealloc {
- [[NSStatusBar systemStatusBar] removeStatusItem:item];
- [[NSNotificationCenter defaultCenter] removeObserver:imageCell];
- imageCell.parent = nil;
- [imageCell release];
- [item release];
+- (void)dealloc
+{
+ self.platformSystemTray = nullptr;
[super dealloc];
}
-- (NSStatusItem *)item {
- return item;
-}
-
-- (QRectF)geometry {
- if (NSWindow *window = item.view.window) {
- if (QCocoaScreen *screen = QCocoaScreen::get(window.screen))
- return screen->mapFromNative(window.frame);
- }
- return QRectF();
-}
-
-- (void)triggerSelector:(id)sender button:(Qt::MouseButton)mouseButton {
- Q_UNUSED(sender);
- if (!systray)
- return;
-
- if (mouseButton == Qt::MidButton)
- emit systray->activated(QPlatformSystemTrayIcon::MiddleClick);
- else
- emit systray->activated(QPlatformSystemTrayIcon::Trigger);
-
- if (menu) {
- NSMenu *m = menu->nsMenu();
- [[NSNotificationCenter defaultCenter] addObserver:imageCell
- selector:@selector(menuTrackingDone:)
- name:NSMenuDidEndTrackingNotification
- object:m];
- [item popUpStatusItemMenu: m];
- }
+- (void)statusItemClicked
+{
+ self.platformSystemTray->emitActivated();
}
-- (void)doubleClickSelector:(id)sender {
- Q_UNUSED(sender);
- if (!systray)
- return;
- emit systray->activated(QPlatformSystemTrayIcon::DoubleClick);
+- (void)statusItemMenuBeganTracking:(NSNotification*)notification
+{
+ self.platformSystemTray->emitActivated();
}
-- (BOOL)userNotificationCenter:(NSUserNotificationCenter *)center shouldPresentNotification:(NSUserNotification *)notification {
+- (BOOL)userNotificationCenter:(NSUserNotificationCenter *)center shouldPresentNotification:(NSUserNotification *)notification
+{
Q_UNUSED(center);
Q_UNUSED(notification);
return YES;
}
-- (void)userNotificationCenter:(NSUserNotificationCenter *)center didActivateNotification:(NSUserNotification *)notification {
+- (void)userNotificationCenter:(NSUserNotificationCenter *)center didActivateNotification:(NSUserNotification *)notification
+{
[center removeDeliveredNotification:notification];
- emit systray->messageClicked();
+ emit self.platformSystemTray->messageClicked();
}
@end
diff --git a/src/plugins/platforms/cocoa/qcocoatheme.h b/src/plugins/platforms/cocoa/qcocoatheme.h
index 50e56ef1bf..c49d83feae 100644
--- a/src/plugins/platforms/cocoa/qcocoatheme.h
+++ b/src/plugins/platforms/cocoa/qcocoatheme.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QPLATFORMTHEME_COCOA_H
#define QPLATFORMTHEME_COCOA_H
@@ -71,8 +35,10 @@ public:
const QFont *font(Font type = SystemFont) const override;
QPixmap standardPixmap(StandardPixmap sp, const QSizeF &size) const override;
QIcon fileIcon(const QFileInfo &fileInfo, QPlatformTheme::IconOptions options = {}) const override;
+ QIconEngine *createIconEngine(const QString &iconName) const override;
QVariant themeHint(ThemeHint hint) const override;
+ Qt::ColorScheme colorScheme() const override;
QString standardButtonText(int button) const override;
QKeySequence standardButtonShortcut(int button) const override;
@@ -80,12 +46,18 @@ public:
void handleSystemThemeChange();
+#ifndef QT_NO_SHORTCUT
+ QList<QKeySequence> keyBindings(QKeySequence::StandardKey key) const override;
+#endif
+
private:
mutable QPalette *m_systemPalette;
QMacNotificationObserver m_systemColorObserver;
mutable QHash<QPlatformTheme::Palette, QPalette*> m_palettes;
- mutable QHash<QPlatformTheme::Font, QFont*> m_fonts;
QMacKeyValueObserver m_appearanceObserver;
+
+ Qt::ColorScheme m_colorScheme = Qt::ColorScheme::Unknown;
+ void updateColorScheme();
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/qcocoatheme.mm b/src/plugins/platforms/cocoa/qcocoatheme.mm
index a76ba300e9..f4fbfadbe4 100644
--- a/src/plugins/platforms/cocoa/qcocoatheme.mm
+++ b/src/plugins/platforms/cocoa/qcocoatheme.mm
@@ -1,46 +1,9 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
-
-#import <AppKit/AppKit.h>
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <AppKit/AppKit.h>
#include "qcocoatheme.h"
-#include "messages.h"
#include <QtCore/QOperatingSystemVersion>
#include <QtCore/QVariant>
@@ -52,45 +15,27 @@
#include "qcocoahelpers.h"
#include <QtCore/qfileinfo.h>
+#include <QtCore/private/qcore_mac_p.h>
#include <QtGui/private/qfont_p.h>
#include <QtGui/private/qguiapplication_p.h>
#include <QtGui/private/qcoregraphics_p.h>
#include <QtGui/qpainter.h>
#include <QtGui/qtextformat.h>
-#include <QtFontDatabaseSupport/private/qcoretextfontdatabase_p.h>
-#include <QtFontDatabaseSupport/private/qfontengine_coretext_p.h>
-#include <QtThemeSupport/private/qabstractfileiconengine_p.h>
+#include <QtGui/private/qcoretextfontdatabase_p.h>
+#include <QtGui/private/qappleiconengine_p.h>
+#include <QtGui/private/qfontengine_coretext_p.h>
+#include <QtGui/private/qabstractfileiconengine_p.h>
#include <qpa/qplatformdialoghelper.h>
#include <qpa/qplatformintegration.h>
#include <qpa/qplatformnativeinterface.h>
-#ifdef QT_WIDGETS_LIB
-#include <QtWidgets/qtwidgetsglobal.h>
-#if QT_CONFIG(colordialog)
#include "qcocoacolordialoghelper.h"
-#endif
-#if QT_CONFIG(filedialog)
#include "qcocoafiledialoghelper.h"
-#endif
-#if QT_CONFIG(fontdialog)
#include "qcocoafontdialoghelper.h"
-#endif
-#endif
+#include "qcocoamessagedialog.h"
#include <CoreServices/CoreServices.h>
-#if !QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_14)
-@interface NSColor (MojaveForwardDeclarations)
-@property (class, strong, readonly) NSColor *selectedContentBackgroundColor NS_AVAILABLE_MAC(10_14);
-@property (class, strong, readonly) NSColor *unemphasizedSelectedTextBackgroundColor NS_AVAILABLE_MAC(10_14);
-@property (class, strong, readonly) NSColor *unemphasizedSelectedTextColor NS_AVAILABLE_MAC(10_14);
-@property (class, strong, readonly) NSColor *unemphasizedSelectedContentBackgroundColor NS_AVAILABLE_MAC(10_14);
-@property (class, strong, readonly) NSArray<NSColor *> *alternatingContentBackgroundColors NS_AVAILABLE_MAC(10_14);
-// Missing from non-Mojave SDKs, even if introduced in 10.10
-@property (class, strong, readonly) NSColor *linkColor NS_AVAILABLE_MAC(10_10);
-@end
-#endif
-
QT_BEGIN_NAMESPACE
static QPalette *qt_mac_createSystemPalette()
@@ -109,7 +54,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);
@@ -121,19 +65,15 @@ static QPalette *qt_mac_createSystemPalette()
// System palette initialization:
QBrush br = qt_mac_toQBrush([NSColor selectedControlColor]);
palette->setBrush(QPalette::Active, QPalette::Highlight, br);
- if (__builtin_available(macOS 10.14, *)) {
- const auto inactiveHighlight = qt_mac_toQBrush([NSColor unemphasizedSelectedContentBackgroundColor]);
- palette->setBrush(QPalette::Inactive, QPalette::Highlight, inactiveHighlight);
- palette->setBrush(QPalette::Disabled, QPalette::Highlight, inactiveHighlight);
- } else {
- palette->setBrush(QPalette::Inactive, QPalette::Highlight, br);
- palette->setBrush(QPalette::Disabled, QPalette::Highlight, br);
- }
+ const auto inactiveHighlight = qt_mac_toQBrush([NSColor unemphasizedSelectedContentBackgroundColor]);
+ palette->setBrush(QPalette::Inactive, QPalette::Highlight, inactiveHighlight);
+ palette->setBrush(QPalette::Disabled, QPalette::Highlight, inactiveHighlight);
palette->setBrush(QPalette::Shadow, qt_mac_toQColor([NSColor shadowColor]));
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);
@@ -142,6 +82,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);
@@ -149,6 +90,14 @@ static QPalette *qt_mac_createSystemPalette()
palette->setColor(QPalette::Normal, QPalette::Link, qt_mac_toQColor([NSColor linkColor]));
+ qc = qt_mac_toQColor([NSColor placeholderTextColor]);
+ palette->setColor(QPalette::Active, QPalette::PlaceholderText, qc);
+ palette->setColor(QPalette::Inactive, QPalette::PlaceholderText, qc);
+ palette->setColor(QPalette::Disabled, QPalette::PlaceholderText, qc);
+
+ qc = qt_mac_toQColor([NSColor controlAccentColor]);
+ palette->setColor(QPalette::Accent, qc);
+
return palette;
}
@@ -206,17 +155,8 @@ static QHash<QPlatformTheme::Palette, QPalette*> qt_mac_createRolePalettes()
}
if (mac_widget_colors[i].paletteRole == QPlatformTheme::MenuPalette
|| mac_widget_colors[i].paletteRole == QPlatformTheme::MenuBarPalette) {
- NSColor *selectedMenuItemColor = nil;
- if (__builtin_available(macOS 10.14, *)) {
- // Cheap approximation for NSVisualEffectView (see deprecation note for selectedMenuItemTextColor)
- selectedMenuItemColor = [[NSColor selectedContentBackgroundColor] highlightWithLevel:0.4];
- } else {
- // selectedMenuItemColor would presumably be the correct color to use as the background
- // for selected menu items. But that color is always blue, and doesn't follow the
- // appearance color in system preferences. So we therefore deliberatly choose to use
- // keyboardFocusIndicatorColor instead, which appears to have the same color value.
- selectedMenuItemColor = [NSColor keyboardFocusIndicatorColor];
- }
+ // Cheap approximation for NSVisualEffectView (see deprecation note for selectedMenuItemTextColor)
+ auto selectedMenuItemColor = [[NSColor controlAccentColor] highlightWithLevel:0.3];
pal.setBrush(QPalette::Highlight, qt_mac_toQColor(selectedMenuItemColor));
qc = qt_mac_toQColor([NSColor labelColor]);
pal.setBrush(QPalette::ButtonText, qc);
@@ -237,17 +177,10 @@ static QHash<QPlatformTheme::Palette, QPalette*> qt_mac_createRolePalettes()
} else if (mac_widget_colors[i].paletteRole == QPlatformTheme::ItemViewPalette) {
NSArray<NSColor *> *baseColors = nil;
NSColor *activeHighlightColor = nil;
- if (__builtin_available(macOS 10.14, *)) {
- baseColors = [NSColor alternatingContentBackgroundColors];
- activeHighlightColor = [NSColor selectedContentBackgroundColor];
- pal.setBrush(QPalette::Inactive, QPalette::HighlightedText,
- qt_mac_toQBrush([NSColor unemphasizedSelectedTextColor]));
- } else {
- baseColors = [NSColor controlAlternatingRowBackgroundColors];
- activeHighlightColor = [NSColor alternateSelectedControlColor];
- pal.setBrush(QPalette::Inactive, QPalette::HighlightedText,
- pal.brush(QPalette::Active, QPalette::Text));
- }
+ baseColors = [NSColor alternatingContentBackgroundColors];
+ activeHighlightColor = [NSColor selectedContentBackgroundColor];
+ pal.setBrush(QPalette::Inactive, QPalette::HighlightedText,
+ qt_mac_toQBrush([NSColor unemphasizedSelectedTextColor]));
pal.setBrush(QPalette::Base, qt_mac_toQBrush(baseColors[0]));
pal.setBrush(QPalette::AlternateBase, qt_mac_toQBrush(baseColors[1]));
pal.setBrush(QPalette::Active, QPalette::Highlight,
@@ -281,27 +214,24 @@ const char *QCocoaTheme::name = "cocoa";
QCocoaTheme::QCocoaTheme()
: m_systemPalette(nullptr)
{
-#if QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_14)
if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::MacOSMojave) {
m_appearanceObserver = QMacKeyValueObserver(NSApp, @"effectiveAppearance", [this] {
- if (__builtin_available(macOS 10.14, *))
- NSAppearance.currentAppearance = NSApp.effectiveAppearance;
-
+ NSAppearance.currentAppearance = NSApp.effectiveAppearance;
handleSystemThemeChange();
});
}
-#endif
m_systemColorObserver = QMacNotificationObserver(nil,
NSSystemColorsDidChangeNotification, [this] {
handleSystemThemeChange();
});
+
+ updateColorScheme();
}
QCocoaTheme::~QCocoaTheme()
{
reset();
- qDeleteAll(m_fonts);
}
void QCocoaTheme::reset()
@@ -315,6 +245,9 @@ void QCocoaTheme::reset()
void QCocoaTheme::handleSystemThemeChange()
{
reset();
+
+ updateColorScheme();
+
m_systemPalette = qt_mac_createSystemPalette();
m_palettes = qt_mac_createRolePalettes();
@@ -323,39 +256,33 @@ void QCocoaTheme::handleSystemThemeChange()
QFontCache::instance()->clear();
}
- QWindowSystemInterface::handleThemeChange<QWindowSystemInterface::SynchronousDelivery>(nullptr);
+ QWindowSystemInterface::handleThemeChange<QWindowSystemInterface::SynchronousDelivery>();
}
bool QCocoaTheme::usePlatformNativeDialog(DialogType dialogType) const
{
- if (dialogType == QPlatformTheme::FileDialog)
- return true;
-#if defined(QT_WIDGETS_LIB) && QT_CONFIG(colordialog)
- if (dialogType == QPlatformTheme::ColorDialog)
- return true;
-#endif
-#if defined(QT_WIDGETS_LIB) && QT_CONFIG(fontdialog)
- if (dialogType == QPlatformTheme::FontDialog)
+ switch (dialogType) {
+ case QPlatformTheme::FileDialog:
+ case QPlatformTheme::ColorDialog:
+ case QPlatformTheme::FontDialog:
+ case QPlatformTheme::MessageDialog:
return true;
-#endif
- return false;
+ default:
+ return false;
+ }
}
QPlatformDialogHelper *QCocoaTheme::createPlatformDialogHelper(DialogType dialogType) const
{
switch (dialogType) {
-#if defined(QT_WIDGETS_LIB) && QT_CONFIG(filedialog)
case QPlatformTheme::FileDialog:
return new QCocoaFileDialogHelper();
-#endif
-#if defined(QT_WIDGETS_LIB) && QT_CONFIG(colordialog)
case QPlatformTheme::ColorDialog:
return new QCocoaColorDialogHelper();
-#endif
-#if defined(QT_WIDGETS_LIB) && QT_CONFIG(fontdialog)
case QPlatformTheme::FontDialog:
return new QCocoaFontDialogHelper();
-#endif
+ case QPlatformTheme::MessageDialog:
+ return new QCocoaMessageDialog;
default:
return nullptr;
}
@@ -384,12 +311,9 @@ const QPalette *QCocoaTheme::palette(Palette type) const
const QFont *QCocoaTheme::font(Font type) const
{
- if (m_fonts.isEmpty()) {
- const auto *platformIntegration = QGuiApplicationPrivate::platformIntegration();
- const auto *coreTextFontDb = static_cast<QCoreTextFontDatabase *>(platformIntegration->fontDatabase());
- m_fonts = coreTextFontDb->themeFonts();
- }
- return m_fonts.value(type, nullptr);
+ const auto *platformIntegration = QGuiApplicationPrivate::platformIntegration();
+ const auto *coreTextFontDatabase = static_cast<QCoreTextFontDatabase *>(platformIntegration->fontDatabase());
+ return coreTextFontDatabase->themeFont(type);
}
//! \internal
@@ -466,11 +390,11 @@ QPixmap QCocoaTheme::standardPixmap(StandardPixmap sp, const QSizeF &size) const
if (iconType != 0) {
QPixmap pixmap;
IconRef icon = nullptr;
- GetIconRef(kOnSystemDisk, kSystemIconsCreator, iconType, &icon);
+ QT_IGNORE_DEPRECATIONS(GetIconRef(kOnSystemDisk, kSystemIconsCreator, iconType, &icon));
if (icon) {
pixmap = qt_mac_convert_iconref(icon, size.width(), size.height());
- ReleaseIconRef(icon);
+ QT_IGNORE_DEPRECATIONS(ReleaseIconRef(icon));
}
return pixmap;
@@ -486,19 +410,8 @@ public:
QPlatformTheme::IconOptions opts) :
QAbstractFileIconEngine(info, opts) {}
- static QList<QSize> availableIconSizes()
- {
- const qreal devicePixelRatio = qGuiApp->devicePixelRatio();
- const int sizes[] = {
- qRound(16 * devicePixelRatio), qRound(32 * devicePixelRatio),
- qRound(64 * devicePixelRatio), qRound(128 * devicePixelRatio),
- qRound(256 * devicePixelRatio)
- };
- return QAbstractFileIconEngine::toSizeList(sizes, sizes + sizeof(sizes) / sizeof(sizes[0]));
- }
-
- QList<QSize> availableSizes(QIcon::Mode = QIcon::Normal, QIcon::State = QIcon::Off) const override
- { return QCocoaFileIconEngine::availableIconSizes(); }
+ QList<QSize> availableSizes(QIcon::Mode = QIcon::Normal, QIcon::State = QIcon::Off) override
+ { return QAppleIconEngine::availableIconSizes(); }
protected:
QPixmap filePixmap(const QSize &size, QIcon::Mode, QIcon::State) override
@@ -517,11 +430,16 @@ QIcon QCocoaTheme::fileIcon(const QFileInfo &fileInfo, QPlatformTheme::IconOptio
return QIcon(new QCocoaFileIconEngine(fileInfo, iconOptions));
}
+QIconEngine *QCocoaTheme::createIconEngine(const QString &iconName) const
+{
+ return new QAppleIconEngine(iconName);
+}
+
QVariant QCocoaTheme::themeHint(ThemeHint hint) const
{
switch (hint) {
case QPlatformTheme::StyleNames:
- return QStringList(QStringLiteral("macintosh"));
+ return QStringList(QStringLiteral("macOS"));
case QPlatformTheme::DialogButtonBoxLayout:
return QVariant(QPlatformDialogHelper::MacLayout);
case KeyboardScheme:
@@ -530,7 +448,7 @@ QVariant QCocoaTheme::themeHint(ThemeHint hint) const
return QVariant([[NSApplication sharedApplication] isFullKeyboardAccessEnabled] ?
int(Qt::TabFocusAllControls) : int(Qt::TabFocusTextControls | Qt::TabFocusListControls));
case IconPixmapSizes:
- return QVariant::fromValue(QCocoaFileIconEngine::availableIconSizes());
+ return QVariant::fromValue(QAppleIconEngine::availableIconSizes());
case QPlatformTheme::PasswordMaskCharacter:
return QVariant(QChar(0x2022));
case QPlatformTheme::UiEffects:
@@ -539,15 +457,44 @@ QVariant QCocoaTheme::themeHint(ThemeHint hint) const
return QVariant(int(QTextCharFormat::DotLine));
case QPlatformTheme::UseFullScreenForPopupMenu:
return QVariant(bool([[NSApplication sharedApplication] presentationOptions] & NSApplicationPresentationFullScreen));
+ case QPlatformTheme::InteractiveResizeAcrossScreens:
+ return !NSScreen.screensHaveSeparateSpaces;
+ case QPlatformTheme::ShowDirectoriesFirst:
+ return false;
+ case QPlatformTheme::MouseDoubleClickInterval:
+ return NSEvent.doubleClickInterval * 1000;
+ case QPlatformTheme::KeyboardInputInterval:
+ return NSEvent.keyRepeatDelay * 1000;
+ case QPlatformTheme::KeyboardAutoRepeatRate:
+ return 1.0 / NSEvent.keyRepeatInterval;
default:
break;
}
return QPlatformTheme::themeHint(hint);
}
+Qt::ColorScheme QCocoaTheme::colorScheme() const
+{
+ return m_colorScheme;
+}
+
+/*
+ Update the theme's color scheme based on the current appearance.
+
+ We can only reference the appearance on the main thread, but the
+ CoreText font engine needs to know the color scheme, and might be
+ used from secondary threads, so we cache the color scheme.
+*/
+void QCocoaTheme::updateColorScheme()
+{
+ m_colorScheme = qt_mac_applicationIsInDarkMode() ? Qt::ColorScheme::Dark : Qt::ColorScheme::Light;
+}
+
QString QCocoaTheme::standardButtonText(int button) const
{
- return button == QPlatformDialogHelper::Discard ? msgDialogButtonDiscard() : QPlatformTheme::standardButtonText(button);
+ return button == QPlatformDialogHelper::Discard ?
+ QCoreApplication::translate("QCocoaTheme", "Don't Save")
+ : QPlatformTheme::standardButtonText(button);
}
QKeySequence QCocoaTheme::standardButtonShortcut(int button) const
@@ -558,12 +505,16 @@ QKeySequence QCocoaTheme::standardButtonShortcut(int button) const
QPlatformMenuItem *QCocoaTheme::createPlatformMenuItem() const
{
- return new QCocoaMenuItem();
+ auto *menuItem = new QCocoaMenuItem();
+ qCDebug(lcQpaMenus) << "Created" << menuItem;
+ return menuItem;
}
QPlatformMenu *QCocoaTheme::createPlatformMenu() const
{
- return new QCocoaMenu();
+ auto *menu = new QCocoaMenu();
+ qCDebug(lcQpaMenus) << "Created" << menu;
+ return menu;
}
QPlatformMenuBar *QCocoaTheme::createPlatformMenuBar() const
@@ -576,7 +527,46 @@ QPlatformMenuBar *QCocoaTheme::createPlatformMenuBar() const
SLOT(onAppFocusWindowChanged(QWindow*)));
}
- return new QCocoaMenuBar();
+ auto *menuBar = new QCocoaMenuBar();
+ qCDebug(lcQpaMenus) << "Created" << menuBar;
+ return menuBar;
}
+#ifndef QT_NO_SHORTCUT
+QList<QKeySequence> QCocoaTheme::keyBindings(QKeySequence::StandardKey key) const
+{
+ // The default key bindings in QPlatformTheme all hard-coded to use the Ctrl
+ // modifier, to match other platforms. In the normal case, when translating
+ // those to key sequences, we'll end up with Qt::ControlModifier+X, which is
+ // then matched against incoming key events that have been mapped from the
+ // command key to Qt::ControlModifier, and we'll get a match. If, however,
+ // the AA_MacDontSwapCtrlAndMeta application attribute is set, we need to
+ // fix the resulting key sequence so that it will match against unmapped
+ // key events that contain Qt::MetaModifier.
+ auto bindings = QPlatformTheme::keyBindings(key);
+
+ if (qApp->testAttribute(Qt::AA_MacDontSwapCtrlAndMeta)) {
+ static auto swapCtrlMeta = [](QKeyCombination keyCombination) {
+ const auto originalKeyModifiers = keyCombination.keyboardModifiers();
+ auto newKeyboardModifiers = originalKeyModifiers & ~(Qt::ControlModifier | Qt::MetaModifier);
+ if (originalKeyModifiers & Qt::ControlModifier)
+ newKeyboardModifiers |= Qt::MetaModifier;
+ if (originalKeyModifiers & Qt::MetaModifier)
+ newKeyboardModifiers |= Qt::ControlModifier;
+ return QKeyCombination(newKeyboardModifiers, keyCombination.key());
+ };
+
+ QList<QKeySequence> swappedBindings;
+ for (auto binding : bindings) {
+ Q_ASSERT(binding.count() == 1);
+ swappedBindings.append(QKeySequence(swapCtrlMeta(binding[0])));
+ }
+
+ bindings = swappedBindings;
+ }
+
+ return bindings;
+}
+#endif
+
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/qcocoavulkaninstance.h b/src/plugins/platforms/cocoa/qcocoavulkaninstance.h
index 5fe6a612af..fd6b7c6452 100644
--- a/src/plugins/platforms/cocoa/qcocoavulkaninstance.h
+++ b/src/plugins/platforms/cocoa/qcocoavulkaninstance.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of 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$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QCOCOAVULKANINSTANCE_H
#define QCOCOAVULKANINSTANCE_H
@@ -47,9 +11,7 @@
#include <MoltenVK/mvk_vulkan.h>
#include <QtCore/QHash>
-#include <QtVulkanSupport/private/qbasicvulkanplatforminstance_p.h>
-
-#include <AppKit/AppKit.h>
+#include <QtGui/private/qbasicvulkanplatforminstance_p.h>
QT_BEGIN_NAMESPACE
@@ -61,9 +23,11 @@ public:
void createOrAdoptInstance() override;
- VkSurfaceKHR *createSurface(QWindow *window);
- VkSurfaceKHR createSurface(NSView *view);
+ VkSurfaceKHR *surface(QWindow *window);
+
private:
+ VkSurfaceKHR createSurface(NSView *view);
+
QVulkanInstance *m_instance = nullptr;
QLibrary m_lib;
VkSurfaceKHR m_nullSurface = nullptr;
diff --git a/src/plugins/platforms/cocoa/qcocoavulkaninstance.mm b/src/plugins/platforms/cocoa/qcocoavulkaninstance.mm
index 7ce78ee738..d2986ea5e6 100644
--- a/src/plugins/platforms/cocoa/qcocoavulkaninstance.mm
+++ b/src/plugins/platforms/cocoa/qcocoavulkaninstance.mm
@@ -1,41 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of 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$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <AppKit/AppKit.h>
#include "qcocoavulkaninstance.h"
#include "qcocoawindow.h"
@@ -57,12 +23,11 @@ void QCocoaVulkanInstance::createOrAdoptInstance()
initInstance(m_instance, QByteArrayList() << QByteArrayLiteral("VK_MVK_macos_surface"));
}
-VkSurfaceKHR *QCocoaVulkanInstance::createSurface(QWindow *window)
+VkSurfaceKHR *QCocoaVulkanInstance::surface(QWindow *window)
{
QCocoaWindow *cocoaWindow = static_cast<QCocoaWindow *>(window->handle());
- if (cocoaWindow->m_vulkanSurface)
- destroySurface(cocoaWindow->m_vulkanSurface);
- cocoaWindow->m_vulkanSurface = createSurface(cocoaWindow->m_view);
+ if (!cocoaWindow->m_vulkanSurface)
+ cocoaWindow->m_vulkanSurface = createSurface(cocoaWindow->m_view);
return &cocoaWindow->m_vulkanSurface;
}
@@ -81,7 +46,7 @@ VkSurfaceKHR QCocoaVulkanInstance::createSurface(NSView *view)
surfaceInfo.sType = VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK;
surfaceInfo.pNext = nullptr;
surfaceInfo.flags = 0;
- surfaceInfo.pView = view;
+ surfaceInfo.pView = view.layer;
VkSurfaceKHR surface = nullptr;
VkResult err = m_createSurface(m_vkInst, &surfaceInfo, nullptr, &surface);
diff --git a/src/plugins/platforms/cocoa/qcocoawindow.h b/src/plugins/platforms/cocoa/qcocoawindow.h
index 4bff1de515..ba1bc052fb 100644
--- a/src/plugins/platforms/cocoa/qcocoawindow.h
+++ b/src/plugins/platforms/cocoa/qcocoawindow.h
@@ -1,48 +1,11 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QCOCOAWINDOW_H
#define QCOCOAWINDOW_H
-#include <AppKit/AppKit.h>
-
#include <qpa/qplatformwindow.h>
+#include <qpa/qplatformwindow_p.h>
#include <QRect>
#include <QPointer>
@@ -51,12 +14,22 @@
#endif
#include "qnsview.h"
#include "qnswindow.h"
-#include "qt_mac_p.h"
#if QT_CONFIG(vulkan)
#include <MoltenVK/mvk_vulkan.h>
#endif
+#include <QHash>
+
+Q_FORWARD_DECLARE_OBJC_CLASS(NSWindow);
+Q_FORWARD_DECLARE_OBJC_CLASS(NSView);
+Q_FORWARD_DECLARE_OBJC_CLASS(NSCursor);
+
+#if !defined(__OBJC__)
+using NSInteger = long;
+using NSUInteger = unsigned long;
+#endif
+
QT_BEGIN_NAMESPACE
#ifndef QT_NO_DEBUG_STREAM
@@ -66,9 +39,9 @@ class QDebug;
// QCocoaWindow
//
// QCocoaWindow is an NSView (not an NSWindow!) in the sense
-// that it relies on a NSView for all event handling and
-// graphics output and does not require a NSWindow, except for
-// for the window-related functions like setWindowTitle.
+// that it relies on an NSView for all event handling and
+// graphics output and does not require an NSWindow, except for
+// the window-related functions like setWindowTitle.
//
// As a consequence of this it is possible to embed the QCocoaWindow
// in an NSView hierarchy by getting a pointer to the "backing"
@@ -92,7 +65,8 @@ class QDebug;
class QCocoaMenuBar;
-class QCocoaWindow : public QObject, public QPlatformWindow
+class QCocoaWindow : public QObject, public QPlatformWindow,
+ public QNativeInterface::Private::QCocoaWindow
{
Q_OBJECT
public:
@@ -103,6 +77,7 @@ public:
void setGeometry(const QRect &rect) override;
QRect geometry() const override;
+ QRect normalGeometry() const override;
void setCocoaGeometry(const QRect &rect);
void setVisible(bool visible) override;
@@ -145,13 +120,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();
@@ -162,14 +135,16 @@ 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();
+
+ void windowWillZoom();
bool windowShouldClose();
bool windowIsPopupType(Qt::WindowType type = Qt::Widget) const;
NSInteger windowLevel(Qt::WindowFlags flags);
NSUInteger windowStyleMask(Qt::WindowFlags flags);
- void setWindowZoomButton(Qt::WindowFlags flags);
+ void updateTitleBarButtons(Qt::WindowFlags flags);
+ bool isFixedSize() const;
bool setWindowModified(bool modified) override;
@@ -183,20 +158,22 @@ public:
void setWindowCursor(NSCursor *cursor);
void registerTouch(bool enable);
- void setContentBorderThickness(int topThickness, int bottomThickness);
+
void registerContentBorderArea(quintptr identifier, int upper, int lower);
void setContentBorderAreaEnabled(quintptr identifier, bool enable);
- void setContentBorderEnabled(bool enable);
+ void setContentBorderEnabled(bool enable) override;
bool testContentBorderAreaPosition(int position) const;
void applyContentBorderThickness(NSWindow *window = nullptr);
- void updateNSToolbar();
qreal devicePixelRatio() const override;
QWindow *childWindowAt(QPoint windowPoint);
bool shouldRefuseKeyWindowAndFirstResponder();
- static QPoint bottomLeftClippedByNSWindowOffsetStatic(QWindow *window);
- QPoint bottomLeftClippedByNSWindowOffset() const;
+ bool windowEvent(QEvent *event) override;
+
+ QPoint bottomLeftClippedByNSWindowOffset() const override;
+
+ void updateNormalGeometry();
enum RecreationReason {
RecreationNotNeeded = 0,
@@ -213,7 +190,7 @@ protected:
void recreateWindowIfNeeded();
QCocoaNSWindow *createNSWindow(bool shouldBePanel);
- Qt::WindowState windowState() const;
+ Qt::WindowStates windowState() const;
void applyWindowState(Qt::WindowStates newState);
void toggleMaximized();
void toggleFullScreen();
@@ -229,7 +206,6 @@ public: // for QNSView
bool isContentView() const;
bool alwaysShowToolWindow() const;
- void removeMonitor();
enum HandleFlags {
NoHandleFlags = 0,
@@ -240,34 +216,35 @@ public: // for QNSView
void handleWindowStateChanged(HandleFlags flags = NoHandleFlags);
void handleExposeEvent(const QRegion &region);
- NSView *m_view;
- QCocoaNSWindow *m_nsWindow;
+ static void closeAllPopups();
+ static void setupPopupMonitor();
+ static void removePopupMonitor();
+
+ NSView *m_view = nil;
+ QCocoaNSWindow *m_nsWindow = nil;
- Qt::WindowStates m_lastReportedWindowState;
- Qt::WindowModality m_windowModality;
- QPointer<QWindow> m_enterLeaveTargetWindow;
- bool m_windowUnderMouse;
+ Qt::WindowStates m_lastReportedWindowState = Qt::WindowNoState;
+ Qt::WindowModality m_windowModality = Qt::NonModal;
- bool m_initialized;
- bool m_inSetVisible;
- bool m_inSetGeometry;
- bool m_inSetStyleMask;
- QCocoaMenuBar *m_menubar;
+ static QPointer<QCocoaWindow> s_windowUnderMouse;
- bool m_needsInvalidateShadow;
+ bool m_initialized = false;
+ bool m_inSetVisible = false;
+ bool m_inSetGeometry = false;
+ bool m_inSetStyleMask = false;
- bool m_frameStrutEventsEnabled;
+ QCocoaMenuBar *m_menubar = nullptr;
+
+ bool m_frameStrutEventsEnabled = false;
QRect m_exposedRect;
- int m_registerTouchCount;
- bool m_resizableTransientParent;
+ QRect m_normalGeometry;
+ int m_registerTouchCount = 0;
+ bool m_resizableTransientParent = false;
static const int NoAlertRequest;
- NSInteger m_alertRequest;
- id monitor;
+ NSInteger m_alertRequest = NoAlertRequest;
- bool m_drawContentBorderGradient;
- int m_topContentBorderThickness;
- int m_bottomContentBorderThickness;
+ bool m_drawContentBorderGradient = false;
struct BorderRange {
BorderRange(quintptr i, int u, int l) : identifier(i), upper(u), lower(l) { }
@@ -278,14 +255,19 @@ public: // for QNSView
return upper < right.upper;
}
};
- QHash<quintptr, BorderRange> m_contentBorderAreas; // identifer -> uppper/lower
- QHash<quintptr, bool> m_enabledContentBorderAreas; // identifer -> enabled state (true/false)
+ QHash<quintptr, BorderRange> m_contentBorderAreas; // identifier -> uppper/lower
+ QHash<quintptr, bool> m_enabledContentBorderAreas; // identifier -> enabled state (true/false)
+
+ static inline id s_globalMouseMonitor = 0;
+ static inline id s_applicationActivationObserver = 0;
#if QT_CONFIG(vulkan)
VkSurfaceKHR m_vulkanSurface = nullptr;
#endif
};
+extern const NSNotificationName QCocoaWindowWillReleaseQNSViewNotification;
+
#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug debug, const QCocoaWindow *window);
#endif
diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm
index 28da4fcf5d..4a245a0f8a 100644
--- a/src/plugins/platforms/cocoa/qcocoawindow.mm
+++ b/src/plugins/platforms/cocoa/qcocoawindow.mm
@@ -1,41 +1,9 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <AppKit/AppKit.h>
+#include <QuartzCore/QuartzCore.h>
+
#include "qcocoawindow.h"
#include "qcocoaintegration.h"
#include "qcocoascreen.h"
@@ -57,9 +25,6 @@
#include <QtGui/private/qcoregraphics_p.h>
#include <QtGui/private/qhighdpiscaling_p.h>
-#include <AppKit/AppKit.h>
-#include <QuartzCore/QuartzCore.h>
-
#include <QDebug>
#include <vector>
@@ -75,11 +40,11 @@ Q_LOGGING_CATEGORY(lcCocoaNotifications, "qt.qpa.cocoa.notifications");
static void qRegisterNotificationCallbacks()
{
- static const QLatin1String notificationHandlerPrefix(Q_NOTIFICATION_PREFIX);
+ static const QLatin1StringView notificationHandlerPrefix(Q_NOTIFICATION_PREFIX);
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
- const QMetaObject *metaObject = QMetaType::metaObjectForType(qRegisterMetaType<QCocoaWindow*>());
+ const QMetaObject *metaObject = QMetaType(qRegisterMetaType<QCocoaWindow*>()).metaObject();
Q_ASSERT(metaObject);
for (int i = 0; i < metaObject->methodCount(); ++i) {
@@ -104,7 +69,7 @@ static void qRegisterNotificationCallbacks()
if (QNSView *qnsView = qnsview_cast(notification.object))
cocoaWindows += qnsView.platformWindow;
} else {
- qCWarning(lcCocoaNotifications) << "Unhandled notifcation"
+ qCWarning(lcCocoaNotifications) << "Unhandled notification"
<< notification.name << "for" << notification.object;
return;
}
@@ -131,28 +96,9 @@ static void qRegisterNotificationCallbacks()
Q_CONSTRUCTOR_FUNCTION(qRegisterNotificationCallbacks)
const int QCocoaWindow::NoAlertRequest = -1;
+QPointer<QCocoaWindow> QCocoaWindow::s_windowUnderMouse;
-QCocoaWindow::QCocoaWindow(QWindow *win, WId nativeHandle)
- : QPlatformWindow(win)
- , m_view(nil)
- , m_nsWindow(nil)
- , m_lastReportedWindowState(Qt::WindowNoState)
- , m_windowModality(Qt::NonModal)
- , m_windowUnderMouse(false)
- , m_initialized(false)
- , m_inSetVisible(false)
- , m_inSetGeometry(false)
- , m_inSetStyleMask(false)
- , m_menubar(nullptr)
- , m_needsInvalidateShadow(false)
- , m_frameStrutEventsEnabled(false)
- , m_registerTouchCount(0)
- , m_resizableTransientParent(false)
- , m_alertRequest(NoAlertRequest)
- , monitor(nil)
- , m_drawContentBorderGradient(false)
- , m_topContentBorderThickness(0)
- , m_bottomContentBorderThickness(0)
+QCocoaWindow::QCocoaWindow(QWindow *win, WId nativeHandle) : QPlatformWindow(win)
{
qCDebug(lcQpaWindow) << "QCocoaWindow::QCocoaWindow" << window();
@@ -171,14 +117,32 @@ void QCocoaWindow::initialize()
if (!m_view)
m_view = [[QNSView alloc] initWithCocoaWindow:this];
- setGeometry(initialGeometry(window(), windowGeometry(), defaultWindowWidth, defaultWindowHeight));
+ if (!isForeignWindow()) {
+ // Compute the initial geometry based on the geometry set on the
+ // QWindow. This geometry has already been reflected to the
+ // QPlatformWindow in the constructor, so to ensure that the
+ // resulting setGeometry call does not think the geometry has
+ // already been applied, we reset the QPlatformWindow's view
+ // of the geometry first.
+ auto initialGeometry = QPlatformWindow::initialGeometry(window(),
+ windowGeometry(), defaultWindowWidth, defaultWindowHeight);
+ QPlatformWindow::d_ptr->rect = QRect();
+ setGeometry(initialGeometry);
+
+ setMask(QHighDpi::toNativeLocalRegion(window()->mask(), window()));
+
+ } else {
+ // Pick up essential foreign window state
+ QPlatformWindow::setGeometry(QRectF::fromCGRect(m_view.frame).toRect());
+ }
recreateWindowIfNeeded();
- window()->setGeometry(geometry());
m_initialized = true;
}
+const NSNotificationName QCocoaWindowWillReleaseQNSViewNotification = @"QCocoaWindowWillReleaseQNSViewNotification";
+
QCocoaWindow::~QCocoaWindow()
{
qCDebug(lcQpaWindow) << "QCocoaWindow::~QCocoaWindow" << window();
@@ -186,43 +150,39 @@ QCocoaWindow::~QCocoaWindow()
QMacAutoReleasePool pool;
[m_nsWindow makeFirstResponder:nil];
[m_nsWindow setContentView:nil];
- if ([m_view superview])
- [m_view removeFromSuperview];
- removeMonitor();
+ // Remove from superview only if we have a Qt window parent,
+ // as we don't want to affect window container foreign windows.
+ if (QPlatformWindow::parent())
+ [m_view removeFromSuperview];
// 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
+
+ // Must send notification before calling release, as doing it from
+ // [QNSView dealloc] would mean that any weak references to the view
+ // would already return nil.
+ [NSNotificationCenter.defaultCenter
+ postNotificationName:QCocoaWindowWillReleaseQNSViewNotification
+ object:m_view];
[m_view release];
- [m_nsWindow close];
- [m_nsWindow release];
+ [m_nsWindow closeAndRelease];
}
QSurfaceFormat QCocoaWindow::format() const
{
- QSurfaceFormat format = window()->requestedFormat();
-
- // Upgrade the default surface format to include an alpha channel. The default RGB format
- // causes Cocoa to spend an unreasonable amount of time converting it to RGBA internally.
- if (format.alphaBufferSize() < 0)
- format.setAlphaBufferSize(8);
-
- return format;
+ return window()->requestedFormat();
}
void QCocoaWindow::setGeometry(const QRect &rectIn)
@@ -252,7 +212,7 @@ bool QCocoaWindow::isForeignWindow() const
QRect QCocoaWindow::geometry() const
{
- // QWindows that are embedded in a NSView hiearchy may be considered
+ // QWindows that are embedded in a NSView hierarchy may be considered
// top-level from Qt's point of view but are not from Cocoa's point
// of view. Embedded QWindows get global (screen) geometry.
if (isEmbedded()) {
@@ -267,6 +227,40 @@ QRect QCocoaWindow::geometry() const
return QPlatformWindow::geometry();
}
+/*!
+ \brief the geometry of the window as it will appear when shown as
+ a normal (not maximized or full screen) top-level window.
+
+ For child windows this property always holds an empty rectangle.
+
+ \sa QWidget::normalGeometry()
+*/
+QRect QCocoaWindow::normalGeometry() const
+{
+ if (!isContentView())
+ return QRect();
+
+ // We only persist the normal the geometry when going into
+ // fullscreen and maximized states. For all other cases we
+ // can just report the geometry as is.
+
+ if (!(windowState() & (Qt::WindowFullScreen | Qt::WindowMaximized)))
+ return geometry();
+
+ return m_normalGeometry;
+}
+
+void QCocoaWindow::updateNormalGeometry()
+{
+ if (!isContentView())
+ return;
+
+ if (windowState() != Qt::WindowNoState)
+ return;
+
+ m_normalGeometry = geometry();
+}
+
void QCocoaWindow::setCocoaGeometry(const QRect &rect)
{
qCDebug(lcQpaWindow) << "QCocoaWindow::setCocoaGeometry" << window() << rect;
@@ -298,6 +292,9 @@ bool QCocoaWindow::startSystemMove()
case NSEventTypeRightMouseDown:
case NSEventTypeOtherMouseDown:
case NSEventTypeMouseMoved:
+ case NSEventTypeLeftMouseDragged:
+ case NSEventTypeRightMouseDragged:
+ case NSEventTypeOtherMouseDragged:
// The documentation only describes starting a system move
// based on mouse down events, but move events also work.
[m_view.window performWindowDragWithEvent:NSApp.currentEvent];
@@ -311,6 +308,31 @@ void QCocoaWindow::setVisible(bool visible)
{
qCDebug(lcQpaWindow) << "QCocoaWindow::setVisible" << window() << visible;
+ // Our implementation of setVisible below is not idempotent, as for
+ // modal windows it calls beginSheet/endSheet or starts/ends modal
+ // sessions. However we can't simply guard for m_view.hidden already
+ // having the right state, as the behavior of this function differs
+ // based on whether the window has been initialized or not, as
+ // handleGeometryChange will bail out if the window is still
+ // initializing. Since we know we'll get a second setVisible
+ // call after creation, we can check for that case specifically,
+ // which means we can then safely guard on m_view.hidden changing.
+
+ if (!m_initialized) {
+ qCDebug(lcQpaWindow) << "Window still initializing, skipping setting visibility";
+ return; // We'll get another setVisible call after create is done
+ }
+
+ if (visible == !m_view.hidden && (!isContentView() || visible == m_view.window.visible)) {
+ qCDebug(lcQpaWindow) << "No change in visible status. Ignoring.";
+ return;
+ }
+
+ if (m_inSetVisible) {
+ qCWarning(lcQpaWindow) << "Already setting window visible!";
+ return;
+ }
+
QScopedValueRollback<bool> rollback(m_inSetVisible, true);
QMacAutoReleasePool pool;
@@ -332,11 +354,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.
@@ -354,6 +371,9 @@ void QCocoaWindow::setVisible(bool visible)
}
+ // Make the NSView visible first, before showing the NSWindow (in case of top level windows)
+ m_view.hidden = NO;
+
if (isContentView()) {
QWindowSystemInterface::flushWindowSystemEvents(QEventLoop::ExcludeUserInputEvents);
@@ -364,39 +384,33 @@ 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());
- } else if (m_view.window.canBecomeKeyWindow && !eventDispatcher()->hasModalSession()) {
- [m_view.window makeKeyAndOrderFront:nil];
+ } else if (m_view.window.canBecomeKeyWindow) {
+ bool shouldBecomeKeyNow = !NSApp.modalWindow
+ || m_view.window.worksWhenModal
+ || !NSApp.modalWindow.visible;
+
+ // Panels with becomesKeyOnlyIfNeeded set should not activate until a view
+ // with needsPanelToBecomeKey, for example a line edit, is clicked.
+ if ([m_view.window isKindOfClass:[NSPanel class]])
+ shouldBecomeKeyNow &= !(static_cast<NSPanel*>(m_view.window).becomesKeyOnlyIfNeeded);
+
+ if (shouldBecomeKeyNow)
+ [m_view.window makeKeyAndOrderFront:nil];
+ else
+ [m_view.window orderFront:nil];
} 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;
- 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);
- }];
- }
}
}
-
- // In some cases, e.g. QDockWidget, the content view is hidden before moving to its own
- // Cocoa window, and then shown again. Therefore, we test for the view being hidden even
- // if it's attached to an NSWindow.
- if ([m_view isHidden])
- [m_view setHidden:NO];
-
} else {
// Window not visible, hide it
if (isContentView()) {
@@ -425,14 +439,27 @@ void QCocoaWindow::setVisible(bool visible)
if (mainWindow && [mainWindow canBecomeKeyWindow])
[mainWindow makeKeyWindow];
}
- } else {
- [m_view setHidden:YES];
}
- removeMonitor();
+ // AppKit will in some cases set up the key view loop for child views, even if we
+ // don't set autorecalculatesKeyViewLoop, nor call recalculateKeyViewLoop ourselves.
+ // When a child window is promoted to a top level, AppKit will maintain the key view
+ // loop between the views, even if these views now cross NSWindows, even after we
+ // explicitly call recalculateKeyViewLoop. When the top level is then hidden, AppKit
+ // will complain when -[NSView _setHidden:setNeedsDisplay:] tries to transfer first
+ // responder by reading the nextValidKeyView, and it turns out to live in a different
+ // window. We mitigate this by a last second reset of the first responder, which is
+ // what AppKit also falls back to. It's unclear if the original situation of views
+ // having their nextKeyView pointing to views in other windows is kosher or not.
+ if (m_view.window.firstResponder == m_view && m_view.nextValidKeyView
+ && m_view.nextValidKeyView.window != m_view.window) {
+ qCDebug(lcQpaWindow) << "Detected nextValidKeyView" << m_view.nextValidKeyView
+ << "in different window" << m_view.nextValidKeyView.window
+ << "Resetting" << m_view.window << "first responder to nil.";
+ [m_view.window makeFirstResponder:nil];
+ }
- if (window()->type() == Qt::Popup || window()->type() == Qt::ToolTip)
- QCocoaIntegration::instance()->popupWindowStack()->removeAll(this);
+ m_view.hidden = YES;
if (parentCocoaWindow && window()->type() == Qt::Popup) {
NSWindow *nativeParentWindow = parentCocoaWindow->nativeWindow();
@@ -499,60 +526,110 @@ NSInteger QCocoaWindow::windowLevel(Qt::WindowFlags flags)
NSUInteger QCocoaWindow::windowStyleMask(Qt::WindowFlags flags)
{
const Qt::WindowType type = static_cast<Qt::WindowType>(int(flags & Qt::WindowType_Mask));
- const bool frameless = (flags & Qt::FramelessWindowHint) || windowIsPopupType(type);
-
- // Remove zoom button by disabling resize for CustomizeWindowHint windows, except for
- // Qt::Tool windows (e.g. dock windows) which should always be resizable.
- const bool resizable = !(flags & Qt::CustomizeWindowHint) || (type == Qt::Tool);
-
- // Select base window type. Note that the value of NSBorderlessWindowMask is 0.
- NSUInteger styleMask = (frameless || !resizable) ? NSWindowStyleMaskBorderless : NSWindowStyleMaskResizable;
-
- if (frameless) {
- // No further customizations for frameless since there are no window decorations.
- } else if (flags & Qt::CustomizeWindowHint) {
- if (flags & Qt::WindowTitleHint)
- styleMask |= NSWindowStyleMaskTitled;
- if (flags & Qt::WindowCloseButtonHint)
- styleMask |= NSWindowStyleMaskClosable;
- if (flags & Qt::WindowMinimizeButtonHint)
- styleMask |= NSWindowStyleMaskMiniaturizable;
- if (flags & Qt::WindowMaximizeButtonHint)
- styleMask |= NSWindowStyleMaskResizable;
- } else {
- styleMask |= NSWindowStyleMaskClosable | NSWindowStyleMaskTitled;
- if (type != Qt::Dialog)
- styleMask |= NSWindowStyleMaskMiniaturizable;
- }
+ // Determine initial style mask based on whether the window should
+ // have a frame and title or not. The NSWindowStyleMaskBorderless
+ // and NSWindowStyleMaskTitled styles are mutually exclusive, with
+ // values of 0 and 1 correspondingly.
+ NSUInteger styleMask = [&]{
+ // Honor explicit requests for borderless windows
+ if (flags & Qt::FramelessWindowHint)
+ return NSWindowStyleMaskBorderless;
+
+ // Popup windows should always be borderless
+ if (windowIsPopupType(type))
+ return NSWindowStyleMaskBorderless;
+
+ if (flags & Qt::CustomizeWindowHint) {
+ // CustomizeWindowHint turns off the default window title hints,
+ // so the choice is then up to the user via Qt::WindowTitleHint.
+ return flags & Qt::WindowTitleHint
+ ? NSWindowStyleMaskTitled
+ : NSWindowStyleMaskBorderless;
+ } else {
+ // Otherwise, default to using titled windows
+ return NSWindowStyleMaskTitled;
+ }
+ }();
+
+ // We determine which buttons to show in updateTitleBarButtons,
+ // so we can enable all the relevant style masks here to ensure
+ // that behaviors that don't involve the title bar buttons are
+ // working (for example minimizing frameless windows, or resizing
+ // windows that don't have zoom or fullscreen titlebar buttons).
+ styleMask |= NSWindowStyleMaskClosable
+ | NSWindowStyleMaskMiniaturizable;
+
+ if (type != Qt::Popup) // We only care about popups exactly.
+ styleMask |= NSWindowStyleMaskResizable;
if (type == Qt::Tool)
styleMask |= NSWindowStyleMaskUtilityWindow;
+ // FIXME: Remove use of deprecated style mask
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;
}
-void QCocoaWindow::setWindowZoomButton(Qt::WindowFlags flags)
+bool QCocoaWindow::isFixedSize() const
+{
+ return windowMinimumSize().isValid() && windowMaximumSize().isValid()
+ && windowMinimumSize() == windowMaximumSize();
+}
+
+void QCocoaWindow::updateTitleBarButtons(Qt::WindowFlags windowFlags)
{
if (!isContentView())
return;
- // Disable the zoom (maximize) button for fixed-sized windows and customized
- // no-WindowMaximizeButtonHint windows. From a Qt perspective it migth be expected
- // that the button would be removed in the latter case, but disabling it is more
- // in line with the platform style guidelines.
- bool fixedSizeNoZoom = (windowMinimumSize().isValid() && windowMaximumSize().isValid()
- && windowMinimumSize() == windowMaximumSize());
- bool customizeNoZoom = ((flags & Qt::CustomizeWindowHint)
- && !(flags & (Qt::WindowMaximizeButtonHint | Qt::WindowFullscreenButtonHint)));
- [[m_view.window standardWindowButton:NSWindowZoomButton] setEnabled:!(fixedSizeNoZoom || customizeNoZoom)];
+ static constexpr std::pair<NSWindowButton, Qt::WindowFlags> buttons[] = {
+ { NSWindowCloseButton, Qt::WindowCloseButtonHint },
+ { NSWindowMiniaturizeButton, Qt::WindowMinimizeButtonHint},
+ { NSWindowZoomButton, Qt::WindowMaximizeButtonHint | Qt::WindowFullscreenButtonHint }
+ };
+
+ bool hideButtons = true;
+ for (const auto &[button, buttonHint] : buttons) {
+ // Set up Qt defaults based on window type
+ bool enabled = true;
+ if (button == NSWindowMiniaturizeButton)
+ enabled = window()->type() != Qt::Dialog;
+
+ // Let users override via CustomizeWindowHint
+ if (windowFlags & Qt::CustomizeWindowHint)
+ enabled = windowFlags & buttonHint;
+
+ // Then do some final sanitizations
+
+ if (button == NSWindowZoomButton && isFixedSize())
+ enabled = false;
+
+ // Mimic what macOS natively does for parent windows of modal
+ // sheets, which is to disable the close button, but leave the
+ // other buttons as they were.
+ if (button == NSWindowCloseButton && enabled
+ && QWindowPrivate::get(window())->blockedByModalWindow) {
+ enabled = false;
+ // If we end up having no enabled buttons, our workaround
+ // should not be a reason for hiding all of them.
+ hideButtons = false;
+ }
+
+ [m_view.window standardWindowButton:button].enabled = enabled;
+ hideButtons &= !enabled;
+ }
+
+ // Hide buttons in case we disabled all of them
+ for (const auto &[button, buttonHint] : buttons)
+ [m_view.window standardWindowButton:button].hidden = hideButtons;
}
void QCocoaWindow::setWindowFlags(Qt::WindowFlags flags)
@@ -597,7 +674,7 @@ void QCocoaWindow::setWindowFlags(Qt::WindowFlags flags)
if (!(flags & Qt::FramelessWindowHint))
setWindowTitle(window()->title());
- setWindowZoomButton(flags);
+ updateTitleBarButtons(flags);
// Make window ignore mouse events if WindowTransparentForInput is set.
// Note that ignoresMouseEvents has a special initial state where events
@@ -631,7 +708,7 @@ void QCocoaWindow::applyWindowState(Qt::WindowStates requestedState)
if (!isContentView())
return;
- const Qt::WindowState currentState = windowState();
+ const Qt::WindowState currentState = QWindowPrivate::effectiveState(windowState());
const Qt::WindowState newState = QWindowPrivate::effectiveState(requestedState);
if (newState == currentState)
@@ -663,9 +740,10 @@ void QCocoaWindow::applyWindowState(Qt::WindowStates requestedState)
switch (currentState) {
case Qt::WindowMinimized:
[nsWindow deminiaturize:sender];
- Q_ASSERT_X(windowState() != Qt::WindowMinimized, "QCocoaWindow",
- "[NSWindow deminiaturize:] is synchronous");
- break;
+ // Deminiaturizing is not synchronous, so we need to wait for the
+ // NSWindowDidMiniaturizeNotification before continuing to apply
+ // the new state.
+ return;
case Qt::WindowFullScreen: {
toggleFullScreen();
// Exiting fullscreen is not synchronous, so we need to wait for the
@@ -699,23 +777,27 @@ void QCocoaWindow::applyWindowState(Qt::WindowStates requestedState)
}
}
-Qt::WindowState QCocoaWindow::windowState() const
+Qt::WindowStates QCocoaWindow::windowState() const
{
- // FIXME: Support compound states (Qt::WindowStates)
-
+ Qt::WindowStates states = Qt::WindowNoState;
NSWindow *window = m_view.window;
+
if (window.miniaturized)
- return Qt::WindowMinimized;
- if (window.qt_fullScreen)
- return Qt::WindowFullScreen;
- if ((window.zoomed && !isTransitioningToFullScreen())
- || (m_lastReportedWindowState == Qt::WindowMaximized && isTransitioningToFullScreen()))
- return Qt::WindowMaximized;
+ states |= Qt::WindowMinimized;
+
+ // Full screen and maximized are mutually exclusive, as macOS
+ // will report a full screen window as zoomed.
+ if (window.qt_fullScreen) {
+ states |= Qt::WindowFullScreen;
+ } else if ((window.zoomed && !isTransitioningToFullScreen())
+ || (m_lastReportedWindowState == Qt::WindowMaximized && isTransitioningToFullScreen())) {
+ states |= Qt::WindowMaximized;
+ }
// Note: We do not report Qt::WindowActive, even if isActive()
// is true, as QtGui does not expect this window state to be set.
- return Qt::WindowNoState;
+ return states;
}
void QCocoaWindow::toggleMaximized()
@@ -734,6 +816,11 @@ void QCocoaWindow::toggleMaximized()
window.styleMask &= ~NSWindowStyleMaskResizable;
}
+void QCocoaWindow::windowWillZoom()
+{
+ updateNormalGeometry();
+}
+
void QCocoaWindow::toggleFullScreen()
{
const NSWindow *window = m_view.window;
@@ -752,6 +839,8 @@ void QCocoaWindow::windowWillEnterFullScreen()
if (!isContentView())
return;
+ updateNormalGeometry();
+
// The NSWindow needs to be resizable, otherwise we'll end up with
// the normal window geometry, centered in the middle of the screen
// on a black background. The styleMask will be reset below.
@@ -811,11 +900,6 @@ void QCocoaWindow::windowDidExitFullScreen()
}
}
-void QCocoaWindow::windowWillMiniaturize()
-{
- QCocoaIntegration::instance()->closePopups(window());
-}
-
void QCocoaWindow::windowDidMiniaturize()
{
if (!isContentView())
@@ -829,12 +913,20 @@ void QCocoaWindow::windowDidDeminiaturize()
if (!isContentView())
return;
+ Qt::WindowState requestedState = window()->windowState();
+
handleWindowStateChanged();
+
+ if (requestedState != windowState() && requestedState != Qt::WindowMinimized) {
+ // We were only going out of minimized as an intermediate step before
+ // progressing into the final step, so re-sync the desired state.
+ applyWindowState(requestedState);
+ }
}
void QCocoaWindow::handleWindowStateChanged(HandleFlags flags)
{
- Qt::WindowState currentState = windowState();
+ Qt::WindowStates currentState = windowState();
if (!(flags & HandleUnconditionally) && currentState == m_lastReportedWindowState)
return;
@@ -892,12 +984,11 @@ void QCocoaWindow::setWindowIcon(const QIcon &icon)
QMacAutoReleasePool pool;
if (icon.isNull()) {
- NSWorkspace *workspace = [NSWorkspace sharedWorkspace];
- [iconButton setImage:[workspace iconForFile:m_view.window.representedFilename]];
+ iconButton.image = [NSWorkspace.sharedWorkspace iconForFile:m_view.window.representedFilename];
} else {
- QPixmap pixmap = icon.pixmap(QSize(22, 22));
- NSImage *image = static_cast<NSImage *>(qt_mac_create_nsimage(pixmap));
- [iconButton setImage:[image autorelease]];
+ // Fall back to a size that looks good on the highest resolution screen available
+ auto fallbackSize = iconButton.frame.size.height * qGuiApp->devicePixelRatio();
+ iconButton.image = [NSImage imageFromQIcon:icon withSize:fallbackSize];
}
}
@@ -1010,7 +1101,7 @@ void QCocoaWindow::propagateSizeHints()
window.contentMaxSize = NSSizeFromCGSize(windowMaximumSize().toCGSize());
// The window may end up with a fixed size; in this case the zoom button should be disabled.
- setWindowZoomButton(this->window()->flags());
+ updateTitleBarButtons(this->window()->flags());
// sizeIncrement is observed to take values of (-1, -1) and (0, 0) for windows that should be
// resizable and that have no specific size increment set. Cocoa expects (1.0, 1.0) in this case.
@@ -1038,52 +1129,26 @@ void QCocoaWindow::setMask(const QRegion &region)
{
qCDebug(lcQpaWindow) << "QCocoaWindow::setMask" << window() << region;
- if (m_view.layer) {
- if (!region.isEmpty()) {
- QCFType<CGMutablePathRef> maskPath = CGPathCreateMutable();
- for (const QRect &r : region)
- CGPathAddRect(maskPath, nullptr, r.toCGRect());
- CAShapeLayer *maskLayer = [CAShapeLayer layer];
- maskLayer.path = maskPath;
- m_view.layer.mask = maskLayer;
- } else {
- m_view.layer.mask = nil;
- }
+ if (!region.isEmpty()) {
+ QCFType<CGMutablePathRef> maskPath = CGPathCreateMutable();
+ for (const QRect &r : region)
+ CGPathAddRect(maskPath, nullptr, r.toCGRect());
+ CAShapeLayer *maskLayer = [CAShapeLayer layer];
+ maskLayer.path = maskPath;
+ m_view.layer.mask = maskLayer;
} else {
- if (isContentView()) {
- // Setting the mask requires invalidating the NSWindow shadow, but that needs
- // to happen after the backingstore has been redrawn, so that AppKit can pick
- // up the new window shape based on the backingstore content. Doing a display
- // directly here is not an option, as the window might not be exposed at this
- // time, and so would not result in an updated backingstore.
- m_needsInvalidateShadow = true;
- [m_view setNeedsDisplay:YES];
- }
+ m_view.layer.mask = nil;
}
}
-bool QCocoaWindow::setKeyboardGrabEnabled(bool grab)
+bool QCocoaWindow::setKeyboardGrabEnabled(bool)
{
- qCDebug(lcQpaWindow) << "QCocoaWindow::setKeyboardGrabEnabled" << window() << grab;
- if (!isContentView())
- return false;
-
- if (grab && ![m_view.window isKeyWindow])
- [m_view.window makeKeyWindow];
-
- return true;
+ return false; // FIXME (QTBUG-106597)
}
-bool QCocoaWindow::setMouseGrabEnabled(bool grab)
+bool QCocoaWindow::setMouseGrabEnabled(bool)
{
- qCDebug(lcQpaWindow) << "QCocoaWindow::setMouseGrabEnabled" << window() << grab;
- if (!isContentView())
- return false;
-
- if (grab && ![m_view.window isKeyWindow])
- [m_view.window makeKeyWindow];
-
- return true;
+ return false; // FIXME (QTBUG-106597)
}
WId QCocoaWindow::winId() const
@@ -1095,11 +1160,9 @@ void QCocoaWindow::setParent(const QPlatformWindow *parentWindow)
{
qCDebug(lcQpaWindow) << "QCocoaWindow::setParent" << window() << (parentWindow ? parentWindow->window() : 0);
- // recreate the window for compatibility
- bool unhideAfterRecreate = parentWindow && !isEmbedded() && ![m_view isHidden];
+ // Recreate in case we need to get rid of a NSWindow, or create one
recreateWindowIfNeeded();
- if (unhideAfterRecreate)
- [m_view setHidden:NO];
+
setCocoaGeometry(geometry());
}
@@ -1115,7 +1178,7 @@ NSWindow *QCocoaWindow::nativeWindow() const
void QCocoaWindow::setEmbeddedInForeignView()
{
- // Release any previosly created NSWindow.
+ // Release any previously created NSWindow.
[m_nsWindow closeAndRelease];
m_nsWindow = 0;
}
@@ -1151,12 +1214,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())
@@ -1189,55 +1246,97 @@ void QCocoaWindow::windowDidEndLiveResize()
void QCocoaWindow::windowDidBecomeKey()
{
- if (!isContentView())
+ // The NSWindow we're part of become key. Check if we're the first
+ // responder, and if so, deliver focus window change to our window.
+ if (m_view.window.firstResponder != m_view)
return;
- if (isForeignWindow())
- return;
+ qCDebug(lcQpaWindow) << m_view.window << "became key window."
+ << "Updating focus window to" << this << "with view" << m_view;
- if (m_windowUnderMouse) {
- QPointF windowPoint;
- QPointF screenPoint;
- [qnsview_cast(m_view) convertFromScreen:[NSEvent mouseLocation] toWindowPoint:&windowPoint andScreenPoint:&screenPoint];
- QWindowSystemInterface::handleEnterEvent(m_enterLeaveTargetWindow, windowPoint, screenPoint);
+ if (windowIsPopupType()) {
+ qCDebug(lcQpaWindow) << "Window is popup. Skipping focus window change.";
+ return;
}
- if (!windowIsPopupType())
- QWindowSystemInterface::handleWindowActivated<QWindowSystemInterface::SynchronousDelivery>(window());
+ // See also [QNSView becomeFirstResponder]
+ QWindowSystemInterface::handleFocusWindowChanged<QWindowSystemInterface::SynchronousDelivery>(
+ window(), Qt::ActiveWindowFocusReason);
}
void QCocoaWindow::windowDidResignKey()
{
- if (!isContentView())
+ // The NSWindow we're part of lost key. Check if we're the first
+ // responder, and if so, deliver window deactivation to our window.
+ if (m_view.window.firstResponder != m_view)
return;
- if (isForeignWindow())
+ qCDebug(lcQpaWindow) << m_view.window << "resigned key window."
+ << "Clearing focus window" << this << "with view" << m_view;
+
+ // Make sure popups are closed before we deliver activation changes, which are
+ // otherwise ignored by QApplication.
+ closeAllPopups();
+
+ // The current key window will be non-nil if another window became key. If that
+ // window is a Qt window, we delay the window activation event until the didBecomeKey
+ // notification is delivered to the active window, to ensure an atomic update.
+ NSWindow *newKeyWindow = [NSApp keyWindow];
+ if (newKeyWindow && newKeyWindow != m_view.window
+ && [newKeyWindow conformsToProtocol:@protocol(QNSWindowProtocol)]) {
+ qCDebug(lcQpaWindow) << "New key window" << newKeyWindow
+ << "is Qt window. Deferring focus window change.";
return;
+ }
- // Key window will be non-nil if another window became key, so do not
- // set the active window to zero here -- the new key window's
- // NSWindowDidBecomeKeyNotification hander will change the active window.
- NSWindow *keyWindow = [NSApp keyWindow];
- if (!keyWindow || keyWindow == m_view.window) {
- // No new key window, go ahead and set the active window to zero
- if (!windowIsPopupType())
- QWindowSystemInterface::handleWindowActivated<QWindowSystemInterface::SynchronousDelivery>(0);
+ // Lost key window, go ahead and set the active window to zero
+ if (!windowIsPopupType()) {
+ QWindowSystemInterface::handleFocusWindowChanged<QWindowSystemInterface::SynchronousDelivery>(
+ nullptr, Qt::ActiveWindowFocusReason);
}
}
void QCocoaWindow::windowDidOrderOnScreen()
{
+ // The current mouse window needs to get a leave event when a popup window opens.
+ // For modal dialogs, QGuiApplicationPrivate::showModalWindow takes care of this.
+ if (QWindowPrivate::get(window())->isPopup()) {
+ QWindowSystemInterface::handleLeaveEvent<QWindowSystemInterface::SynchronousDelivery>
+ (QGuiApplicationPrivate::currentMouseWindow);
+ }
+
[m_view setNeedsDisplay:YES];
}
void QCocoaWindow::windowDidOrderOffScreen()
{
handleExposeEvent(QRegion());
+ // We are closing a window, so the window that is now under the mouse
+ // might need to get an Enter event if it isn't already the mouse window.
+ if (window()->type() & Qt::Window) {
+ const QPointF screenPoint = QCocoaScreen::mapFromNative([NSEvent mouseLocation]);
+ if (QWindow *windowUnderMouse = QGuiApplication::topLevelAt(screenPoint.toPoint())) {
+ if (windowUnderMouse != QGuiApplicationPrivate::instance()->currentMouseWindow) {
+ const auto windowPoint = windowUnderMouse->mapFromGlobal(screenPoint);
+ // asynchronous delivery on purpose
+ QWindowSystemInterface::handleEnterEvent<QWindowSystemInterface::AsynchronousDelivery>
+ (windowUnderMouse, windowPoint, screenPoint);
+ }
+ }
+ }
}
void QCocoaWindow::windowDidChangeOcclusionState()
{
- if (m_view.window.occlusionState & NSWindowOcclusionStateVisible)
+ // Note, we don't take the view's hiddenOrHasHiddenAncestor state into
+ // account here, but instead leave that up to handleExposeEvent, just
+ // like all the other signals that could potentially change the exposed
+ // state of the window.
+ bool visible = m_view.window.occlusionState & NSWindowOcclusionStateVisible;
+ qCDebug(lcQpaWindow) << "Occlusion state of" << m_view.window << "for"
+ << window() << "changed to" << (visible ? "visible" : "occluded");
+
+ if (visible)
[m_view setNeedsDisplay:YES];
else
handleExposeEvent(QRegion());
@@ -1249,11 +1348,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
@@ -1266,7 +1369,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);
@@ -1279,22 +1381,24 @@ 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()
{
qCDebug(lcQpaWindow) << "QCocoaWindow::windowShouldClose" << window();
+
// This callback should technically only determine if the window
// should (be allowed to) close, but since our QPA API to determine
// that also involves actually closing the window we do both at the
// same time, instead of doing the latter in windowWillClose.
+
+ // If the window is closed, we will release and deallocate the NSWindow.
+ // But frames higher up in the stack might still expect the window to
+ // be alive, since the windowShouldClose: callback is technically only
+ // supposed to answer YES or NO. To ensure the window is still alive
+ // we put an autorelease in the closest pool (typically the runloop).
+ [[m_view.window retain] autorelease];
+
return QWindowSystemInterface::handleCloseEvent<QWindowSystemInterface::SynchronousDelivery>(window());
}
@@ -1399,14 +1503,30 @@ void QCocoaWindow::recreateWindowIfNeeded()
QMacAutoReleasePool pool;
QPlatformWindow *parentWindow = QPlatformWindow::parent();
-
- const bool isEmbeddedView = isEmbedded();
- RecreationReasons recreateReason = RecreationNotNeeded;
+ auto *parentCocoaWindow = static_cast<QCocoaWindow *>(parentWindow);
QCocoaWindow *oldParentCocoaWindow = nullptr;
if (QNSView *qnsView = qnsview_cast(m_view.superview))
oldParentCocoaWindow = qnsView.platformWindow;
+ if (isForeignWindow()) {
+ // A foreign window is created as such, and can never move between being
+ // foreign and not, so we don't need to get rid of any existing NSWindows,
+ // nor create new ones, as a foreign window is a single simple NSView.
+ qCDebug(lcQpaWindow) << "Skipping NSWindow management for foreign window" << this;
+
+ // We do however need to manage the parent relationship
+ if (parentCocoaWindow)
+ [parentCocoaWindow->m_view addSubview:m_view];
+ else if (oldParentCocoaWindow)
+ [m_view removeFromSuperview];
+
+ return;
+ }
+
+ const bool isEmbeddedView = isEmbedded();
+ RecreationReasons recreateReason = RecreationNotNeeded;
+
if (parentWindow != oldParentCocoaWindow)
recreateReason |= ParentChanged;
@@ -1437,17 +1557,10 @@ void QCocoaWindow::recreateWindowIfNeeded()
if (recreateReason == RecreationNotNeeded)
return;
- QCocoaWindow *parentCocoaWindow = static_cast<QCocoaWindow *>(parentWindow);
-
// Remove current window (if any)
if ((isContentView() && !shouldBeContentView) || (recreateReason & PanelChanged)) {
if (m_nsWindow) {
qCDebug(lcQpaWindow) << "Getting rid of existing window" << m_nsWindow;
- if (m_nsWindow.observationInfo) {
- qCCritical(lcQpaWindow) << m_nsWindow << "has active key-value observers (KVO)!"
- << "These will stop working now that the window is recreated, and will result in exceptions"
- << "when the observers are removed. Break in QCocoaWindow::recreateWindowIfNeeded to debug.";
- }
[m_nsWindow closeAndRelease];
if (isContentView() && !isEmbeddedView) {
// We explicitly disassociate m_view from the window's contentView,
@@ -1473,38 +1586,10 @@ void QCocoaWindow::recreateWindowIfNeeded()
}
}
- if (isEmbeddedView) {
- // An embedded window doesn't have its own NSWindow.
- } else if (!parentWindow) {
- // QPlatformWindow subclasses must sync up with QWindow on creation:
- propagateSizeHints();
- setWindowFlags(window()->flags());
- setWindowTitle(window()->title());
- setWindowFilePath(window()->filePath()); // Also sets window icon
- setWindowState(window()->windowState());
- } else {
- // Child windows have no NSWindow, link the NSViews instead.
+ if (parentCocoaWindow) {
+ // Child windows have no NSWindow, re-parent to superview instead
[parentCocoaWindow->m_view addSubview:m_view];
- QRect rect = windowGeometry();
- // Prevent setting a (0,0) window size; causes opengl context
- // "Invalid Drawable" warnings.
- if (rect.isNull())
- rect.setSize(QSize(1, 1));
- NSRect frame = NSMakeRect(rect.x(), rect.y(), rect.width(), rect.height());
- [m_view setFrame:frame];
- [m_view setHidden:!window()->isVisible()];
}
-
- const qreal opacity = qt_window_private(window())->opacity;
- if (!qFuzzyCompare(opacity, qreal(1.0)))
- setOpacity(opacity);
-
- setMask(QHighDpi::toNativeLocalRegion(window()->mask(), window()));
-
- // top-level QWindows may have an attached NSToolBar, call
- // update function which will attach to the NSWindow.
- if (!parentWindow && !isEmbeddedView)
- updateNSToolbar();
}
void QCocoaWindow::requestUpdate()
@@ -1513,7 +1598,10 @@ void QCocoaWindow::requestUpdate()
<< "using" << (updatesWithDisplayLink() ? "display-link" : "timer");
if (updatesWithDisplayLink()) {
- static_cast<QCocoaScreen *>(screen())->requestUpdate();
+ if (!static_cast<QCocoaScreen *>(screen())->requestUpdate()) {
+ qCDebug(lcQpaDrawing) << "Falling back to timer-based update request";
+ QPlatformWindow::requestUpdate();
+ }
} else {
// Fall back to the un-throttled timer-based callback
QPlatformWindow::requestUpdate();
@@ -1539,6 +1627,75 @@ void QCocoaWindow::requestActivateWindow()
[m_view.window makeKeyWindow];
}
+/*
+ Closes all popups, and removes observers and monitors.
+*/
+void QCocoaWindow::closeAllPopups()
+{
+ QGuiApplicationPrivate::instance()->closeAllPopups();
+
+ removePopupMonitor();
+}
+
+void QCocoaWindow::removePopupMonitor()
+{
+ if (s_globalMouseMonitor) {
+ [NSEvent removeMonitor:s_globalMouseMonitor];
+ s_globalMouseMonitor = nil;
+ }
+ if (s_applicationActivationObserver) {
+ [[[NSWorkspace sharedWorkspace] notificationCenter] removeObserver:s_applicationActivationObserver];
+ s_applicationActivationObserver = nil;
+ }
+}
+
+void QCocoaWindow::setupPopupMonitor()
+{
+ // we open a popup window while we are not active. None of our existing event
+ // handlers will get called if the user now clicks anywhere outside the application
+ // or activates another window. Use a global event monitor to watch for mouse
+ // presses, and close popups. We also want mouse tracking in the popup to work, so
+ // also watch for MouseMoved.
+ if (!s_globalMouseMonitor) {
+ // we only get LeftMouseDown events when we also set LeftMouseUp.
+ constexpr NSEventMask mouseButtonMask = NSEventTypeLeftMouseDown | NSEventTypeLeftMouseUp
+ | NSEventMaskRightMouseDown | NSEventMaskOtherMouseDown
+ | NSEventMaskMouseMoved;
+ s_globalMouseMonitor = [NSEvent addGlobalMonitorForEventsMatchingMask:mouseButtonMask
+ handler:^(NSEvent *e){
+ if (!QGuiApplicationPrivate::instance()->popupActive()) {
+ removePopupMonitor();
+ return;
+ }
+ const auto eventType = cocoaEvent2QtMouseEvent(e);
+ if (eventType == QEvent::MouseMove) {
+ if (s_windowUnderMouse) {
+ QWindow *window = s_windowUnderMouse->window();
+ const auto button = cocoaButton2QtButton(e);
+ const auto buttons = currentlyPressedMouseButtons();
+ const auto globalPoint = QCocoaScreen::mapFromNative(NSEvent.mouseLocation);
+ const auto localPoint = window->mapFromGlobal(globalPoint.toPoint());
+ QWindowSystemInterface::handleMouseEvent(window, localPoint, globalPoint,
+ buttons, button, eventType);
+ }
+ } else {
+ closeAllPopups();
+ }
+ }];
+ }
+ // The activation observer also gets called when we become active because the user clicks
+ // into the popup. This should not close the popup, so QCocoaApplicationDelegate's
+ // applicationDidBecomeActive implementation removes this observer.
+ if (!s_applicationActivationObserver) {
+ s_applicationActivationObserver = [[[NSWorkspace sharedWorkspace] notificationCenter]
+ addObserverForName:NSWorkspaceDidActivateApplicationNotification
+ object:nil queue:nil
+ usingBlock:^(NSNotification *){
+ closeAllPopups();
+ }];
+ }
+}
+
QCocoaNSWindow *QCocoaWindow::createNSWindow(bool shouldBePanel)
{
QMacAutoReleasePool pool;
@@ -1632,17 +1789,21 @@ QCocoaNSWindow *QCocoaWindow::createNSWindow(bool shouldBePanel)
nsWindow.restorable = NO;
nsWindow.level = windowLevel(flags);
+ nsWindow.tabbingMode = NSWindowTabbingModeDisallowed;
if (shouldBePanel) {
// Qt::Tool windows hide on app deactivation, unless Qt::WA_MacAlwaysShowToolWindow is set
nsWindow.hidesOnDeactivate = ((type & Qt::Tool) == Qt::Tool) && !alwaysShowToolWindow();
- // Make popup windows show on the same desktop as the parent full-screen window
- nsWindow.collectionBehavior = NSWindowCollectionBehaviorFullScreenAuxiliary;
+ // Make popup windows show on the same desktop as the parent window
+ nsWindow.collectionBehavior = NSWindowCollectionBehaviorFullScreenAuxiliary
+ | NSWindowCollectionBehaviorMoveToActiveSpace;
if ((type & Qt::Popup) == Qt::Popup) {
nsWindow.hasShadow = YES;
nsWindow.animationBehavior = NSWindowAnimationBehaviorUtilityWindow;
+ if (QGuiApplication::applicationState() != Qt::ApplicationActive)
+ setupPopupMonitor();
}
}
@@ -1651,8 +1812,15 @@ QCocoaNSWindow *QCocoaWindow::createNSWindow(bool shouldBePanel)
applyContentBorderThickness(nsWindow);
- if (format().colorSpace() == QSurfaceFormat::sRGBColorSpace)
- nsWindow.colorSpace = NSColorSpace.sRGBColorSpace;
+ // We propagate the view's color space granulary to both the IOSurfaces
+ // used for QSurface::RasterSurface, as well as the CAMetalLayer used for
+ // QSurface::MetalSurface, but for QSurface::OpenGLSurface we don't have
+ // that option as we use NSOpenGLContext instead of CAOpenGLLayer. As a
+ // workaround we set the NSWindow's color space, which affects GL drawing
+ // with NSOpenGLContext as well. This does not conflict with the granular
+ // modifications we do to each surface for raster or Metal.
+ if (auto *qtView = qnsview_cast(m_view))
+ nsWindow.colorSpace = qtView.colorSpace;
return nsWindow;
}
@@ -1662,14 +1830,6 @@ bool QCocoaWindow::alwaysShowToolWindow() const
return qt_mac_resolveOption(false, window(), "_q_macAlwaysShowToolWindow", "");
}
-void QCocoaWindow::removeMonitor()
-{
- if (!monitor)
- return;
- [NSEvent removeMonitor:monitor];
- monitor = nil;
-}
-
bool QCocoaWindow::setWindowModified(bool modified)
{
if (!isContentView())
@@ -1695,13 +1855,37 @@ void QCocoaWindow::setWindowCursor(NSCursor *cursor)
if (isForeignWindow())
return;
+ qCInfo(lcQpaMouse) << "Setting" << this << "cursor to" << cursor;
+
QNSView *view = qnsview_cast(m_view);
if (cursor == view.cursor)
return;
view.cursor = cursor;
+ // We're not using the the legacy cursor rects API to manage our
+ // cursor, but calling this function also invalidates AppKit's
+ // view of whether or not we need a cursorUpdate callback for
+ // our tracking area.
[m_view.window invalidateCursorRectsForView:m_view];
+
+ // We've informed AppKit that we need a cursorUpdate, but cursor
+ // updates for tracking areas are deferred in some cases, such as
+ // when the mouse is down, whereas we want a synchronous update.
+ // To ensure an updated cursor we synthesize a cursor update event
+ // now if the window is otherwise allowed to change the cursor.
+ auto locationInWindow = m_view.window.mouseLocationOutsideOfEventStream;
+ auto locationInSuperview = [m_view.superview convertPoint:locationInWindow fromView:nil];
+ bool mouseIsOverView = [m_view hitTest:locationInSuperview] == m_view;
+ auto utilityMask = NSWindowStyleMaskUtilityWindow | NSWindowStyleMaskTitled;
+ bool isUtilityWindow = (m_view.window.styleMask & utilityMask) == utilityMask;
+ if (mouseIsOverView && (m_view.window.keyWindow || isUtilityWindow)) {
+ qCDebug(lcQpaMouse) << "Synthesizing cursor update";
+ [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)
@@ -1713,16 +1897,6 @@ void QCocoaWindow::registerTouch(bool enable)
m_view.allowedTouchTypes &= ~NSTouchTypeMaskIndirect;
}
-void QCocoaWindow::setContentBorderThickness(int topThickness, int bottomThickness)
-{
- m_topContentBorderThickness = topThickness;
- m_bottomContentBorderThickness = bottomThickness;
- bool enable = (topThickness > 0 || bottomThickness > 0);
- m_drawContentBorderGradient = enable;
-
- applyContentBorderThickness();
-}
-
void QCocoaWindow::registerContentBorderArea(quintptr identifier, int upper, int lower)
{
m_contentBorderAreas.insert(identifier, BorderRange(identifier, upper, lower));
@@ -1759,13 +1933,13 @@ void QCocoaWindow::applyContentBorderThickness(NSWindow *window)
// Find consecutive registered border areas, starting from the top.
std::vector<BorderRange> ranges(m_contentBorderAreas.cbegin(), m_contentBorderAreas.cend());
std::sort(ranges.begin(), ranges.end());
- int effectiveTopContentBorderThickness = m_topContentBorderThickness;
+ int effectiveTopContentBorderThickness = 0;
for (BorderRange range : ranges) {
// Skip disiabled ranges (typically hidden tool bars)
if (!m_enabledContentBorderAreas.value(range.identifier, false))
continue;
- // Is this sub-range adjacent to or overlaping the
+ // Is this sub-range adjacent to or overlapping the
// existing total border area range? If so merge
// it into the total range,
if (range.upper <= (effectiveTopContentBorderThickness + 1))
@@ -1774,7 +1948,7 @@ void QCocoaWindow::applyContentBorderThickness(NSWindow *window)
break;
}
- int effectiveBottomContentBorderThickness = m_bottomContentBorderThickness;
+ int effectiveBottomContentBorderThickness = 0;
[window setStyleMask:[window styleMask] | NSWindowStyleMaskTexturedBackground];
window.titlebarAppearsTransparent = YES;
@@ -1796,32 +1970,26 @@ void QCocoaWindow::applyContentBorderThickness(NSWindow *window)
[[[window contentView] superview] setNeedsDisplay:YES];
}
-void QCocoaWindow::updateNSToolbar()
-{
- if (!isContentView())
- return;
-
- NSToolbar *toolbar = QCocoaIntegration::instance()->toolbar(window());
- const NSWindow *window = m_view.window;
-
- if (window.toolbar == toolbar)
- return;
-
- window.toolbar = toolbar;
- window.showsToolbarButton = YES;
-}
-
bool QCocoaWindow::testContentBorderAreaPosition(int position) const
{
- return isContentView() && m_drawContentBorderGradient &&
- 0 <= position && position < [m_view.window contentBorderThicknessForEdge:NSMaxYEdge];
+ if (!m_drawContentBorderGradient || !isContentView())
+ return false;
+
+ // Determine if the given y position (relative to the content area) is inside the
+ // unified toolbar area. Note that the value returned by contentBorderThicknessForEdge
+ // includes the title bar height; subtract it.
+ const int contentBorderThickness = [m_view.window contentBorderThicknessForEdge:NSMaxYEdge];
+ const NSRect frameRect = m_view.window.frame;
+ const NSRect contentRect = [m_view.window contentRectForFrameRect:frameRect];
+ const CGFloat titlebarHeight = frameRect.size.height - contentRect.size.height;
+ return 0 <= position && position < (contentBorderThickness - titlebarHeight);
}
qreal QCocoaWindow::devicePixelRatio() const
{
// The documented way to observe the relationship between device-independent
// and device pixels is to use one for the convertToBacking functions. Other
- // methods such as [NSWindow backingScaleFacor] might not give the correct
+ // methods such as [NSWindow backingScaleFactor] might not give the correct
// result, for example if setWantsBestResolutionOpenGLSurface is not set or
// or ignored by the OpenGL driver.
NSSize backingSize = [m_view convertSizeToBacking:NSMakeSize(1.0, 1.0)];
@@ -1831,7 +1999,7 @@ qreal QCocoaWindow::devicePixelRatio() const
QWindow *QCocoaWindow::childWindowAt(QPoint windowPoint)
{
QWindow *targetWindow = window();
- foreach (QObject *child, targetWindow->children())
+ for (QObject *child : targetWindow->children())
if (QWindow *childWindow = qobject_cast<QWindow *>(child))
if (QPlatformWindow *handle = childWindow->handle())
if (handle->isExposed() && childWindow->geometry().contains(windowPoint))
@@ -1845,9 +2013,25 @@ bool QCocoaWindow::shouldRefuseKeyWindowAndFirstResponder()
// This function speaks up if there's any reason
// to refuse key window or first responder state.
- if (window()->flags() & Qt::WindowDoesNotAcceptFocus)
+ if (window()->flags() & (Qt::WindowDoesNotAcceptFocus | Qt::WindowTransparentForInput))
return true;
+ // For application modal windows, as well as direct parent windows
+ // of window modal windows, AppKit takes care of blocking interaction.
+ // The Qt expectation however, is that all transient parents of a
+ // window modal window is blocked, as reflected by QGuiApplication.
+ // We reflect this by returning false from this function for transient
+ // parents blocked by a modal window, but limit it to the cases not
+ // covered by AppKit to avoid potential unwanted side effects.
+ QWindow *modalWindow = nullptr;
+ if (QGuiApplicationPrivate::instance()->isWindowBlocked(window(), &modalWindow)) {
+ if (modalWindow->modality() == Qt::WindowModal && modalWindow->transientParent() != window()) {
+ qCDebug(lcQpaWindow) << "Refusing key window for" << this << "due to being"
+ << "blocked by" << modalWindow;
+ return true;
+ }
+ }
+
if (m_inSetVisible) {
QVariant showWithoutActivating = window()->property("_q_showWithoutActivating");
if (showWithoutActivating.isValid() && showWithoutActivating.toBool())
@@ -1857,11 +2041,18 @@ bool QCocoaWindow::shouldRefuseKeyWindowAndFirstResponder()
return false;
}
-QPoint QCocoaWindow::bottomLeftClippedByNSWindowOffsetStatic(QWindow *window)
+bool QCocoaWindow::windowEvent(QEvent *event)
{
- if (window->handle())
- return static_cast<QCocoaWindow *>(window->handle())->bottomLeftClippedByNSWindowOffset();
- return QPoint();
+ switch (event->type()) {
+ case QEvent::WindowBlocked:
+ case QEvent::WindowUnblocked:
+ updateTitleBarButtons(window()->flags());
+ break;
+ default:
+ break;
+ }
+
+ return QPlatformWindow::windowEvent(event);
}
QPoint QCocoaWindow::bottomLeftClippedByNSWindowOffset() const
@@ -1907,6 +2098,6 @@ QDebug operator<<(QDebug debug, const QCocoaWindow *window)
}
#endif // !QT_NO_DEBUG_STREAM
-#include "moc_qcocoawindow.cpp"
-
QT_END_NAMESPACE
+
+#include "moc_qcocoawindow.cpp"
diff --git a/src/plugins/platforms/cocoa/qcocoawindowmanager.h b/src/plugins/platforms/cocoa/qcocoawindowmanager.h
index 54f17eeccd..85e44e2a5d 100644
--- a/src/plugins/platforms/cocoa/qcocoawindowmanager.h
+++ b/src/plugins/platforms/cocoa/qcocoawindowmanager.h
@@ -1,60 +1,25 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 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$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QCOCOAWINDOWMANAGER_H
#define QCOCOAWINDOWMANAGER_H
#include <QtCore/qglobal.h>
-
-#include <AppKit/AppKit.h>
+#include <QtCore/private/qcore_mac_p.h>
QT_BEGIN_NAMESPACE
class QCocoaWindowManager
{
public:
- static QCocoaWindowManager *instance();
+ QCocoaWindowManager();
private:
- QCocoaWindowManager();
+
+ QMacNotificationObserver m_applicationDidFinishLaunchingObserver;
void initialize();
+ QMacKeyValueObserver m_modalSessionObserver;
void modalSessionChanged();
};
diff --git a/src/plugins/platforms/cocoa/qcocoawindowmanager.mm b/src/plugins/platforms/cocoa/qcocoawindowmanager.mm
index 9c45d8c7fc..ad5d5b23d8 100644
--- a/src/plugins/platforms/cocoa/qcocoawindowmanager.mm
+++ b/src/plugins/platforms/cocoa/qcocoawindowmanager.mm
@@ -1,41 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 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$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <AppKit/AppKit.h>
#include "qcocoawindowmanager.h"
#include "qcocoawindow.h"
@@ -47,19 +13,13 @@
QT_BEGIN_NAMESPACE
-QCocoaWindowManager *QCocoaWindowManager::instance()
-{
- static auto *instance = new QCocoaWindowManager;
- return instance;
-}
-
QCocoaWindowManager::QCocoaWindowManager()
{
if (NSApp) {
initialize();
} else {
- static auto applicationDidFinishLaunching(QMacNotificationObserver(nil,
- NSApplicationDidFinishLaunchingNotification, [this] { initialize(); }));
+ m_applicationDidFinishLaunchingObserver = QMacNotificationObserver(nil,
+ NSApplicationDidFinishLaunchingNotification, [this] { initialize(); });
}
}
@@ -72,9 +32,9 @@ void QCocoaWindowManager::initialize()
// event dispatcher sessions allows us to track session started by native
// APIs as well. We need to check the initial state as well, in case there
// is already a modal session running.
- static auto modalSessionObserver(QMacKeyValueObserver(
+ m_modalSessionObserver = QMacKeyValueObserver(
NSApp, @"modalWindow", [this] { modalSessionChanged(); },
- NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew));
+ NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew);
}
void QCocoaWindowManager::modalSessionChanged()
@@ -100,10 +60,19 @@ void QCocoaWindowManager::modalSessionChanged()
}
}
}
-}
-static void initializeWindowManager() { Q_UNUSED(QCocoaWindowManager::instance()); }
-Q_CONSTRUCTOR_FUNCTION(initializeWindowManager)
+ // Our worksWhenModal implementation is declarative and will normally be picked
+ // up by AppKit when needed, but to make sure AppKit also reflects the state
+ // in the window tag, so that the window can be ordered front by clicking it,
+ // we need to explicitly call setWorksWhenModal.
+ for (id window in NSApp.windows) {
+ if ([window isKindOfClass:[QNSPanel class]]) {
+ auto *panel = static_cast<QNSPanel *>(window);
+ // Call setter to tell AppKit that our state has changed
+ [panel setWorksWhenModal:panel.worksWhenModal];
+ }
+ }
+}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/qiosurfacegraphicsbuffer.h b/src/plugins/platforms/cocoa/qiosurfacegraphicsbuffer.h
index e070ba977d..9fe3d01c77 100644
--- a/src/plugins/platforms/cocoa/qiosurfacegraphicsbuffer.h
+++ b/src/plugins/platforms/cocoa/qiosurfacegraphicsbuffer.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 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$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QIOSURFACEGRAPHICSBUFFER_H
#define QIOSURFACEGRAPHICSBUFFER_H
@@ -43,6 +7,9 @@
#include <qpa/qplatformgraphicsbuffer.h>
#include <private/qcore_mac_p.h>
+#include <CoreGraphics/CGColorSpace.h>
+#include <IOSurface/IOSurface.h>
+
QT_BEGIN_NAMESPACE
class QIOSurfaceGraphicsBuffer : public QPlatformGraphicsBuffer
diff --git a/src/plugins/platforms/cocoa/qiosurfacegraphicsbuffer.mm b/src/plugins/platforms/cocoa/qiosurfacegraphicsbuffer.mm
index fc187e0f51..b987723b8a 100644
--- a/src/plugins/platforms/cocoa/qiosurfacegraphicsbuffer.mm
+++ b/src/plugins/platforms/cocoa/qiosurfacegraphicsbuffer.mm
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 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$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qiosurfacegraphicsbuffer.h"
diff --git a/src/plugins/platforms/cocoa/qmacclipboard.h b/src/plugins/platforms/cocoa/qmacclipboard.h
index f2f460c048..95267565f2 100644
--- a/src/plugins/platforms/cocoa/qmacclipboard.h
+++ b/src/plugins/platforms/cocoa/qmacclipboard.h
@@ -1,89 +1,61 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QMACCLIPBOARD_H
#define QMACCLIPBOARD_H
#include <QtGui>
-#include <QtClipboardSupport/private/qmacmime_p.h>
+#include <QtGui/qutimimeconverter.h>
-#import <AppKit/AppKit.h>
+#include <QtCore/qpointer.h>
+
+#include <ApplicationServices/ApplicationServices.h>
QT_BEGIN_NAMESPACE
-class QMacMimeData;
+class QUtiMimeConverter;
+
class QMacPasteboard
{
public:
enum DataRequestType { EagerRequest, LazyRequest };
private:
struct Promise {
- Promise() : itemId(0), convertor(nullptr) { }
+ Promise() : itemId(0), converter(nullptr) { }
- static Promise eagerPromise(int itemId, QMacInternalPasteboardMime *c, QString m, QMacMimeData *d, int o = 0);
- static Promise lazyPromise(int itemId, QMacInternalPasteboardMime *c, QString m, QMacMimeData *d, int o = 0);
- Promise(int itemId, QMacInternalPasteboardMime *c, QString m, QMacMimeData *md, int o, DataRequestType drt);
+ static Promise eagerPromise(int itemId, const QUtiMimeConverter *c, const QString &m, QMimeData *d, int o = 0);
+ static Promise lazyPromise(int itemId, const QUtiMimeConverter *c, const QString &m, QMimeData *d, int o = 0);
+ Promise(int itemId, const QUtiMimeConverter *c, const QString &m, QMimeData *md, int o, DataRequestType drt);
int itemId, offset;
- QMacInternalPasteboardMime *convertor;
+ const QUtiMimeConverter *converter;
QString mime;
- QPointer<QMacMimeData> mimeData;
+ QPointer<QMimeData> mimeData;
QVariant variantData;
DataRequestType dataRequestType;
+ // QMimeData can be set from QVariant, holding
+ // QPixmap. When converting, this triggers
+ // QPixmap's ctor which in turn requires QGuiApplication
+ // to exist and thus will abort the application
+ // abnormally if not.
+ bool isPixmap = false;
};
QList<Promise> promises;
PasteboardRef paste;
- uchar mime_type;
+ const QUtiMimeConverter::HandlerScope scope;
mutable QPointer<QMimeData> mime;
mutable bool mac_mime_source;
bool resolvingBeforeDestruction;
static OSStatus promiseKeeper(PasteboardRef, PasteboardItemID, CFStringRef, void *);
void clear_helper();
public:
- QMacPasteboard(PasteboardRef p, uchar mime_type=0);
- QMacPasteboard(uchar mime_type);
- QMacPasteboard(CFStringRef name=nullptr, uchar mime_type=0);
+ QMacPasteboard(PasteboardRef p, QUtiMimeConverter::HandlerScope scope = QUtiMimeConverter::HandlerScopeFlag::All);
+ QMacPasteboard(QUtiMimeConverter::HandlerScope scope);
+ QMacPasteboard(CFStringRef name=nullptr, QUtiMimeConverter::HandlerScope scope = QUtiMimeConverter::HandlerScopeFlag::All);
~QMacPasteboard();
- bool hasFlavor(QString flavor) const;
- bool hasOSType(int c_flavor) const;
+ bool hasUti(const QString &uti) const;
PasteboardRef pasteBoard() const;
QMimeData *mimeData() const;
@@ -92,7 +64,7 @@ public:
QStringList formats() const;
bool hasFormat(const QString &format) const;
- QVariant retrieveData(const QString &format, QVariant::Type) const;
+ QVariant retrieveData(const QString &format) const;
void clear();
bool sync() const;
diff --git a/src/plugins/platforms/cocoa/qmacclipboard.mm b/src/plugins/platforms/cocoa/qmacclipboard.mm
index 654647b35a..edafa3b6a1 100644
--- a/src/plugins/platforms/cocoa/qmacclipboard.mm
+++ b/src/plugins/platforms/cocoa/qmacclipboard.mm
@@ -1,51 +1,21 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <AppKit/AppKit.h>
#include "qmacclipboard.h"
-#include "qclipboard.h"
-#include "qguiapplication.h"
-#include "qbitmap.h"
-#include "qdatetime.h"
-#include "qdebug.h"
-#include "qguiapplication.h"
-#include "qevent.h"
-#include "qurl.h"
+#include <QtGui/private/qmacmimeregistry_p.h>
+#include <QtGui/qutimimeconverter.h>
+#include <QtGui/qclipboard.h>
+#include <QtGui/qguiapplication.h>
+#include <QtGui/qbitmap.h>
+#include <QtCore/qdatetime.h>
+#include <QtCore/qmetatype.h>
+#include <QtCore/qdebug.h>
+#include <QtCore/private/qcore_mac_p.h>
+#include <QtGui/qguiapplication.h>
+#include <QtGui/qevent.h>
+#include <QtCore/qurl.h>
#include <stdlib.h>
#include <string.h>
#include "qcocoahelpers.h"
@@ -53,10 +23,7 @@
QT_BEGIN_NAMESPACE
-/*****************************************************************************
- QClipboard debug facilities
- *****************************************************************************/
-//#define DEBUG_PASTEBOARD
+using namespace Qt::StringLiterals;
/*****************************************************************************
QMacPasteboard code
@@ -82,50 +49,52 @@ OSStatus PasteboardGetItemCountSafe(PasteboardRef paste, ItemCount *cnt)
class QMacMimeData : public QMimeData
{
public:
- QVariant variantData(const QString &mime) { return retrieveData(mime, QVariant::Invalid); }
+ QVariant variantData(const QString &mime) { return retrieveData(mime, QMetaType()); }
private:
QMacMimeData();
};
-QMacPasteboard::Promise::Promise(int itemId, QMacInternalPasteboardMime *c, QString m, QMacMimeData *md, int o, DataRequestType drt)
- : itemId(itemId), offset(o), convertor(c), mime(m), dataRequestType(drt)
+QMacPasteboard::Promise::Promise(int itemId, const QUtiMimeConverter *c, const QString &m, QMimeData *md, int o, DataRequestType drt)
+ : itemId(itemId), offset(o), converter(c), mime(m), dataRequestType(drt)
{
// Request the data from the application immediately for eager requests.
if (dataRequestType == QMacPasteboard::EagerRequest) {
- variantData = md->variantData(m);
+ variantData = static_cast<QMacMimeData *>(md)->variantData(m);
+ isPixmap = variantData.metaType().id() == QMetaType::QPixmap;
mimeData = nullptr;
} else {
mimeData = md;
+ if (md->hasImage())
+ isPixmap = md->imageData().metaType().id() == QMetaType::QPixmap;
}
}
-QMacPasteboard::QMacPasteboard(PasteboardRef p, uchar mt)
+QMacPasteboard::QMacPasteboard(PasteboardRef p, QUtiMimeConverter::HandlerScope scope)
+ : scope(scope)
{
mac_mime_source = false;
- mime_type = mt ? mt : uchar(QMacInternalPasteboardMime::MIME_ALL);
paste = p;
CFRetain(paste);
resolvingBeforeDestruction = false;
}
-QMacPasteboard::QMacPasteboard(uchar mt)
+QMacPasteboard::QMacPasteboard(QUtiMimeConverter::HandlerScope scope)
+ : scope(scope)
{
mac_mime_source = false;
- mime_type = mt ? mt : uchar(QMacInternalPasteboardMime::MIME_ALL);
paste = nullptr;
OSStatus err = PasteboardCreate(nullptr, &paste);
- if (err == noErr) {
+ if (err == noErr)
PasteboardSetPromiseKeeper(paste, promiseKeeper, this);
- } else {
+ else
qDebug("PasteBoard: Error creating pasteboard: [%d]", (int)err);
- }
resolvingBeforeDestruction = false;
}
-QMacPasteboard::QMacPasteboard(CFStringRef name, uchar mt)
+QMacPasteboard::QMacPasteboard(CFStringRef name, QUtiMimeConverter::HandlerScope scope)
+ : scope(scope)
{
mac_mime_source = false;
- mime_type = mt ? mt : uchar(QMacInternalPasteboardMime::MIME_ALL);
paste = nullptr;
OSStatus err = PasteboardCreate(name, &paste);
if (err == noErr) {
@@ -142,89 +111,91 @@ QMacPasteboard::~QMacPasteboard()
Commit all promises for paste when shutting down,
unless we are the stack-allocated clipboard used by QCocoaDrag.
*/
- if (mime_type == QMacInternalPasteboardMime::MIME_DND)
+ if (scope == QUtiMimeConverter::HandlerScopeFlag::DnD)
resolvingBeforeDestruction = true;
PasteboardResolvePromises(paste);
if (paste)
CFRelease(paste);
}
-PasteboardRef
-QMacPasteboard::pasteBoard() const
+PasteboardRef QMacPasteboard::pasteBoard() const
{
return paste;
}
-OSStatus QMacPasteboard::promiseKeeper(PasteboardRef paste, PasteboardItemID id, CFStringRef flavor, void *_qpaste)
+OSStatus QMacPasteboard::promiseKeeper(PasteboardRef paste, PasteboardItemID id,
+ CFStringRef uti, void *_qpaste)
{
QMacPasteboard *qpaste = (QMacPasteboard*)_qpaste;
const long promise_id = (long)id;
// Find the kept promise
- QList<QMacInternalPasteboardMime*> availableConverters
- = QMacInternalPasteboardMime::all(QMacInternalPasteboardMime::MIME_ALL);
- const QString flavorAsQString = QString::fromCFString(flavor);
+ const QList<QUtiMimeConverter*> availableConverters = QMacMimeRegistry::all(QUtiMimeConverter::HandlerScopeFlag::All);
+ const QString utiAsQString = QString::fromCFString(uti);
QMacPasteboard::Promise promise;
for (int i = 0; i < qpaste->promises.size(); i++){
- QMacPasteboard::Promise tmp = qpaste->promises[i];
- if (!availableConverters.contains(tmp.convertor)) {
+ const QMacPasteboard::Promise tmp = qpaste->promises[i];
+ if (!availableConverters.contains(tmp.converter)) {
// promise.converter is a pointer initialized by the value found
- // in QMacInternalPasteboardMime's global list of QMacInternalPasteboardMimes.
- // We add pointers to this list in QMacInternalPasteboardMime's ctor;
- // we remove these pointers in QMacInternalPasteboardMime's dtor.
+ // in QUtiMimeConverter's global list of QMacMimes.
+ // We add pointers to this list in QUtiMimeConverter's ctor;
+ // we remove these pointers in QUtiMimeConverter's dtor.
// If tmp.converter was not found in this list, we probably have a
// dangling pointer so let's skip it.
continue;
}
- if (tmp.itemId == promise_id && tmp.convertor->canConvert(tmp.mime, flavorAsQString)){
+ if (tmp.itemId == promise_id && tmp.converter->canConvert(tmp.mime, utiAsQString)) {
promise = tmp;
break;
}
}
- if (!promise.itemId && flavorAsQString == QLatin1String("com.trolltech.qt.MimeTypeName")) {
+ if (!promise.itemId && utiAsQString == "com.trolltech.qt.MimeTypeName"_L1) {
// we have promised this data, but won't be able to convert, so return null data.
// This helps in making the application/x-qt-mime-type-name hidden from normal use.
QByteArray ba;
- QCFType<CFDataRef> data = CFDataCreate(nullptr, (UInt8*)ba.constData(), ba.size());
- PasteboardPutItemFlavor(paste, id, flavor, data, kPasteboardFlavorNoFlags);
+ const QCFType<CFDataRef> data = CFDataCreate(nullptr, (UInt8*)ba.constData(), ba.size());
+ PasteboardPutItemFlavor(paste, id, uti, data, kPasteboardFlavorNoFlags);
return noErr;
}
if (!promise.itemId) {
// There was no promise that could deliver data for the
- // given id and flavor. This should not happend.
- qDebug("Pasteboard: %d: Request for %ld, %s, but no promise found!", __LINE__, promise_id, qPrintable(flavorAsQString));
+ // given id and uti. This should not happen.
+ qDebug("Pasteboard: %d: Request for %ld, %s, but no promise found!", __LINE__, promise_id, qPrintable(utiAsQString));
return cantGetFlavorErr;
}
-#ifdef DEBUG_PASTEBOARD
- qDebug("PasteBoard: Calling in promise for %s[%ld] [%s] (%s) [%d]", qPrintable(promise.mime), promise_id,
- qPrintable(flavorAsQString), qPrintable(promise.convertor->convertorName()), promise.offset);
-#endif
+ qCDebug(lcQpaClipboard, "PasteBoard: Calling in promise for %s[%ld] [%s] [%d]", qPrintable(promise.mime), promise_id,
+ qPrintable(utiAsQString), promise.offset);
// Get the promise data. If this is a "lazy" promise call variantData()
// to request the data from the application.
QVariant promiseData;
if (promise.dataRequestType == LazyRequest) {
- if (!qpaste->resolvingBeforeDestruction && !promise.mimeData.isNull())
- promiseData = promise.mimeData->variantData(promise.mime);
+ if (!qpaste->resolvingBeforeDestruction && !promise.mimeData.isNull()) {
+ if (promise.isPixmap && !QGuiApplication::instance()) {
+ qCWarning(lcQpaClipboard,
+ "Cannot keep promise, data contains QPixmap and requires livining QGuiApplication");
+ return cantGetFlavorErr;
+ }
+ promiseData = static_cast<QMacMimeData *>(promise.mimeData.data())->variantData(promise.mime);
+ }
} else {
promiseData = promise.variantData;
}
- QList<QByteArray> md = promise.convertor->convertFromMime(promise.mime, promiseData, flavorAsQString);
+ const QList<QByteArray> md = promise.converter->convertFromMime(promise.mime, promiseData, utiAsQString);
if (md.size() <= promise.offset)
return cantGetFlavorErr;
const QByteArray &ba = md[promise.offset];
- QCFType<CFDataRef> data = CFDataCreate(nullptr, (UInt8*)ba.constData(), ba.size());
- PasteboardPutItemFlavor(paste, id, flavor, data, kPasteboardFlavorNoFlags);
+ const QCFType<CFDataRef> data = CFDataCreate(nullptr, (UInt8*)ba.constData(), ba.size());
+ PasteboardPutItemFlavor(paste, id, uti, data, kPasteboardFlavorNoFlags);
return noErr;
}
-bool
-QMacPasteboard::hasOSType(int c_flavor) const
+bool QMacPasteboard::hasUti(const QString &uti) const
{
if (!paste)
return false;
@@ -235,56 +206,8 @@ QMacPasteboard::hasOSType(int c_flavor) const
if (PasteboardGetItemCountSafe(paste, &cnt) || !cnt)
return false;
-#ifdef DEBUG_PASTEBOARD
- qDebug("PasteBoard: hasOSType [%c%c%c%c]", (c_flavor>>24)&0xFF, (c_flavor>>16)&0xFF,
- (c_flavor>>8)&0xFF, (c_flavor>>0)&0xFF);
-#endif
- for (uint index = 1; index <= cnt; ++index) {
-
- PasteboardItemID id;
- if (PasteboardGetItemIdentifier(paste, index, &id) != noErr)
- return false;
-
- QCFType<CFArrayRef> types;
- if (PasteboardCopyItemFlavors(paste, id, &types ) != noErr)
- return false;
-
- const int type_count = CFArrayGetCount(types);
- for (int i = 0; i < type_count; ++i) {
- CFStringRef flavor = (CFStringRef)CFArrayGetValueAtIndex(types, i);
- CFStringRef preferredTag = UTTypeCopyPreferredTagWithClass(flavor, kUTTagClassOSType);
- const int os_flavor = UTGetOSTypeFromString(preferredTag);
- if (preferredTag)
- CFRelease(preferredTag);
- if (os_flavor == c_flavor) {
-#ifdef DEBUG_PASTEBOARD
- qDebug(" - Found!");
-#endif
- return true;
- }
- }
- }
-#ifdef DEBUG_PASTEBOARD
- qDebug(" - NotFound!");
-#endif
- return false;
-}
-
-bool
-QMacPasteboard::hasFlavor(QString c_flavor) const
-{
- if (!paste)
- return false;
-
- sync();
-
- ItemCount cnt = 0;
- if (PasteboardGetItemCountSafe(paste, &cnt) || !cnt)
- return false;
-
-#ifdef DEBUG_PASTEBOARD
- qDebug("PasteBoard: hasFlavor [%s]", qPrintable(c_flavor));
-#endif
+ qCDebug(lcQpaClipboard, "PasteBoard: hasUti [%s]", qPrintable(uti));
+ const QCFString c_uti(uti);
for (uint index = 1; index <= cnt; ++index) {
PasteboardItemID id;
@@ -292,30 +215,29 @@ QMacPasteboard::hasFlavor(QString c_flavor) const
return false;
PasteboardFlavorFlags flags;
- if (PasteboardGetItemFlavorFlags(paste, id, QCFString(c_flavor), &flags) == noErr) {
-#ifdef DEBUG_PASTEBOARD
- qDebug(" - Found!");
-#endif
+ if (PasteboardGetItemFlavorFlags(paste, id, c_uti, &flags) == noErr) {
+ qCDebug(lcQpaClipboard, " - Found!");
return true;
}
}
-#ifdef DEBUG_PASTEBOARD
- qDebug(" - NotFound!");
-#endif
+ qCDebug(lcQpaClipboard, " - NotFound!");
return false;
}
-class QMacPasteboardMimeSource : public QMimeData {
+class QMacPasteboardMimeSource : public QMimeData
+{
const QMacPasteboard *paste;
public:
QMacPasteboardMimeSource(const QMacPasteboard *p) : QMimeData(), paste(p) { }
~QMacPasteboardMimeSource() { }
- virtual QStringList formats() const { return paste->formats(); }
- virtual QVariant retrieveData(const QString &format, QVariant::Type type) const { return paste->retrieveData(format, type); }
+ QStringList formats() const override { return paste->formats(); }
+ QVariant retrieveData(const QString &format, QMetaType) const override
+ {
+ return paste->retrieveData(format);
+ }
};
-QMimeData
-*QMacPasteboard::mimeData() const
+QMimeData *QMacPasteboard::mimeData() const
{
if (!mime) {
mac_mime_source = true;
@@ -325,8 +247,7 @@ QMimeData
return mime;
}
-void
-QMacPasteboard::setMimeData(QMimeData *mime_src, DataRequestType dataRequestType)
+void QMacPasteboard::setMimeData(QMimeData *mime_src, DataRequestType dataRequestType)
{
if (!paste)
return;
@@ -337,48 +258,42 @@ QMacPasteboard::setMimeData(QMimeData *mime_src, DataRequestType dataRequestType
delete mime;
mime = mime_src;
- QList<QMacInternalPasteboardMime*> availableConverters = QMacInternalPasteboardMime::all(mime_type);
- if (mime != 0) {
+ const QList<QUtiMimeConverter*> availableConverters = QMacMimeRegistry::all(scope);
+ if (mime != nullptr) {
clear_helper();
QStringList formats = mime_src->formats();
// QMimeData sub classes reimplementing the formats() might not expose the
// temporary "application/x-qt-mime-type-name" mimetype. So check the existence
// of this mime type while doing drag and drop.
- QString dummyMimeType(QLatin1String("application/x-qt-mime-type-name"));
+ QString dummyMimeType("application/x-qt-mime-type-name"_L1);
if (!formats.contains(dummyMimeType)) {
QByteArray dummyType = mime_src->data(dummyMimeType);
- if (!dummyType.isEmpty()) {
+ if (!dummyType.isEmpty())
formats.append(dummyMimeType);
- }
}
- for (int f = 0; f < formats.size(); ++f) {
- QString mimeType = formats.at(f);
- for (QList<QMacInternalPasteboardMime *>::Iterator it = availableConverters.begin(); it != availableConverters.end(); ++it) {
- QMacInternalPasteboardMime *c = (*it);
+ for (const auto &mimeType : formats) {
+ for (const auto *c : availableConverters) {
// Hack: The Rtf handler converts incoming Rtf to Html. We do
// not want to convert outgoing Html to Rtf but instead keep
// posting it as Html. Skip the Rtf handler here.
- if (c->convertorName() == QLatin1String("Rtf"))
+ if (c->utiForMime("text/html"_L1) == "public.rtf"_L1)
continue;
- QString flavor(c->flavorFor(mimeType));
- if (!flavor.isEmpty()) {
- QMacMimeData *mimeData = static_cast<QMacMimeData*>(mime_src);
+ const QString uti(c->utiForMime(mimeType));
+ if (!uti.isEmpty()) {
- int numItems = c->count(mime_src);
+ const int numItems = c->count(mime_src);
for (int item = 0; item < numItems; ++item) {
- const NSInteger itemID = item+1; //id starts at 1
+ const NSInteger itemID = item + 1; //id starts at 1
//QMacPasteboard::Promise promise = (dataRequestType == QMacPasteboard::EagerRequest) ?
// QMacPasteboard::Promise::eagerPromise(itemID, c, mimeType, mimeData, item) :
// QMacPasteboard::Promise::lazyPromise(itemID, c, mimeType, mimeData, item);
- QMacPasteboard::Promise promise(itemID, c, mimeType, mimeData, item, dataRequestType);
+ const QMacPasteboard::Promise promise(itemID, c, mimeType, mime_src, item, dataRequestType);
promises.append(promise);
- PasteboardPutItemFlavor(paste, reinterpret_cast<PasteboardItemID>(itemID), QCFString(flavor), 0, kPasteboardFlavorNoFlags);
-#ifdef DEBUG_PASTEBOARD
- qDebug(" - adding %d %s [%s] <%s> [%d]",
- itemID, qPrintable(mimeType), qPrintable(flavor), qPrintable(c->convertorName()), item);
-#endif
+ PasteboardPutItemFlavor(paste, reinterpret_cast<PasteboardItemID>(itemID), QCFString(uti), 0, kPasteboardFlavorNoFlags);
+ qCDebug(lcQpaClipboard, " - adding %ld %s [%s] [%d]",
+ itemID, qPrintable(mimeType), qPrintable(uti), item);
}
}
}
@@ -386,8 +301,7 @@ QMacPasteboard::setMimeData(QMimeData *mime_src, DataRequestType dataRequestType
}
}
-QStringList
-QMacPasteboard::formats() const
+QStringList QMacPasteboard::formats() const
{
if (!paste)
return QStringList();
@@ -399,9 +313,7 @@ QMacPasteboard::formats() const
if (PasteboardGetItemCountSafe(paste, &cnt) || !cnt)
return ret;
-#ifdef DEBUG_PASTEBOARD
- qDebug("PasteBoard: Formats [%d]", (int)cnt);
-#endif
+ qCDebug(lcQpaClipboard, "PasteBoard: Formats [%d]", (int)cnt);
for (uint index = 1; index <= cnt; ++index) {
PasteboardItemID id;
@@ -414,15 +326,11 @@ QMacPasteboard::formats() const
const int type_count = CFArrayGetCount(types);
for (int i = 0; i < type_count; ++i) {
- const QString flavor = QString::fromCFString((CFStringRef)CFArrayGetValueAtIndex(types, i));
-#ifdef DEBUG_PASTEBOARD
- qDebug(" -%s", qPrintable(QString(flavor)));
-#endif
- QString mimeType = QMacInternalPasteboardMime::flavorToMime(mime_type, flavor);
+ const QString uti = QString::fromCFString((CFStringRef)CFArrayGetValueAtIndex(types, i));
+ qCDebug(lcQpaClipboard, " -%s", qPrintable(QString(uti)));
+ const QString mimeType = QMacMimeRegistry::flavorToMime(scope, uti);
if (!mimeType.isEmpty() && !ret.contains(mimeType)) {
-#ifdef DEBUG_PASTEBOARD
- qDebug(" -<%d> %s [%s]", ret.size(), qPrintable(mimeType), qPrintable(QString(flavor)));
-#endif
+ qCDebug(lcQpaClipboard, " -<%lld> %s [%s]", ret.size(), qPrintable(mimeType), qPrintable(QString(uti)));
ret << mimeType;
}
}
@@ -430,8 +338,7 @@ QMacPasteboard::formats() const
return ret;
}
-bool
-QMacPasteboard::hasFormat(const QString &format) const
+bool QMacPasteboard::hasFormat(const QString &format) const
{
if (!paste)
return false;
@@ -442,9 +349,7 @@ QMacPasteboard::hasFormat(const QString &format) const
if (PasteboardGetItemCountSafe(paste, &cnt) || !cnt)
return false;
-#ifdef DEBUG_PASTEBOARD
- qDebug("PasteBoard: hasFormat [%s]", qPrintable(format));
-#endif
+ qCDebug(lcQpaClipboard, "PasteBoard: hasFormat [%s]", qPrintable(format));
for (uint index = 1; index <= cnt; ++index) {
PasteboardItemID id;
@@ -457,15 +362,11 @@ QMacPasteboard::hasFormat(const QString &format) const
const int type_count = CFArrayGetCount(types);
for (int i = 0; i < type_count; ++i) {
- const QString flavor = QString::fromCFString((CFStringRef)CFArrayGetValueAtIndex(types, i));
-#ifdef DEBUG_PASTEBOARD
- qDebug(" -%s [0x%x]", qPrintable(QString(flavor)), mime_type);
-#endif
- QString mimeType = QMacInternalPasteboardMime::flavorToMime(mime_type, flavor);
-#ifdef DEBUG_PASTEBOARD
+ const QString uti = QString::fromCFString((CFStringRef)CFArrayGetValueAtIndex(types, i));
+ qCDebug(lcQpaClipboard, " -%s [0x%x]", qPrintable(uti), uchar(scope));
+ QString mimeType = QMacMimeRegistry::flavorToMime(scope, uti);
if (!mimeType.isEmpty())
- qDebug(" - %s", qPrintable(mimeType));
-#endif
+ qCDebug(lcQpaClipboard, " - %s", qPrintable(mimeType));
if (mimeType == format)
return true;
}
@@ -473,8 +374,7 @@ QMacPasteboard::hasFormat(const QString &format) const
return false;
}
-QVariant
-QMacPasteboard::retrieveData(const QString &format, QVariant::Type) const
+QVariant QMacPasteboard::retrieveData(const QString &format) const
{
if (!paste)
return QVariant();
@@ -485,21 +385,18 @@ QMacPasteboard::retrieveData(const QString &format, QVariant::Type) const
if (PasteboardGetItemCountSafe(paste, &cnt) || !cnt)
return QByteArray();
-#ifdef DEBUG_PASTEBOARD
- qDebug("Pasteboard: retrieveData [%s]", qPrintable(format));
-#endif
- const QList<QMacInternalPasteboardMime *> mimes = QMacInternalPasteboardMime::all(mime_type);
- for (int mime = 0; mime < mimes.size(); ++mime) {
- QMacInternalPasteboardMime *c = mimes.at(mime);
- QString c_flavor = c->flavorFor(format);
- if (!c_flavor.isEmpty()) {
+ qCDebug(lcQpaClipboard, "Pasteboard: retrieveData [%s]", qPrintable(format));
+ const QList<QUtiMimeConverter *> availableConverters = QMacMimeRegistry::all(scope);
+ for (const auto *c : availableConverters) {
+ const QString c_uti = c->utiForMime(format);
+ if (!c_uti.isEmpty()) {
// Converting via PasteboardCopyItemFlavorData below will for some UITs result
// in newlines mapping to '\r' instead of '\n'. To work around this we shortcut
// the conversion via NSPasteboard's NSStringPboardType if possible.
- if (c_flavor == QLatin1String("com.apple.traditional-mac-plain-text")
- || c_flavor == QLatin1String("public.utf8-plain-text")
- || c_flavor == QLatin1String("public.utf16-plain-text")) {
- QString str = qt_mac_get_pasteboardString(paste);
+ if (c_uti == "com.apple.traditional-mac-plain-text"_L1
+ || c_uti == "public.utf8-plain-text"_L1
+ || c_uti == "public.utf16-plain-text"_L1) {
+ const QString str = qt_mac_get_pasteboardString(paste);
if (!str.isEmpty())
return str;
}
@@ -517,30 +414,29 @@ QMacPasteboard::retrieveData(const QString &format, QVariant::Type) const
const int type_count = CFArrayGetCount(types);
for (int i = 0; i < type_count; ++i) {
- CFStringRef flavor = static_cast<CFStringRef>(CFArrayGetValueAtIndex(types, i));
- if (c_flavor == QString::fromCFString(flavor)) {
+ const CFStringRef uti = static_cast<CFStringRef>(CFArrayGetValueAtIndex(types, i));
+ if (c_uti == QString::fromCFString(uti)) {
QCFType<CFDataRef> macBuffer;
- if (PasteboardCopyItemFlavorData(paste, id, flavor, &macBuffer) == noErr) {
- QByteArray buffer((const char *)CFDataGetBytePtr(macBuffer), CFDataGetLength(macBuffer));
+ if (PasteboardCopyItemFlavorData(paste, id, uti, &macBuffer) == noErr) {
+ QByteArray buffer((const char *)CFDataGetBytePtr(macBuffer),
+ CFDataGetLength(macBuffer));
if (!buffer.isEmpty()) {
-#ifdef DEBUG_PASTEBOARD
- qDebug(" - %s [%s] (%s)", qPrintable(format), qPrintable(QString::fromNSString(flavor)), qPrintable(c->convertorName()));
-#endif
+ qCDebug(lcQpaClipboard, " - %s [%s]", qPrintable(format),
+ qPrintable(c_uti));
buffer.detach(); //detach since we release the macBuffer
retList.append(buffer);
break; //skip to next element
}
}
} else {
-#ifdef DEBUG_PASTEBOARD
- qDebug(" - NoMatch %s [%s] (%s)", qPrintable(c_flavor), qPrintable(QString::fromNSString(flavor)), qPrintable(c->convertorName()));
-#endif
+ qCDebug(lcQpaClipboard, " - NoMatch %s [%s]", qPrintable(c_uti),
+ qPrintable(QString::fromCFString(uti)));
}
}
}
if (!retList.isEmpty()) {
- ret = c->convertToMime(format, retList, c_flavor);
+ ret = c->convertToMime(format, retList, c_uti);
return ret;
}
}
@@ -555,17 +451,13 @@ void QMacPasteboard::clear_helper()
promises.clear();
}
-void
-QMacPasteboard::clear()
+void QMacPasteboard::clear()
{
-#ifdef DEBUG_PASTEBOARD
- qDebug("PasteBoard: clear!");
-#endif
+ qCDebug(lcQpaClipboard, "PasteBoard: clear!");
clear_helper();
}
-bool
-QMacPasteboard::sync() const
+bool QMacPasteboard::sync() const
{
if (!paste)
return false;
@@ -574,10 +466,8 @@ QMacPasteboard::sync() const
if (fromGlobal)
const_cast<QMacPasteboard *>(this)->setMimeData(nullptr);
-#ifdef DEBUG_PASTEBOARD
if (fromGlobal)
- qDebug("Pasteboard: Synchronize!");
-#endif
+ qCDebug(lcQpaClipboard, "Pasteboard: Synchronize!");
return fromGlobal;
}
@@ -594,7 +484,7 @@ QString qt_mac_get_pasteboardString(PasteboardRef paste)
pb = [NSPasteboard generalPasteboard];
}
if (pb) {
- NSString *text = [pb stringForType:NSStringPboardType];
+ NSString *text = [pb stringForType:NSPasteboardTypeString];
if (text)
return QString::fromNSString(text);
}
diff --git a/src/plugins/platforms/cocoa/qmacdefines_mac.h b/src/plugins/platforms/cocoa/qmacdefines_mac.h
deleted file mode 100644
index 9e229b8dcb..0000000000
--- a/src/plugins/platforms/cocoa/qmacdefines_mac.h
+++ /dev/null
@@ -1,129 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and 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$
-**
-****************************************************************************/
-
-/****************************************************************************
-**
-** Copyright (c) 2007-2008, Apple, Inc.
-**
-** All rights reserved.
-**
-** Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are met:
-**
-** * Redistributions of source code must retain the above copyright notice,
-** this list of conditions and the following disclaimer.
-**
-** * Redistributions in binary form must reproduce the above copyright notice,
-** this list of conditions and the following disclaimer in the documentation
-** and/or other materials provided with the distribution.
-**
-** * Neither the name of Apple, Inc. nor the names of its contributors
-** may be used to endorse or promote products derived from this software
-** without specific prior written permission.
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-** EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-** PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-** LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-** NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-**
-****************************************************************************/
-
-/*
- * qmacdefines_mac_p.h
- * All the defines you'll ever need for Qt/Mac :-)
- */
-
-/* This is just many defines. Therefore it doesn't need things like:
-QT_BEGIN_NAMESPACE
-
-
-QT_END_NAMESPACE
-
-Yes, it is an informative comment ;-)
-*/
-
-#include <QtCore/qglobal.h>
-
-#ifdef __LP64__
-typedef signed int OSStatus;
-#else
-typedef signed long OSStatus;
-#endif
-
-typedef struct OpaqueEventHandlerCallRef * EventHandlerCallRef;
-typedef struct OpaqueEventRef * EventRef;
-typedef struct OpaqueMenuRef * MenuRef;
-typedef struct OpaquePasteboardRef* PasteboardRef;
-typedef struct OpaqueRgnHandle * RgnHandle;
-typedef const struct __HIShape *HIShapeRef;
-typedef struct __HIShape *HIMutableShapeRef;
-typedef struct CGRect CGRect;
-typedef struct CGImage *CGImageRef;
-typedef struct CGContext *CGContextRef;
-typedef struct GDevice * GDPtr;
-typedef GDPtr * GDHandle;
-typedef struct OpaqueIconRef * IconRef;
-
-#ifdef __OBJC__
-typedef NSWindow* OSWindowRef;
-typedef NSView *OSViewRef;
-typedef NSMenu *OSMenuRef;
-typedef NSEvent *OSEventRef;
-#else
-typedef void *OSWindowRef;
-typedef void *OSViewRef;
-typedef void *OSMenuRef;
-typedef void *OSEventRef;
-#endif
-
-typedef PasteboardRef OSPasteboardRef;
-typedef struct AEDesc AEDescList;
-typedef AEDescList AERecord;
-typedef AERecord AppleEvent;
-
-#ifdef check
-#undef check
-#endif
diff --git a/src/plugins/platforms/cocoa/qmultitouch_mac.mm b/src/plugins/platforms/cocoa/qmultitouch_mac.mm
index 10652dc6a1..f818b04acd 100644
--- a/src/plugins/platforms/cocoa/qmultitouch_mac.mm
+++ b/src/plugins/platforms/cocoa/qmultitouch_mac.mm
@@ -1,55 +1,21 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <AppKit/AppKit.h>
#include "qmultitouch_mac_p.h"
#include "qcocoahelpers.h"
#include "qcocoascreen.h"
-#include <private/qtouchdevice_p.h>
+#include <private/qpointingdevice_p.h>
QT_BEGIN_NAMESPACE
-Q_LOGGING_CATEGORY(lcInputDevices, "qt.qpa.input.devices")
+using namespace Qt::StringLiterals;
-QHash<qint64, QCocoaTouch*> QCocoaTouch::_currentTouches;
-QHash<quint64, QTouchDevice*> QCocoaTouch::_touchDevices;
-QPointF QCocoaTouch::_screenReferencePos;
-QPointF QCocoaTouch::_trackpadReferencePos;
+Q_CONSTINIT QHash<qint64, QCocoaTouch*> QCocoaTouch::_currentTouches;
+Q_CONSTINIT QHash<quint64, QPointingDevice*> QCocoaTouch::_touchDevices;
+Q_CONSTINIT QPointF QCocoaTouch::_screenReferencePos;
+Q_CONSTINIT QPointF QCocoaTouch::_trackpadReferencePos;
int QCocoaTouch::_idAssignmentCount = 0;
int QCocoaTouch::_touchCount = 0;
bool QCocoaTouch::_updateInternalStateOnly = true;
@@ -110,22 +76,22 @@ QCocoaTouch *QCocoaTouch::findQCocoaTouch(NSTouch *nstouch)
return nullptr;
}
-Qt::TouchPointState QCocoaTouch::toTouchPointState(NSTouchPhase nsState)
+QEventPoint::State QCocoaTouch::toTouchPointState(NSTouchPhase nsState)
{
- Qt::TouchPointState qtState = Qt::TouchPointReleased;
+ QEventPoint::State qtState = QEventPoint::State::Released;
switch (nsState) {
case NSTouchPhaseBegan:
- qtState = Qt::TouchPointPressed;
+ qtState = QEventPoint::State::Pressed;
break;
case NSTouchPhaseMoved:
- qtState = Qt::TouchPointMoved;
+ qtState = QEventPoint::State::Updated;
break;
case NSTouchPhaseStationary:
- qtState = Qt::TouchPointStationary;
+ qtState = QEventPoint::State::Stationary;
break;
case NSTouchPhaseEnded:
case NSTouchPhaseCancelled:
- qtState = Qt::TouchPointReleased;
+ qtState = QEventPoint::State::Released;
break;
default:
break;
@@ -179,14 +145,17 @@ QCocoaTouch::getCurrentTouchPointList(NSEvent *event, bool acceptSingleTouch)
// Next: sadly, we need to check that our touch hash is in
// sync with cocoa. This is typically not the case after a system
- // gesture happend (like a four-finger-swipe to show expose).
+ // gesture happened (like a four-finger-swipe to show expose).
if (_touchCount != _currentTouches.size()) {
// Remove all instances, and basically start from scratch:
touchPoints.clear();
- foreach (QCocoaTouch *qcocoaTouch, _currentTouches) {
+ // Deleting touch points will remove them from current touches,
+ // so we make a copy of the touches before iterating them.
+ const auto currentTouchesSnapshot = _currentTouches;
+ for (QCocoaTouch *qcocoaTouch : currentTouchesSnapshot) {
if (!_updateInternalStateOnly) {
- qcocoaTouch->_touchPoint.state = Qt::TouchPointReleased;
+ qcocoaTouch->_touchPoint.state = QEventPoint::State::Released;
touchPoints.insert(qcocoaTouch->_touchPoint.id, qcocoaTouch->_touchPoint);
}
delete qcocoaTouch;
@@ -202,7 +171,7 @@ QCocoaTouch::getCurrentTouchPointList(NSEvent *event, bool acceptSingleTouch)
if (_updateInternalStateOnly && !wasUpdateInternalStateOnly && !_currentTouches.isEmpty()) {
QCocoaTouch *qcocoaTouch = _currentTouches.cbegin().value();
- qcocoaTouch->_touchPoint.state = Qt::TouchPointReleased;
+ qcocoaTouch->_touchPoint.state = QEventPoint::State::Released;
touchPoints.insert(qcocoaTouch->_touchPoint.id, qcocoaTouch->_touchPoint);
// Since this last touch also will end up being the first
// touch (if the user adds a second finger without lifting
@@ -214,17 +183,18 @@ QCocoaTouch::getCurrentTouchPointList(NSEvent *event, bool acceptSingleTouch)
return touchPoints.values();
}
-QTouchDevice *QCocoaTouch::getTouchDevice(QTouchDevice::DeviceType type, quint64 id)
+QPointingDevice *QCocoaTouch::getTouchDevice(QInputDevice::DeviceType type, quint64 id)
{
- QTouchDevice *ret = _touchDevices.value(id);
+ QPointingDevice *ret = _touchDevices.value(id);
if (!ret) {
- ret = new QTouchDevice;
- ret->setType(type);
- ret->setCapabilities(QTouchDevice::Position | QTouchDevice::NormalizedPosition | QTouchDevice::MouseEmulation);
- QWindowSystemInterface::registerTouchDevice(ret);
+ ret = new QPointingDevice(type == QInputDevice::DeviceType::TouchScreen ? "touchscreen"_L1 : "trackpad"_L1,
+ id, type, QPointingDevice::PointerType::Finger,
+ QInputDevice::Capability::Position |
+ QInputDevice::Capability::NormalizedPosition |
+ QInputDevice::Capability::MouseEmulation,
+ 10, 0);
+ QWindowSystemInterface::registerInputDevice(ret);
_touchDevices.insert(id, ret);
- qCDebug(lcInputDevices) << "touch device" << id << "of type" << type
- << "registered as Qt device" << QTouchDevicePrivate::get(ret)->id;
}
return ret;
}
diff --git a/src/plugins/platforms/cocoa/qmultitouch_mac_p.h b/src/plugins/platforms/cocoa/qmultitouch_mac_p.h
index 044bcd1882..d47d37729f 100644
--- a/src/plugins/platforms/cocoa/qmultitouch_mac_p.h
+++ b/src/plugins/platforms/cocoa/qmultitouch_mac_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
//
// W A R N I N G
@@ -52,12 +16,15 @@
#define QMULTITOUCH_MAC_P_H
#include <QtCore/qglobal.h>
-
-#import <AppKit/AppKit.h>
-
#include <qpa/qwindowsysteminterface.h>
#include <qhash.h>
#include <QtCore>
+#include <QtGui/qpointingdevice.h>
+
+#include <QtCore/private/qcore_mac_p.h>
+
+Q_FORWARD_DECLARE_OBJC_CLASS(NSTouch);
+QT_FORWARD_DECLARE_OBJC_ENUM(NSTouchPhase, unsigned long);
QT_BEGIN_NAMESPACE
@@ -66,10 +33,10 @@ class QCocoaTouch
public:
static QList<QWindowSystemInterface::TouchPoint> getCurrentTouchPointList(NSEvent *event, bool acceptSingleTouch);
static void setMouseInDraggingState(bool inDraggingState);
- static QTouchDevice *getTouchDevice(QTouchDevice::DeviceType type, quint64 id);
+ static QPointingDevice *getTouchDevice(QInputDevice::DeviceType type, quint64 id);
private:
- static QHash<quint64, QTouchDevice*> _touchDevices;
+ static QHash<quint64, QPointingDevice*> _touchDevices;
static QHash<qint64, QCocoaTouch*> _currentTouches;
static QPointF _screenReferencePos;
static QPointF _trackpadReferencePos;
@@ -85,7 +52,7 @@ class QCocoaTouch
void updateTouchData(NSTouch *nstouch, NSTouchPhase phase);
static QCocoaTouch *findQCocoaTouch(NSTouch *nstouch);
- static Qt::TouchPointState toTouchPointState(NSTouchPhase nsState);
+ static QEventPoint::State toTouchPointState(NSTouchPhase nsState);
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/qnsview.h b/src/plugins/platforms/cocoa/qnsview.h
index 74d0735b4c..7f845a5c3b 100644
--- a/src/plugins/platforms/cocoa/qnsview.h
+++ b/src/plugins/platforms/cocoa/qnsview.h
@@ -1,49 +1,12 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QNSVIEW_H
#define QNSVIEW_H
-#include <AppKit/AppKit.h>
-#include <MetalKit/MetalKit.h>
+#include <AppKit/NSView.h>
-#include "private/qcore_mac_p.h"
+#include <QtCore/private/qcore_mac_p.h>
QT_BEGIN_NAMESPACE
class QCocoaWindow;
@@ -51,30 +14,34 @@ class QCocoaGLContext;
class QPointF;
QT_END_NAMESPACE
-@interface QT_MANGLE_NAMESPACE(QNSView) : NSView
+QT_DECLARE_NAMESPACED_OBJC_INTERFACE(QNSView, NSView
@property (nonatomic, retain) NSCursor *cursor;
- (instancetype)initWithCocoaWindow:(QCocoaWindow *)platformWindow;
- (void)convertFromScreen:(NSPoint)mouseLocation toWindowPoint:(QPointF *)qtWindowPoint andScreenPoint:(QPointF *)qtScreenPoint;
-@end
-
-QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSView);
+)
+#if defined(__OBJC__)
@interface QNSView (MouseAPI)
+- (void)handleMouseEvent:(NSEvent *)theEvent;
- (void)handleFrameStrutMouseEvent:(NSEvent *)theEvent;
- (void)resetMouseButtons;
@end
-@interface QNSView (KeysAPI)
-+ (Qt::KeyboardModifiers)convertKeyModifiers:(ulong)modifierFlags;
-@end
-
@interface QNSView (ComplexTextAPI)
- (void)unmarkText;
- (void)cancelComposingText;
@end
+Q_FORWARD_DECLARE_OBJC_CLASS(NSColorSpace);
+
+@interface QNSView (DrawingAPI)
+@property (nonatomic, readonly) NSColorSpace *colorSpace;
+@end
+
@interface QNSView (QtExtras)
@property (nonatomic, readonly) QCocoaWindow *platformWindow;
@end
+#endif // __OBJC__
+
#endif //QNSVIEW_H
diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm
index a6e5ca5f7b..48ffa5c1cc 100644
--- a/src/plugins/platforms/cocoa/qnsview.mm
+++ b/src/plugins/platforms/cocoa/qnsview.mm
@@ -1,44 +1,12 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtGui/qtguiglobal.h>
+#include <AppKit/AppKit.h>
+#include <MetalKit/MetalKit.h>
+#include <UniformTypeIdentifiers/UTCoreTypes.h>
+
#include "qnsview.h"
#include "qcocoawindow.h"
#include "qcocoahelpers.h"
@@ -54,23 +22,20 @@
#include <QtCore/QPointer>
#include <QtCore/QSet>
#include <QtCore/qsysinfo.h>
+#include <QtCore/private/qcore_mac_p.h>
#include <QtGui/QAccessible>
#include <QtGui/QImage>
#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"
#endif
#include "qcocoaintegration.h"
-
-// Private interface
-@interface QNSView ()
-- (BOOL)isTransparentForUserInput;
-@property (assign) NSView* previousSuperview;
-@property (assign) NSWindow* previousWindow;
-@end
+#include <QtGui/private/qmacmimeregistry_p.h>
@interface QNSView (Drawing) <CALayerDelegate>
- (void)initDrawing;
@@ -112,38 +77,63 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSViewMouseMoveHelper);
@end
@interface QNSView (ComplexText) <NSTextInputClient>
-- (void)textInputContextKeyboardSelectionDidChangeNotification:(NSNotification *)textInputContextKeyboardSelectionDidChangeNotification;
+@property (readonly) QObject* focusObject;
+@end
+
+@interface QT_MANGLE_NAMESPACE(QNSViewMenuHelper) : NSObject
+- (instancetype)initWithView:(QNSView *)theView;
+@end
+QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSViewMenuHelper);
+
+// Private interface
+@interface QNSView ()
+- (BOOL)isTransparentForUserInput;
+@property (assign) NSView* previousSuperview;
+@property (assign) NSWindow* previousWindow;
+@property (retain) QNSViewMenuHelper* menuHelper;
+@property (nonatomic, retain) NSColorSpace *colorSpace;
@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_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;
+ bool m_sendKeyEventWithoutText;
NSEvent *m_currentlyInterpretedKeyEvent;
QSet<quint32> m_acceptedKeyDowns;
+
+ // Text
+ QString m_composingText;
+ QPointer<QObject> m_composingFocusObject;
+ NSDraggingContext m_lastSeenContext;
}
+@synthesize colorSpace = m_colorSpace;
+
- (instancetype)initWithCocoaWindow:(QCocoaWindow *)platformWindow
{
if ((self = [super initWithFrame:NSZeroRect])) {
m_platformWindow = platformWindow;
- m_sendKeyEvent = false;
- m_inputSource = nil;
- m_resendKeyEvent = false;
- m_updatingDrag = false;
- m_currentlyInterpretedKeyEvent = nil;
+
+ // NSViews are by default visible, but QWindows are not.
+ // We should ideally pick up the actual QWindow state here,
+ // but QWindowPrivate::setVisible() expects to control the
+ // order of events tightly, so we need to wait for a call
+ // to QCocoaWindow::setVisible().
+ self.hidden = YES;
self.focusRingType = NSFocusRingTypeNone;
@@ -154,10 +144,14 @@ 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;
+ m_lastSeenContext = NSDraggingContextWithinApplication;
+
+ self.menuHelper = [[[QNSViewMenuHelper alloc] initWithView:self] autorelease];
}
return self;
}
@@ -166,7 +160,6 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSViewMouseMoveHelper);
{
qCDebug(lcQpaWindow) << "Deallocating" << self;
- [m_inputSource release];
[[NSNotificationCenter defaultCenter] removeObserver:self];
[m_mouseMoveHelper release];
@@ -284,15 +277,29 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSViewMouseMoveHelper);
return focusWindow;
}
+/*
+ Invoked when the view is hidden, either directly,
+ or in response to an ancestor being hidden.
+*/
- (void)viewDidHide
{
+ qCDebug(lcQpaWindow) << "Did hide" << self;
+
if (!m_platformWindow->isExposed())
return;
m_platformWindow->handleExposeEvent(QRegion());
+}
+
+/*
+ Invoked when the view is unhidden, either directly,
+ or in response to an ancestor being unhidden.
+*/
+- (void)viewDidUnhide
+{
+ qCDebug(lcQpaWindow) << "Did unhide" << self;
- // Note: setNeedsDisplay is automatically called for
- // viewDidUnhide so no reason to override it here.
+ [self setNeedsDisplay:YES];
}
- (BOOL)isTransparentForUserInput
@@ -307,8 +314,28 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSViewMouseMoveHelper);
return NO;
if ([self isTransparentForUserInput])
return NO;
- if (!m_platformWindow->windowIsPopupType())
- QWindowSystemInterface::handleWindowActivated([self topLevelWindow]);
+
+ if (!m_platformWindow->windowIsPopupType()
+ && (!self.window.canBecomeKeyWindow || self.window.keyWindow)) {
+ // Calling handleWindowActivated for a QWindow has two effects: first, it
+ // will set the QWindow (and all other QWindows in the same hierarchy)
+ // as Active. Being Active means that the window should appear active from
+ // a style perspective (according to QWindow::isActive()). The second
+ // effect is that it will set QQuiApplication::focusWindow() to point to
+ // the QWindow. The latter means that the QWindow should have keyboard
+ // focus. But those two are not necessarily the same; A tool window could e.g be
+ // rendered as Active while the parent window, which is also Active, has
+ // input focus. But we currently don't distinguish between that cleanly in Qt.
+ // Since we don't want a QWindow to be rendered as Active when the NSWindow
+ // it belongs to is not key, we skip calling handleWindowActivated when
+ // that is the case. Instead, we wait for the window to become key, and handle
+ // 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::handleFocusWindowChanged<QWindowSystemInterface::SynchronousDelivery>(
+ [self topLevelWindow], Qt::ActiveWindowFocusReason);
+ }
+
return YES;
}
@@ -375,7 +402,7 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSViewMouseMoveHelper);
#include "qnsview_keys.mm"
#include "qnsview_complextext.mm"
#include "qnsview_menus.mm"
-#ifndef QT_NO_ACCESSIBILITY
+#if QT_CONFIG(accessibility)
#include "qnsview_accessibility.mm"
#endif
diff --git a/src/plugins/platforms/cocoa/qnsview_accessibility.mm b/src/plugins/platforms/cocoa/qnsview_accessibility.mm
index 7041e14da7..e781f21a6c 100644
--- a/src/plugins/platforms/cocoa/qnsview_accessibility.mm
+++ b/src/plugins/platforms/cocoa/qnsview_accessibility.mm
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
// This file is included from qnsview.mm, and only used to organize the code
@@ -45,10 +9,19 @@
#include <QtGui/qaccessible.h>
-#import <AppKit/NSAccessibility.h>
+#include <AppKit/NSAccessibility.h>
@implementation QNSView (Accessibility)
+- (void)activateQtAccessibility
+{
+ // Activate the Qt accessibility machinery for all entry points
+ // below that may be triggered by system accessibility queries,
+ // as otherwise Qt is not aware that the system needs to know
+ // about all accessibility state changes in Qt.
+ QCocoaIntegration::instance()->accessibility()->setActive(true);
+}
+
- (id)childAccessibleElement
{
QCocoaWindow *platformWindow = self.platformWindow;
@@ -68,8 +41,7 @@
- (id)accessibilityAttributeValue:(NSString *)attribute
{
- // activate accessibility updates
- QCocoaIntegration::instance()->accessibility()->setActive(true);
+ [self activateQtAccessibility];
if ([attribute isEqualToString:NSAccessibilityChildrenAttribute])
return NSAccessibilityUnignoredChildrenForOnlyChild([self childAccessibleElement]);
@@ -79,11 +51,13 @@
- (id)accessibilityHitTest:(NSPoint)point
{
+ [self activateQtAccessibility];
return [[self childAccessibleElement] accessibilityHitTest:point];
}
- (id)accessibilityFocusedUIElement
{
+ [self activateQtAccessibility];
return [[self childAccessibleElement] accessibilityFocusedUIElement];
}
diff --git a/src/plugins/platforms/cocoa/qnsview_complextext.mm b/src/plugins/platforms/cocoa/qnsview_complextext.mm
index 5926840cf3..d7f8f4baf0 100644
--- a/src/plugins/platforms/cocoa/qnsview_complextext.mm
+++ b/src/plugins/platforms/cocoa/qnsview_complextext.mm
@@ -1,315 +1,600 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 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$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
// This file is included from qnsview.mm, and only used to organize the code
-@implementation QNSView (ComplexTextAPI)
+@implementation QNSView (ComplexText)
-- (void)cancelComposingText
+// ------------- Text insertion -------------
+
+- (QObject*)focusObject
{
- if (m_composingText.isEmpty())
- return;
+ // The text input system may still hold a reference to our QNSView,
+ // even after QCocoaWindow has been destructed, delivering text input
+ // events to us, so we need to guard for this situation explicitly.
+ if (!m_platformWindow)
+ return nullptr;
- 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);
- }
+ return m_platformWindow->window()->focusObject();
+}
+
+/*
+ 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;
-}
+ if (queryInputMethod(self.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(self.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];
+ if (!m_platformWindow)
+ return;
+
+ // 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(m_currentlyInterpretedKeyEvent ?
+ m_currentlyInterpretedKeyEvent : NSApp.currentEvent);
+ newlineEvent.type = QEvent::KeyPress;
+
+ const bool isEnter = newlineEvent.modifiers & Qt::KeypadModifier;
+ newlineEvent.key = isEnter ? Qt::Key_Enter : Qt::Key_Return;
+ newlineEvent.text = isEnter ? QLatin1Char(kEnterCharCode)
+ : QLatin1Char(kReturnCharCode);
+ newlineEvent.nativeVirtualKey = isEnter ? quint32(kVK_ANSI_KeypadEnter)
+ : quint32(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 = self.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
+{
+ if (auto queryResult = queryInputMethod(self.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 = self.focusObject;
+ if (queryInputMethod(focusObject)) {
+ QInputMethodEvent e;
+ e.setCommitString(m_composingText);
+ QCoreApplication::sendEvent(focusObject, &e);
}
}
-}
-- (BOOL)hasMarkedText
-{
- return (m_composingText.isEmpty() ? NO: YES);
+ m_composingText.clear();
+ m_composingFocusObject = nullptr;
}
-- (NSAttributedString *)attributedSubstringForProposedRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange
+/*
+ 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
{
- 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;
+ if (m_composingText.isEmpty())
+ return;
- QString selectedText = queryEvent.value(Qt::ImCurrentSelection).toString();
- if (selectedText.isEmpty())
- return nil;
+ qCDebug(lcQpaKeys) << "Canceling composition" << m_composingText
+ << "for focus object" << m_composingFocusObject;
- 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];
+ if (queryInputMethod(m_composingFocusObject)) {
+ QInputMethodEvent e;
+ QCoreApplication::sendEvent(m_composingFocusObject, &e);
+ }
+
+ m_composingText.clear();
+ m_composingFocusObject = nullptr;
}
-- (NSRange)markedRange
+// ------------- Key binding command handling -------------
+
+- (void)doCommandBySelector:(SEL)selector
{
- NSRange range;
- if (!m_composingText.isEmpty()) {
- range.location = 0;
- range.length = m_composingText.length();
- } else {
- range.location = NSNotFound;
- range.length = 0;
+ // 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;
+
+ if (![NSStringFromSelector(selector) hasPrefix:@"insert"]) {
+ // The text input system determined that the key event was not
+ // meant for text insertion, and instead asked us to treat it
+ // as a (possibly noop) command. This typically happens for key
+ // events with either ⌘ or ⌃, function keys such as F1-F35,
+ // arrow keys, etc. We reflect that when sending the key event
+ // later on, by removing the text from the event, so that the
+ // event does not result in text insertion on the client side.
+ m_sendKeyEventWithoutText = true;
+ }
}
- return range;
}
+// ------------- Various text properties -------------
+
+/*
+ Returns the range of selected text, or {cursorPosition, 0} if there's none.
+
+ The returned range measures from the start of the receiver’s text storage,
+ that is, from 0 to the document length.
+*/
- (NSRange)selectedRange
{
- 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();
+ if (auto queryResult = queryInputMethod(self.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 {
+ return {NSNotFound, 0};
}
- return selectedRange;
}
-- (NSRect)firstRectForCharacterRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange
+/*
+ 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
{
- Q_UNUSED(aRange)
- Q_UNUSED(actualRange)
+ if (auto queryResult = queryInputMethod(self.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();
- QObject *fo = m_platformWindow->window()->focusObject();
- if (!fo)
- return NSZeroRect;
+ // 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());
- QInputMethodQueryEvent queryEvent(Qt::ImEnabled);
- if (!QCoreApplication::sendEvent(fo, &queryEvent))
- return NSZeroRect;
- if (!queryEvent.value(Qt::ImEnabled).toBool())
- return NSZeroRect;
+ 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];
- // 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);
+ } else {
+ return nil;
+ }
}
-- (NSUInteger)characterIndexForPoint:(NSPoint)aPoint
+- (NSRect)firstRectForCharacterRange:(NSRange)range actualRange:(NSRangePointer)actualRange
+{
+ Q_UNUSED(range);
+ Q_UNUSED(actualRange);
+
+ QWindow *window = m_platformWindow ? m_platformWindow->window() : nullptr;
+ if (window && queryInputMethod(window->focusObject())) {
+ QRect cursorRect = qApp->inputMethod()->cursorRectangle().toRect();
+ cursorRect.moveBottomLeft(window->mapToGlobal(cursorRect.bottomLeft()));
+ return QCocoaScreen::mapToNative(cursorRect);
+ } else {
+ return NSZeroRect;
+ }
+}
+
+- (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
+/*
+ Returns the window level of the text input.
+
+ This allows the input method to place its input panel
+ above the text input.
+*/
+- (NSInteger)windowLevel
{
- if (!m_platformWindow)
- return nil;
+ // The default level assumed by input methods is NSFloatingWindowLevel,
+ // but our NSWindow level could be higher than that for many reasons,
+ // including being set via QWindow::setFlags() or directly on the
+ // NSWindow, or because we're embedded into a native view hierarchy.
+ // Return the actual window level to account for this.
+ auto level = m_platformWindow ? m_platformWindow->nativeWindow().level
+ : NSNormalWindowLevel;
+
+ // The logic above only covers our own window though. In some cases,
+ // such as when a completer is active, the text input has a lower
+ // window level than another window that's also visible, and we don't
+ // want the input panel to be sandwiched between these two windows.
+ // Account for this by explicitly using NSPopUpMenuWindowLevel as
+ // the minimum window level, which corresponds to the highest level
+ // one can get via QWindow::setFlags(), except for Qt::ToolTip.
+ return qMax(level, NSPopUpMenuWindowLevel);
+}
- if (m_platformWindow->window() != QGuiApplication::focusWindow())
- return nil;
+// ------------- Helper functions -------------
- QObject *fo = m_platformWindow->window()->focusObject();
- if (!fo)
- return nil;
+/*
+ Sanitizes the replacement range, ensuring it's valid.
- QInputMethodQueryEvent queryEvent(Qt::ImEnabled);
- if (!QCoreApplication::sendEvent(fo, &queryEvent))
- return nil;
- if (!queryEvent.value(Qt::ImEnabled).toBool())
- return nil;
+ If \a range is not valid the range of the current
+ marked text will be used.
+
+ 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
+
+ // If the replacement range is not specified we are expected to compute
+ // the range ourselves, based on the current state of the input context.
- // Support only underline color/style.
- return @[NSUnderlineColorAttributeName, NSUnderlineStyleAttributeName];
+ 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_dragging.mm b/src/plugins/platforms/cocoa/qnsview_dragging.mm
index 650612e7ff..4f7d35a0d6 100644
--- a/src/plugins/platforms/cocoa/qnsview_dragging.mm
+++ b/src/plugins/platforms/cocoa/qnsview_dragging.mm
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 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$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
// This file is included from qnsview.mm, and only used to organize the code
@@ -47,18 +11,17 @@
NSString * const mimeTypeGeneric = @"com.trolltech.qt.MimeTypeName";
NSMutableArray<NSString *> *supportedTypes = [NSMutableArray<NSString *> arrayWithArray:@[
- NSColorPboardType,
- NSFilenamesPboardType, NSStringPboardType,
- NSFilenamesPboardType, NSPostScriptPboardType, NSTIFFPboardType,
- NSRTFPboardType, NSTabularTextPboardType, NSFontPboardType,
- NSRulerPboardType, NSFileContentsPboardType, NSColorPboardType,
- NSRTFDPboardType, NSHTMLPboardType,
- NSURLPboardType, NSPDFPboardType, NSVCardPboardType,
- NSFilesPromisePboardType, NSInkTextPboardType,
- NSMultipleTextSelectionPboardType, mimeTypeGeneric]];
+ NSPasteboardTypeColor, NSPasteboardTypeString,
+ NSPasteboardTypeFileURL, @"com.adobe.encapsulated-postscript", NSPasteboardTypeTIFF,
+ NSPasteboardTypeRTF, NSPasteboardTypeTabularText, NSPasteboardTypeFont,
+ NSPasteboardTypeRuler, NSFileContentsPboardType,
+ NSPasteboardTypeRTFD , NSPasteboardTypeHTML,
+ NSPasteboardTypeURL, NSPasteboardTypePDF, UTTypeVCard.identifier,
+ (NSString *)kPasteboardTypeFileURLPromise,
+ NSPasteboardTypeMultipleTextSelection, mimeTypeGeneric]];
// Add custom types supported by the application
- for (const QString &customType : qt_mac_enabledDraggedTypes())
+ for (const QString &customType : QMacMimeRegistry::enabledDraggedTypes())
[supportedTypes addObject:customType.toNSString()];
[self registerForDraggedTypes:supportedTypes];
@@ -82,8 +45,8 @@ static QPoint mapWindowCoordinates(QWindow *source, QWindow *target, QPoint poin
- (NSDragOperation)draggingSession:(NSDraggingSession *)session sourceOperationMaskForDraggingContext:(NSDraggingContext)context
{
Q_UNUSED(session);
- Q_UNUSED(context);
+ m_lastSeenContext = context;
QCocoaDrag* nativeDrag = QCocoaIntegration::instance()->drag();
return qt_mac_mapDropActions(nativeDrag->currentDrag()->supportedActions());
}
@@ -98,8 +61,11 @@ static QPoint mapWindowCoordinates(QWindow *source, QWindow *target, QPoint poin
//
// Since Qt already takes care of tracking the keyboard modifiers, we
// don't need (or want) Cocoa to filter anything. Instead, we'll let
- // the application do the actual filtering.
- return YES;
+ // the application do the actual filtering. But only while dragging
+ // within application, otherwise ignored modifiers may end up in a
+ // wrong drop operation executed.
+
+ return m_lastSeenContext == NSDraggingContextWithinApplication;
}
- (BOOL)wantsPeriodicDraggingUpdates
@@ -150,10 +116,8 @@ static QPoint mapWindowCoordinates(QWindow *source, QWindow *target, QPoint poin
break;
}
} else {
- NSImage *nsimage = qt_mac_create_nsimage(pixmapCursor);
- nsimage.size = NSSizeFromCGSize((pixmapCursor.size() / pixmapCursor.devicePixelRatioF()).toCGSize());
+ auto *nsimage = [NSImage imageFromQImage:pixmapCursor.toImage()];
nativeCursor = [[NSCursor alloc] initWithImage:nsimage hotSpot:NSZeroPoint];
- [nsimage release];
}
// Change the cursor
@@ -200,7 +164,7 @@ static QPoint mapWindowCoordinates(QWindow *source, QWindow *target, QPoint poin
if (!target)
return NSDragOperationNone;
- const auto modifiers = [QNSView convertKeyModifiers:NSApp.currentEvent.modifierFlags];
+ const auto modifiers = QAppleKeyMapper::fromCocoaModifiers(NSApp.currentEvent.modifierFlags);
const auto buttons = currentlyPressedMouseButtons();
const auto point = mapWindowCoordinates(m_platformWindow->window(), target, windowPoint);
@@ -234,6 +198,10 @@ static QPoint mapWindowCoordinates(QWindow *source, QWindow *target, QPoint poin
if (!target)
return;
+ auto *nativeDrag = QCocoaIntegration::instance()->drag();
+ Q_ASSERT(nativeDrag);
+ nativeDrag->exitDragLoop();
+
QPoint windowPoint = QPointF::fromCGPoint([self convertPoint:sender.draggingLocation fromView:nil]).toPoint();
qCDebug(lcQpaMouse) << QEvent::DragLeave << self << "at" << windowPoint;
@@ -260,7 +228,7 @@ static QPoint mapWindowCoordinates(QWindow *source, QWindow *target, QPoint poin
QPlatformDropQtResponse response(false, Qt::IgnoreAction);
QCocoaDrag* nativeDrag = QCocoaIntegration::instance()->drag();
- const auto modifiers = [QNSView convertKeyModifiers:NSApp.currentEvent.modifierFlags];
+ const auto modifiers = QAppleKeyMapper::fromCocoaModifiers(NSApp.currentEvent.modifierFlags);
const auto buttons = currentlyPressedMouseButtons();
const auto point = mapWindowCoordinates(m_platformWindow->window(), target, windowPoint);
@@ -285,6 +253,8 @@ static QPoint mapWindowCoordinates(QWindow *source, QWindow *target, QPoint poin
Q_UNUSED(screenPoint);
Q_UNUSED(operation);
+ m_lastSeenContext = NSDraggingContextWithinApplication;
+
if (!m_platformWindow)
return;
@@ -292,13 +262,18 @@ static QPoint mapWindowCoordinates(QWindow *source, QWindow *target, QPoint poin
if (!target)
return;
- QCocoaIntegration::instance()->drag();
+ QCocoaDrag* nativeDrag = QCocoaIntegration::instance()->drag();
+ Q_ASSERT(nativeDrag);
+ nativeDrag->exitDragLoop();
+ // for internal drag'n'drop, don't override the action the drop event accepted
+ if (!nativeDrag->currentDrag())
+ nativeDrag->setAcceptedAction(qt_mac_mapNSDragOperation(operation));
// Qt starts drag-and-drop on a mouse button press event. Cococa in
// this case won't send the matching release event, so we have to
// synthesize it here.
m_buttons = currentlyPressedMouseButtons();
- const auto modifiers = [QNSView convertKeyModifiers:NSApp.currentEvent.modifierFlags];
+ const auto modifiers = QAppleKeyMapper::fromCocoaModifiers(NSApp.currentEvent.modifierFlags);
NSPoint windowPoint = [self.window convertRectFromScreen:NSMakeRect(screenPoint.x, screenPoint.y, 1, 1)].origin;
NSPoint nsViewPoint = [self convertPoint: windowPoint fromView: nil];
diff --git a/src/plugins/platforms/cocoa/qnsview_drawing.mm b/src/plugins/platforms/cocoa/qnsview_drawing.mm
index 2fd63fad67..bf102e43f8 100644
--- a/src/plugins/platforms/cocoa/qnsview_drawing.mm
+++ b/src/plugins/platforms/cocoa/qnsview_drawing.mm
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 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$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
// This file is included from qnsview.mm, and only used to organize the code
@@ -43,7 +7,21 @@
- (void)initDrawing
{
- [self updateLayerBacking];
+ if (qt_mac_resolveOption(-1, m_platformWindow->window(),
+ "_q_mac_wantsLayer", "QT_MAC_WANTS_LAYER") != -1) {
+ qCWarning(lcQpaDrawing) << "Layer-backing is always enabled."
+ << " QT_MAC_WANTS_LAYER/_q_mac_wantsLayer has no effect.";
+ }
+
+ // Pick up and persist requested color space from surface format
+ const QSurfaceFormat surfaceFormat = m_platformWindow->format();
+ if (QColorSpace colorSpace = surfaceFormat.colorSpace(); colorSpace.isValid()) {
+ NSData *iccData = colorSpace.iccProfile().toNSData();
+ self.colorSpace = [[[NSColorSpace alloc] initWithICCProfileData:iccData] autorelease];
+ }
+
+ // Trigger creation of the layer
+ self.wantsLayer = YES;
}
- (BOOL)isOpaque
@@ -58,41 +36,13 @@
return YES;
}
-// ----------------------- Layer setup -----------------------
-
-- (void)updateLayerBacking
+- (NSColorSpace*)colorSpace
{
- self.wantsLayer = [self layerEnabledByMacOS]
- || [self layerExplicitlyRequested]
- || [self shouldUseMetalLayer];
+ // If no explicit color space was set, use the NSWindow's color space
+ return m_colorSpace ? m_colorSpace : self.window.colorSpace;
}
-- (BOOL)layerEnabledByMacOS
-{
- // AppKit has its own logic for this, but if we rely on that, our layers are created
- // by AppKit at a point where we've already set up other parts of the platform plugin
- // based on the presence of layers or not. Once we've rewritten these parts to support
- // dynamically picking up layer enablement we can let AppKit do its thing.
- return QMacVersion::buildSDK() >= QOperatingSystemVersion::MacOSMojave
- && QMacVersion::currentRuntime() >= QOperatingSystemVersion::MacOSMojave;
-}
-
-- (BOOL)layerExplicitlyRequested
-{
- static bool wantsLayer = [&]() {
- int wantsLayer = qt_mac_resolveOption(-1, m_platformWindow->window(),
- "_q_mac_wantsLayer", "QT_MAC_WANTS_LAYER");
-
- if (wantsLayer != -1 && [self layerEnabledByMacOS]) {
- qCWarning(lcQpaDrawing) << "Layer-backing cannot be explicitly controlled on 10.14 when built against the 10.14 SDK";
- return true;
- }
-
- return wantsLayer == 1;
- }();
-
- return wantsLayer;
-}
+// ----------------------- Layer setup -----------------------
- (BOOL)shouldUseMetalLayer
{
@@ -146,8 +96,7 @@
{
qCDebug(lcQpaDrawing) << "Making" << self
<< (self.wantsLayer ? "layer-backed" : "layer-hosted")
- << "with" << layer << "due to being" << ([self layerExplicitlyRequested] ? "explicitly requested"
- : [self shouldUseMetalLayer] ? "needed by surface type" : "enabled by macOS");
+ << "with" << layer;
if (layer.delegate && layer.delegate != self) {
qCWarning(lcQpaDrawing) << "Layer already has delegate" << layer.delegate
@@ -158,12 +107,7 @@
[super setLayer:layer];
- // When adding a view to a view hierarchy the backing properties will change
- // which results in updating the contents scale, but in case of switching the
- // layer on a view that's already in a view hierarchy we need to manually ensure
- // the scale is up to date.
- if (self.superview)
- [self updateLayerContentsScale];
+ [self propagateBackingProperties];
if (self.opaque && lcQpaDrawing().isDebugEnabled()) {
// If the view claims to be opaque we expect it to fill the entire
@@ -196,8 +140,7 @@
{
qCDebug(lcQpaDrawing) << "Backing properties changed for" << self;
- if (self.layer)
- [self updateLayerContentsScale];
+ [self propagateBackingProperties];
// Ideally we would plumb this situation through QPA in a way that lets
// clients invalidate their own caches, recreate QBackingStore, etc.
@@ -206,8 +149,11 @@
[self setNeedsDisplay:YES];
}
-- (void)updateLayerContentsScale
+- (void)propagateBackingProperties
{
+ if (!self.layer)
+ return;
+
// We expect clients to fill the layer with retina aware content,
// based on the devicePixelRatio of the QWindow, so we set the
// layer's content scale to match that. By going via devicePixelRatio
@@ -218,6 +164,12 @@
auto devicePixelRatio = m_platformWindow->devicePixelRatio();
qCDebug(lcQpaDrawing) << "Updating" << self.layer << "content scale to" << devicePixelRatio;
self.layer.contentsScale = devicePixelRatio;
+
+ if ([self.layer isKindOfClass:CAMetalLayer.class]) {
+ CAMetalLayer *metalLayer = static_cast<CAMetalLayer *>(self.layer);
+ metalLayer.colorspace = self.colorSpace.CGColorSpace;
+ qCDebug(lcQpaDrawing) << "Set" << metalLayer << "color space to" << metalLayer.colorspace;
+ }
}
/*
@@ -228,7 +180,9 @@
*/
- (BOOL)layer:(CALayer *)layer shouldInheritContentsScale:(CGFloat)scale fromWindow:(NSWindow *)window
{
- Q_UNUSED(layer); Q_UNUSED(scale); Q_UNUSED(window);
+ Q_UNUSED(layer);
+ Q_UNUSED(scale);
+ Q_UNUSED(window);
return NO;
}
@@ -240,24 +194,11 @@
*/
- (void)drawRect:(NSRect)dirtyBoundingRect
{
- Q_ASSERT_X(!self.layer, "QNSView",
- "The drawRect code path should not be hit when we are layer backed");
-
- if (!m_platformWindow)
- return;
-
- QRegion exposedRegion;
- const NSRect *dirtyRects;
- NSInteger numDirtyRects;
- [self getRectsBeingDrawn:&dirtyRects count:&numDirtyRects];
- for (int i = 0; i < numDirtyRects; ++i)
- exposedRegion += QRectF::fromCGRect(dirtyRects[i]).toRect();
-
- if (exposedRegion.isEmpty())
- exposedRegion = QRectF::fromCGRect(dirtyBoundingRect).toRect();
-
- qCDebug(lcQpaDrawing) << "[QNSView drawRect:]" << m_platformWindow->window() << exposedRegion;
- m_platformWindow->handleExposeEvent(exposedRegion);
+ Q_UNUSED(dirtyBoundingRect);
+ // As we are layer backed we shouldn't really end up here, but AppKit will
+ // in some cases call this method just because we implement it.
+ // FIXME: Remove drawRect and switch from displayLayer to updateLayer
+ qCWarning(lcQpaDrawing) << "[QNSView drawRect] called for layer backed view";
}
/*
diff --git a/src/plugins/platforms/cocoa/qnsview_gestures.mm b/src/plugins/platforms/cocoa/qnsview_gestures.mm
index a80261fd6a..7c64e3356f 100644
--- a/src/plugins/platforms/cocoa/qnsview_gestures.mm
+++ b/src/plugins/platforms/cocoa/qnsview_gestures.mm
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 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$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
// This file is included from qnsview.mm, and only used to organize the code
@@ -75,8 +39,9 @@ Q_LOGGING_CATEGORY(lcQpaGestures, "qt.qpa.input.gestures")
QPointF windowPoint;
QPointF screenPoint;
[self convertFromScreen:[self screenMousePoint:event] toWindowPoint:&windowPoint andScreenPoint:&screenPoint];
- QWindowSystemInterface::handleGestureEventWithRealValue(m_platformWindow->window(), QCocoaTouch::getTouchDevice(QTouchDevice::TouchPad, [event deviceID]), timestamp, Qt::ZoomNativeGesture,
- [event magnification], windowPoint, screenPoint);
+ QWindowSystemInterface::handleGestureEventWithRealValue(m_platformWindow->window(), timestamp,
+ QCocoaTouch::getTouchDevice(QInputDevice::DeviceType::TouchPad, [event deviceID]),
+ Qt::ZoomNativeGesture, [event magnification], windowPoint, screenPoint);
}
- (void)smartMagnifyWithEvent:(NSEvent *)event
@@ -90,8 +55,9 @@ Q_LOGGING_CATEGORY(lcQpaGestures, "qt.qpa.input.gestures")
QPointF windowPoint;
QPointF screenPoint;
[self convertFromScreen:[self screenMousePoint:event] toWindowPoint:&windowPoint andScreenPoint:&screenPoint];
- QWindowSystemInterface::handleGestureEventWithRealValue(m_platformWindow->window(), QCocoaTouch::getTouchDevice(QTouchDevice::TouchPad, [event deviceID]), timestamp, Qt::SmartZoomNativeGesture,
- zoomIn ? 1.0f : 0.0f, windowPoint, screenPoint);
+ QWindowSystemInterface::handleGestureEventWithRealValue(m_platformWindow->window(), timestamp,
+ QCocoaTouch::getTouchDevice(QInputDevice::DeviceType::TouchPad, [event deviceID]),
+ Qt::SmartZoomNativeGesture, zoomIn ? 1.0f : 0.0f, windowPoint, screenPoint);
zoomIn = !zoomIn;
}
@@ -107,8 +73,9 @@ Q_LOGGING_CATEGORY(lcQpaGestures, "qt.qpa.input.gestures")
QPointF windowPoint;
QPointF screenPoint;
[self convertFromScreen:[self screenMousePoint:event] toWindowPoint:&windowPoint andScreenPoint:&screenPoint];
- QWindowSystemInterface::handleGestureEventWithRealValue(m_platformWindow->window(), QCocoaTouch::getTouchDevice(QTouchDevice::TouchPad, [event deviceID]), timestamp, Qt::RotateNativeGesture,
- -[event rotation], windowPoint, screenPoint);
+ QWindowSystemInterface::handleGestureEventWithRealValue(m_platformWindow->window(), timestamp,
+ QCocoaTouch::getTouchDevice(QInputDevice::DeviceType::TouchPad, [event deviceID]),
+ Qt::RotateNativeGesture, -[event rotation], windowPoint, screenPoint);
}
- (void)swipeWithEvent:(NSEvent *)event
@@ -132,8 +99,9 @@ Q_LOGGING_CATEGORY(lcQpaGestures, "qt.qpa.input.gestures")
else if ([event deltaY] == -1)
angle = 270.0f;
- QWindowSystemInterface::handleGestureEventWithRealValue(m_platformWindow->window(), QCocoaTouch::getTouchDevice(QTouchDevice::TouchPad, [event deviceID]), timestamp, Qt::SwipeNativeGesture,
- angle, windowPoint, screenPoint);
+ QWindowSystemInterface::handleGestureEventWithRealValue(m_platformWindow->window(), timestamp,
+ QCocoaTouch::getTouchDevice(QInputDevice::DeviceType::TouchPad, [event deviceID]),
+ Qt::SwipeNativeGesture, angle, windowPoint, screenPoint, 3);
}
- (void)beginGestureWithEvent:(NSEvent *)event
@@ -146,8 +114,9 @@ Q_LOGGING_CATEGORY(lcQpaGestures, "qt.qpa.input.gestures")
QPointF screenPoint;
[self convertFromScreen:[self screenMousePoint:event] toWindowPoint:&windowPoint andScreenPoint:&screenPoint];
qCDebug(lcQpaGestures) << "beginGestureWithEvent @" << windowPoint << "from device" << Qt::hex << [event deviceID];
- QWindowSystemInterface::handleGestureEvent(m_platformWindow->window(), QCocoaTouch::getTouchDevice(QTouchDevice::TouchPad, [event deviceID]), timestamp, Qt::BeginNativeGesture,
- windowPoint, screenPoint);
+ QWindowSystemInterface::handleGestureEvent(m_platformWindow->window(), timestamp,
+ QCocoaTouch::getTouchDevice(QInputDevice::DeviceType::TouchPad, [event deviceID]),
+ Qt::BeginNativeGesture, windowPoint, screenPoint);
}
- (void)endGestureWithEvent:(NSEvent *)event
@@ -160,8 +129,9 @@ Q_LOGGING_CATEGORY(lcQpaGestures, "qt.qpa.input.gestures")
QPointF windowPoint;
QPointF screenPoint;
[self convertFromScreen:[self screenMousePoint:event] toWindowPoint:&windowPoint andScreenPoint:&screenPoint];
- QWindowSystemInterface::handleGestureEvent(m_platformWindow->window(), QCocoaTouch::getTouchDevice(QTouchDevice::TouchPad, [event deviceID]), timestamp, Qt::EndNativeGesture,
- windowPoint, screenPoint);
+ QWindowSystemInterface::handleGestureEvent(m_platformWindow->window(), timestamp,
+ QCocoaTouch::getTouchDevice(QInputDevice::DeviceType::TouchPad, [event deviceID]),
+ Qt::EndNativeGesture, windowPoint, screenPoint);
}
@end
diff --git a/src/plugins/platforms/cocoa/qnsview_keys.mm b/src/plugins/platforms/cocoa/qnsview_keys.mm
index 847adca207..abee622e65 100644
--- a/src/plugins/platforms/cocoa/qnsview_keys.mm
+++ b/src/plugins/platforms/cocoa/qnsview_keys.mm
@@ -1,161 +1,143 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 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$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
// This file is included from qnsview.mm, and only used to organize the code
-@implementation QNSView (KeysAPI)
+/*
+ Determines if the text represents one of the "special keys" on macOS
-+ (Qt::KeyboardModifiers)convertKeyModifiers:(ulong)modifierFlags
-{
- const bool dontSwapCtrlAndMeta = qApp->testAttribute(Qt::AA_MacDontSwapCtrlAndMeta);
- Qt::KeyboardModifiers qtMods =Qt::NoModifier;
- if (modifierFlags & NSEventModifierFlagShift)
- qtMods |= Qt::ShiftModifier;
- if (modifierFlags & NSEventModifierFlagControl)
- qtMods |= dontSwapCtrlAndMeta ? Qt::ControlModifier : Qt::MetaModifier;
- if (modifierFlags & NSEventModifierFlagOption)
- qtMods |= Qt::AltModifier;
- if (modifierFlags & NSEventModifierFlagCommand)
- qtMods |= dontSwapCtrlAndMeta ? Qt::MetaModifier : Qt::ControlModifier;
- if (modifierFlags & NSEventModifierFlagNumericPad)
- qtMods |= Qt::KeypadModifier;
- return qtMods;
-}
+ As a legacy from OpenStep, macOS reserves the range 0xF700-0xF8FF of the
+ Unicode private use area for representing function keys on the keyboard:
-@end
+ http://www.unicode.org/Public/MAPPINGS/VENDORS/APPLE/CORPCHAR.TXT
-@implementation QNSView (Keys)
+ https://developer.apple.com/documentation/appkit/nsevent/specialkey
-- (int)convertKeyCode:(QChar)keyChar
+ These code points are not supposed to have any glyphs associated with them,
+ but since we can't guarantee that the system doesn't have a font that does
+ provide glyphs for this range (Arial Unicode MS e.g.) we need to filter
+ the text of our key events up front.
+*/
+static bool isSpecialKey(const QString &text)
{
- return qt_mac_cocoaKey2QtKey(keyChar);
+ if (text.length() != 1)
+ return false;
+
+ const char16_t unicode = text.at(0).unicode();
+ if (unicode >= 0xF700 && unicode <= 0xF8FF)
+ return true;
+
+ return false;
}
-- (bool)handleKeyEvent:(NSEvent *)nsevent eventType:(int)eventType
+static bool sendAsShortcut(const KeyEvent &keyEvent, QWindow *window)
{
- ulong timestamp = [nsevent timestamp] * 1000;
- ulong nativeModifiers = [nsevent modifierFlags];
- Qt::KeyboardModifiers modifiers = [QNSView convertKeyModifiers: nativeModifiers];
- NSString *charactersIgnoringModifiers = [nsevent charactersIgnoringModifiers];
- NSString *characters = [nsevent characters];
- if (m_inputSource != characters) {
- [m_inputSource release];
- m_inputSource = [characters retain];
+ KeyEvent shortcutEvent = keyEvent;
+ shortcutEvent.type = QEvent::Shortcut;
+ qCDebug(lcQpaKeys) << "Trying potential shortcuts in" << window
+ << "for" << shortcutEvent;
+
+ if (shortcutEvent.sendWindowSystemEvent(window)) {
+ qCDebug(lcQpaKeys) << "Found matching shortcut; will not send as key event";
+ return true;
}
+ qCDebug(lcQpaKeys) << "No matching shortcuts; continuing with key event delivery";
+ return false;
+}
- // There is no way to get the scan code from carbon/cocoa. But we cannot
- // use the value 0, since it indicates that the event originates from somewhere
- // else than the keyboard.
- quint32 nativeScanCode = 1;
- 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) {
- auto ctrlOrMetaModifier = qApp->testAttribute(Qt::AA_MacDontSwapCtrlAndMeta) ? Qt::ControlModifier : Qt::MetaModifier;
- if (((modifiers & ctrlOrMetaModifier) || (modifiers & Qt::AltModifier)) && ([charactersIgnoringModifiers length] != 0))
- ch = QChar([charactersIgnoringModifiers characterAtIndex:0]);
- else if ([characters length] != 0)
- ch = QChar([characters characterAtIndex:0]);
- keyCode = [self convertKeyCode:ch];
+@implementation QNSView (Keys)
+
+- (bool)performKeyEquivalent:(NSEvent *)nsevent
+{
+ // Implemented to handle shortcuts for modified Tab keys, which are
+ // handled by Cocoa and not delivered to your keyDown implementation.
+ if (nsevent.type == NSEventTypeKeyDown && m_composingText.isEmpty()) {
+ const bool ctrlDown = [nsevent modifierFlags] & NSEventModifierFlagControl;
+ const bool isTabKey = nsevent.keyCode == kVK_Tab;
+ if (ctrlDown && isTabKey && sendAsShortcut(KeyEvent(nsevent), [self topLevelWindow]))
+ return YES;
}
+ return NO;
+}
- // 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);
+- (bool)handleKeyEvent:(NSEvent *)nsevent
+{
+ 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) {
+ // Assume we should send key events with text, unless told
+ // otherwise by doCommandBySelector.
+ m_sendKeyEventWithoutText = false;
- if (m_composingText.isEmpty()) {
- m_sendKeyEvent = !QWindowSystemInterface::handleShortcutEvent(window, timestamp, keyCode,
- modifiers, nativeScanCode, nativeVirtualKey, nativeModifiers, text, [nsevent isARepeat], 1);
+ bool didInterpretKeyEvent = false;
+
+ if (keyEvent.type == QEvent::KeyPress) {
- // Handling a shortcut may result in closing the window
- if (!m_platformWindow)
+ if (m_composingText.isEmpty()) {
+ if (sendAsShortcut(keyEvent, window))
return true;
}
- 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());
- if (imEnabled && !(hints & Qt::ImhDigitsOnly || hints & Qt::ImhFormattedNumbersOnly || hints & Qt::ImhHiddenText)) {
- // pass the key event to the input method. note that m_sendKeyEvent may be set to false during this call
+ QObject *focusObject = m_platformWindow ? m_platformWindow->window()->focusObject() : nullptr;
+ 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 (![self.inputContext handleEvent:nsevent]) {
+ qCDebug(lcQpaKeys) << "Input context did not consume event";
+ m_sendKeyEvent = true;
+ }
m_currentlyInterpretedKeyEvent = 0;
+ didInterpretKeyEvent = true;
+
+ // 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();
+ // Trust text input system on whether to send the event with text or not,
+ // or otherwise apply heuristics to filter out private use symbols.
+ if (didInterpretKeyEvent ? m_sendKeyEventWithoutText : isSpecialKey(keyEvent.text))
+ keyEvent.text = {};
+ qCDebug(lcQpaKeys) << "Sending as" << keyEvent;
+ accepted = keyEvent.sendWindowSystemEvent(window);
}
- m_sendKeyEvent = false;
- m_resendKeyEvent = false;
return accepted;
}
@@ -164,7 +146,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,
@@ -175,7 +157,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];
@@ -186,12 +168,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
+ // accepted. Qt text controls will 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];
}
@@ -200,63 +182,157 @@
{
Q_UNUSED(sender);
- NSEvent *currentEvent = [NSApp currentEvent];
+ NSEvent *currentEvent = NSApp.currentEvent;
if (!currentEvent || currentEvent.type != NSEventTypeKeyDown)
return;
// Handling the key event may recurse back here through interpretKeyEvents
// (when IM is enabled), so we need to guard against that.
- if (currentEvent == m_currentlyInterpretedKeyEvent)
+ if (currentEvent == m_currentlyInterpretedKeyEvent) {
+ m_sendKeyEvent = true;
return;
+ }
// 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 modifiers = [nsevent modifierFlags];
- Qt::KeyboardModifiers qmodifiers = [QNSView convertKeyModifiers:modifiers];
-
- // calculate the delta and remember the current modifiers for next time
- static ulong m_lastKnownModifiers;
- ulong lastKnownModifiers = m_lastKnownModifiers;
- ulong delta = lastKnownModifiers ^ modifiers;
- m_lastKnownModifiers = modifiers;
-
- 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::handleKeyEvent(m_platformWindow->window(),
- timestamp,
- (lastKnownModifiers & mac_mask) ? QEvent::KeyRelease : QEvent::KeyPress,
- qtCode,
- qmodifiers ^ [QNSView convertKeyModifiers: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;
+ nativeModifiers = nsevent.modifierFlags;
+ modifiers = QAppleKeyMapper::fromCocoaModifiers(nativeModifiers);
+
+ switch (nsevent.type) {
+ case NSEventTypeKeyDown: type = QEvent::KeyPress; break;
+ case NSEventTypeKeyUp: type = QEvent::KeyRelease; break;
+ default: break; // Must be manually set
+ }
+
+ switch (nsevent.type) {
+ case NSEventTypeKeyDown:
+ case NSEventTypeKeyUp:
+ case NSEventTypeFlagsChanged:
+ nativeVirtualKey = nsevent.keyCode;
+ default:
+ break;
+ }
+
+ 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);
+ }
+
+ text = QString::fromNSString(characters);
+
+ isRepeat = nsevent.ARepeat;
+ }
+}
+
+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;
+ QWindowSystemInterface::handleExtendedKeyEvent(window, timestamp,
+ type, key, modifiers, nativeScanCode, nativeVirtualKey, nativeModifiers,
+ text, isRepeat, count);
+ // 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_menus.mm b/src/plugins/platforms/cocoa/qnsview_menus.mm
index b6cd832282..2840936975 100644
--- a/src/plugins/platforms/cocoa/qnsview_menus.mm
+++ b/src/plugins/platforms/cocoa/qnsview_menus.mm
@@ -1,66 +1,64 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 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$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
// This file is included from qnsview.mm, and only used to organize the code
-#include <qcocoaapplicationdelegate.h>
-#include <qcocoansmenu.h>
-#include <qcocoamenuitem.h>
-#include <qcocoamenu.h>
-#include <qcocoamenubar.h>
+#include "qcocoaapplicationdelegate.h"
+#include "qcocoansmenu.h"
+#include "qcocoamenuitem.h"
+#include "qcocoamenu.h"
+#include "qcocoamenubar.h"
-static bool selectorIsCutCopyPaste(SEL selector)
+@implementation QNSView (Menus)
+
+// Qt does not (yet) have a mechanism for propagating generic actions,
+// so we can only support actions that originate from a QCocoaNSMenuItem,
+// where we can forward the action by emitting QPlatformMenuItem::activated().
+// But waiting for forwardInvocation to check that the sender is a
+// QCocoaNSMenuItem is too late, as AppKit has at that point chosen
+// our view as the target for the action, and if we can't handle it
+// the action will not propagate up the responder chain as it should.
+// Instead, we hook in early in the process of determining the target
+// via the supplementalTargetForAction API, and if we can support the
+// action we forward it to a helper. The helper must be tied to the
+// view, as the menu validation logic depends on the view's state.
+
+- (id)supplementalTargetForAction:(SEL)action sender:(id)sender
{
- return (selector == @selector(cut:)
- || selector == @selector(copy:)
- || selector == @selector(paste:)
- || selector == @selector(selectAll:));
+ qCDebug(lcQpaMenus) << "Resolving action target for" << action << "from" << sender << "via" << self;
+
+ if (qt_objc_cast<QCocoaNSMenuItem *>(sender)) {
+ // The supplemental target must support the selector, but we
+ // determine so dynamically, so check here before continuing.
+ if ([self.menuHelper respondsToSelector:action])
+ return self.menuHelper;
+ } else {
+ qCDebug(lcQpaMenus) << "Ignoring action for menu item we didn't create";
+ }
+
+ return [super supplementalTargetForAction:action sender:sender];
}
-@interface QNSView (Menus)
-- (void)qt_itemFired:(QCocoaNSMenuItem *)item;
@end
-@implementation QNSView (Menus)
+@interface QNSViewMenuHelper ()
+@property (assign) QNSView* view;
+@end
+
+@implementation QNSViewMenuHelper
+
+- (instancetype)initWithView:(QNSView *)theView
+{
+ if ((self = [super init]))
+ self.view = theView;
+
+ return self;
+}
- (BOOL)validateMenuItem:(NSMenuItem*)item
{
+ qCDebug(lcQpaMenus) << "Validating" << item << "for" << self.view;
+
auto *nativeItem = qt_objc_cast<QCocoaNSMenuItem *>(item);
if (!nativeItem)
return item.enabled; // FIXME Test with with Qt as plugin or embedded QWindow.
@@ -73,19 +71,21 @@ static bool selectorIsCutCopyPaste(SEL selector)
if (platformItem->menu())
return YES;
- // Check if a modal dialog is active. Validate only menu
- // items belonging to this view's window own menu bar.
- if (QGuiApplication::modalWindow()) {
+ // Check if a modal dialog is active. If so, enable only menu
+ // items explicitly belonging to this window's own menu bar, or to the window.
+ if (QGuiApplication::modalWindow() && QGuiApplication::modalWindow()->isActive()) {
QCocoaMenuBar *menubar = nullptr;
+ QCocoaWindow *menuWindow = nullptr;
QObject *menuParent = platformItem->menuParent();
while (menuParent && !(menubar = qobject_cast<QCocoaMenuBar *>(menuParent))) {
+ menuWindow = qobject_cast<QCocoaWindow *>(menuParent);
auto *menuObject = dynamic_cast<QCocoaMenuObject *>(menuParent);
- menuParent = menuObject->menuParent();
+ menuParent = menuObject ? menuObject->menuParent() : nullptr;
}
- // we have no menubar parent for the application menu items, e.g About and Preferences
- if (!menubar || menubar->cocoaWindow() != self.platformWindow)
+ if ((!menuWindow || menuWindow->window() != QGuiApplication::modalWindow())
+ && (!menubar || menubar->cocoaWindow() != self.view.platformWindow))
return NO;
}
@@ -94,41 +94,42 @@ static bool selectorIsCutCopyPaste(SEL selector)
- (BOOL)respondsToSelector:(SEL)selector
{
- // Not exactly true. Both copy: and selectAll: can work on non key views.
- if (selectorIsCutCopyPaste(selector))
- return ([NSApp keyWindow] == self.window) && (self.window.firstResponder == self);
+ // See QCocoaMenuItem::resolveTargetAction()
+
+ if (selector == @selector(cut:)
+ || selector == @selector(copy:)
+ || selector == @selector(paste:)
+ || selector == @selector(selectAll:)) {
+ // Not exactly true. Both copy: and selectAll: can work on non key views.
+ return NSApp.keyWindow == self.view.window
+ && self.view.window.firstResponder == self.view;
+ }
- return [super respondsToSelector:selector];
-}
+ if (selector == @selector(qt_itemFired:))
+ return YES;
-- (void)qt_itemFired:(QCocoaNSMenuItem *)item
-{
- auto *appDelegate = [QCocoaApplicationDelegate sharedDelegate];
- [appDelegate qt_itemFired:item];
+ return [super respondsToSelector:selector];
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector
{
- if (selectorIsCutCopyPaste(selector)) {
- NSMethodSignature *itemFiredSign = [super methodSignatureForSelector:@selector(qt_itemFired:)];
- return itemFiredSign;
- }
+ // Double check, in case something has cached that we respond
+ // to the selector, but the result has changed since then.
+ if (![self respondsToSelector:selector])
+ return nil;
- return [super methodSignatureForSelector:selector];
+ auto *appDelegate = [QCocoaApplicationDelegate sharedDelegate];
+ return [appDelegate methodSignatureForSelector:@selector(qt_itemFired:)];
}
- (void)forwardInvocation:(NSInvocation *)invocation
{
- if (selectorIsCutCopyPaste(invocation.selector)) {
- NSObject *sender;
- [invocation getArgument:&sender atIndex:2];
- if (auto *nativeItem = qt_objc_cast<QCocoaNSMenuItem *>(sender)) {
- [self qt_itemFired:nativeItem];
- return;
- }
- }
-
- [super forwardInvocation:invocation];
+ NSObject *sender;
+ [invocation getArgument:&sender atIndex:2];
+ qCDebug(lcQpaMenus) << "Forwarding" << invocation.selector << "from" << sender;
+ Q_ASSERT(qt_objc_cast<QCocoaNSMenuItem *>(sender));
+ invocation.selector = @selector(qt_itemFired:);
+ [invocation invokeWithTarget:[QCocoaApplicationDelegate sharedDelegate]];
}
@end
diff --git a/src/plugins/platforms/cocoa/qnsview_mouse.mm b/src/plugins/platforms/cocoa/qnsview_mouse.mm
index 9e2761f850..2fd57fe68e 100644
--- a/src/plugins/platforms/cocoa/qnsview_mouse.mm
+++ b/src/plugins/platforms/cocoa/qnsview_mouse.mm
@@ -1,44 +1,40 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 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$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
// This file is included from qnsview.mm, and only used to organize the code
+using namespace Qt::StringLiterals;
+
+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("mouse"_L1, 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.
@@ -93,31 +89,68 @@
- (void)resetMouseButtons
{
- qCDebug(lcQpaMouse) << "Reseting mouse buttons";
+ qCDebug(lcQpaMouse) << "Resetting mouse buttons";
m_buttons = Qt::NoButton;
m_frameStrutButtons = Qt::NoButton;
}
-- (void)handleFrameStrutMouseEvent:(NSEvent *)theEvent
+- (void)handleMouseEvent:(NSEvent *)theEvent
{
if (!m_platformWindow)
return;
- // get m_buttons in sync
- // Don't send frme strut events if we are in the middle of a mouse drag.
- if (m_buttons != Qt::NoButton)
+#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)
return;
switch (theEvent.type) {
case NSEventTypeLeftMouseDown:
- case NSEventTypeLeftMouseDragged:
m_frameStrutButtons |= Qt::LeftButton;
break;
case NSEventTypeLeftMouseUp:
m_frameStrutButtons &= ~Qt::LeftButton;
break;
case NSEventTypeRightMouseDown:
- case NSEventTypeRightMouseDragged:
m_frameStrutButtons |= Qt::RightButton;
break;
case NSEventTypeRightMouseUp:
@@ -132,6 +165,22 @@
break;
}
+ // m_buttons can sometimes get out of sync with the button state in AppKit
+ // E.g if the QNSView where a drag starts is reparented to another window
+ // while the drag is ongoing, it will not get the corresponding mouseUp
+ // call. This will result in m_buttons to be stuck on Qt::LeftButton.
+ // Since we know which buttons was pressed/released directly on the frame
+ // strut, we can rectify m_buttons here so that we at least don't return early
+ // from the drag test underneath because of the faulty m_buttons state.
+ // FIXME: get m_buttons in sync with AppKit/NSEvent all over in QNSView.
+ m_buttons &= ~m_frameStrutButtons;
+
+ if (m_buttons != Qt::NoButton) {
+ // Don't send frame strut events if we are in the middle of
+ // a mouse drag that didn't start on the frame strut.
+ return;
+ }
+
NSWindow *window = [self window];
NSPoint windowPoint = [theEvent locationInWindow];
@@ -160,20 +209,19 @@
case NSEventTypeOtherMouseUp:
return QEvent::NonClientAreaMouseButtonRelease;
+ case NSEventTypeMouseMoved:
case NSEventTypeLeftMouseDragged:
case NSEventTypeRightMouseDragged:
case NSEventTypeOtherMouseDragged:
return QEvent::NonClientAreaMouseMove;
default:
- break;
+ Q_UNREACHABLE();
}
-
- return QEvent::None;
}();
qCInfo(lcQpaMouse) << eventType << "at" << qtWindowPoint << "with" << m_frameStrutButtons << "in" << self.window;
- QWindowSystemInterface::handleFrameStrutMouseEvent(m_platformWindow->window(),
+ QWindowSystemInterface::handleMouseEvent(m_platformWindow->window(),
timestamp, qtWindowPoint, qtScreenPoint, m_frameStrutButtons, button, eventType);
}
@end
@@ -195,8 +243,13 @@
m_mouseMoveHelper = [[QNSViewMouseMoveHelper alloc] initWithView:self];
- NSUInteger trackingOptions = NSTrackingActiveInActiveApp
- | NSTrackingMouseEnteredAndExited | NSTrackingCursorUpdate;
+ NSUInteger trackingOptions = NSTrackingCursorUpdate | NSTrackingMouseEnteredAndExited;
+
+ // Ideally we should have used NSTrackingActiveInActiveApp, but that
+ // fails when the application is deactivated from using e.g cmd+tab, and later
+ // reactivated again from a mouse click. So as a work-around we use NSTrackingActiveAlways
+ // instead, and simply ignore any related callbacks while the application is inactive.
+ trackingOptions |= NSTrackingActiveAlways;
// Ideally, NSTrackingMouseMoved should be turned on only if QWidget::mouseTracking
// is enabled, hover is on, or a tool tip is set. Unfortunately, Qt will send "tooltip"
@@ -217,7 +270,7 @@
- (BOOL)acceptsFirstMouse:(NSEvent *)theEvent
{
- Q_UNUSED(theEvent)
+ Q_UNUSED(theEvent);
if (!m_platformWindow)
return NO;
if ([self isTransparentForUserInput])
@@ -225,8 +278,6 @@
QPointF windowPoint;
QPointF screenPoint;
[self convertFromScreen:[NSEvent mouseLocation] toWindowPoint: &windowPoint andScreenPoint: &screenPoint];
- if (!qt_window_private(m_platformWindow->window())->allowClickThrough(screenPoint.toPoint()))
- return NO;
return YES;
}
@@ -247,56 +298,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 = [QNSView convertKeyModifiers: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])
@@ -310,7 +311,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;
@@ -374,46 +375,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(popup->window());
- QWindowSystemInterface::flushWindowSystemEvents();
- }
- // 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)
@@ -427,18 +394,35 @@
return;
}
- if ([self hasMarkedText]) {
- [[NSTextInputContext currentInputContext] handleEvent:theEvent];
- } else {
- auto ctrlOrMetaModifier = qApp->testAttribute(Qt::AA_MacDontSwapCtrlAndMeta) ? Qt::ControlModifier : Qt::MetaModifier;
- if (!m_dontOverrideCtrlLMB && [QNSView convertKeyModifiers:[theEvent modifierFlags]] & ctrlOrMetaModifier) {
- m_buttons |= Qt::RightButton;
- m_sendUpAsRightButton = true;
- } else {
- m_buttons |= Qt::LeftButton;
+ // FIXME: AppKit transfers first responder to the view before calling mouseDown,
+ // whereas we only transfer focus once the mouse press is delivered, which means
+ // on first click the focus item won't be the correct one when transferring focus.
+ auto *focusObject = m_platformWindow->window()->focusObject();
+ if (queryInputMethod(focusObject)) {
+ // Input method is enabled. Pass on to the input context if we
+ // are hitting the input item.
+ if (QPlatformInputContext::inputItemClipRectangle().contains(qtWindowPoint)) {
+ qCDebug(lcQpaInputMethods) << "Asking input context to handle mouse press"
+ << "for focus object" << focusObject;
+ if ([NSTextInputContext.currentInputContext handleEvent:theEvent]) {
+ // NSTextView bails out if the input context handled the event,
+ // which is e.g. the case for 2-Set Korean input. We follow suit,
+ // even if that means having to click twice to move the cursor
+ // for these input methods when they are composing.
+ qCDebug(lcQpaInputMethods) << "Input context handled event; bailing out.";
+ return;
+ }
}
- [self handleMouseEvent:theEvent];
}
+
+ if (!m_dontOverrideCtrlLMB && (theEvent.modifierFlags & NSEventModifierFlagControl)) {
+ m_buttons |= Qt::RightButton;
+ m_sendUpAsRightButton = true;
+ } else {
+ m_buttons |= Qt::LeftButton;
+ }
+
+ [self handleMouseEvent:theEvent];
}
- (void)mouseDragged:(NSEvent *)theEvent
@@ -499,9 +483,8 @@
- (void)cursorUpdate:(NSEvent *)theEvent
{
- // Note: We do not get this callback when moving from a subview that
- // uses the legacy cursorRect API, so the cursor is reset to the arrow
- // cursor. See rdar://34183708
+ if (!NSApp.active)
+ return;
auto previousCursor = NSCursor.currentCursor;
@@ -519,56 +502,112 @@
if (!m_platformWindow)
return;
- if ([self isTransparentForUserInput])
- return;
-
- QPointF windowPoint;
- QPointF screenPoint;
- [self convertFromScreen:[self screenMousePoint:theEvent] toWindowPoint:&windowPoint andScreenPoint:&screenPoint];
- QWindow *childWindow = m_platformWindow->childWindowAt(windowPoint.toPoint());
-
// Top-level windows generate enter-leave events for sub-windows.
// Qt wants to know which window (if any) will be entered at the
// the time of the leave. This is dificult to accomplish by
// handling mouseEnter and mouseLeave envents, since they are sent
// individually to different views.
- if (m_platformWindow->isContentView() && childWindow) {
- if (childWindow != m_platformWindow->m_enterLeaveTargetWindow) {
- QWindowSystemInterface::handleEnterLeaveEvent(childWindow, m_platformWindow->m_enterLeaveTargetWindow, windowPoint, screenPoint);
- m_platformWindow->m_enterLeaveTargetWindow = childWindow;
+ QPointF windowPoint;
+ QPointF screenPoint;
+ QCocoaWindow *windowToLeave = nullptr;
+
+ if (m_platformWindow->isContentView()) {
+ [self convertFromScreen:[self screenMousePoint:theEvent] toWindowPoint:&windowPoint andScreenPoint:&screenPoint];
+ QWindow *childUnderMouse = m_platformWindow->childWindowAt(windowPoint.toPoint());
+ QCocoaWindow *childWindow = static_cast<QCocoaWindow *>(childUnderMouse->handle());
+ if (childWindow != QCocoaWindow::s_windowUnderMouse) {
+ if (QCocoaWindow::s_windowUnderMouse)
+ windowToLeave = QCocoaWindow::s_windowUnderMouse;
+ QCocoaWindow::s_windowUnderMouse = childWindow;
}
}
+ if (!NSApp.active)
+ return;
+
+ if ([self isTransparentForUserInput])
+ return;
+
+ if (windowToLeave) {
+ qCInfo(lcQpaMouse) << "Detected new window under mouse at" << windowPoint << "; sending"
+ << QEvent::Enter << QCocoaWindow::s_windowUnderMouse->window()
+ << QEvent::Leave << windowToLeave->window();
+ QWindowSystemInterface::handleEnterLeaveEvent(QCocoaWindow::s_windowUnderMouse->window(), windowToLeave->window(), windowPoint, screenPoint);
+ }
+
// Cocoa keeps firing mouse move events for obscured parent views. Qt should not
// send those events so filter them out here.
- if (childWindow != m_platformWindow->window())
+ if (m_platformWindow != QCocoaWindow::s_windowUnderMouse)
return;
[self handleMouseEvent: theEvent];
}
-- (void)mouseEnteredImpl:(NSEvent *)theEvent
+- (BOOL)shouldPropagateMouseEnterExit
{
- Q_UNUSED(theEvent)
- if (!m_platformWindow)
- return;
+ Q_ASSERT(m_platformWindow);
- m_platformWindow->m_windowUnderMouse = true;
+ // We send out enter and leave events mainly from mouse move events (mouseMovedImpl),
+ // but in some case (see mouseEnteredImpl:) we also want to propagate enter/leave
+ // events from the platform. We only do this for windows that themselves are not
+ // handled by another parent QWindow.
- if ([self isTransparentForUserInput])
+ if (m_platformWindow->isContentView())
+ return true;
+
+ // Windows manually embedded into a native view does not have a QWindow parent
+ if (m_platformWindow->isEmbedded())
+ return true;
+
+ // Windows embedded via fromWinId do, but the parent isn't a QNSView
+ QPlatformWindow *parentWindow = m_platformWindow->QPlatformWindow::parent();
+ if (parentWindow && parentWindow->isForeignWindow())
+ return true;
+
+ return false;
+}
+
+- (void)mouseEnteredImpl:(NSEvent *)theEvent
+{
+ Q_UNUSED(theEvent);
+ if (!m_platformWindow)
return;
- // Top-level windows generate enter events for sub-windows.
- if (!m_platformWindow->isContentView())
+ // We send out enter and leave events mainly from mouse move events (mouseMovedImpl).
+ // Therefore, in most cases, we should not send out enter/leave events from here, as
+ // this results in duplicated enter/leave events being delivered.
+ // This is especially important when working with NSTrackingArea, since AppKit documents that
+ // the order of enter/exit events when several NSTrackingAreas are in use is not guaranteed.
+ // So if we just forwarded enter/leave events from NSTrackingArea directly, it would not only
+ // result in duplicated events, but also sometimes events that would be out of sync.
+ // But not all enter events can be resolved from mouse move events. E.g if a window is raised
+ // in front of the mouse, or if the application is activated while the mouse is on top of a
+ // window, we need to send out enter events for those cases as well. And we do so from this
+ // function to support the former case. But only when we receive an enter event for the
+ // top-level window, when no child QWindows are being hovered from before.
+ // Since QWSI expects us to send both the window entered, and the window left, in the same
+ // callback, we manually keep track of which child QWindow is under the mouse at any point
+ // in time (s_windowUnderMouse). The latter is also used to also send out enter/leave
+ // events when the application is activated/deactivated.
+
+ if (![self shouldPropagateMouseEnterExit])
return;
QPointF windowPoint;
QPointF screenPoint;
[self convertFromScreen:[self screenMousePoint:theEvent] toWindowPoint:&windowPoint andScreenPoint:&screenPoint];
- m_platformWindow->m_enterLeaveTargetWindow = m_platformWindow->childWindowAt(windowPoint.toPoint());
+ QWindow *childUnderMouse = m_platformWindow->childWindowAt(windowPoint.toPoint());
+ QCocoaWindow::s_windowUnderMouse = static_cast<QCocoaWindow *>(childUnderMouse->handle());
+
+ if ([self isTransparentForUserInput])
+ return;
- qCInfo(lcQpaMouse) << QEvent::Enter << self << "at" << windowPoint << "with" << currentlyPressedMouseButtons();
- QWindowSystemInterface::handleEnterEvent(m_platformWindow->m_enterLeaveTargetWindow, windowPoint, screenPoint);
+ if (!NSApp.active)
+ return;
+
+ qCInfo(lcQpaMouse) << "Mouse entered" << self << "at" << windowPoint << "with" << currentlyPressedMouseButtons()
+ << "; sending" << QEvent::Enter << "to" << QCocoaWindow::s_windowUnderMouse->window();
+ QWindowSystemInterface::handleEnterEvent(QCocoaWindow::s_windowUnderMouse->window(), windowPoint, screenPoint);
}
- (void)mouseExitedImpl:(NSEvent *)theEvent
@@ -577,18 +616,23 @@
if (!m_platformWindow)
return;
- m_platformWindow->m_windowUnderMouse = false;
+ if (![self shouldPropagateMouseEnterExit])
+ return;
+
+ QCocoaWindow *windowToLeave = QCocoaWindow::s_windowUnderMouse;
+ QCocoaWindow::s_windowUnderMouse = nullptr;
if ([self isTransparentForUserInput])
return;
- // Top-level windows generate leave events for sub-windows.
- if (!m_platformWindow->isContentView())
+ if (!NSApp.active)
+ return;
+
+ if (!windowToLeave)
return;
- qCInfo(lcQpaMouse) << QEvent::Leave << self;
- QWindowSystemInterface::handleLeaveEvent(m_platformWindow->m_enterLeaveTargetWindow);
- m_platformWindow->m_enterLeaveTargetWindow = 0;
+ qCInfo(lcQpaMouse) << "Mouse left" << self << "; sending" << QEvent::Leave << "to" << windowToLeave->window();
+ QWindowSystemInterface::handleLeaveEvent(windowToLeave->window());
}
#if QT_CONFIG(wheelevent)
@@ -653,14 +697,18 @@
// had time to emit a momentum phase event.
if ([NSApp nextEventMatchingMask:NSEventMaskScrollWheel untilDate:[NSDate distantPast]
inMode:@"QtMomementumEventSearchMode" dequeue:NO].momentumPhase == NSEventPhaseBegan) {
- Q_ASSERT(pixelDelta.isNull() && angleDelta.isNull());
- return; // Ignore this event, as it has a delta of 0,0
+ return; // Ignore, even if it has delta
+ } else {
+ phase = Qt::ScrollEnd;
+ m_scrolling = false;
}
- phase = Qt::ScrollEnd;
- m_scrolling = false;
} else if (theEvent.momentumPhase == NSEventPhaseBegan) {
Q_ASSERT(!pixelDelta.isNull() && !angleDelta.isNull());
- phase = Qt::ScrollUpdate; // Send as update, it has a delta
+ // If we missed finding a momentum NSEventPhaseBegan when the non-momentum
+ // phase ended we need to treat this as a scroll begin, to not confuse client
+ // code. Otherwise we treat it as a continuation of the existing scroll.
+ phase = m_scrolling ? Qt::ScrollUpdate : Qt::ScrollBegin;
+ m_scrolling = true;
} else if (theEvent.momentumPhase == NSEventPhaseChanged) {
phase = Qt::ScrollMomentum;
} else if (theEvent.phase == NSEventPhaseCancelled
@@ -672,6 +720,16 @@
Q_ASSERT(theEvent.momentumPhase != NSEventPhaseStationary);
}
+ // Sanitize deltas for events that should not result in scrolling.
+ // On macOS 12.1 this phase has been observed to report deltas.
+ if (theEvent.phase == NSEventPhaseCancelled) {
+ if (!pixelDelta.isNull() || !angleDelta.isNull()) {
+ qCInfo(lcQpaMouse) << "Ignoring unexpected delta for" << theEvent;
+ pixelDelta = QPoint();
+ angleDelta = QPoint();
+ }
+ }
+
// Prevent keyboard modifier state from changing during scroll event streams.
// A two-finger trackpad flick generates a stream of scroll events. We want
// the keyboard modifier state to be the state at the beginning of the
@@ -680,7 +738,7 @@
// after scrolling in Qt Creator: not taking the phase into account causes
// the end of the event stream to be interpreted as font size changes.
if (theEvent.momentumPhase == NSEventPhaseNone)
- m_currentWheelModifiers = [QNSView convertKeyModifiers:[theEvent modifierFlags]];
+ m_currentWheelModifiers = QAppleKeyMapper::fromCocoaModifiers(theEvent.modifierFlags);
// "isInverted": natural OS X scrolling, inverted from the Qt/other platform/Jens perspective.
bool isInverted = [theEvent isDirectionInvertedFromDevice];
@@ -689,8 +747,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 = "trackpad or magic mouse"_L1;
+ 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/qnsview_tablet.mm b/src/plugins/platforms/cocoa/qnsview_tablet.mm
index ba1fa55892..4c6e351b3f 100644
--- a/src/plugins/platforms/cocoa/qnsview_tablet.mm
+++ b/src/plugins/platforms/cocoa/qnsview_tablet.mm
@@ -1,58 +1,17 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 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$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
// This file is included from qnsview.mm, and only used to organize the code
#ifndef QT_NO_TABLETEVENT
-Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
+#include <QtGui/qpointingdevice.h>
+#include <QtCore/private/qflatmap_p.h>
-struct QCocoaTabletDeviceData
-{
- QTabletEvent::TabletDevice device;
- QTabletEvent::PointerType pointerType;
- uint capabilityMask;
- qint64 uid;
-};
+Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
-typedef QHash<uint, QCocoaTabletDeviceData> QCocoaTabletDeviceDataHash;
-Q_GLOBAL_STATIC(QCocoaTabletDeviceDataHash, tabletDeviceDataHash)
+using QCocoaTabletDeviceMap = QFlatMap<qint64, const QPointingDevice*>;
+Q_GLOBAL_STATIC(QCocoaTabletDeviceMap, devicesInProximity)
@implementation QNSView (Tablet)
@@ -73,14 +32,19 @@ Q_GLOBAL_STATIC(QCocoaTabletDeviceDataHash, tabletDeviceDataHash)
QPointF screenPoint;
[self convertFromScreen:[self screenMousePoint:theEvent] toWindowPoint: &windowPoint andScreenPoint: &screenPoint];
- uint deviceId = [theEvent deviceID];
- if (!tabletDeviceDataHash->contains(deviceId)) {
- // Error: Unknown tablet device. Qt also gets into this state
- // when running on a VM. This appears to be harmless; don't
- // print a warning.
- return false;
+ // We use devicesInProximity because deviceID is typically 0,
+ // so QInputDevicePrivate::fromId() won't work.
+ const auto deviceId = theEvent.deviceID;
+ const auto *device = devicesInProximity->value(deviceId);
+ if (!device && deviceId == 0) {
+ // Application started up with stylus in proximity already, so we missed the proximity event?
+ // Create a generic tablet device for now.
+ device = tabletToolInstance(theEvent);
+ devicesInProximity->insert(deviceId, device);
}
- const QCocoaTabletDeviceData &deviceData = tabletDeviceDataHash->value(deviceId);
+
+ if (Q_UNLIKELY(!device))
+ return false;
bool down = (eventType != NSEventTypeMouseMoved);
@@ -97,28 +61,21 @@ Q_GLOBAL_STATIC(QCocoaTabletDeviceDataHash, tabletDeviceDataHash)
qreal tangentialPressure = 0;
qreal rotation = 0;
int z = 0;
- if (deviceData.capabilityMask & 0x0200)
+ if (device->hasCapability(QInputDevice::Capability::ZPosition))
z = [theEvent absoluteZ];
- if (deviceData.capabilityMask & 0x0800)
+ if (device->hasCapability(QInputDevice::Capability::TangentialPressure))
tangentialPressure = ([theEvent tangentialPressure] * 2.0) - 1.0;
rotation = 360.0 - [theEvent rotation];
if (rotation > 180.0)
rotation -= 360.0;
- Qt::KeyboardModifiers keyboardModifiers = [QNSView convertKeyModifiers:[theEvent modifierFlags]];
+ Qt::KeyboardModifiers keyboardModifiers = QAppleKeyMapper::fromCocoaModifiers(theEvent.modifierFlags);
Qt::MouseButtons buttons = ignoreButtonMapping ? static_cast<Qt::MouseButtons>(static_cast<uint>([theEvent buttonMask])) : m_buttons;
- qCDebug(lcQpaTablet, "event on tablet %d with tool %d type %d unique ID %lld pos %6.1f, %6.1f root pos %6.1f, %6.1f buttons 0x%x pressure %4.2lf tilt %d, %d rotation %6.2lf",
- deviceId, deviceData.device, deviceData.pointerType, deviceData.uid,
- windowPoint.x(), windowPoint.y(), screenPoint.x(), screenPoint.y(),
- static_cast<uint>(buttons), pressure, xTilt, yTilt, rotation);
-
- QWindowSystemInterface::handleTabletEvent(m_platformWindow->window(), timestamp, windowPoint, screenPoint,
- deviceData.device, deviceData.pointerType, buttons, pressure, xTilt, yTilt,
- tangentialPressure, rotation, z, deviceData.uid,
- keyboardModifiers);
+ QWindowSystemInterface::handleTabletEvent(m_platformWindow->window(), timestamp, device, windowPoint, screenPoint,
+ buttons, pressure, xTilt, yTilt, tangentialPressure, rotation, z, keyboardModifiers);
return true;
}
@@ -130,10 +87,17 @@ Q_GLOBAL_STATIC(QCocoaTabletDeviceDataHash, tabletDeviceDataHash)
[self handleTabletEvent: theEvent];
}
-static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
+/*!
+ \internal
+ Find the existing QPointingDevice instance representing a particular tablet or stylus;
+ or create and register a new instance if it was not found.
+
+ An instance can be uniquely identified by various properties taken from \a theEvent.
+*/
+static const QPointingDevice *tabletToolInstance(NSEvent *theEvent)
{
- qint64 uid = [theEvent uniqueID];
- uint bits = [theEvent vendorPointingDeviceType];
+ qint64 uid = theEvent.uniqueID;
+ uint bits = theEvent.vendorPointingDeviceType;
if (bits == 0 && uid != 0) {
// Fallback. It seems that the driver doesn't always include all the information.
// High-End Wacom devices store their "type" in the uper bits of the Unique ID.
@@ -141,82 +105,96 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
bits = uid >> 32;
}
- QTabletEvent::TabletDevice device;
// Defined in the "EN0056-NxtGenImpGuideX"
// on Wacom's Developer Website (www.wacomeng.com)
- if (((bits & 0x0006) == 0x0002) && ((bits & 0x0F06) != 0x0902)) {
- device = QTabletEvent::Stylus;
+ static const quint32 CursorTypeBitMask = 0x0F06;
+ quint32 toolId = bits & CursorTypeBitMask;
+ QInputDevice::Capabilities caps = QInputDevice::Capability::Position |
+ QInputDevice::Capability::Pressure | QInputDevice::Capability::Hover;
+ QInputDevice::DeviceType device;
+ int buttonCount = 3; // the tip, plus two barrel buttons
+ if (((bits & 0x0006) == 0x0002) && (toolId != 0x0902)) {
+ device = QInputDevice::DeviceType::Stylus;
} else {
- switch (bits & 0x0F06) {
- case 0x0802:
- device = QTabletEvent::Stylus;
- break;
- case 0x0902:
- device = QTabletEvent::Airbrush;
- break;
- case 0x0004:
- device = QTabletEvent::FourDMouse;
- break;
- case 0x0006:
- device = QTabletEvent::Puck;
- break;
- case 0x0804:
- device = QTabletEvent::RotationStylus;
- break;
- default:
- device = QTabletEvent::NoDevice;
- }
- }
- return device;
-}
-
-- (void)tabletProximity:(NSEvent *)theEvent
-{
- if ([self isTransparentForUserInput])
- return [super tabletProximity:theEvent];
-
- ulong timestamp = [theEvent timestamp] * 1000;
-
- QCocoaTabletDeviceData deviceData;
- deviceData.uid = [theEvent uniqueID];
- deviceData.capabilityMask = [theEvent capabilityMask];
-
- switch ([theEvent pointingDeviceType]) {
- case NSPointingDeviceTypeUnknown:
- default:
- deviceData.pointerType = QTabletEvent::UnknownPointer;
+ switch (toolId) {
+ // TODO same cases as in qxcbconnection_xi2.cpp? then we could share this function
+ case 0x0802:
+ device = QInputDevice::DeviceType::Stylus;
break;
- case NSPointingDeviceTypePen:
- deviceData.pointerType = QTabletEvent::Pen;
+ case 0x0902:
+ device = QInputDevice::DeviceType::Airbrush;
+ caps.setFlag(QInputDevice::Capability::TangentialPressure);
+ buttonCount = 2;
break;
- case NSPointingDeviceTypeCursor:
- deviceData.pointerType = QTabletEvent::Cursor;
+ case 0x0004:
+ device = QInputDevice::DeviceType::Mouse;
+ caps.setFlag(QInputDevice::Capability::Scroll);
break;
- case NSPointingDeviceTypeEraser:
- deviceData.pointerType = QTabletEvent::Eraser;
+ case 0x0006:
+ device = QInputDevice::DeviceType::Puck;
break;
+ case 0x0804:
+ device = QInputDevice::DeviceType::Stylus; // Art Pen
+ caps.setFlag(QInputDevice::Capability::Rotation);
+ buttonCount = 1;
+ break;
+ default:
+ device = QInputDevice::DeviceType::Unknown;
+ }
}
- deviceData.device = wacomTabletDevice(theEvent);
+ uint capabilityMask = theEvent.capabilityMask;
+ if (capabilityMask & 0x0200)
+ caps.setFlag(QInputDevice::Capability::ZPosition);
+ if (capabilityMask & 0x0800)
+ Q_ASSERT(caps.testFlag(QInputDevice::Capability::TangentialPressure));
+
+ QPointingDevice::PointerType pointerType = QPointingDevice::PointerType::Unknown;
+ switch (theEvent.pointingDeviceType) {
+ case NSPointingDeviceTypeUnknown:
+ default:
+ break;
+ case NSPointingDeviceTypePen:
+ pointerType = QPointingDevice::PointerType::Pen;
+ break;
+ case NSPointingDeviceTypeCursor:
+ pointerType = QPointingDevice::PointerType::Cursor;
+ break;
+ case NSPointingDeviceTypeEraser:
+ pointerType = QPointingDevice::PointerType::Eraser;
+ break;
+ }
- // The deviceID is "unique" while in the proximity, it's a key that we can use for
- // linking up QCocoaTabletDeviceData to an event (especially if there are two devices in action).
- bool entering = [theEvent isEnteringProximity];
- uint deviceId = [theEvent deviceID];
- if (entering) {
- tabletDeviceDataHash->insert(deviceId, deviceData);
- } else {
- tabletDeviceDataHash->remove(deviceId);
+ const auto uniqueID = QPointingDeviceUniqueId::fromNumericId(uid);
+ auto windowSystemId = theEvent.deviceID;
+ const QPointingDevice *ret = QPointingDevicePrivate::queryTabletDevice(device, pointerType, uniqueID, caps, windowSystemId);
+ if (!ret) {
+ // TODO get the device name? (first argument)
+ // TODO associate each stylus with a "master" device representing the tablet itself
+ ret = new QPointingDevice(QString(), windowSystemId, device, pointerType,
+ caps, 1, buttonCount, QString(), uniqueID, QCocoaIntegration::instance());
+ QWindowSystemInterface::registerInputDevice(ret);
}
+ QPointingDevicePrivate *devPriv = QPointingDevicePrivate::get(const_cast<QPointingDevice *>(ret));
+ devPriv->toolId = toolId;
+ return ret;
+}
- qCDebug(lcQpaTablet, "proximity change on tablet %d: current tool %d type %d unique ID %lld",
- deviceId, deviceData.device, deviceData.pointerType, deviceData.uid);
+- (void)tabletProximity:(NSEvent *)theEvent
+{
+ if ([self isTransparentForUserInput])
+ return [super tabletProximity:theEvent];
- if (entering) {
- QWindowSystemInterface::handleTabletEnterProximityEvent(timestamp, deviceData.device, deviceData.pointerType, deviceData.uid);
- } else {
- QWindowSystemInterface::handleTabletLeaveProximityEvent(timestamp, deviceData.device, deviceData.pointerType, deviceData.uid);
- }
+ const ulong timestamp = theEvent.timestamp * 1000;
+ const qint64 windowSystemId = theEvent.deviceID;
+ const QPointingDevice *device = tabletToolInstance(theEvent);
+ // TODO which window?
+ QWindowSystemInterface::handleTabletEnterLeaveProximityEvent(nullptr, timestamp, device, theEvent.isEnteringProximity);
+ // The windowSystemId starts at 0, but is "unique" while in proximity
+ if (theEvent.isEnteringProximity)
+ devicesInProximity->insert_or_assign(windowSystemId, device);
+ else
+ devicesInProximity->remove(windowSystemId);
}
@end
diff --git a/src/plugins/platforms/cocoa/qnsview_touch.mm b/src/plugins/platforms/cocoa/qnsview_touch.mm
index 8dfae27c63..97ed5b7624 100644
--- a/src/plugins/platforms/cocoa/qnsview_touch.mm
+++ b/src/plugins/platforms/cocoa/qnsview_touch.mm
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 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$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
// This file is included from qnsview.mm, and only used to organize the code
@@ -61,7 +25,10 @@ Q_LOGGING_CATEGORY(lcQpaTouch, "qt.qpa.input.touch")
const NSTimeInterval timestamp = [event timestamp];
const QList<QWindowSystemInterface::TouchPoint> points = QCocoaTouch::getCurrentTouchPointList(event, [self shouldSendSingleTouch]);
qCDebug(lcQpaTouch) << "touchesBeganWithEvent" << points << "from device" << Qt::hex << [event deviceID];
- QWindowSystemInterface::handleTouchEvent(m_platformWindow->window(), timestamp * 1000, QCocoaTouch::getTouchDevice(QTouchDevice::TouchPad, [event deviceID]), points);
+ QWindowSystemInterface::handleTouchEvent<QWindowSystemInterface::SynchronousDelivery>(
+ m_platformWindow->window(), timestamp * 1000,
+ QCocoaTouch::getTouchDevice(QInputDevice::DeviceType::TouchPad, [event deviceID]),
+ points);
}
- (void)touchesMovedWithEvent:(NSEvent *)event
@@ -72,7 +39,10 @@ Q_LOGGING_CATEGORY(lcQpaTouch, "qt.qpa.input.touch")
const NSTimeInterval timestamp = [event timestamp];
const QList<QWindowSystemInterface::TouchPoint> points = QCocoaTouch::getCurrentTouchPointList(event, [self shouldSendSingleTouch]);
qCDebug(lcQpaTouch) << "touchesMovedWithEvent" << points << "from device" << Qt::hex << [event deviceID];
- QWindowSystemInterface::handleTouchEvent(m_platformWindow->window(), timestamp * 1000, QCocoaTouch::getTouchDevice(QTouchDevice::TouchPad, [event deviceID]), points);
+ QWindowSystemInterface::handleTouchEvent<QWindowSystemInterface::SynchronousDelivery>(
+ m_platformWindow->window(), timestamp * 1000,
+ QCocoaTouch::getTouchDevice(QInputDevice::DeviceType::TouchPad, [event deviceID]),
+ points);
}
- (void)touchesEndedWithEvent:(NSEvent *)event
@@ -83,7 +53,10 @@ Q_LOGGING_CATEGORY(lcQpaTouch, "qt.qpa.input.touch")
const NSTimeInterval timestamp = [event timestamp];
const QList<QWindowSystemInterface::TouchPoint> points = QCocoaTouch::getCurrentTouchPointList(event, [self shouldSendSingleTouch]);
qCDebug(lcQpaTouch) << "touchesEndedWithEvent" << points << "from device" << Qt::hex << [event deviceID];
- QWindowSystemInterface::handleTouchEvent(m_platformWindow->window(), timestamp * 1000, QCocoaTouch::getTouchDevice(QTouchDevice::TouchPad, [event deviceID]), points);
+ QWindowSystemInterface::handleTouchEvent<QWindowSystemInterface::SynchronousDelivery>(
+ m_platformWindow->window(), timestamp * 1000,
+ QCocoaTouch::getTouchDevice(QInputDevice::DeviceType::TouchPad, [event deviceID]),
+ points);
}
- (void)touchesCancelledWithEvent:(NSEvent *)event
@@ -94,7 +67,10 @@ Q_LOGGING_CATEGORY(lcQpaTouch, "qt.qpa.input.touch")
const NSTimeInterval timestamp = [event timestamp];
const QList<QWindowSystemInterface::TouchPoint> points = QCocoaTouch::getCurrentTouchPointList(event, [self shouldSendSingleTouch]);
qCDebug(lcQpaTouch) << "touchesCancelledWithEvent" << points << "from device" << Qt::hex << [event deviceID];
- QWindowSystemInterface::handleTouchEvent(m_platformWindow->window(), timestamp * 1000, QCocoaTouch::getTouchDevice(QTouchDevice::TouchPad, [event deviceID]), points);
+ QWindowSystemInterface::handleTouchEvent<QWindowSystemInterface::SynchronousDelivery>(
+ m_platformWindow->window(), timestamp * 1000,
+ QCocoaTouch::getTouchDevice(QInputDevice::DeviceType::TouchPad, [event deviceID]),
+ points);
}
@end
diff --git a/src/plugins/platforms/cocoa/qnswindow.h b/src/plugins/platforms/cocoa/qnswindow.h
index 5fc48d826f..8f842eba85 100644
--- a/src/plugins/platforms/cocoa/qnswindow.h
+++ b/src/plugins/platforms/cocoa/qnswindow.h
@@ -1,53 +1,20 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QNSWINDOW_H
#define QNSWINDOW_H
#include <qglobal.h>
#include <QPointer>
-#include "qt_mac_p.h"
+#include <QtCore/private/qcore_mac_p.h>
-#include <AppKit/AppKit.h>
+#include <AppKit/NSWindow.h>
+#include <AppKit/NSPanel.h>
QT_FORWARD_DECLARE_CLASS(QCocoaWindow)
+#if defined(__OBJC__)
+
// @compatibility_alias doesn't work with categories or their methods
#define FullScreenProperty QT_MANGLE_NAMESPACE(FullScreenProperty)
#define qt_fullScreen QT_MANGLE_NAMESPACE(qt_fullScreen)
@@ -69,10 +36,13 @@ QT_FORWARD_DECLARE_CLASS(QCocoaWindow)
typedef NSWindow<QNSWindowProtocol> QCocoaNSWindow;
-@interface QT_MANGLE_NAMESPACE(QNSWindow) : NSWindow<QNSWindowProtocol> @end
-QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSWindow);
+QCocoaNSWindow *qnswindow_cast(NSWindow *window);
+
+#else
+class QCocoaNSWindow;
+#endif // __OBJC__
-@interface QT_MANGLE_NAMESPACE(QNSPanel) : NSPanel<QNSWindowProtocol> @end
-QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSPanel);
+QT_DECLARE_NAMESPACED_OBJC_INTERFACE(QNSWindow, NSWindow <QNSWindowProtocol>)
+QT_DECLARE_NAMESPACED_OBJC_INTERFACE(QNSPanel, NSPanel <QNSWindowProtocol>)
#endif // QNSWINDOW_H
diff --git a/src/plugins/platforms/cocoa/qnswindow.mm b/src/plugins/platforms/cocoa/qnswindow.mm
index 6b4e110af2..74ba6f65ac 100644
--- a/src/plugins/platforms/cocoa/qnswindow.mm
+++ b/src/plugins/platforms/cocoa/qnswindow.mm
@@ -1,48 +1,15 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#if !defined(QNSWINDOW_PROTOCOL_IMPLMENTATION)
+#include <AppKit/AppKit.h>
+
#include "qnswindow.h"
#include "qcocoawindow.h"
#include "qcocoahelpers.h"
#include "qcocoaeventdispatcher.h"
+#include "qcocoaintegration.h"
#include <qpa/qwindowsysteminterface.h>
#include <qoperatingsystemversion.h>
@@ -91,6 +58,15 @@ static bool isMouseEvent(NSEvent *ev)
}
@end
+
+NSWindow<QNSWindowProtocol> *qnswindow_cast(NSWindow *window)
+{
+ if ([window conformsToProtocol:@protocol(QNSWindowProtocol)])
+ return static_cast<QCocoaNSWindow *>(window);
+ else
+ return nil;
+}
+
@implementation QNSWindow
#define QNSWINDOW_PROTOCOL_IMPLMENTATION 1
#include "qnswindow.mm"
@@ -104,7 +80,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
@@ -131,9 +107,10 @@ static bool isMouseEvent(NSEvent *ev)
continue;
if ([window conformsToProtocol:@protocol(QNSWindowProtocol)]) {
- QCocoaWindow *cocoaWindow = static_cast<QCocoaNSWindow *>(window).platformWindow;
- window.level = notification.name == NSApplicationWillResignActiveNotification ?
- NSNormalWindowLevel : cocoaWindow->windowLevel(cocoaWindow->window()->flags());
+ if (QCocoaWindow *cocoaWindow = static_cast<QCocoaNSWindow *>(window).platformWindow) {
+ window.level = notification.name == NSApplicationWillResignActiveNotification ?
+ NSNormalWindowLevel : cocoaWindow->windowLevel(cocoaWindow->window()->flags());
+ }
}
// The documentation says that "when a window enters a new level, it’s ordered
@@ -158,6 +135,46 @@ static bool isMouseEvent(NSEvent *ev)
#define QNSWINDOW_PROTOCOL_IMPLMENTATION 1
#include "qnswindow.mm"
#undef QNSWINDOW_PROTOCOL_IMPLMENTATION
+
+- (BOOL)worksWhenModal
+{
+ if (!m_platformWindow)
+ return NO;
+
+ // Conceptually there are two sets of windows we need consider:
+ //
+ // - windows 'lower' in the modal session stack
+ // - windows 'within' the current modal session
+ //
+ // The first set of windows should always be blocked by the current
+ // modal session, regardless of window type. The latter set may contain
+ // windows with a transient parent, which from Qt's point of view makes
+ // them 'child' windows, so we treat them as operable within the current
+ // modal session.
+
+ if (!NSApp.modalWindow)
+ return NO;
+
+ // Special case popup windows (menus, completions, etc), as these usually
+ // don't have a transient parent set, and we don't want to block them. The
+ // assumption is that these windows are only opened intermittently, from
+ // within windows that can already be interacted with in this modal session.
+ Qt::WindowType type = m_platformWindow->window()->type();
+ if (type == Qt::Popup)
+ return YES;
+
+ // If the current modal window (top level modal session) is not a Qt window we
+ // have no way of knowing if this window is transient child of the modal window.
+ if (![NSApp.modalWindow conformsToProtocol:@protocol(QNSWindowProtocol)])
+ return NO;
+
+ if (auto *modalWindow = static_cast<QCocoaNSWindow *>(NSApp.modalWindow).platformWindow) {
+ if (modalWindow->window()->isAncestorOf(m_platformWindow->window(), QWindow::IncludeTransients))
+ return YES;
+ }
+
+ return NO;
+}
@end
#else // QNSWINDOW_PROTOCOL_IMPLMENTATION
@@ -167,6 +184,7 @@ static bool isMouseEvent(NSEvent *ev)
{
// Member variables
QPointer<QCocoaWindow> m_platformWindow;
+ bool m_isMinimizing;
}
- (instancetype)initWithContentRect:(NSRect)contentRect styleMask:(NSWindowStyleMask)style
@@ -178,6 +196,8 @@ static bool isMouseEvent(NSEvent *ev)
// we can properly reflect the window's state during initialization.
m_platformWindow = window;
+ m_isMinimizing = false;
+
return [super initWithContentRect:contentRect styleMask:style backing:backingStoreType defer:defer screen:screen];
}
@@ -186,6 +206,29 @@ static bool isMouseEvent(NSEvent *ev)
return m_platformWindow;
}
+- (void)setContentView:(NSView*)view
+{
+ [super setContentView:view];
+
+ if (!qnsview_cast(self.contentView))
+ return;
+
+ // Now that we're the content view, we can apply the properties of
+ // the QWindow. We do this here, instead of in init, so that we can
+ // use the same code paths for setting these properties during
+ // NSWindow initialization as we do when setting them later on.
+ const QWindow *window = m_platformWindow->window();
+ qCDebug(lcQpaWindow) << "Reflecting" << window << "state to" << self;
+
+ m_platformWindow->propagateSizeHints();
+ m_platformWindow->setWindowFlags(window->flags());
+ m_platformWindow->setWindowTitle(window->title());
+ m_platformWindow->setWindowFilePath(window->filePath()); // Also sets window icon
+ m_platformWindow->setWindowState(window->windowState());
+ m_platformWindow->setOpacity(window->opacity());
+ m_platformWindow->setVisible(window->isVisible());
+}
+
- (NSString *)description
{
NSMutableString *description = [NSMutableString stringWithString:[super description]];
@@ -227,25 +270,12 @@ static bool isMouseEvent(NSEvent *ev)
- (BOOL)canBecomeMainWindow
{
- BOOL canBecomeMain = YES; // By default, windows can become the main window
-
// Windows with a transient parent (such as combobox popup windows)
// cannot become the main window:
if (!m_platformWindow || m_platformWindow->window()->transientParent())
- canBecomeMain = NO;
-
- return canBecomeMain;
-}
-
-- (BOOL)worksWhenModal
-{
- if (m_platformWindow && [self isKindOfClass:[QNSPanel class]]) {
- Qt::WindowType type = m_platformWindow->window()->type();
- if (type == Qt::Popup || type == Qt::Dialog || type == Qt::Tool)
- return YES;
- }
+ return NO;
- return [super worksWhenModal];
+ return [super canBecomeMainWindow];
}
- (BOOL)isOpaque
@@ -255,8 +285,23 @@ static bool isMouseEvent(NSEvent *ev)
- (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) {
+ // Qt::Popup also requires clearColor - in qmacstyle
+ // we fill background using a special path with rounded corners.
+ if (window->flags().testFlag(Qt::FramelessWindowHint)
+ || (window->flags() & Qt::WindowType_Mask) == Qt::Popup)
+ 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
@@ -281,18 +326,64 @@ static bool isMouseEvent(NSEvent *ev)
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)miniaturize:(id)sender
+{
+ QBoolBlocker miniaturizeTracker(m_isMinimizing, true);
+ [super miniaturize:sender];
+}
+
+- (NSButton *)standardWindowButton:(NSWindowButton)buttonType
+{
+ NSButton *button = [super standardWindowButton:buttonType];
+
+ // When an NSWindow is asked to minimize it will check the
+ // NSWindowMiniaturizeButton for enablement before continuing,
+ // even if the style mask includes NSWindowStyleMaskMiniaturizable.
+ // To ensure that a window can be minimized, even when the
+ // minimize button has been disabled in response to the user
+ // setting CustomizeWindowHint, we temporarily return a default
+ // minimize-button that we haven't modified in updateTitleBarButtons.
+ // This ensures the window can be minimized, without visually
+ // toggling the actual minimize-button on and off.
+ if (buttonType == NSWindowMiniaturizeButton && m_isMinimizing && !button.enabled)
+ return [NSWindow standardWindowButton:buttonType forStyleMask:self.styleMask];
+
+ return button;
}
- (void)closeAndRelease
diff --git a/src/plugins/platforms/cocoa/qnswindowdelegate.h b/src/plugins/platforms/cocoa/qnswindowdelegate.h
index be870deb3a..e5b3c4b3a9 100644
--- a/src/plugins/platforms/cocoa/qnswindowdelegate.h
+++ b/src/plugins/platforms/cocoa/qnswindowdelegate.h
@@ -1,55 +1,15 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QNSWINDOWDELEGATE_H
#define QNSWINDOWDELEGATE_H
-#include <AppKit/AppKit.h>
#include <QtCore/private/qcore_mac_p.h>
QT_BEGIN_NAMESPACE
class QCocoaWindow;
QT_END_NAMESPACE
-@interface QT_MANGLE_NAMESPACE(QNSWindowDelegate) : NSObject <NSWindowDelegate>
-@end
-
-QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSWindowDelegate);
+QT_DECLARE_NAMESPACED_OBJC_INTERFACE(QNSWindowDelegate, NSObject <NSWindowDelegate>)
#endif // QNSWINDOWDELEGATE_H
diff --git a/src/plugins/platforms/cocoa/qnswindowdelegate.mm b/src/plugins/platforms/cocoa/qnswindowdelegate.mm
index 9502a315d8..1db7772771 100644
--- a/src/plugins/platforms/cocoa/qnswindowdelegate.mm
+++ b/src/plugins/platforms/cocoa/qnswindowdelegate.mm
@@ -1,41 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <AppKit/AppKit.h>
#include "qnswindowdelegate.h"
#include "qcocoahelpers.h"
@@ -47,13 +13,17 @@
#include <qpa/qplatformscreen.h>
#include <qpa/qwindowsysteminterface.h>
-static QRegExp whitespaceRegex = QRegExp(QStringLiteral("\\s*"));
+static inline bool isWhiteSpace(const QString &s)
+{
+ for (int i = 0; i < s.size(); ++i)
+ if (!s.at(i).isSpace())
+ return false;
+ return true;
+}
static QCocoaWindow *toPlatformWindow(NSWindow *window)
{
- if ([window conformsToProtocol:@protocol(QNSWindowProtocol)])
- return static_cast<QCocoaNSWindow *>(window).platformWindow;
- return nullptr;
+ return qnswindow_cast(window).platformWindow;
}
@implementation QNSWindowDelegate
@@ -104,6 +74,14 @@ static QCocoaWindow *toPlatformWindow(NSWindow *window)
return QCocoaScreen::mapToNative(maximizedFrame);
}
+- (BOOL)windowShouldZoom:(NSWindow*)window toFrame:(NSRect)newFrame
+{
+ QCocoaWindow *platformWindow = toPlatformWindow(window);
+ Q_ASSERT(platformWindow);
+ platformWindow->windowWillZoom();
+ return YES;
+}
+
- (BOOL)window:(NSWindow *)window shouldPopUpDocumentPathMenu:(NSMenu *)menu
{
Q_UNUSED(menu);
@@ -113,7 +91,7 @@ static QCocoaWindow *toPlatformWindow(NSWindow *window)
// Only pop up document path if the filename is non-empty. We allow whitespace, to
// allow faking a window icon by setting the file path to a single space character.
- return !whitespaceRegex.exactMatch(platformWindow->window()->filePath());
+ return !isWhiteSpace(platformWindow->window()->filePath());
}
- (BOOL)window:(NSWindow *)window shouldDragDocumentWithEvent:(NSEvent *)event from:(NSPoint)dragImageLocation withPasteboard:(NSPasteboard *)pasteboard
@@ -127,6 +105,6 @@ static QCocoaWindow *toPlatformWindow(NSWindow *window)
// Only allow drag if the filename is non-empty. We allow whitespace, to
// allow faking a window icon by setting the file path to a single space.
- return !whitespaceRegex.exactMatch(platformWindow->window()->filePath());
+ return !isWhiteSpace(platformWindow->window()->filePath());
}
@end
diff --git a/src/plugins/platforms/cocoa/qpaintengine_mac.mm b/src/plugins/platforms/cocoa/qpaintengine_mac.mm
deleted file mode 100644
index 00b2267f0d..0000000000
--- a/src/plugins/platforms/cocoa/qpaintengine_mac.mm
+++ /dev/null
@@ -1,1422 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 "qpaintengine_mac_p.h"
-#if defined(QT_PRINTSUPPORT_LIB)
-#include "qprintengine_mac_p.h"
-#endif
-
-#include <qbitmap.h>
-#include <qpaintdevice.h>
-#include <qpainterpath.h>
-#include <qpixmapcache.h>
-#include <private/qpaintengine_raster_p.h>
-#if defined(QT_PRINTSUPPORT_LIB)
-#include <qprinter.h>
-#endif
-#include <qstack.h>
-#include <qwidget.h>
-#include <qvarlengtharray.h>
-#include <qdebug.h>
-#include <qcoreapplication.h>
-#include <qmath.h>
-
-#include <qpa/qplatformpixmap.h>
-
-#include <private/qfont_p.h>
-#include <private/qfontengine_p.h>
-#include <private/qfontengine_coretext_p.h>
-#include <private/qnumeric_p.h>
-#include <private/qpainter_p.h>
-#include <private/qpainterpath_p.h>
-#include <private/qtextengine_p.h>
-#include <private/qcoregraphics_p.h>
-
-#include "qcocoahelpers.h"
-
-#include <string.h>
-
-QT_BEGIN_NAMESPACE
-
-/*****************************************************************************
- QCoreGraphicsPaintEngine utility functions
- *****************************************************************************/
-
-void qt_mac_cgimage_data_free(void *, const void *memoryToFree, size_t)
-{
- free(const_cast<void *>(memoryToFree));
-}
-
-CGImageRef qt_mac_create_imagemask(const QPixmap &pixmap, const QRectF &sr)
-{
- QImage image = pixmap.toImage();
- if (image.format() != QImage::Format_ARGB32_Premultiplied)
- image = image.convertToFormat(QImage::Format_ARGB32_Premultiplied);
-
- const int sx = qRound(sr.x()), sy = qRound(sr.y()), sw = qRound(sr.width()), sh = qRound(sr.height());
- const int sbpr = image.bytesPerLine();
- const uint nbytes = sw * sh;
- // alpha is always 255 for bitmaps, ignore it in this case.
- const quint32 mask = pixmap.depth() == 1 ? 0x00ffffff : 0xffffffff;
- quint8 *dptr = static_cast<quint8 *>(malloc(nbytes));
- quint32 *sptr = reinterpret_cast<quint32 *>(image.scanLine(0)), *srow;
- for (int y = sy, offset=0; y < sh; ++y) {
- srow = sptr + (y * (sbpr / 4));
- for (int x = sx; x < sw; ++x)
- *(dptr+(offset++)) = (*(srow+x) & mask) ? 255 : 0;
- }
- QCFType<CGDataProviderRef> provider = CGDataProviderCreateWithData(nullptr, dptr, nbytes, qt_mac_cgimage_data_free);
- return CGImageMaskCreate(sw, sh, 8, 8, nbytes / sh, provider, nullptr, false);
-}
-
-//conversion
-inline static float qt_mac_convert_color_to_cg(int c) { return ((float)c * 1000 / 255) / 1000; }
-CGAffineTransform qt_mac_convert_transform_to_cg(const QTransform &t) {
- return CGAffineTransformMake(t.m11(), t.m12(), t.m21(), t.m22(), t.dx(), t.dy());
-}
-
-inline static QCFType<CGColorRef> cgColorForQColor(const QColor &col)
-{
- CGFloat components[] = {
- qt_mac_convert_color_to_cg(col.red()),
- qt_mac_convert_color_to_cg(col.green()),
- qt_mac_convert_color_to_cg(col.blue()),
- qt_mac_convert_color_to_cg(col.alpha())
- };
- QCFType<CGColorSpaceRef> colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceSRGB);
- return CGColorCreate(colorSpace, components);
-}
-
-// There's architectural problems with using native gradients
-// on the Mac at the moment, so disable them.
-// #define QT_MAC_USE_NATIVE_GRADIENTS
-
-#ifdef QT_MAC_USE_NATIVE_GRADIENTS
-static bool drawGradientNatively(const QGradient *gradient)
-{
- return gradient->spread() == QGradient::PadSpread;
-}
-
-// gradiant callback
-static void qt_mac_color_gradient_function(void *info, const CGFloat *in, CGFloat *out)
-{
- QBrush *brush = static_cast<QBrush *>(info);
- Q_ASSERT(brush && brush->gradient());
-
- const QGradientStops stops = brush->gradient()->stops();
- const int n = stops.count();
- Q_ASSERT(n >= 1);
- const QGradientStop *begin = stops.constBegin();
- const QGradientStop *end = begin + n;
-
- qreal p = in[0];
- const QGradientStop *i = begin;
- while (i != end && i->first < p)
- ++i;
-
- QRgb c;
- if (i == begin) {
- c = begin->second.rgba();
- } else if (i == end) {
- c = (end - 1)->second.rgba();
- } else {
- const QGradientStop &s1 = *(i - 1);
- const QGradientStop &s2 = *i;
- qreal p1 = s1.first;
- qreal p2 = s2.first;
- QRgb c1 = s1.second.rgba();
- QRgb c2 = s2.second.rgba();
- int idist = 256 * (p - p1) / (p2 - p1);
- int dist = 256 - idist;
- c = qRgba(INTERPOLATE_PIXEL_256(qRed(c1), dist, qRed(c2), idist),
- INTERPOLATE_PIXEL_256(qGreen(c1), dist, qGreen(c2), idist),
- INTERPOLATE_PIXEL_256(qBlue(c1), dist, qBlue(c2), idist),
- INTERPOLATE_PIXEL_256(qAlpha(c1), dist, qAlpha(c2), idist));
- }
-
- out[0] = qt_mac_convert_color_to_cg(qRed(c));
- out[1] = qt_mac_convert_color_to_cg(qGreen(c));
- out[2] = qt_mac_convert_color_to_cg(qBlue(c));
- out[3] = qt_mac_convert_color_to_cg(qAlpha(c));
-}
-#endif
-
-//clipping handling
-void QCoreGraphicsPaintEnginePrivate::resetClip()
-{
- static bool inReset = false;
- if (inReset)
- return;
- inReset = true;
-
- CGAffineTransform old_xform = CGContextGetCTM(hd);
-
- //setup xforms
- CGContextConcatCTM(hd, CGAffineTransformInvert(old_xform));
- while (stackCount > 0) {
- restoreGraphicsState();
- }
- saveGraphicsState();
- inReset = false;
- //reset xforms
- CGContextConcatCTM(hd, CGAffineTransformInvert(CGContextGetCTM(hd)));
- CGContextConcatCTM(hd, old_xform);
-}
-
-static CGRect qt_mac_compose_rect(const QRectF &r, float off=0)
-{
- return CGRectMake(r.x()+off, r.y()+off, r.width(), r.height());
-}
-
-static CGMutablePathRef qt_mac_compose_path(const QPainterPath &p, float off=0)
-{
- CGMutablePathRef ret = CGPathCreateMutable();
- QPointF startPt;
- for (int i=0; i<p.elementCount(); ++i) {
- const QPainterPath::Element &elm = p.elementAt(i);
- switch (elm.type) {
- case QPainterPath::MoveToElement:
- if (i > 0
- && p.elementAt(i - 1).x == startPt.x()
- && p.elementAt(i - 1).y == startPt.y())
- CGPathCloseSubpath(ret);
- startPt = QPointF(elm.x, elm.y);
- CGPathMoveToPoint(ret, 0, elm.x+off, elm.y+off);
- break;
- case QPainterPath::LineToElement:
- CGPathAddLineToPoint(ret, 0, elm.x+off, elm.y+off);
- break;
- case QPainterPath::CurveToElement:
- Q_ASSERT(p.elementAt(i+1).type == QPainterPath::CurveToDataElement);
- Q_ASSERT(p.elementAt(i+2).type == QPainterPath::CurveToDataElement);
- CGPathAddCurveToPoint(ret, 0,
- elm.x+off, elm.y+off,
- p.elementAt(i+1).x+off, p.elementAt(i+1).y+off,
- p.elementAt(i+2).x+off, p.elementAt(i+2).y+off);
- i+=2;
- break;
- default:
- qFatal("QCoreGraphicsPaintEngine::drawPath(), unhandled type: %d", elm.type);
- break;
- }
- }
- if (!p.isEmpty()
- && p.elementAt(p.elementCount() - 1).x == startPt.x()
- && p.elementAt(p.elementCount() - 1).y == startPt.y())
- CGPathCloseSubpath(ret);
- return ret;
-}
-
-//pattern handling (tiling)
-#if 1
-# define QMACPATTERN_MASK_MULTIPLIER 32
-#else
-# define QMACPATTERN_MASK_MULTIPLIER 1
-#endif
-class QMacPattern
-{
-public:
- QMacPattern() : as_mask(false), pdev(0), image(0) { data.bytes = 0; }
- ~QMacPattern() { CGImageRelease(image); }
- int width() {
- if (image)
- return CGImageGetWidth(image);
- if (data.bytes)
- return 8*QMACPATTERN_MASK_MULTIPLIER;
- return data.pixmap.width();
- }
- int height() {
- if (image)
- return CGImageGetHeight(image);
- if (data.bytes)
- return 8*QMACPATTERN_MASK_MULTIPLIER;
- return data.pixmap.height();
- }
-
- //input
- QColor foreground;
- bool as_mask;
- struct {
- QPixmap pixmap;
- const uchar *bytes;
- } data;
- QPaintDevice *pdev;
- //output
- CGImageRef image;
-};
-static void qt_mac_draw_pattern(void *info, CGContextRef c)
-{
- QMacPattern *pat = (QMacPattern*)info;
- int w = 0, h = 0;
- bool isBitmap = (pat->data.pixmap.depth() == 1);
- if (!pat->image) { //lazy cache
- if (pat->as_mask) {
- Q_ASSERT(pat->data.bytes);
- w = h = 8;
-#if (QMACPATTERN_MASK_MULTIPLIER == 1)
- CGDataProviderRef provider = CGDataProviderCreateWithData(nullptr, pat->data.bytes, w*h, nullptr);
- pat->image = CGImageMaskCreate(w, h, 1, 1, 1, provider, nullptr, false);
- CGDataProviderRelease(provider);
-#else
- const int numBytes = (w*h)/sizeof(uchar);
- uchar xor_bytes[numBytes];
- for (int i = 0; i < numBytes; ++i)
- xor_bytes[i] = pat->data.bytes[i] ^ 0xFF;
- CGDataProviderRef provider = CGDataProviderCreateWithData(nullptr, xor_bytes, w*h, nullptr);
- CGImageRef swatch = CGImageMaskCreate(w, h, 1, 1, 1, provider, nullptr, false);
- CGDataProviderRelease(provider);
-
- const QColor c0(0, 0, 0, 0), c1(255, 255, 255, 255);
- QPixmap pm(w*QMACPATTERN_MASK_MULTIPLIER, h*QMACPATTERN_MASK_MULTIPLIER);
- pm.fill(c0);
- QMacCGContext pm_ctx(&pm);
- CGContextSetFillColorWithColor(c, cgColorForQColor(c1));
- CGRect rect = CGRectMake(0, 0, w, h);
- for (int x = 0; x < QMACPATTERN_MASK_MULTIPLIER; ++x) {
- rect.origin.x = x * w;
- for (int y = 0; y < QMACPATTERN_MASK_MULTIPLIER; ++y) {
- rect.origin.y = y * h;
- qt_mac_drawCGImage(pm_ctx, &rect, swatch);
- }
- }
- pat->image = qt_mac_create_imagemask(pm, pm.rect());
- CGImageRelease(swatch);
- w *= QMACPATTERN_MASK_MULTIPLIER;
- h *= QMACPATTERN_MASK_MULTIPLIER;
-#endif
- } else {
- w = pat->data.pixmap.width();
- h = pat->data.pixmap.height();
- if (isBitmap)
- pat->image = qt_mac_create_imagemask(pat->data.pixmap, pat->data.pixmap.rect());
- else
- pat->image = qt_mac_toCGImage(pat->data.pixmap.toImage());
- }
- } else {
- w = CGImageGetWidth(pat->image);
- h = CGImageGetHeight(pat->image);
- }
-
- //draw
- bool needRestore = false;
- if (CGImageIsMask(pat->image)) {
- CGContextSaveGState(c);
- CGContextSetFillColorWithColor(c, cgColorForQColor(pat->foreground));
- }
- CGRect rect = CGRectMake(0, 0, w, h);
- qt_mac_drawCGImage(c, &rect, pat->image);
- if (needRestore)
- CGContextRestoreGState(c);
-}
-static void qt_mac_dispose_pattern(void *info)
-{
- QMacPattern *pat = (QMacPattern*)info;
- delete pat;
-}
-
-/*****************************************************************************
- QCoreGraphicsPaintEngine member functions
- *****************************************************************************/
-
-inline static QPaintEngine::PaintEngineFeatures qt_mac_cg_features()
-{
- return QPaintEngine::PaintEngineFeatures(QPaintEngine::AllFeatures & ~QPaintEngine::PaintOutsidePaintEvent
- & ~QPaintEngine::PerspectiveTransform
- & ~QPaintEngine::ConicalGradientFill
- & ~QPaintEngine::LinearGradientFill
- & ~QPaintEngine::RadialGradientFill
- & ~QPaintEngine::BrushStroke);
-}
-
-QCoreGraphicsPaintEngine::QCoreGraphicsPaintEngine()
-: QPaintEngine(*(new QCoreGraphicsPaintEnginePrivate), qt_mac_cg_features())
-{
-}
-
-QCoreGraphicsPaintEngine::QCoreGraphicsPaintEngine(QPaintEnginePrivate &dptr)
-: QPaintEngine(dptr, qt_mac_cg_features())
-{
-}
-
-QCoreGraphicsPaintEngine::~QCoreGraphicsPaintEngine()
-{
-}
-
-bool
-QCoreGraphicsPaintEngine::begin(QPaintDevice *pdev)
-{
- Q_D(QCoreGraphicsPaintEngine);
- if (isActive()) { // already active painting
- qWarning("QCoreGraphicsPaintEngine::begin: Painter already active");
- return false;
- }
-
- //initialization
- d->pdev = pdev;
- d->complexXForm = false;
- d->cosmeticPen = QCoreGraphicsPaintEnginePrivate::CosmeticSetPenWidth;
- d->cosmeticPenSize = 1;
- d->current.clipEnabled = false;
- d->pixelSize = QPoint(1,1);
- QMacCGContext ctx(pdev);
- d->hd = CGContextRetain(ctx);
- if (d->hd) {
- d->saveGraphicsState();
- d->orig_xform = CGContextGetCTM(d->hd);
- if (d->shading) {
- CGShadingRelease(d->shading);
- d->shading = nullptr;
- }
- d->setClip(nullptr); //clear the context's clipping
- }
-
- setActive(true);
-
- if (d->pdev->devType() == QInternal::Widget) { // device is a widget
- QWidget *w = (QWidget*)d->pdev;
- bool unclipped = w->testAttribute(Qt::WA_PaintUnclipped);
-
- if ((w->windowType() == Qt::Desktop)) {
- if (!unclipped)
- qWarning("QCoreGraphicsPaintEngine::begin: Does not support clipped desktop on OS X");
- // ## need to do [qt_mac_window_for(w) makeKeyAndOrderFront]; (need to rename the file)
- } else if (unclipped) {
- qWarning("QCoreGraphicsPaintEngine::begin: Does not support unclipped painting");
- }
- } else if (d->pdev->devType() == QInternal::Pixmap) { // device is a pixmap
- QPixmap *pm = (QPixmap*)d->pdev;
- if (pm->isNull()) {
- qWarning("QCoreGraphicsPaintEngine::begin: Cannot paint null pixmap");
- end();
- return false;
- }
- }
-
- setDirty(QPaintEngine::DirtyPen);
- setDirty(QPaintEngine::DirtyBrush);
- setDirty(QPaintEngine::DirtyBackground);
- setDirty(QPaintEngine::DirtyHints);
- return true;
-}
-
-bool
-QCoreGraphicsPaintEngine::end()
-{
- Q_D(QCoreGraphicsPaintEngine);
- setActive(false);
- if (d->pdev->devType() == QInternal::Widget && static_cast<QWidget*>(d->pdev)->windowType() == Qt::Desktop) {
- // ### need to do [qt_mac_window_for(static_cast<QWidget *>(d->pdev)) orderOut]; (need to rename)
- }
- if (d->shading) {
- CGShadingRelease(d->shading);
- d->shading = 0;
- }
- d->pdev = nullptr;
- if (d->hd) {
- d->restoreGraphicsState();
- CGContextSynchronize(d->hd);
- CGContextRelease(d->hd);
- d->hd = nullptr;
- }
- return true;
-}
-
-void
-QCoreGraphicsPaintEngine::updateState(const QPaintEngineState &state)
-{
- Q_D(QCoreGraphicsPaintEngine);
- QPaintEngine::DirtyFlags flags = state.state();
-
- if (flags & DirtyTransform)
- updateMatrix(state.transform());
-
- if (flags & DirtyClipEnabled) {
- if (state.isClipEnabled())
- updateClipPath(painter()->clipPath(), Qt::ReplaceClip);
- else
- updateClipPath(QPainterPath(), Qt::NoClip);
- }
-
- if (flags & DirtyClipPath) {
- updateClipPath(state.clipPath(), state.clipOperation());
- } else if (flags & DirtyClipRegion) {
- updateClipRegion(state.clipRegion(), state.clipOperation());
- }
-
- // If the clip has changed we need to update all other states
- // too, since they are included in the system context on OSX,
- // and changing the clip resets that context back to scratch.
- if (flags & (DirtyClipPath | DirtyClipRegion | DirtyClipEnabled))
- flags |= AllDirty;
-
- if (flags & DirtyPen)
- updatePen(state.pen());
- if (flags & (DirtyBrush|DirtyBrushOrigin))
- updateBrush(state.brush(), state.brushOrigin());
- if (flags & DirtyFont)
- updateFont(state.font());
- if (flags & DirtyOpacity)
- updateOpacity(state.opacity());
- if (flags & DirtyHints)
- updateRenderHints(state.renderHints());
- if (flags & DirtyCompositionMode)
- updateCompositionMode(state.compositionMode());
-
- if (flags & (DirtyPen | DirtyTransform | DirtyHints)) {
- if (!qt_pen_is_cosmetic(d->current.pen, state.renderHints())) {
- d->cosmeticPen = QCoreGraphicsPaintEnginePrivate::CosmeticNone;
- } else if (d->current.transform.m11() < d->current.transform.m22()-1.0 ||
- d->current.transform.m11() > d->current.transform.m22()+1.0) {
- d->cosmeticPen = QCoreGraphicsPaintEnginePrivate::CosmeticTransformPath;
- d->cosmeticPenSize = d->adjustPenWidth(d->current.pen.widthF());
- if (!d->cosmeticPenSize)
- d->cosmeticPenSize = 1.0;
- } else {
- d->cosmeticPen = QCoreGraphicsPaintEnginePrivate::CosmeticSetPenWidth;
- static const float sqrt2 = std::sqrt(2.0f);
- qreal width = d->current.pen.widthF();
- if (!width)
- width = 1;
- d->cosmeticPenSize = std::sqrt(std::pow(d->pixelSize.y(), 2) + std::pow(d->pixelSize.x(), 2)) / sqrt2 * width;
- }
- }
-}
-
-void
-QCoreGraphicsPaintEngine::updatePen(const QPen &pen)
-{
- Q_D(QCoreGraphicsPaintEngine);
- Q_ASSERT(isActive());
- d->current.pen = pen;
- d->setStrokePen(pen);
-}
-
-void
-QCoreGraphicsPaintEngine::updateBrush(const QBrush &brush, const QPointF &brushOrigin)
-{
- Q_D(QCoreGraphicsPaintEngine);
- Q_ASSERT(isActive());
- d->current.brush = brush;
-
-#ifdef QT_MAC_USE_NATIVE_GRADIENTS
- // Quartz supports only pad spread
- if (const QGradient *gradient = brush.gradient()) {
- if (drawGradientNatively(gradient)) {
- gccaps |= QPaintEngine::LinearGradientFill | QPaintEngine::RadialGradientFill;
- } else {
- gccaps &= ~(QPaintEngine::LinearGradientFill | QPaintEngine::RadialGradientFill);
- }
- }
-#endif
-
- if (d->shading) {
- CGShadingRelease(d->shading);
- d->shading = nullptr;
- }
- d->setFillBrush(brushOrigin);
-}
-
-void
-QCoreGraphicsPaintEngine::updateOpacity(qreal opacity)
-{
- Q_D(QCoreGraphicsPaintEngine);
- CGContextSetAlpha(d->hd, opacity);
-}
-
-void
-QCoreGraphicsPaintEngine::updateFont(const QFont &)
-{
- Q_D(QCoreGraphicsPaintEngine);
- Q_ASSERT(isActive());
- updatePen(d->current.pen);
-}
-
-void
-QCoreGraphicsPaintEngine::updateMatrix(const QTransform &transform)
-{
- Q_D(QCoreGraphicsPaintEngine);
- Q_ASSERT(isActive());
-
- if (qt_is_nan(transform.m11()) || qt_is_nan(transform.m12()) || qt_is_nan(transform.m13())
- || qt_is_nan(transform.m21()) || qt_is_nan(transform.m22()) || qt_is_nan(transform.m23())
- || qt_is_nan(transform.m31()) || qt_is_nan(transform.m32()) || qt_is_nan(transform.m33()))
- return;
-
- d->current.transform = transform;
- d->setTransform(transform.isIdentity() ? 0 : &transform);
- d->complexXForm = (transform.m11() != 1 || transform.m22() != 1
- || transform.m12() != 0 || transform.m21() != 0);
- d->pixelSize = d->devicePixelSize(d->hd);
-}
-
-void
-QCoreGraphicsPaintEngine::updateClipPath(const QPainterPath &p, Qt::ClipOperation op)
-{
- Q_D(QCoreGraphicsPaintEngine);
- Q_ASSERT(isActive());
- if (op == Qt::NoClip) {
- if (d->current.clipEnabled) {
- d->current.clipEnabled = false;
- d->current.clip = QRegion();
- d->setClip(nullptr);
- }
- } else {
- if (!d->current.clipEnabled)
- op = Qt::ReplaceClip;
- d->current.clipEnabled = true;
- QRegion clipRegion(p.toFillPolygon().toPolygon(), p.fillRule());
- if (op == Qt::ReplaceClip) {
- d->current.clip = clipRegion;
- d->setClip(nullptr);
- if (p.isEmpty()) {
- CGRect rect = CGRectMake(0, 0, 0, 0);
- CGContextClipToRect(d->hd, rect);
- } else {
- CGMutablePathRef path = qt_mac_compose_path(p);
- CGContextBeginPath(d->hd);
- CGContextAddPath(d->hd, path);
- if (p.fillRule() == Qt::WindingFill)
- CGContextClip(d->hd);
- else
- CGContextEOClip(d->hd);
- CGPathRelease(path);
- }
- } else if (op == Qt::IntersectClip) {
- d->current.clip = d->current.clip.intersected(clipRegion);
- d->setClip(&d->current.clip);
- }
- }
-}
-
-void
-QCoreGraphicsPaintEngine::updateClipRegion(const QRegion &clipRegion, Qt::ClipOperation op)
-{
- Q_D(QCoreGraphicsPaintEngine);
- Q_ASSERT(isActive());
- if (op == Qt::NoClip) {
- d->current.clipEnabled = false;
- d->current.clip = QRegion();
- d->setClip(nullptr);
- } else {
- if (!d->current.clipEnabled)
- op = Qt::ReplaceClip;
- d->current.clipEnabled = true;
- if (op == Qt::IntersectClip)
- d->current.clip = d->current.clip.intersected(clipRegion);
- else if (op == Qt::ReplaceClip)
- d->current.clip = clipRegion;
- d->setClip(&d->current.clip);
- }
-}
-
-void
-QCoreGraphicsPaintEngine::drawPath(const QPainterPath &p)
-{
- Q_D(QCoreGraphicsPaintEngine);
- Q_ASSERT(isActive());
-
- if (state->compositionMode() == QPainter::CompositionMode_Destination)
- return;
-
- CGMutablePathRef path = qt_mac_compose_path(p);
- uchar ops = QCoreGraphicsPaintEnginePrivate::CGStroke;
- if (p.fillRule() == Qt::WindingFill)
- ops |= QCoreGraphicsPaintEnginePrivate::CGFill;
- else
- ops |= QCoreGraphicsPaintEnginePrivate::CGEOFill;
- CGContextBeginPath(d->hd);
- d->drawPath(ops, path);
- CGPathRelease(path);
-}
-
-void
-QCoreGraphicsPaintEngine::drawRects(const QRectF *rects, int rectCount)
-{
- Q_D(QCoreGraphicsPaintEngine);
- Q_ASSERT(isActive());
-
- if (state->compositionMode() == QPainter::CompositionMode_Destination)
- return;
-
- for (int i=0; i<rectCount; ++i) {
- QRectF r = rects[i];
-
- CGMutablePathRef path = CGPathCreateMutable();
- CGPathAddRect(path, nullptr, qt_mac_compose_rect(r));
- d->drawPath(QCoreGraphicsPaintEnginePrivate::CGFill|QCoreGraphicsPaintEnginePrivate::CGStroke,
- path);
- CGPathRelease(path);
- }
-}
-
-void
-QCoreGraphicsPaintEngine::drawPoints(const QPointF *points, int pointCount)
-{
- Q_D(QCoreGraphicsPaintEngine);
- Q_ASSERT(isActive());
-
- if (state->compositionMode() == QPainter::CompositionMode_Destination)
- return;
-
- if (d->current.pen.capStyle() == Qt::FlatCap)
- CGContextSetLineCap(d->hd, kCGLineCapSquare);
-
- CGMutablePathRef path = CGPathCreateMutable();
- for (int i=0; i < pointCount; i++) {
- float x = points[i].x(), y = points[i].y();
- CGPathMoveToPoint(path, nullptr, x, y);
- CGPathAddLineToPoint(path, nullptr, x+0.001, y);
- }
-
- bool doRestore = false;
- if (d->cosmeticPen == QCoreGraphicsPaintEnginePrivate::CosmeticNone && !(state->renderHints() & QPainter::Antialiasing)) {
- //we don't want adjusted pens for point rendering
- doRestore = true;
- d->saveGraphicsState();
- CGContextSetLineWidth(d->hd, d->current.pen.widthF());
- }
- d->drawPath(QCoreGraphicsPaintEnginePrivate::CGStroke, path);
- if (doRestore)
- d->restoreGraphicsState();
- CGPathRelease(path);
- if (d->current.pen.capStyle() == Qt::FlatCap)
- CGContextSetLineCap(d->hd, kCGLineCapButt);
-}
-
-void
-QCoreGraphicsPaintEngine::drawEllipse(const QRectF &r)
-{
- Q_D(QCoreGraphicsPaintEngine);
- Q_ASSERT(isActive());
-
- if (state->compositionMode() == QPainter::CompositionMode_Destination)
- return;
-
- CGMutablePathRef path = CGPathCreateMutable();
- CGAffineTransform transform = CGAffineTransformMakeScale(r.width() / r.height(), 1);
- CGPathAddArc(path, &transform,(r.x() + (r.width() / 2)) / (r.width() / r.height()),
- r.y() + (r.height() / 2), r.height() / 2, 0, (2 * M_PI), false);
- d->drawPath(QCoreGraphicsPaintEnginePrivate::CGFill | QCoreGraphicsPaintEnginePrivate::CGStroke,
- path);
- CGPathRelease(path);
-}
-
-void
-QCoreGraphicsPaintEngine::drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode)
-{
- Q_D(QCoreGraphicsPaintEngine);
- Q_ASSERT(isActive());
-
- if (state->compositionMode() == QPainter::CompositionMode_Destination)
- return;
-
- CGMutablePathRef path = CGPathCreateMutable();
- CGPathMoveToPoint(path, nullptr, points[0].x(), points[0].y());
- for (int x = 1; x < pointCount; ++x)
- CGPathAddLineToPoint(path, nullptr, points[x].x(), points[x].y());
- if (mode != PolylineMode && points[0] != points[pointCount-1])
- CGPathAddLineToPoint(path, nullptr, points[0].x(), points[0].y());
- uint op = QCoreGraphicsPaintEnginePrivate::CGStroke;
- if (mode != PolylineMode)
- op |= mode == OddEvenMode ? QCoreGraphicsPaintEnginePrivate::CGEOFill
- : QCoreGraphicsPaintEnginePrivate::CGFill;
- d->drawPath(op, path);
- CGPathRelease(path);
-}
-
-void
-QCoreGraphicsPaintEngine::drawLines(const QLineF *lines, int lineCount)
-{
- Q_D(QCoreGraphicsPaintEngine);
- Q_ASSERT(isActive());
-
- if (state->compositionMode() == QPainter::CompositionMode_Destination)
- return;
-
- CGMutablePathRef path = CGPathCreateMutable();
- for (int i = 0; i < lineCount; i++) {
- const QPointF start = lines[i].p1(), end = lines[i].p2();
- CGPathMoveToPoint(path, nullptr, start.x(), start.y());
- CGPathAddLineToPoint(path, nullptr, end.x(), end.y());
- }
- d->drawPath(QCoreGraphicsPaintEnginePrivate::CGStroke, path);
- CGPathRelease(path);
-}
-
-void QCoreGraphicsPaintEngine::drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr)
-{
- Q_D(QCoreGraphicsPaintEngine);
- Q_ASSERT(isActive());
-
- if (state->compositionMode() == QPainter::CompositionMode_Destination)
- return;
-
- if (pm.isNull())
- return;
-
- bool differentSize = (QRectF(0, 0, pm.width(), pm.height()) != sr), doRestore = false;
- CGRect rect = CGRectMake(r.x(), r.y(), r.width(), r.height());
- QCFType<CGImageRef> image;
- bool isBitmap = (pm.depth() == 1);
- if (isBitmap) {
- doRestore = true;
- d->saveGraphicsState();
-
- const QColor &col = d->current.pen.color();
- CGContextSetFillColorWithColor(d->hd, cgColorForQColor(col));
- image = qt_mac_create_imagemask(pm, sr);
- } else if (differentSize) {
- QCFType<CGImageRef> img = qt_mac_toCGImage(pm.toImage());
- if (img)
- image = CGImageCreateWithImageInRect(img, CGRectMake(qRound(sr.x()), qRound(sr.y()), qRound(sr.width()), qRound(sr.height())));
- } else {
- image = qt_mac_toCGImage(pm.toImage());
- }
- qt_mac_drawCGImage(d->hd, &rect, image);
- if (doRestore)
- d->restoreGraphicsState();
-}
-
-void QCoreGraphicsPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRectF &sr,
- Qt::ImageConversionFlags flags)
-{
- Q_D(QCoreGraphicsPaintEngine);
- Q_UNUSED(flags);
- Q_ASSERT(isActive());
-
- if (img.isNull() || state->compositionMode() == QPainter::CompositionMode_Destination)
- return;
-
- QCFType<CGImageRef> cgimage = qt_mac_toCGImage(img);
- CGRect rect = CGRectMake(r.x(), r.y(), r.width(), r.height());
- if (QRectF(0, 0, img.width(), img.height()) != sr)
- cgimage = CGImageCreateWithImageInRect(cgimage, CGRectMake(sr.x(), sr.y(),
- sr.width(), sr.height()));
- qt_mac_drawCGImage(d->hd, &rect, cgimage);
-}
-
-void QCoreGraphicsPaintEngine::initialize()
-{
-}
-
-void QCoreGraphicsPaintEngine::cleanup()
-{
-}
-
-CGContextRef
-QCoreGraphicsPaintEngine::handle() const
-{
- return d_func()->hd;
-}
-
-void
-QCoreGraphicsPaintEngine::drawTiledPixmap(const QRectF &r, const QPixmap &pixmap,
- const QPointF &p)
-{
- Q_D(QCoreGraphicsPaintEngine);
- Q_ASSERT(isActive());
-
- if (state->compositionMode() == QPainter::CompositionMode_Destination)
- return;
-
- //save the old state
- d->saveGraphicsState();
-
- //setup the pattern
- QMacPattern *qpattern = new QMacPattern;
- qpattern->data.pixmap = pixmap;
- qpattern->foreground = d->current.pen.color();
- qpattern->pdev = d->pdev;
- CGPatternCallbacks callbks;
- callbks.version = 0;
- callbks.drawPattern = qt_mac_draw_pattern;
- callbks.releaseInfo = qt_mac_dispose_pattern;
- const int width = qpattern->width(), height = qpattern->height();
- CGAffineTransform trans = CGContextGetCTM(d->hd);
- CGPatternRef pat = CGPatternCreate(qpattern, CGRectMake(0, 0, width, height),
- trans, width, height,
- kCGPatternTilingNoDistortion, true, &callbks);
- CGColorSpaceRef cs = CGColorSpaceCreatePattern(nullptr);
- CGContextSetFillColorSpace(d->hd, cs);
- CGFloat component = 1.0; //just one
- CGContextSetFillPattern(d->hd, pat, &component);
- CGSize phase = CGSizeApplyAffineTransform(CGSizeMake(-(p.x()-r.x()), -(p.y()-r.y())), trans);
- CGContextSetPatternPhase(d->hd, phase);
-
- //fill the rectangle
- CGRect mac_rect = CGRectMake(r.x(), r.y(), r.width(), r.height());
- CGContextFillRect(d->hd, mac_rect);
-
- //restore the state
- d->restoreGraphicsState();
- //cleanup
- CGColorSpaceRelease(cs);
- CGPatternRelease(pat);
-}
-
-void QCoreGraphicsPaintEngine::drawTextItem(const QPointF &pos, const QTextItem &item)
-{
- Q_D(QCoreGraphicsPaintEngine);
- if (d->current.transform.type() == QTransform::TxProject
-#ifndef QMAC_NATIVE_GRADIENTS
- || painter()->pen().brush().gradient() //Just let the base engine "emulate" the gradient
-#endif
- ) {
- QPaintEngine::drawTextItem(pos, item);
- return;
- }
-
- if (state->compositionMode() == QPainter::CompositionMode_Destination)
- return;
-
- const QTextItemInt &ti = static_cast<const QTextItemInt &>(item);
-
- QPen oldPen = painter()->pen();
- QBrush oldBrush = painter()->brush();
- QPointF oldBrushOrigin = painter()->brushOrigin();
- updatePen(Qt::NoPen);
- updateBrush(oldPen.brush(), QPointF(0, 0));
-
- Q_ASSERT(type() == QPaintEngine::CoreGraphics);
-
- QFontEngine *fe = ti.fontEngine;
-
- const bool textAA = ((state->renderHints() & QPainter::TextAntialiasing)
- && !(fe->fontDef.styleStrategy & QFont::NoAntialias));
- const bool lineAA = state->renderHints() & QPainter::Antialiasing;
- if (textAA != lineAA)
- CGContextSetShouldAntialias(d->hd, textAA);
-
- const bool smoothing = textAA && !(fe->fontDef.styleStrategy & QFont::NoSubpixelAntialias);
- if (d->disabledSmoothFonts == smoothing)
- CGContextSetShouldSmoothFonts(d->hd, smoothing);
-
- if (ti.glyphs.numGlyphs) {
- switch (fe->type()) {
- case QFontEngine::Mac:
- static_cast<QCoreTextFontEngine *>(fe)->draw(d->hd, pos.x(), pos.y(), ti, paintDevice()->height());
- break;
- case QFontEngine::Box:
- d->drawBoxTextItem(pos, ti);
- break;
- default:
- break;
- }
- }
-
- if (textAA != lineAA)
- CGContextSetShouldAntialias(d->hd, !textAA);
-
- if (smoothing == d->disabledSmoothFonts)
- CGContextSetShouldSmoothFonts(d->hd, !d->disabledSmoothFonts);
-
- updatePen(oldPen);
- updateBrush(oldBrush, oldBrushOrigin);
-}
-
-QPainter::RenderHints
-QCoreGraphicsPaintEngine::supportedRenderHints() const
-{
- return QPainter::RenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform);
-}
-enum CGCompositeMode {
- kCGCompositeModeClear = 0,
- kCGCompositeModeCopy = 1,
- kCGCompositeModeSourceOver = 2,
- kCGCompositeModeSourceIn = 3,
- kCGCompositeModeSourceOut = 4,
- kCGCompositeModeSourceAtop = 5,
- kCGCompositeModeDestinationOver = 6,
- kCGCompositeModeDestinationIn = 7,
- kCGCompositeModeDestinationOut = 8,
- kCGCompositeModeDestinationAtop = 9,
- kCGCompositeModeXOR = 10,
- kCGCompositeModePlusDarker = 11, // (max (0, (1-d) + (1-s)))
- kCGCompositeModePlusLighter = 12, // (min (1, s + d))
- };
-extern "C" {
- extern void CGContextSetCompositeOperation(CGContextRef, int);
-} // private function, but is in all versions of OS X.
-void
-QCoreGraphicsPaintEngine::updateCompositionMode(QPainter::CompositionMode mode)
-{
- int cg_mode = kCGBlendModeNormal;
- switch (mode) {
- case QPainter::CompositionMode_Multiply:
- cg_mode = kCGBlendModeMultiply;
- break;
- case QPainter::CompositionMode_Screen:
- cg_mode = kCGBlendModeScreen;
- break;
- case QPainter::CompositionMode_Overlay:
- cg_mode = kCGBlendModeOverlay;
- break;
- case QPainter::CompositionMode_Darken:
- cg_mode = kCGBlendModeDarken;
- break;
- case QPainter::CompositionMode_Lighten:
- cg_mode = kCGBlendModeLighten;
- break;
- case QPainter::CompositionMode_ColorDodge:
- cg_mode = kCGBlendModeColorDodge;
- break;
- case QPainter::CompositionMode_ColorBurn:
- cg_mode = kCGBlendModeColorBurn;
- break;
- case QPainter::CompositionMode_HardLight:
- cg_mode = kCGBlendModeHardLight;
- break;
- case QPainter::CompositionMode_SoftLight:
- cg_mode = kCGBlendModeSoftLight;
- break;
- case QPainter::CompositionMode_Difference:
- cg_mode = kCGBlendModeDifference;
- break;
- case QPainter::CompositionMode_Exclusion:
- cg_mode = kCGBlendModeExclusion;
- break;
- case QPainter::CompositionMode_Plus:
- cg_mode = kCGBlendModePlusLighter;
- break;
- case QPainter::CompositionMode_SourceOver:
- cg_mode = kCGBlendModeNormal;
- break;
- case QPainter::CompositionMode_DestinationOver:
- cg_mode = kCGBlendModeDestinationOver;
- break;
- case QPainter::CompositionMode_Clear:
- cg_mode = kCGBlendModeClear;
- break;
- case QPainter::CompositionMode_Source:
- cg_mode = kCGBlendModeCopy;
- break;
- case QPainter::CompositionMode_Destination:
- cg_mode = -1;
- break;
- case QPainter::CompositionMode_SourceIn:
- cg_mode = kCGBlendModeSourceIn;
- break;
- case QPainter::CompositionMode_DestinationIn:
- cg_mode = kCGCompositeModeDestinationIn;
- break;
- case QPainter::CompositionMode_SourceOut:
- cg_mode = kCGBlendModeSourceOut;
- break;
- case QPainter::CompositionMode_DestinationOut:
- cg_mode = kCGBlendModeDestinationOver;
- break;
- case QPainter::CompositionMode_SourceAtop:
- cg_mode = kCGBlendModeSourceAtop;
- break;
- case QPainter::CompositionMode_DestinationAtop:
- cg_mode = kCGBlendModeDestinationAtop;
- break;
- case QPainter::CompositionMode_Xor:
- cg_mode = kCGBlendModeXOR;
- break;
- default:
- break;
- }
- if (cg_mode > -1) {
- CGContextSetBlendMode(d_func()->hd, CGBlendMode(cg_mode));
- }
-}
-
-void
-QCoreGraphicsPaintEngine::updateRenderHints(QPainter::RenderHints hints)
-{
- Q_D(QCoreGraphicsPaintEngine);
- CGContextSetShouldAntialias(d->hd, hints & QPainter::Antialiasing);
- CGContextSetInterpolationQuality(d->hd, (hints & QPainter::SmoothPixmapTransform) ?
- kCGInterpolationHigh : kCGInterpolationNone);
- bool textAntialiasing = (hints & QPainter::TextAntialiasing) == QPainter::TextAntialiasing;
- if (!textAntialiasing || d->disabledSmoothFonts) {
- d->disabledSmoothFonts = !textAntialiasing;
- CGContextSetShouldSmoothFonts(d->hd, textAntialiasing);
- }
-}
-
-/*
- Returns the size of one device pixel in user-space coordinates.
-*/
-QPointF QCoreGraphicsPaintEnginePrivate::devicePixelSize(CGContextRef)
-{
- QPointF p1 = current.transform.inverted().map(QPointF(0, 0));
- QPointF p2 = current.transform.inverted().map(QPointF(1, 1));
- return QPointF(qAbs(p2.x() - p1.x()), qAbs(p2.y() - p1.y()));
-}
-
-/*
- Adjusts the pen width so we get correct line widths in the
- non-transformed, aliased case.
-*/
-float QCoreGraphicsPaintEnginePrivate::adjustPenWidth(float penWidth)
-{
- Q_Q(QCoreGraphicsPaintEngine);
- float ret = penWidth;
- if (!complexXForm && !(q->state->renderHints() & QPainter::Antialiasing)) {
- if (penWidth < 2)
- ret = 1;
- else if (penWidth < 3)
- ret = 1.5;
- else
- ret = penWidth -1;
- }
- return ret;
-}
-
-void
-QCoreGraphicsPaintEnginePrivate::setStrokePen(const QPen &pen)
-{
- //pencap
- CGLineCap cglinecap = kCGLineCapButt;
- if (pen.capStyle() == Qt::SquareCap)
- cglinecap = kCGLineCapSquare;
- else if (pen.capStyle() == Qt::RoundCap)
- cglinecap = kCGLineCapRound;
- CGContextSetLineCap(hd, cglinecap);
- CGContextSetLineWidth(hd, adjustPenWidth(pen.widthF()));
-
- //join
- CGLineJoin cglinejoin = kCGLineJoinMiter;
- if (pen.joinStyle() == Qt::BevelJoin)
- cglinejoin = kCGLineJoinBevel;
- else if (pen.joinStyle() == Qt::RoundJoin)
- cglinejoin = kCGLineJoinRound;
- CGContextSetLineJoin(hd, cglinejoin);
-// CGContextSetMiterLimit(hd, pen.miterLimit());
-
- //pen style
- QVector<CGFloat> linedashes;
- if (pen.style() == Qt::CustomDashLine) {
- QVector<qreal> customs = pen.dashPattern();
- for (int i = 0; i < customs.size(); ++i)
- linedashes.append(customs.at(i));
- } else if (pen.style() == Qt::DashLine) {
- linedashes.append(4);
- linedashes.append(2);
- } else if (pen.style() == Qt::DotLine) {
- linedashes.append(1);
- linedashes.append(2);
- } else if (pen.style() == Qt::DashDotLine) {
- linedashes.append(4);
- linedashes.append(2);
- linedashes.append(1);
- linedashes.append(2);
- } else if (pen.style() == Qt::DashDotDotLine) {
- linedashes.append(4);
- linedashes.append(2);
- linedashes.append(1);
- linedashes.append(2);
- linedashes.append(1);
- linedashes.append(2);
- }
- const CGFloat cglinewidth = pen.widthF() <= 0.0f ? 1.0f : float(pen.widthF());
- for (int i = 0; i < linedashes.size(); ++i) {
- linedashes[i] *= cglinewidth;
- if (cglinewidth < 3 && (cglinecap == kCGLineCapSquare || cglinecap == kCGLineCapRound)) {
- if ((i%2))
- linedashes[i] += cglinewidth/2;
- else
- linedashes[i] -= cglinewidth/2;
- }
- }
- CGContextSetLineDash(hd, pen.dashOffset() * cglinewidth, linedashes.data(), linedashes.size());
-
- // color
- CGContextSetStrokeColorWithColor(hd, cgColorForQColor(pen.color()));
-}
-
-// Add our own patterns here to deal with the fact that the coordinate system
-// is flipped vertically with Quartz2D.
-static const uchar *qt_mac_patternForBrush(int brushStyle)
-{
- Q_ASSERT(brushStyle > Qt::SolidPattern && brushStyle < Qt::LinearGradientPattern);
- static const uchar dense1_pat[] = { 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x44, 0x00 };
- static const uchar dense2_pat[] = { 0x00, 0x22, 0x00, 0x88, 0x00, 0x22, 0x00, 0x88 };
- static const uchar dense3_pat[] = { 0x11, 0xaa, 0x44, 0xaa, 0x11, 0xaa, 0x44, 0xaa };
- static const uchar dense4_pat[] = { 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55 };
- static const uchar dense5_pat[] = { 0xee, 0x55, 0xbb, 0x55, 0xee, 0x55, 0xbb, 0x55 };
- static const uchar dense6_pat[] = { 0xff, 0xdd, 0xff, 0x77, 0xff, 0xdd, 0xff, 0x77 };
- static const uchar dense7_pat[] = { 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb, 0xff };
- static const uchar hor_pat[] = { 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff };
- static const uchar ver_pat[] = { 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef };
- static const uchar cross_pat[] = { 0xef, 0xef, 0xef, 0xef, 0x00, 0xef, 0xef, 0xef };
- static const uchar fdiag_pat[] = { 0x7f, 0xbf, 0xdf, 0xef, 0xf7, 0xfb, 0xfd, 0xfe };
- static const uchar bdiag_pat[] = { 0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f };
- static const uchar dcross_pat[] = { 0x7e, 0xbd, 0xdb, 0xe7, 0xe7, 0xdb, 0xbd, 0x7e };
- static const uchar *const pat_tbl[] = {
- dense1_pat, dense2_pat, dense3_pat, dense4_pat, dense5_pat,
- dense6_pat, dense7_pat,
- hor_pat, ver_pat, cross_pat, bdiag_pat, fdiag_pat, dcross_pat };
- return pat_tbl[brushStyle - Qt::Dense1Pattern];
-}
-
-void QCoreGraphicsPaintEnginePrivate::setFillBrush(const QPointF &offset)
-{
- // pattern
- Qt::BrushStyle bs = current.brush.style();
-#ifdef QT_MAC_USE_NATIVE_GRADIENTS
- if (bs == Qt::LinearGradientPattern || bs == Qt::RadialGradientPattern) {
- const QGradient *grad = static_cast<const QGradient*>(current.brush.gradient());
- if (drawGradientNatively(grad)) {
- Q_ASSERT(grad->spread() == QGradient::PadSpread);
-
- static const CGFloat domain[] = { 0.0f, +1.0f };
- static const CGFunctionCallbacks callbacks = { 0, qt_mac_color_gradient_function, nullptr };
- CGFunctionRef fill_func = CGFunctionCreate(reinterpret_cast<void *>(&current.brush),
- 1, domain, 4, nullptr, &callbacks);
-
- CGColorSpaceRef colorspace = CGColorSpaceCreateWithName(kCGColorSpaceSRGB)
- if (bs == Qt::LinearGradientPattern) {
- const QLinearGradient *linearGrad = static_cast<const QLinearGradient *>(grad);
- const QPointF start(linearGrad->start());
- const QPointF stop(linearGrad->finalStop());
- shading = CGShadingCreateAxial(colorspace, CGPointMake(start.x(), start.y()),
- CGPointMake(stop.x(), stop.y()), fill_func, true, true);
- } else {
- Q_ASSERT(bs == Qt::RadialGradientPattern);
- const QRadialGradient *radialGrad = static_cast<const QRadialGradient *>(grad);
- QPointF center(radialGrad->center());
- QPointF focal(radialGrad->focalPoint());
- qreal radius = radialGrad->radius();
- qreal focalRadius = radialGrad->focalRadius();
- shading = CGShadingCreateRadial(colorspace, CGPointMake(focal.x(), focal.y()),
- focalRadius, CGPointMake(center.x(), center.y()), radius, fill_func, false, true);
- }
-
- CGFunctionRelease(fill_func);
- }
- } else
-#endif
- if (bs != Qt::SolidPattern && bs != Qt::NoBrush
-#ifndef QT_MAC_USE_NATIVE_GRADIENTS
- && (bs < Qt::LinearGradientPattern || bs > Qt::ConicalGradientPattern)
-#endif
- )
- {
- QMacPattern *qpattern = new QMacPattern;
- qpattern->pdev = pdev;
- CGFloat components[4] = { 1.0, 1.0, 1.0, 1.0 };
- CGColorSpaceRef base_colorspace = nullptr;
- if (bs == Qt::TexturePattern) {
- qpattern->data.pixmap = current.brush.texture();
- if (qpattern->data.pixmap.isQBitmap()) {
- const QColor &col = current.brush.color();
- components[0] = qt_mac_convert_color_to_cg(col.red());
- components[1] = qt_mac_convert_color_to_cg(col.green());
- components[2] = qt_mac_convert_color_to_cg(col.blue());
- base_colorspace = CGColorSpaceCreateWithName(kCGColorSpaceSRGB);
- }
- } else {
- qpattern->as_mask = true;
-
- qpattern->data.bytes = qt_mac_patternForBrush(bs);
- const QColor &col = current.brush.color();
- components[0] = qt_mac_convert_color_to_cg(col.red());
- components[1] = qt_mac_convert_color_to_cg(col.green());
- components[2] = qt_mac_convert_color_to_cg(col.blue());
- base_colorspace = CGColorSpaceCreateWithName(kCGColorSpaceSRGB);
- }
- int width = qpattern->width(), height = qpattern->height();
- qpattern->foreground = current.brush.color();
-
- CGColorSpaceRef fill_colorspace = CGColorSpaceCreatePattern(base_colorspace);
- CGContextSetFillColorSpace(hd, fill_colorspace);
-
- CGAffineTransform xform = CGContextGetCTM(hd);
- xform = CGAffineTransformConcat(qt_mac_convert_transform_to_cg(current.brush.transform()), xform);
- xform = CGAffineTransformTranslate(xform, offset.x(), offset.y());
-
- CGPatternCallbacks callbks;
- callbks.version = 0;
- callbks.drawPattern = qt_mac_draw_pattern;
- callbks.releaseInfo = qt_mac_dispose_pattern;
- CGPatternRef fill_pattern = CGPatternCreate(qpattern, CGRectMake(0, 0, width, height),
- xform, width, height, kCGPatternTilingNoDistortion,
- !base_colorspace, &callbks);
- CGContextSetFillPattern(hd, fill_pattern, components);
-
-
- CGPatternRelease(fill_pattern);
- CGColorSpaceRelease(base_colorspace);
- CGColorSpaceRelease(fill_colorspace);
- } else if (bs != Qt::NoBrush) {
- CGContextSetFillColorWithColor(hd, cgColorForQColor(current.brush.color()));
- }
-}
-
-void
-QCoreGraphicsPaintEnginePrivate::setClip(const QRegion *rgn)
-{
- Q_Q(QCoreGraphicsPaintEngine);
- if (hd) {
- resetClip();
- QRegion sysClip = q->systemClip();
- if (!sysClip.isEmpty())
- qt_mac_clip_cg(hd, sysClip, &orig_xform);
- if (rgn)
- qt_mac_clip_cg(hd, *rgn, nullptr);
- }
-}
-
-struct qt_mac_cg_transform_path {
- CGMutablePathRef path;
- CGAffineTransform transform;
-};
-
-void qt_mac_cg_transform_path_apply(void *info, const CGPathElement *element)
-{
- Q_ASSERT(info && element);
- qt_mac_cg_transform_path *t = (qt_mac_cg_transform_path*)info;
- switch (element->type) {
- case kCGPathElementMoveToPoint:
- CGPathMoveToPoint(t->path, &t->transform, element->points[0].x, element->points[0].y);
- break;
- case kCGPathElementAddLineToPoint:
- CGPathAddLineToPoint(t->path, &t->transform, element->points[0].x, element->points[0].y);
- break;
- case kCGPathElementAddQuadCurveToPoint:
- CGPathAddQuadCurveToPoint(t->path, &t->transform, element->points[0].x, element->points[0].y,
- element->points[1].x, element->points[1].y);
- break;
- case kCGPathElementAddCurveToPoint:
- CGPathAddCurveToPoint(t->path, &t->transform, element->points[0].x, element->points[0].y,
- element->points[1].x, element->points[1].y,
- element->points[2].x, element->points[2].y);
- break;
- case kCGPathElementCloseSubpath:
- CGPathCloseSubpath(t->path);
- break;
- default:
- qDebug() << "Unhandled path transform type: " << element->type;
- }
-}
-
-void QCoreGraphicsPaintEnginePrivate::drawPath(uchar ops, CGMutablePathRef path)
-{
- Q_Q(QCoreGraphicsPaintEngine);
- Q_ASSERT((ops & (CGFill | CGEOFill)) != (CGFill | CGEOFill)); //can't really happen
- if ((ops & (CGFill | CGEOFill))) {
- if (shading) {
- Q_ASSERT(path);
- CGContextBeginPath(hd);
- CGContextAddPath(hd, path);
- saveGraphicsState();
- if (ops & CGFill)
- CGContextClip(hd);
- else if (ops & CGEOFill)
- CGContextEOClip(hd);
- if (current.brush.gradient()->coordinateMode() == QGradient::ObjectBoundingMode) {
- CGRect boundingBox = CGPathGetBoundingBox(path);
- CGContextConcatCTM(hd,
- CGAffineTransformMake(boundingBox.size.width, 0,
- 0, boundingBox.size.height,
- boundingBox.origin.x, boundingBox.origin.y));
- }
- CGContextDrawShading(hd, shading);
- restoreGraphicsState();
- ops &= ~CGFill;
- ops &= ~CGEOFill;
- } else if (current.brush.style() == Qt::NoBrush) {
- ops &= ~CGFill;
- ops &= ~CGEOFill;
- }
- }
- if ((ops & CGStroke) && current.pen.style() == Qt::NoPen)
- ops &= ~CGStroke;
-
- if (ops & (CGEOFill | CGFill)) {
- CGContextBeginPath(hd);
- CGContextAddPath(hd, path);
- if (ops & CGEOFill) {
- CGContextEOFillPath(hd);
- } else {
- CGContextFillPath(hd);
- }
- }
-
- // Avoid saving and restoring the context if we can.
- const bool needContextSave = (cosmeticPen != QCoreGraphicsPaintEnginePrivate::CosmeticNone ||
- !(q->state->renderHints() & QPainter::Antialiasing));
- if (ops & CGStroke) {
- if (needContextSave)
- saveGraphicsState();
- CGContextBeginPath(hd);
-
- // Translate a fraction of a pixel size in the y direction
- // to make sure that primitives painted at pixel borders
- // fills the right pixel. This is needed since the y xais
- // in the Quartz coordinate system is inverted compared to Qt.
- if (!(q->state->renderHints() & QPainter::Antialiasing)) {
- if (current.pen.style() == Qt::SolidLine || current.pen.width() >= 3)
- CGContextTranslateCTM(hd, double(pixelSize.x()) * 0.25, double(pixelSize.y()) * 0.25);
- else
- CGContextTranslateCTM(hd, 0, double(pixelSize.y()) * 0.1);
- }
-
- if (cosmeticPen != QCoreGraphicsPaintEnginePrivate::CosmeticNone) {
- // If antialiazing is enabled, use the cosmetic pen size directly.
- if (q->state->renderHints() & QPainter::Antialiasing)
- CGContextSetLineWidth(hd, cosmeticPenSize);
- else if (current.pen.widthF() <= 1)
- CGContextSetLineWidth(hd, cosmeticPenSize * 0.9f);
- else
- CGContextSetLineWidth(hd, cosmeticPenSize);
- }
- if (cosmeticPen == QCoreGraphicsPaintEnginePrivate::CosmeticTransformPath) {
- qt_mac_cg_transform_path t;
- t.transform = qt_mac_convert_transform_to_cg(current.transform);
- t.path = CGPathCreateMutable();
- CGPathApply(path, &t, qt_mac_cg_transform_path_apply); //transform the path
- setTransform(nullptr); //unset the context transform
- CGContextSetLineWidth(hd, cosmeticPenSize);
- CGContextAddPath(hd, t.path);
- CGPathRelease(t.path);
- } else {
- CGContextAddPath(hd, path);
- }
-
- CGContextStrokePath(hd);
- if (needContextSave)
- restoreGraphicsState();
- }
-}
-
-QT_END_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/qpaintengine_mac_p.h b/src/plugins/platforms/cocoa/qpaintengine_mac_p.h
deleted file mode 100644
index 1416386745..0000000000
--- a/src/plugins/platforms/cocoa/qpaintengine_mac_p.h
+++ /dev/null
@@ -1,205 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 QPAINTENGINE_MAC_P_H
-#define QPAINTENGINE_MAC_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 "QtGui/qpaintengine.h"
-#include "private/qpaintengine_p.h"
-#include "private/qpolygonclipper_p.h"
-#include "private/qfont_p.h"
-#include "QtCore/qhash.h"
-
-#include "qt_mac_p.h"
-
-typedef struct CGColorSpace *CGColorSpaceRef;
-QT_BEGIN_NAMESPACE
-
-class QCoreGraphicsPaintEnginePrivate;
-class QCoreGraphicsPaintEngine : public QPaintEngine
-{
- Q_DECLARE_PRIVATE(QCoreGraphicsPaintEngine)
-
-public:
- QCoreGraphicsPaintEngine();
- ~QCoreGraphicsPaintEngine();
-
- bool begin(QPaintDevice *pdev);
- bool end();
-
- void updateState(const QPaintEngineState &state);
-
- void updatePen(const QPen &pen);
- void updateBrush(const QBrush &brush, const QPointF &pt);
- void updateFont(const QFont &font);
- void updateOpacity(qreal opacity);
- void updateMatrix(const QTransform &matrix);
- void updateTransform(const QTransform &matrix);
- void updateClipRegion(const QRegion &region, Qt::ClipOperation op);
- void updateClipPath(const QPainterPath &path, Qt::ClipOperation op);
- void updateCompositionMode(QPainter::CompositionMode mode);
- void updateRenderHints(QPainter::RenderHints hints);
-
- void drawLines(const QLineF *lines, int lineCount);
- void drawRects(const QRectF *rects, int rectCount);
- void drawPoints(const QPointF *p, int pointCount);
- void drawEllipse(const QRectF &r);
- void drawPath(const QPainterPath &path);
-
- void drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode);
- void drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr);
- void drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPointF &s);
-
- void drawTextItem(const QPointF &pos, const QTextItem &item);
- void drawImage(const QRectF &r, const QImage &pm, const QRectF &sr,
- Qt::ImageConversionFlags flags = Qt::AutoColor);
-
- Type type() const { return QPaintEngine::CoreGraphics; }
-
- CGContextRef handle() const;
-
- static void initialize();
- static void cleanup();
-
- QPainter::RenderHints supportedRenderHints() const;
-
- //avoid partial shadowed overload warnings...
- void drawLines(const QLine *lines, int lineCount) { QPaintEngine::drawLines(lines, lineCount); }
- void drawRects(const QRect *rects, int rectCount) { QPaintEngine::drawRects(rects, rectCount); }
- void drawPoints(const QPoint *p, int pointCount) { QPaintEngine::drawPoints(p, pointCount); }
- void drawEllipse(const QRect &r) { QPaintEngine::drawEllipse(r); }
- void drawPolygon(const QPoint *points, int pointCount, PolygonDrawMode mode)
- { QPaintEngine::drawPolygon(points, pointCount, mode); }
-
-protected:
- friend class QMacPrintEngine;
- friend class QMacPrintEnginePrivate;
- QCoreGraphicsPaintEngine(QPaintEnginePrivate &dptr);
-
-private:
- Q_DISABLE_COPY(QCoreGraphicsPaintEngine)
-};
-
-/*****************************************************************************
- Private data
- *****************************************************************************/
-class QCoreGraphicsPaintEnginePrivate : public QPaintEnginePrivate
-{
- Q_DECLARE_PUBLIC(QCoreGraphicsPaintEngine)
-public:
- QCoreGraphicsPaintEnginePrivate()
- : hd(nullptr), shading(nullptr), stackCount(0), complexXForm(false), disabledSmoothFonts(false)
- {
- }
-
- struct {
- QPen pen;
- QBrush brush;
- uint clipEnabled : 1;
- QRegion clip;
- QTransform transform;
- } current;
-
- //state info (shared with QD)
- CGAffineTransform orig_xform;
-
- //cg structures
- CGContextRef hd;
- CGShadingRef shading;
- int stackCount;
- bool complexXForm;
- bool disabledSmoothFonts;
- enum { CosmeticNone, CosmeticTransformPath, CosmeticSetPenWidth } cosmeticPen;
-
- // pixel and cosmetic pen size in user coordinates.
- QPointF pixelSize;
- float cosmeticPenSize;
-
- //internal functions
- enum { CGStroke=0x01, CGEOFill=0x02, CGFill=0x04 };
- void drawPath(uchar ops, CGMutablePathRef path = nullptr);
- void setClip(const QRegion *rgn = nullptr);
- void resetClip();
- void setFillBrush(const QPointF &origin=QPoint());
- void setStrokePen(const QPen &pen);
- inline void saveGraphicsState();
- inline void restoreGraphicsState();
- float penOffset();
- QPointF devicePixelSize(CGContextRef context);
- float adjustPenWidth(float penWidth);
- inline void setTransform(const QTransform *matrix = nullptr)
- {
- CGContextConcatCTM(hd, CGAffineTransformInvert(CGContextGetCTM(hd)));
- CGAffineTransform xform = orig_xform;
- if (matrix) {
- extern CGAffineTransform qt_mac_convert_transform_to_cg(const QTransform &);
- xform = CGAffineTransformConcat(qt_mac_convert_transform_to_cg(*matrix), xform);
- }
- CGContextConcatCTM(hd, xform);
- CGContextSetTextMatrix(hd, xform);
- }
-};
-
-inline void QCoreGraphicsPaintEnginePrivate::saveGraphicsState()
-{
- ++stackCount;
- CGContextSaveGState(hd);
-}
-
-inline void QCoreGraphicsPaintEnginePrivate::restoreGraphicsState()
-{
- --stackCount;
- Q_ASSERT(stackCount >= 0);
- CGContextRestoreGState(hd);
-}
-
-QT_END_NAMESPACE
-
-#endif // QPAINTENGINE_MAC_P_H
diff --git a/src/plugins/platforms/cocoa/qprintengine_mac.mm b/src/plugins/platforms/cocoa/qprintengine_mac.mm
deleted file mode 100644
index dcb9a85a3c..0000000000
--- a/src/plugins/platforms/cocoa/qprintengine_mac.mm
+++ /dev/null
@@ -1,793 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 "qprintengine_mac_p.h"
-#include "qcocoaprintersupport.h"
-#include <quuid.h>
-#include <QtGui/qpagelayout.h>
-#include <QtCore/qcoreapplication.h>
-#include <QtCore/qdebug.h>
-
-
-#ifndef QT_NO_PRINTER
-
-QT_BEGIN_NAMESPACE
-
-extern QMarginsF qt_convertMargins(const QMarginsF &margins, QPageLayout::Unit fromUnits, QPageLayout::Unit toUnits);
-
-QMacPrintEngine::QMacPrintEngine(QPrinter::PrinterMode mode, const QString &deviceId)
- : QPaintEngine(*(new QMacPrintEnginePrivate))
-{
- Q_D(QMacPrintEngine);
- d->mode = mode;
- QString id = deviceId;
- if (id.isEmpty())
- id = QCocoaPrinterSupport().defaultPrintDeviceId();
- else
- setProperty(QPrintEngine::PPK_PrinterName, deviceId);
- d->m_printDevice.reset(new QCocoaPrintDevice(id));
- d->m_pageLayout.setPageSize(d->m_printDevice->defaultPageSize());
- d->initialize();
-}
-
-bool QMacPrintEngine::begin(QPaintDevice *dev)
-{
- Q_D(QMacPrintEngine);
-
- Q_ASSERT(dev && dev->devType() == QInternal::Printer);
- if (!static_cast<QPrinter *>(dev)->isValid())
- return false;
-
- if (d->state == QPrinter::Idle && !d->isPrintSessionInitialized()) // Need to reinitialize
- d->initialize();
-
- d->paintEngine->state = state;
- d->paintEngine->begin(dev);
- Q_ASSERT_X(d->state == QPrinter::Idle, "QMacPrintEngine", "printer already active");
-
- if (PMSessionValidatePrintSettings(d->session(), d->settings(), kPMDontWantBoolean) != noErr
- || PMSessionValidatePageFormat(d->session(), d->format(), kPMDontWantBoolean) != noErr) {
- d->state = QPrinter::Error;
- return false;
- }
-
- if (!d->outputFilename.isEmpty()) {
- QCFType<CFURLRef> outFile = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault,
- QCFString(d->outputFilename),
- kCFURLPOSIXPathStyle,
- false);
- if (PMSessionSetDestination(d->session(), d->settings(), kPMDestinationFile,
- kPMDocumentFormatPDF, outFile) != noErr) {
- qWarning("QMacPrintEngine::begin: Problem setting file [%s]", d->outputFilename.toUtf8().constData());
- return false;
- }
- }
-
- OSStatus status = PMSessionBeginCGDocumentNoDialog(d->session(), d->settings(), d->format());
- if (status != noErr) {
- d->state = QPrinter::Error;
- return false;
- }
-
- d->state = QPrinter::Active;
- setActive(true);
- d->newPage_helper();
- return true;
-}
-
-bool QMacPrintEngine::end()
-{
- Q_D(QMacPrintEngine);
- if (d->state == QPrinter::Aborted)
- return true; // I was just here a function call ago :)
- if (d->paintEngine->type() == QPaintEngine::CoreGraphics) {
- // We don't need the paint engine to call restoreGraphicsState()
- static_cast<QCoreGraphicsPaintEngine*>(d->paintEngine)->d_func()->stackCount = 0;
- static_cast<QCoreGraphicsPaintEngine*>(d->paintEngine)->d_func()->hd = nullptr;
- }
- d->paintEngine->end();
- if (d->state != QPrinter::Idle)
- d->releaseSession();
- d->state = QPrinter::Idle;
- return true;
-}
-
-QPaintEngine *
-QMacPrintEngine::paintEngine() const
-{
- return d_func()->paintEngine;
-}
-
-Qt::HANDLE QMacPrintEngine::handle() const
-{
- QCoreGraphicsPaintEngine *cgEngine = static_cast<QCoreGraphicsPaintEngine*>(paintEngine());
- return cgEngine->d_func()->hd;
-}
-
-QMacPrintEnginePrivate::~QMacPrintEnginePrivate()
-{
- [printInfo release];
- delete paintEngine;
-}
-
-QPrinter::PrinterState QMacPrintEngine::printerState() const
-{
- return d_func()->state;
-}
-
-bool QMacPrintEngine::newPage()
-{
- Q_D(QMacPrintEngine);
- Q_ASSERT(d->state == QPrinter::Active);
- OSStatus err = PMSessionEndPageNoDialog(d->session());
- if (err != noErr) {
- if (err == kPMCancel) {
- // User canceled, we need to abort!
- abort();
- } else {
- // Not sure what the problem is...
- qWarning("QMacPrintEngine::newPage: Cannot end current page. %ld", long(err));
- d->state = QPrinter::Error;
- }
- return false;
- }
- return d->newPage_helper();
-}
-
-bool QMacPrintEngine::abort()
-{
- Q_D(QMacPrintEngine);
- if (d->state != QPrinter::Active)
- return false;
- bool ret = end();
- d->state = QPrinter::Aborted;
- return ret;
-}
-
-int QMacPrintEngine::metric(QPaintDevice::PaintDeviceMetric m) const
-{
- Q_D(const QMacPrintEngine);
- int val = 1;
- switch (m) {
- case QPaintDevice::PdmWidth:
- val = d->m_pageLayout.paintRectPixels(d->resolution.hRes).width();
- break;
- case QPaintDevice::PdmHeight:
- val = d->m_pageLayout.paintRectPixels(d->resolution.hRes).height();
- break;
- case QPaintDevice::PdmWidthMM:
- val = qRound(d->m_pageLayout.paintRect(QPageLayout::Millimeter).width());
- break;
- case QPaintDevice::PdmHeightMM:
- val = qRound(d->m_pageLayout.paintRect(QPageLayout::Millimeter).height());
- break;
- case QPaintDevice::PdmPhysicalDpiX:
- case QPaintDevice::PdmPhysicalDpiY: {
- PMPrinter printer;
- if (PMSessionGetCurrentPrinter(d->session(), &printer) == noErr) {
- PMResolution resolution;
- PMPrinterGetOutputResolution(printer, d->settings(), &resolution);
- val = (int)resolution.vRes;
- break;
- }
- Q_FALLTHROUGH();
- }
- case QPaintDevice::PdmDpiY:
- val = (int)d->resolution.vRes;
- break;
- case QPaintDevice::PdmDpiX:
- val = (int)d->resolution.hRes;
- break;
- case QPaintDevice::PdmNumColors:
- val = (1 << metric(QPaintDevice::PdmDepth));
- break;
- case QPaintDevice::PdmDepth:
- val = 24;
- break;
- case QPaintDevice::PdmDevicePixelRatio:
- val = 1;
- break;
- case QPaintDevice::PdmDevicePixelRatioScaled:
- val = 1 * QPaintDevice::devicePixelRatioFScale();
- break;
- default:
- val = 0;
- qWarning("QPrinter::metric: Invalid metric command");
- }
- return val;
-}
-
-void QMacPrintEnginePrivate::initialize()
-{
- Q_Q(QMacPrintEngine);
-
- Q_ASSERT(!printInfo);
-
- if (!paintEngine)
- paintEngine = new QCoreGraphicsPaintEngine();
-
- q->gccaps = paintEngine->gccaps;
-
- QMacAutoReleasePool pool;
- printInfo = [[NSPrintInfo alloc] initWithDictionary:[NSDictionary dictionary]];
-
- QList<int> resolutions = m_printDevice->supportedResolutions();
- if (!resolutions.isEmpty() && mode != QPrinter::ScreenResolution) {
- std::sort(resolutions.begin(), resolutions.end());
- if (resolutions.count() > 1 && mode == QPrinter::HighResolution)
- resolution.hRes = resolution.vRes = resolutions.last();
- else
- resolution.hRes = resolution.vRes = resolutions.first();
- if (resolution.hRes == 0)
- resolution.hRes = resolution.vRes = 600;
- } else {
- resolution.hRes = resolution.vRes = qt_defaultDpi();
- }
-
- setPageSize(m_pageLayout.pageSize());
-
- QHash<QMacPrintEngine::PrintEnginePropertyKey, QVariant>::const_iterator propC;
- for (propC = valueCache.constBegin(); propC != valueCache.constEnd(); ++propC) {
- q->setProperty(propC.key(), propC.value());
- }
-}
-
-void QMacPrintEnginePrivate::releaseSession()
-{
- PMSessionEndPageNoDialog(session());
- PMSessionEndDocumentNoDialog(session());
- [printInfo release];
- printInfo = nil;
-}
-
-bool QMacPrintEnginePrivate::newPage_helper()
-{
- Q_Q(QMacPrintEngine);
- Q_ASSERT(state == QPrinter::Active);
-
- if (PMSessionError(session()) != noErr) {
- q->abort();
- return false;
- }
-
- // pop the stack of saved graphic states, in case we get the same
- // context back - either way, the stack count should be 0 when we
- // get the new one
- QCoreGraphicsPaintEngine *cgEngine = static_cast<QCoreGraphicsPaintEngine*>(paintEngine);
- while (cgEngine->d_func()->stackCount > 0)
- cgEngine->d_func()->restoreGraphicsState();
-
- OSStatus status = PMSessionBeginPageNoDialog(session(), format(), nullptr);
- if (status != noErr) {
- state = QPrinter::Error;
- return false;
- }
-
- QRect page = m_pageLayout.paintRectPixels(resolution.hRes);
- QRect paper = m_pageLayout.fullRectPixels(resolution.hRes);
-
- CGContextRef cgContext;
- OSStatus err = noErr;
- err = PMSessionGetCGGraphicsContext(session(), &cgContext);
- if (err != noErr) {
- qWarning("QMacPrintEngine::newPage: Cannot retrieve CoreGraphics context: %ld", long(err));
- state = QPrinter::Error;
- return false;
- }
- cgEngine->d_func()->hd = cgContext;
-
- // Set the resolution as a scaling ration of 72 (the default).
- CGContextScaleCTM(cgContext, 72 / resolution.hRes, 72 / resolution.vRes);
-
- CGContextScaleCTM(cgContext, 1, -1);
- CGContextTranslateCTM(cgContext, 0, -paper.height());
- if (m_pageLayout.mode() != QPageLayout::FullPageMode)
- CGContextTranslateCTM(cgContext, page.x() - paper.x(), page.y() - paper.y());
- cgEngine->d_func()->orig_xform = CGContextGetCTM(cgContext);
- cgEngine->d_func()->setClip(nullptr);
- cgEngine->state->dirtyFlags = QPaintEngine::DirtyFlag(QPaintEngine::AllDirty
- & ~(QPaintEngine::DirtyClipEnabled
- | QPaintEngine::DirtyClipRegion
- | QPaintEngine::DirtyClipPath));
- if (cgEngine->painter()->hasClipping())
- cgEngine->state->dirtyFlags |= QPaintEngine::DirtyClipEnabled;
- cgEngine->syncState();
- return true;
-}
-
-void QMacPrintEnginePrivate::setPageSize(const QPageSize &pageSize)
-{
- if (!pageSize.isValid())
- return;
-
- // Get the matching printer paper
- QPageSize printerPageSize = m_printDevice->supportedPageSize(pageSize);
- QPageSize usePageSize = printerPageSize.isValid() ? printerPageSize : pageSize;
-
- // Get the PMPaper and check it is valid
- PMPaper macPaper = m_printDevice->macPaper(usePageSize);
- if (!macPaper) {
- qWarning() << "QMacPrintEngine: Invalid PMPaper returned for " << pageSize;
- return;
- }
-
- QMarginsF printable = m_printDevice->printableMargins(usePageSize, m_pageLayout.orientation(), resolution.hRes);
- m_pageLayout.setPageSize(usePageSize, qt_convertMargins(printable, QPageLayout::Point, m_pageLayout.units()));
-
- // You cannot set the page size on a PMPageFormat, you must create a new PMPageFormat
- PMPageFormat pageFormat;
- PMCreatePageFormatWithPMPaper(&pageFormat, macPaper);
- PMSetOrientation(pageFormat, m_pageLayout.orientation() == QPageLayout::Landscape ? kPMLandscape : kPMPortrait, kPMUnlocked);
- PMCopyPageFormat(pageFormat, format());
- if (PMSessionValidatePageFormat(session(), format(), kPMDontWantBoolean) != noErr)
- qWarning("QMacPrintEngine: Invalid page format");
- PMRelease(pageFormat);
-}
-
-void QMacPrintEngine::updateState(const QPaintEngineState &state)
-{
- d_func()->paintEngine->updateState(state);
-}
-
-void QMacPrintEngine::drawRects(const QRectF *r, int num)
-{
- Q_D(QMacPrintEngine);
- Q_ASSERT(d->state == QPrinter::Active);
- d->paintEngine->drawRects(r, num);
-}
-
-void QMacPrintEngine::drawPoints(const QPointF *points, int pointCount)
-{
- Q_D(QMacPrintEngine);
- Q_ASSERT(d->state == QPrinter::Active);
- d->paintEngine->drawPoints(points, pointCount);
-}
-
-void QMacPrintEngine::drawEllipse(const QRectF &r)
-{
- Q_D(QMacPrintEngine);
- Q_ASSERT(d->state == QPrinter::Active);
- d->paintEngine->drawEllipse(r);
-}
-
-void QMacPrintEngine::drawLines(const QLineF *lines, int lineCount)
-{
- Q_D(QMacPrintEngine);
- Q_ASSERT(d->state == QPrinter::Active);
- d->paintEngine->drawLines(lines, lineCount);
-}
-
-void QMacPrintEngine::drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode)
-{
- Q_D(QMacPrintEngine);
- Q_ASSERT(d->state == QPrinter::Active);
- d->paintEngine->drawPolygon(points, pointCount, mode);
-}
-
-void QMacPrintEngine::drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr)
-{
- Q_D(QMacPrintEngine);
- Q_ASSERT(d->state == QPrinter::Active);
- d->paintEngine->drawPixmap(r, pm, sr);
-}
-
-void QMacPrintEngine::drawImage(const QRectF &r, const QImage &pm, const QRectF &sr, Qt::ImageConversionFlags flags)
-{
- Q_D(QMacPrintEngine);
- Q_ASSERT(d->state == QPrinter::Active);
- d->paintEngine->drawImage(r, pm, sr, flags);
-}
-
-void QMacPrintEngine::drawTextItem(const QPointF &p, const QTextItem &ti)
-{
- Q_D(QMacPrintEngine);
- Q_ASSERT(d->state == QPrinter::Active);
- if (!d->embedFonts)
- QPaintEngine::drawTextItem(p, ti);
- else
- d->paintEngine->drawTextItem(p, ti);
-}
-
-void QMacPrintEngine::drawTiledPixmap(const QRectF &dr, const QPixmap &pixmap, const QPointF &sr)
-{
- Q_D(QMacPrintEngine);
- Q_ASSERT(d->state == QPrinter::Active);
- d->paintEngine->drawTiledPixmap(dr, pixmap, sr);
-}
-
-void QMacPrintEngine::drawPath(const QPainterPath &path)
-{
- Q_D(QMacPrintEngine);
- Q_ASSERT(d->state == QPrinter::Active);
- d->paintEngine->drawPath(path);
-}
-
-
-void QMacPrintEngine::setProperty(PrintEnginePropertyKey key, const QVariant &value)
-{
- Q_D(QMacPrintEngine);
-
- d->valueCache.insert(key, value);
- if (!d->printInfo)
- return;
-
- switch (key) {
-
- // The following keys are properties or derived values and so cannot be set
- case PPK_PageRect:
- break;
- case PPK_PaperRect:
- break;
- case PPK_PaperSources:
- break;
- case PPK_SupportsMultipleCopies:
- break;
- case PPK_SupportedResolutions:
- break;
-
- // The following keys are settings that are unsupported by the Mac PrintEngine
- case PPK_ColorMode:
- break;
- case PPK_CustomBase:
- break;
- case PPK_PageOrder:
- // TODO Check if can be supported via Cups Options
- break;
- case PPK_PaperSource:
- // TODO Check if can be supported via Cups Options
- break;
- case PPK_PrinterProgram:
- break;
- case PPK_SelectionOption:
- break;
-
- // The following keys are properties and settings that are supported by the Mac PrintEngine
- case PPK_FontEmbedding:
- d->embedFonts = value.toBool();
- break;
- case PPK_Resolution: {
- int bestResolution = 0;
- int dpi = value.toInt();
- int bestDistance = INT_MAX;
- foreach (int resolution, d->m_printDevice->supportedResolutions()) {
- if (dpi == resolution) {
- bestResolution = resolution;
- break;
- } else {
- int distance = qAbs(dpi - resolution);
- if (distance < bestDistance) {
- bestDistance = distance;
- bestResolution = resolution;
- }
- }
- }
- PMResolution resolution;
- resolution.hRes = resolution.vRes = bestResolution;
- if (PMPrinterSetOutputResolution(d->m_printDevice->macPrinter(), d->settings(), &resolution) == noErr) {
- // Setting the resolution succeeded.
- // Now try to read the actual resolution selected by the OS.
- if (PMPrinterGetOutputResolution(d->m_printDevice->macPrinter(), d->settings(), &d->resolution) != noErr) {
- // Reading the resolution somehow failed; d->resolution is in undefined state.
- // So use the value which was acceptable to PMPrinterSetOutputResolution.
- d->resolution = resolution;
- }
- }
- break;
- }
- case PPK_CollateCopies:
- PMSetCollate(d->settings(), value.toBool());
- break;
- case PPK_Creator:
- d->m_creator = value.toString();
- break;
- case PPK_DocumentName:
- PMPrintSettingsSetJobName(d->settings(), QCFString(value.toString()));
- break;
- case PPK_Duplex: {
- QPrint::DuplexMode mode = QPrint::DuplexMode(value.toInt());
- if (mode == property(PPK_Duplex).toInt() || !d->m_printDevice->supportedDuplexModes().contains(mode))
- break;
- switch (mode) {
- case QPrint::DuplexNone:
- PMSetDuplex(d->settings(), kPMDuplexNone);
- break;
- case QPrint::DuplexAuto:
- PMSetDuplex(d->settings(), d->m_pageLayout.orientation() == QPageLayout::Landscape ? kPMDuplexTumble : kPMDuplexNoTumble);
- break;
- case QPrint::DuplexLongSide:
- PMSetDuplex(d->settings(), kPMDuplexNoTumble);
- break;
- case QPrint::DuplexShortSide:
- PMSetDuplex(d->settings(), kPMDuplexTumble);
- break;
- default:
- // Don't change
- break;
- }
- break;
- }
- case PPK_FullPage:
- if (value.toBool())
- d->m_pageLayout.setMode(QPageLayout::FullPageMode);
- else
- d->m_pageLayout.setMode(QPageLayout::StandardMode);
- break;
- case PPK_CopyCount: // fallthrough
- case PPK_NumberOfCopies:
- PMSetCopies(d->settings(), value.toInt(), false);
- break;
- case PPK_Orientation: {
- // First try set the Mac format orientation, then set our orientation to match result
- QPageLayout::Orientation newOrientation = QPageLayout::Orientation(value.toInt());
- PMOrientation macOrientation = (newOrientation == QPageLayout::Landscape) ? kPMLandscape : kPMPortrait;
- PMSetOrientation(d->format(), macOrientation, kPMUnlocked);
- PMSessionValidatePageFormat(d->session(), d->format(), kPMDontWantBoolean);
- PMGetOrientation(d->format(), &macOrientation);
- d->m_pageLayout.setOrientation(macOrientation == kPMLandscape ? QPageLayout::Landscape : QPageLayout::Portrait);
- break;
- }
- case PPK_OutputFileName:
- d->outputFilename = value.toString();
- break;
- case PPK_PageSize:
- d->setPageSize(QPageSize(QPageSize::PageSizeId(value.toInt())));
- break;
- case PPK_PaperName:
- // Get the named page size from the printer if supported
- d->setPageSize(d->m_printDevice->supportedPageSize(value.toString()));
- break;
- case PPK_WindowsPageSize:
- d->setPageSize(QPageSize(QPageSize::id(value.toInt())));
- break;
- case PPK_PrinterName: {
- QVariant pageSize = QVariant::fromValue(d->m_pageLayout.pageSize());
- const bool isFullPage = d->m_pageLayout.mode() == QPageLayout::FullPageMode;
- QVariant orientation = QVariant::fromValue(d->m_pageLayout.orientation());
- QVariant margins = QVariant::fromValue(QPair<QMarginsF, QPageLayout::Unit>(d->m_pageLayout.margins(),
- d->m_pageLayout.units()));
- QString id = value.toString();
- if (id.isEmpty())
- id = QCocoaPrinterSupport().defaultPrintDeviceId();
- else if (!QCocoaPrinterSupport().availablePrintDeviceIds().contains(id))
- break;
- d->m_printDevice.reset(new QCocoaPrintDevice(id));
- PMPrinter printer = d->m_printDevice->macPrinter();
- PMRetain(printer);
- PMSessionSetCurrentPMPrinter(d->session(), printer);
- // Ensure the settings are up to date and valid
- if (d->m_printDevice->supportedPageSize(pageSize.value<QPageSize>()).isValid())
- setProperty(PPK_QPageSize, pageSize);
- else
- setProperty(PPK_CustomPaperSize, pageSize.value<QPageSize>().size(QPageSize::Point));
- setProperty(PPK_FullPage, QVariant(isFullPage));
- setProperty(PPK_Orientation, orientation);
- setProperty(PPK_QPageMargins, margins);
- break;
- }
- case PPK_CustomPaperSize:
- d->setPageSize(QPageSize(value.toSizeF(), QPageSize::Point));
- break;
- case PPK_PageMargins:
- {
- QList<QVariant> margins(value.toList());
- Q_ASSERT(margins.size() == 4);
- d->m_pageLayout.setMargins(QMarginsF(margins.at(0).toReal(), margins.at(1).toReal(),
- margins.at(2).toReal(), margins.at(3).toReal()));
- break;
- }
- case PPK_QPageSize:
- d->setPageSize(value.value<QPageSize>());
- break;
- case PPK_QPageMargins: {
- QPair<QMarginsF, QPageLayout::Unit> pair = value.value<QPair<QMarginsF, QPageLayout::Unit> >();
- d->m_pageLayout.setUnits(pair.second);
- d->m_pageLayout.setMargins(pair.first);
- break;
- }
- case PPK_QPageLayout: {
- QPageLayout pageLayout = value.value<QPageLayout>();
- if (pageLayout.isValid() && d->m_printDevice->isValidPageLayout(pageLayout, d->resolution.hRes)) {
- setProperty(PPK_QPageSize, QVariant::fromValue(pageLayout.pageSize()));
- setProperty(PPK_FullPage, pageLayout.mode() == QPageLayout::FullPageMode);
- setProperty(PPK_Orientation, QVariant::fromValue(pageLayout.orientation()));
- d->m_pageLayout.setUnits(pageLayout.units());
- d->m_pageLayout.setMargins(pageLayout.margins());
- }
- break;
- }
- // No default so that compiler will complain if new keys added and not handled in this engine
- }
-}
-
-QVariant QMacPrintEngine::property(PrintEnginePropertyKey key) const
-{
- Q_D(const QMacPrintEngine);
- QVariant ret;
-
- if (!d->printInfo && d->valueCache.contains(key))
- return *d->valueCache.find(key);
-
- switch (key) {
-
- // The following keys are settings that are unsupported by the Mac PrintEngine
- // Return sensible default values to ensure consistent behavior across platforms
- case PPK_ColorMode:
- ret = QPrinter::Color;
- break;
- case PPK_CustomBase:
- // Special case, leave null
- break;
- case PPK_PageOrder:
- // TODO Check if can be supported via Cups Options
- ret = QPrinter::FirstPageFirst;
- break;
- case PPK_PaperSource:
- // TODO Check if can be supported via Cups Options
- ret = QPrinter::Auto;
- break;
- case PPK_PaperSources: {
- // TODO Check if can be supported via Cups Options
- QList<QVariant> out;
- out << int(QPrinter::Auto);
- ret = out;
- break;
- }
- case PPK_PrinterProgram:
- ret = QString();
- break;
- case PPK_SelectionOption:
- ret = QString();
- break;
-
- // The following keys are properties and settings that are supported by the Mac PrintEngine
- case PPK_FontEmbedding:
- ret = d->embedFonts;
- break;
- case PPK_CollateCopies: {
- Boolean status;
- PMGetCollate(d->settings(), &status);
- ret = bool(status);
- break;
- }
- case PPK_Creator:
- ret = d->m_creator;
- break;
- case PPK_DocumentName: {
- CFStringRef name;
- PMPrintSettingsGetJobName(d->settings(), &name);
- ret = QString::fromCFString(name);
- break;
- }
- case PPK_Duplex: {
- PMDuplexMode mode = kPMDuplexNone;
- PMGetDuplex(d->settings(), &mode);
- switch (mode) {
- case kPMDuplexNoTumble:
- ret = QPrinter::DuplexLongSide;
- break;
- case kPMDuplexTumble:
- ret = QPrinter::DuplexShortSide;
- break;
- case kPMDuplexNone:
- default:
- ret = QPrinter::DuplexNone;
- break;
- }
- break;
- }
- case PPK_FullPage:
- ret = d->m_pageLayout.mode() == QPageLayout::FullPageMode;
- break;
- case PPK_NumberOfCopies:
- ret = 1;
- break;
- case PPK_CopyCount: {
- UInt32 copies = 1;
- PMGetCopies(d->settings(), &copies);
- ret = (uint) copies;
- break;
- }
- case PPK_SupportsMultipleCopies:
- ret = true;
- break;
- case PPK_Orientation:
- ret = d->m_pageLayout.orientation();
- break;
- case PPK_OutputFileName:
- ret = d->outputFilename;
- break;
- case PPK_PageRect:
- // PageRect is returned in device pixels
- ret = d->m_pageLayout.paintRectPixels(d->resolution.hRes);
- break;
- case PPK_PageSize:
- ret = d->m_pageLayout.pageSize().id();
- break;
- case PPK_PaperName:
- ret = d->m_pageLayout.pageSize().name();
- break;
- case PPK_WindowsPageSize:
- ret = d->m_pageLayout.pageSize().windowsId();
- break;
- case PPK_PaperRect:
- // PaperRect is returned in device pixels
- ret = d->m_pageLayout.fullRectPixels(d->resolution.hRes);
- break;
- case PPK_PrinterName:
- return d->m_printDevice->id();
- break;
- case PPK_Resolution: {
- ret = d->resolution.hRes;
- break;
- }
- case PPK_SupportedResolutions: {
- QList<QVariant> list;
- foreach (int resolution, d->m_printDevice->supportedResolutions())
- list << resolution;
- ret = list;
- break;
- }
- case PPK_CustomPaperSize:
- ret = d->m_pageLayout.fullRectPoints().size();
- break;
- case PPK_PageMargins: {
- QList<QVariant> list;
- QMarginsF margins = d->m_pageLayout.margins(QPageLayout::Point);
- list << margins.left() << margins.top() << margins.right() << margins.bottom();
- ret = list;
- break;
- }
- case PPK_QPageSize:
- ret.setValue(d->m_pageLayout.pageSize());
- break;
- case PPK_QPageMargins: {
- QPair<QMarginsF, QPageLayout::Unit> pair = qMakePair(d->m_pageLayout.margins(), d->m_pageLayout.units());
- ret.setValue(pair);
- break;
- }
- case PPK_QPageLayout:
- ret.setValue(d->m_pageLayout);
- // No default so that compiler will complain if new keys added and not handled in this engine
- }
- return ret;
-}
-
-QT_END_NAMESPACE
-
-#endif // QT_NO_PRINTER
diff --git a/src/plugins/platforms/cocoa/qprintengine_mac_p.h b/src/plugins/platforms/cocoa/qprintengine_mac_p.h
deleted file mode 100644
index 6a1ed2e263..0000000000
--- a/src/plugins/platforms/cocoa/qprintengine_mac_p.h
+++ /dev/null
@@ -1,157 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 QPRINTENGINE_MAC_P_H
-#define QPRINTENGINE_MAC_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/qglobal.h>
-
-#ifndef QT_NO_PRINTER
-
-#include <QtPrintSupport/qprinter.h>
-#include <QtPrintSupport/qprintengine.h>
-#include <QtGui/private/qpainter_p.h>
-#include <QtGui/qpagelayout.h>
-
-#include "qcocoaprintdevice.h"
-
-#include "qpaintengine_mac_p.h"
-
-Q_FORWARD_DECLARE_OBJC_CLASS(NSPrintInfo);
-
-QT_BEGIN_NAMESPACE
-
-class QPrinterPrivate;
-class QMacPrintEnginePrivate;
-class QMacPrintEngine : public QPaintEngine, public QPrintEngine
-{
- Q_DECLARE_PRIVATE(QMacPrintEngine)
-public:
- QMacPrintEngine(QPrinter::PrinterMode mode, const QString &deviceId);
-
- Qt::HANDLE handle() const;
-
- bool begin(QPaintDevice *dev);
- bool end();
- virtual QPaintEngine::Type type() const { return QPaintEngine::MacPrinter; }
-
- QPaintEngine *paintEngine() const;
-
- void setProperty(PrintEnginePropertyKey key, const QVariant &value);
- QVariant property(PrintEnginePropertyKey key) const;
-
- QPrinter::PrinterState printerState() const;
-
- bool newPage();
- bool abort();
- int metric(QPaintDevice::PaintDeviceMetric) const;
-
- //forwarded functions
-
- void updateState(const QPaintEngineState &state);
-
- virtual void drawLines(const QLineF *lines, int lineCount);
- virtual void drawRects(const QRectF *r, int num);
- virtual void drawPoints(const QPointF *p, int pointCount);
- virtual void drawEllipse(const QRectF &r);
- virtual void drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode);
- virtual void drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr);
- virtual void drawImage(const QRectF &r, const QImage &pm, const QRectF &sr, Qt::ImageConversionFlags flags);
- virtual void drawTextItem(const QPointF &p, const QTextItem &ti);
- virtual void drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPointF &s);
- virtual void drawPath(const QPainterPath &);
-
-private:
- friend class QCocoaNativeInterface;
-};
-
-class QMacPrintEnginePrivate : public QPaintEnginePrivate
-{
- Q_DECLARE_PUBLIC(QMacPrintEngine)
-public:
- QPrinter::PrinterMode mode;
- QPrinter::PrinterState state;
- QSharedPointer<QCocoaPrintDevice> m_printDevice;
- QPageLayout m_pageLayout;
- NSPrintInfo *printInfo;
- PMResolution resolution;
- QString outputFilename;
- QString m_creator;
- QPaintEngine *paintEngine;
- QHash<QMacPrintEngine::PrintEnginePropertyKey, QVariant> valueCache;
- uint embedFonts;
-
- QMacPrintEnginePrivate() : mode(QPrinter::ScreenResolution), state(QPrinter::Idle),
- m_pageLayout(QPageLayout(QPageSize(QPageSize::A4), QPageLayout::Portrait, QMarginsF(0, 0, 0, 0))),
- printInfo(nullptr), paintEngine(nullptr), embedFonts(true) {}
- ~QMacPrintEnginePrivate();
-
- void initialize();
- void releaseSession();
- bool newPage_helper();
- void setPageSize(const QPageSize &pageSize);
- inline bool isPrintSessionInitialized() const
- {
- return printInfo != 0;
- }
-
- PMPageFormat format() const { return static_cast<PMPageFormat>([printInfo PMPageFormat]); }
- PMPrintSession session() const { return static_cast<PMPrintSession>([printInfo PMPrintSession]); }
- PMPrintSettings settings() const { return static_cast<PMPrintSettings>([printInfo PMPrintSettings]); }
-
- QPaintEngine *aggregateEngine() override { return paintEngine; }
- Qt::HANDLE nativeHandle() override { return q_func()->handle(); }
-};
-
-QT_END_NAMESPACE
-
-#endif // QT_NO_PRINTER
-
-#endif // QPRINTENGINE_WIN_P_H
diff --git a/src/plugins/platforms/cocoa/qt_attribution.json b/src/plugins/platforms/cocoa/qt_attribution.json
index 37c0937f29..1da0d7e370 100644
--- a/src/plugins/platforms/cocoa/qt_attribution.json
+++ b/src/plugins/platforms/cocoa/qt_attribution.json
@@ -3,7 +3,7 @@
"Name": "Cocoa Platform Plugin",
"QDocModule": "qtgui",
"QtUsage": "Code used in the Qt Platform Abstraction (QPA) for macOS.",
- "Files": "qcocoaapplication.h qcocoaapplication.mm qcocoaapplicationdelegate.h qcocoaapplicationdelegate.mm qcocoaeventdispatcher.h qcocoaeventdispatcher.mm qcocoaintrospection.h qcocoaintrospection.mm qcocoasystemtrayicon.mm qmacdefines_mac.h",
+ "Files": "qcocoaapplication.h qcocoaapplication.mm qcocoaapplicationdelegate.h qcocoaapplicationdelegate.mm qcocoaeventdispatcher.h qcocoaeventdispatcher.mm qcocoaintrospection.h qcocoaintrospection.mm qcocoasystemtrayicon.mm",
"Description": "Allows Qt to integrate into Apple's Cocoa API.",
"LicenseId": "BSD-3-Clause",
diff --git a/src/plugins/platforms/cocoa/qt_mac_p.h b/src/plugins/platforms/cocoa/qt_mac_p.h
deleted file mode 100644
index fdcf3bcdd3..0000000000
--- a/src/plugins/platforms/cocoa/qt_mac_p.h
+++ /dev/null
@@ -1,127 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and 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 QT_MAC_P_H
-#define QT_MAC_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.
-//
-
-#ifdef __OBJC__
-#include <AppKit/AppKit.h>
-#include <objc/runtime.h>
-#endif
-
-#include "qmacdefines_mac.h"
-
-#include <CoreServices/CoreServices.h>
-
-#include "QtCore/qglobal.h"
-#include "QtCore/qvariant.h"
-#include "QtCore/qmimedata.h"
-#include "QtCore/qpointer.h"
-#include "QtCore/qloggingcategory.h"
-#include "private/qcore_mac_p.h"
-
-
-#include "QtGui/qpainter.h"
-
-QT_BEGIN_NAMESPACE
-class QWidget;
-class QDragMoveEvent;
-
-// Simple class to manage short-lived regions
-class QMacSmartQuickDrawRegion
-{
- RgnHandle qdRgn;
- Q_DISABLE_COPY(QMacSmartQuickDrawRegion)
-public:
- explicit QMacSmartQuickDrawRegion(RgnHandle rgn) : qdRgn(rgn) {}
- ~QMacSmartQuickDrawRegion() {
- extern void qt_mac_dispose_rgn(RgnHandle); // qregion_mac.cpp
- qt_mac_dispose_rgn(qdRgn);
- }
- operator RgnHandle() {
- return qdRgn;
- }
-};
-
-class QMacInternalPasteboardMime;
-class QMimeData;
-
-
-extern QPaintDevice *qt_mac_safe_pdev; //qapplication_mac.cpp
-
-extern OSWindowRef qt_mac_window_for(const QWidget*); //qwidget_mac.mm
-extern OSViewRef qt_mac_nativeview_for(const QWidget *); //qwidget_mac.mm
-extern QPoint qt_mac_nativeMapFromParent(const QWidget *child, const QPoint &pt); //qwidget_mac.mm
-
-#ifdef check
-# undef check
-#endif
-
-struct QMacDndAnswerRecord {
- QRect rect;
- Qt::KeyboardModifiers modifiers;
- Qt::MouseButtons buttons;
- Qt::DropAction lastAction;
- unsigned int lastOperation;
- void clear() {
- rect = QRect();
- modifiers = Qt::NoModifier;
- buttons = Qt::NoButton;
- lastAction = Qt::IgnoreAction;
- lastOperation = 0;
- }
-};
-extern QMacDndAnswerRecord qt_mac_dnd_answer_rec;
-void qt_mac_copy_answer_rect(const QDragMoveEvent &event);
-bool qt_mac_mouse_inside_answer_rect(QPoint mouse);
-
-QT_END_NAMESPACE
-
-#endif // QT_MAC_P_H
diff --git a/src/plugins/platforms/direct2d/CMakeLists.txt b/src/plugins/platforms/direct2d/CMakeLists.txt
new file mode 100644
index 0000000000..271104b71e
--- /dev/null
+++ b/src/plugins/platforms/direct2d/CMakeLists.txt
@@ -0,0 +1,228 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## QWindowsDirect2DIntegrationPlugin Plugin:
+#####################################################################
+
+qt_internal_add_plugin(QWindowsDirect2DIntegrationPlugin
+ OUTPUT_NAME qdirect2d
+ PLUGIN_TYPE platforms
+ SOURCES
+ ../windows/qtwindowsglobal.h
+ ../windows/qwin10helpers.cpp ../windows/qwin10helpers.h
+ ../windows/qwindowsapplication.cpp ../windows/qwindowsapplication.h
+ ../windows/qwindowscombase.h
+ ../windows/qwindowscontext.cpp ../windows/qwindowscontext.h
+ ../windows/qwindowscursor.cpp ../windows/qwindowscursor.h
+ ../windows/qwindowsdialoghelpers.cpp ../windows/qwindowsdialoghelpers.h
+ ../windows/qwindowsdropdataobject.cpp ../windows/qwindowsdropdataobject.h
+ ../windows/qwindowsiconengine.cpp ../windows/qwindowsiconengine.h
+ ../windows/qwindowsinputcontext.cpp ../windows/qwindowsinputcontext.h
+ ../windows/qwindowsintegration.cpp ../windows/qwindowsintegration.h
+ ../windows/qwindowsinternalmimedata.cpp ../windows/qwindowsinternalmimedata.h
+ ../windows/qwindowskeymapper.cpp ../windows/qwindowskeymapper.h
+ ../windows/qwindowsmenu.cpp ../windows/qwindowsmenu.h
+ ../windows/qwindowsmimeregistry.cpp ../windows/qwindowsmimeregistry.h
+ ../windows/qwindowsmousehandler.cpp ../windows/qwindowsmousehandler.h
+ ../windows/qwindowsnativeinterface.cpp ../windows/qwindowsnativeinterface.h
+ ../windows/qwindowsole.cpp ../windows/qwindowsole.h
+ ../windows/qwindowsopengltester.cpp ../windows/qwindowsopengltester.h
+ ../windows/qwindowspointerhandler.cpp ../windows/qwindowspointerhandler.h
+ ../windows/qwindowsscreen.cpp ../windows/qwindowsscreen.h
+ ../windows/qwindowsservices.cpp ../windows/qwindowsservices.h
+ ../windows/qwindowstheme.cpp ../windows/qwindowstheme.h
+ ../windows/qwindowsthreadpoolrunner.h
+ ../windows/qwindowswindow.cpp ../windows/qwindowswindow.h
+ qwindowsdirect2dbackingstore.cpp qwindowsdirect2dbackingstore.h
+ qwindowsdirect2dbitmap.cpp qwindowsdirect2dbitmap.h
+ qwindowsdirect2dcontext.cpp qwindowsdirect2dcontext.h
+ qwindowsdirect2ddevicecontext.cpp qwindowsdirect2ddevicecontext.h
+ qwindowsdirect2dhelpers.h
+ qwindowsdirect2dintegration.cpp qwindowsdirect2dintegration.h
+ qwindowsdirect2dnativeinterface.cpp qwindowsdirect2dnativeinterface.h
+ qwindowsdirect2dpaintdevice.cpp qwindowsdirect2dpaintdevice.h
+ qwindowsdirect2dpaintengine.cpp qwindowsdirect2dpaintengine.h
+ qwindowsdirect2dplatformpixmap.cpp qwindowsdirect2dplatformpixmap.h
+ qwindowsdirect2dplatformplugin.cpp
+ qwindowsdirect2dwindow.cpp qwindowsdirect2dwindow.h
+ NO_UNITY_BUILD_SOURCES
+ ../windows/qwindowspointerhandler.cpp
+ DEFINES
+ QT_NO_CAST_FROM_ASCII
+ QT_NO_FOREACH
+ INCLUDE_DIRECTORIES
+ ../windows
+ LIBRARIES
+ Qt::Core
+ Qt::CorePrivate
+ Qt::Gui
+ Qt::GuiPrivate
+ advapi32
+ d2d1
+ d3d11
+ dwmapi
+ dwrite
+ dxgi
+ dxguid
+ gdi32
+ imm32
+ ole32
+ oleaut32
+ setupapi
+ shell32
+ shlwapi
+ user32
+ version
+ winmm
+ winspool
+ wtsapi32
+ shcore
+ comdlg32
+ d3d9
+ runtimeobject
+)
+
+# Resources:
+set_source_files_properties("../windows/openglblacklists/default.json"
+ PROPERTIES QT_RESOURCE_ALIAS "default.json"
+)
+set(openglblacklists_resource_files
+ "../windows/openglblacklists/default.json"
+)
+
+qt_internal_add_resource(QWindowsDirect2DIntegrationPlugin "openglblacklists"
+ PREFIX
+ "/qt-project.org/windows/openglblacklists"
+ FILES
+ ${openglblacklists_resource_files}
+)
+
+## Scopes:
+#####################################################################
+
+qt_internal_extend_target(QWindowsDirect2DIntegrationPlugin CONDITION QT_FEATURE_opengl AND NOT QT_FEATURE_dynamicgl
+ LIBRARIES
+ opengl32
+)
+
+qt_internal_extend_target(QWindowsDirect2DIntegrationPlugin CONDITION MINGW
+ LIBRARIES
+ uuid
+ NO_PCH_SOURCES
+ ../windows/qwindowspointerhandler.cpp
+)
+
+qt_internal_extend_target(QWindowsDirect2DIntegrationPlugin CONDITION QT_FEATURE_opengl
+ SOURCES
+ ../windows/qwindowsglcontext.cpp ../windows/qwindowsglcontext.h
+ ../windows/qwindowsopenglcontext.h
+)
+
+qt_internal_extend_target(QWindowsDirect2DIntegrationPlugin CONDITION QT_FEATURE_systemtrayicon
+ SOURCES
+ ../windows/qwindowssystemtrayicon.cpp ../windows/qwindowssystemtrayicon.h
+)
+
+qt_internal_extend_target(QWindowsDirect2DIntegrationPlugin CONDITION QT_FEATURE_vulkan
+ SOURCES
+ ../windows/qwindowsvulkaninstance.cpp ../windows/qwindowsvulkaninstance.h
+)
+
+qt_internal_extend_target(QWindowsDirect2DIntegrationPlugin CONDITION QT_FEATURE_clipboard
+ SOURCES
+ ../windows/qwindowsclipboard.cpp ../windows/qwindowsclipboard.h
+)
+
+qt_internal_extend_target(QWindowsDirect2DIntegrationPlugin CONDITION QT_FEATURE_clipboard AND QT_FEATURE_draganddrop
+ SOURCES
+ ../windows/qwindowsdrag.cpp ../windows/qwindowsdrag.h
+)
+
+qt_internal_extend_target(QWindowsDirect2DIntegrationPlugin CONDITION QT_FEATURE_tabletevent
+ SOURCES
+ ../windows/qwindowstabletsupport.cpp ../windows/qwindowstabletsupport.h
+ INCLUDE_DIRECTORIES
+ ${QtBase_SOURCE_DIR}/src/3rdparty/wintab
+)
+
+qt_internal_extend_target(QWindowsDirect2DIntegrationPlugin CONDITION QT_FEATURE_sessionmanager
+ SOURCES
+ ../windows/qwindowssessionmanager.cpp ../windows/qwindowssessionmanager.h
+)
+
+if(QT_FEATURE_imageformat_png)
+ # Resources:
+ set(cursors_resource_files
+ "../windows/images/closedhandcursor_32.png"
+ "../windows/images/closedhandcursor_48.png"
+ "../windows/images/closedhandcursor_64.png"
+ "../windows/images/dragcopycursor_32.png"
+ "../windows/images/dragcopycursor_48.png"
+ "../windows/images/dragcopycursor_64.png"
+ "../windows/images/draglinkcursor_32.png"
+ "../windows/images/draglinkcursor_48.png"
+ "../windows/images/draglinkcursor_64.png"
+ "../windows/images/dragmovecursor_32.png"
+ "../windows/images/dragmovecursor_48.png"
+ "../windows/images/dragmovecursor_64.png"
+ "../windows/images/openhandcursor_32.png"
+ "../windows/images/openhandcursor_48.png"
+ "../windows/images/openhandcursor_64.png"
+ "../windows/images/splithcursor_32.png"
+ "../windows/images/splithcursor_48.png"
+ "../windows/images/splithcursor_64.png"
+ "../windows/images/splitvcursor_32.png"
+ "../windows/images/splitvcursor_48.png"
+ "../windows/images/splitvcursor_64.png"
+ )
+
+ qt_internal_add_resource(QWindowsDirect2DIntegrationPlugin "cursors"
+ PREFIX
+ "/qt-project.org/windows/cursors"
+ BASE
+ "../windows"
+ FILES
+ ${cursors_resource_files}
+ )
+endif()
+
+qt_internal_extend_target(QWindowsDirect2DIntegrationPlugin CONDITION QT_FEATURE_accessibility
+ SOURCES
+ ../windows/uiautomation/qwindowsuiautomation.cpp ../windows/uiautomation/qwindowsuiautomation.h
+ ../windows/uiautomation/qwindowsuiaaccessibility.cpp ../windows/uiautomation/qwindowsuiaaccessibility.h
+ ../windows/uiautomation/qwindowsuiabaseprovider.cpp ../windows/uiautomation/qwindowsuiabaseprovider.h
+ ../windows/uiautomation/qwindowsuiaexpandcollapseprovider.cpp ../windows/uiautomation/qwindowsuiaexpandcollapseprovider.h
+ ../windows/uiautomation/qwindowsuiagriditemprovider.cpp ../windows/uiautomation/qwindowsuiagriditemprovider.h
+ ../windows/uiautomation/qwindowsuiagridprovider.cpp ../windows/uiautomation/qwindowsuiagridprovider.h
+ ../windows/uiautomation/qwindowsuiainvokeprovider.cpp ../windows/uiautomation/qwindowsuiainvokeprovider.h
+ ../windows/uiautomation/qwindowsuiamainprovider.cpp ../windows/uiautomation/qwindowsuiamainprovider.h
+ ../windows/uiautomation/qwindowsuiaprovidercache.cpp ../windows/uiautomation/qwindowsuiaprovidercache.h
+ ../windows/uiautomation/qwindowsuiarangevalueprovider.cpp ../windows/uiautomation/qwindowsuiarangevalueprovider.h
+ ../windows/uiautomation/qwindowsuiaselectionitemprovider.cpp ../windows/uiautomation/qwindowsuiaselectionitemprovider.h
+ ../windows/uiautomation/qwindowsuiaselectionprovider.cpp ../windows/uiautomation/qwindowsuiaselectionprovider.h
+ ../windows/uiautomation/qwindowsuiatableitemprovider.cpp ../windows/uiautomation/qwindowsuiatableitemprovider.h
+ ../windows/uiautomation/qwindowsuiatableprovider.cpp ../windows/uiautomation/qwindowsuiatableprovider.h
+ ../windows/uiautomation/qwindowsuiatextprovider.cpp ../windows/uiautomation/qwindowsuiatextprovider.h
+ ../windows/uiautomation/qwindowsuiatextrangeprovider.cpp ../windows/uiautomation/qwindowsuiatextrangeprovider.h
+ ../windows/uiautomation/qwindowsuiatoggleprovider.cpp ../windows/uiautomation/qwindowsuiatoggleprovider.h
+ ../windows/uiautomation/qwindowsuiautils.cpp ../windows/uiautomation/qwindowsuiautils.h
+ ../windows/uiautomation/qwindowsuiavalueprovider.cpp ../windows/uiautomation/qwindowsuiavalueprovider.h
+ ../windows/uiautomation/qwindowsuiawindowprovider.cpp ../windows/uiautomation/qwindowsuiawindowprovider.h
+)
+
+if(QT_FEATURE_accessibility)
+ find_library(UI_AUTOMATION_LIBRARY uiautomationcore)
+ if(UI_AUTOMATION_LIBRARY)
+ qt_internal_extend_target(QWindowsDirect2DIntegrationPlugin
+ LIBRARIES
+ ${UI_AUTOMATION_LIBRARY}
+ )
+ endif()
+endif()
+
+qt_internal_extend_target(QWindowsDirect2DIntegrationPlugin CONDITION MINGW AND QT_FEATURE_accessibility
+ LIBRARIES
+ uuid
+)
+
diff --git a/src/plugins/platforms/direct2d/direct2d.pro b/src/plugins/platforms/direct2d/direct2d.pro
deleted file mode 100644
index 6e73bd14f9..0000000000
--- a/src/plugins/platforms/direct2d/direct2d.pro
+++ /dev/null
@@ -1,47 +0,0 @@
-TARGET = qdirect2d
-
-QT += \
- core-private gui-private \
- eventdispatcher_support-private \
- fontdatabase_support-private theme_support-private
-
-qtConfig(accessibility): QT += accessibility_support-private
-qtConfig(vulkan): QT += vulkan_support-private
-
-LIBS += -ldwmapi -lversion
-QMAKE_USE_PRIVATE += gdi32 dwrite_1 d2d1_1 d3d11_1 dxgi1_2
-
-include(../windows/windows.pri)
-
-SOURCES += \
- qwindowsdirect2dpaintengine.cpp \
- qwindowsdirect2dpaintdevice.cpp \
- qwindowsdirect2dplatformpixmap.cpp \
- qwindowsdirect2dcontext.cpp \
- qwindowsdirect2dbitmap.cpp \
- qwindowsdirect2dbackingstore.cpp \
- qwindowsdirect2dintegration.cpp \
- qwindowsdirect2dplatformplugin.cpp \
- qwindowsdirect2ddevicecontext.cpp \
- qwindowsdirect2dnativeinterface.cpp \
- qwindowsdirect2dwindow.cpp
-
-HEADERS += \
- qwindowsdirect2dpaintengine.h \
- qwindowsdirect2dpaintdevice.h \
- qwindowsdirect2dplatformpixmap.h \
- qwindowsdirect2dcontext.h \
- qwindowsdirect2dhelpers.h \
- qwindowsdirect2dbitmap.h \
- qwindowsdirect2dbackingstore.h \
- qwindowsdirect2dintegration.h \
- qwindowsdirect2ddevicecontext.h \
- qwindowsdirect2dnativeinterface.h \
- qwindowsdirect2dwindow.h
-
-OTHER_FILES += direct2d.json
-
-PLUGIN_TYPE = platforms
-PLUGIN_CLASS_NAME = QWindowsDirect2DIntegrationPlugin
-!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = -
-load(qt_plugin)
diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dbackingstore.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dbackingstore.cpp
index 9689d6a89b..7ababe6c65 100644
--- a/src/plugins/platforms/direct2d/qwindowsdirect2dbackingstore.cpp
+++ b/src/plugins/platforms/direct2d/qwindowsdirect2dbackingstore.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qwindowsdirect2dbackingstore.h"
#include "qwindowsdirect2dplatformpixmap.h"
@@ -58,7 +22,6 @@ QT_BEGIN_NAMESPACE
\class QWindowsDirect2DBackingStore
\brief Backing store for windows.
\internal
- \ingroup qt-lighthouse-win
*/
static inline QWindowsDirect2DPlatformPixmap *platformPixmap(QPixmap *p)
diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dbackingstore.h b/src/plugins/platforms/direct2d/qwindowsdirect2dbackingstore.h
index 6d4d47e3da..5ca4580c21 100644
--- a/src/plugins/platforms/direct2d/qwindowsdirect2dbackingstore.h
+++ b/src/plugins/platforms/direct2d/qwindowsdirect2dbackingstore.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QWINDOWSDIRECT2DBACKINGSTORE_H
#define QWINDOWSDIRECT2DBACKINGSTORE_H
diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dbitmap.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dbitmap.cpp
index 587bae3598..310053eedc 100644
--- a/src/plugins/platforms/direct2d/qwindowsdirect2dbitmap.cpp
+++ b/src/plugins/platforms/direct2d/qwindowsdirect2dbitmap.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qwindowsdirect2dbitmap.h"
#include "qwindowsdirect2dcontext.h"
@@ -65,8 +29,11 @@ public:
D2D1_BITMAP_PROPERTIES1 bitmapProperties() const
{
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED // see QTBUG-94043
FLOAT dpiX, dpiY;
QWindowsDirect2DContext::instance()->d2dFactory()->GetDesktopDpi(&dpiX, &dpiY);
+QT_WARNING_POP
return D2D1::BitmapProperties1(
D2D1_BITMAP_OPTIONS_TARGET,
diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dbitmap.h b/src/plugins/platforms/direct2d/qwindowsdirect2dbitmap.h
index 8fd683106d..206121f8bd 100644
--- a/src/plugins/platforms/direct2d/qwindowsdirect2dbitmap.h
+++ b/src/plugins/platforms/direct2d/qwindowsdirect2dbitmap.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QWINDOWSDIRECT2DBITMAP_H
#define QWINDOWSDIRECT2DBITMAP_H
diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dcontext.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dcontext.cpp
index a31477ded9..307ca2e550 100644
--- a/src/plugins/platforms/direct2d/qwindowsdirect2dcontext.cpp
+++ b/src/plugins/platforms/direct2d/qwindowsdirect2dcontext.cpp
@@ -1,42 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+#include <QtCore/qt_windows.h>
#include "qwindowsdirect2dcontext.h"
#include "qwindowsdirect2dhelpers.h"
#include "qwindowsdirect2dintegration.h"
diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dcontext.h b/src/plugins/platforms/direct2d/qwindowsdirect2dcontext.h
index 5bce056ad1..360582ff93 100644
--- a/src/plugins/platforms/direct2d/qwindowsdirect2dcontext.h
+++ b/src/plugins/platforms/direct2d/qwindowsdirect2dcontext.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QWINDOWSDIRECT2DCONTEXT_H
#define QWINDOWSDIRECT2DCONTEXT_H
diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2ddevicecontext.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2ddevicecontext.cpp
index d578a58982..2eb6e2c36d 100644
--- a/src/plugins/platforms/direct2d/qwindowsdirect2ddevicecontext.cpp
+++ b/src/plugins/platforms/direct2d/qwindowsdirect2ddevicecontext.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qwindowsdirect2dcontext.h"
#include "qwindowsdirect2dhelpers.h"
diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2ddevicecontext.h b/src/plugins/platforms/direct2d/qwindowsdirect2ddevicecontext.h
index a28c674671..9cc0691954 100644
--- a/src/plugins/platforms/direct2d/qwindowsdirect2ddevicecontext.h
+++ b/src/plugins/platforms/direct2d/qwindowsdirect2ddevicecontext.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QWINDOWSDIRECT2DDEVICECONTEXT_H
#define QWINDOWSDIRECT2DDEVICECONTEXT_H
diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dhelpers.h b/src/plugins/platforms/direct2d/qwindowsdirect2dhelpers.h
index 6d880e24cf..07924332cd 100644
--- a/src/plugins/platforms/direct2d/qwindowsdirect2dhelpers.h
+++ b/src/plugins/platforms/direct2d/qwindowsdirect2dhelpers.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QWINDOWSDIRECT2DHELPERS_H
#define QWINDOWSDIRECT2DHELPERS_H
diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dintegration.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dintegration.cpp
index e074f87eb4..a5fbb7ad5a 100644
--- a/src/plugins/platforms/direct2d/qwindowsdirect2dintegration.cpp
+++ b/src/plugins/platforms/direct2d/qwindowsdirect2dintegration.cpp
@@ -1,42 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+#include <QtCore/qt_windows.h>
#include "qwindowsdirect2dcontext.h"
#include "qwindowsdirect2dintegration.h"
#include "qwindowsdirect2dbackingstore.h"
diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dintegration.h b/src/plugins/platforms/direct2d/qwindowsdirect2dintegration.h
index 5ea36e04bc..342482c346 100644
--- a/src/plugins/platforms/direct2d/qwindowsdirect2dintegration.h
+++ b/src/plugins/platforms/direct2d/qwindowsdirect2dintegration.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QWINDOWSDIRECT2DINTEGRATION_H
#define QWINDOWSDIRECT2DINTEGRATION_H
diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dnativeinterface.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dnativeinterface.cpp
index 220302d041..0523f2cd5f 100644
--- a/src/plugins/platforms/direct2d/qwindowsdirect2dnativeinterface.cpp
+++ b/src/plugins/platforms/direct2d/qwindowsdirect2dnativeinterface.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qwindowsdirect2dnativeinterface.h"
diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dnativeinterface.h b/src/plugins/platforms/direct2d/qwindowsdirect2dnativeinterface.h
index fce6ff9969..a532ca2760 100644
--- a/src/plugins/platforms/direct2d/qwindowsdirect2dnativeinterface.h
+++ b/src/plugins/platforms/direct2d/qwindowsdirect2dnativeinterface.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QWINDOWSDIRECT2DNATIVEINTERFACE_H
#define QWINDOWSDIRECT2DNATIVEINTERFACE_H
diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintdevice.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintdevice.cpp
index 3c86168a74..2866c68de2 100644
--- a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintdevice.cpp
+++ b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintdevice.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qwindowsdirect2dpaintdevice.h"
#include "qwindowsdirect2dpaintengine.h"
@@ -103,6 +67,8 @@ int QWindowsDirect2DPaintDevice::metric(QPaintDevice::PaintDeviceMetric metric)
case QPaintDevice::PdmDpiX:
case QPaintDevice::PdmPhysicalDpiX:
{
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED // See QTBUG-94043
FLOAT x, y;
QWindowsDirect2DContext::instance()->d2dFactory()->GetDesktopDpi(&x, &y);
return qRound(x);
@@ -113,6 +79,7 @@ int QWindowsDirect2DPaintDevice::metric(QPaintDevice::PaintDeviceMetric metric)
FLOAT x, y;
QWindowsDirect2DContext::instance()->d2dFactory()->GetDesktopDpi(&x, &y);
return qRound(y);
+QT_WARNING_POP
}
case QPaintDevice::PdmDevicePixelRatio:
return 1;
diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintdevice.h b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintdevice.h
index 013d7a9b79..e22727f37f 100644
--- a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintdevice.h
+++ b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintdevice.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QWINDOWSDIRECT2DPAINTDEVICE_H
#define QWINDOWSDIRECT2DPAINTDEVICE_H
diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp
index 03be44e095..bc304f78be 100644
--- a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp
+++ b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qwindowsdirect2dpaintengine.h"
#include "qwindowsdirect2dplatformpixmap.h"
@@ -45,8 +9,7 @@
#include "qwindowsdirect2dbitmap.h"
#include "qwindowsdirect2ddevicecontext.h"
-#include <QtFontDatabaseSupport/private/qwindowsfontdatabase_p.h>
-#include <QtFontDatabaseSupport/private/qwindowsfontengine_p.h>
+#include <QtGui/private/qwindowsfontdatabase_p.h>
#include "qwindowsintegration.h"
#include <QtCore/qmath.h>
@@ -125,9 +88,9 @@ static inline D2D1_MATRIX_3X2_F transformFromLine(const QLineF &line, qreal penW
static void adjustLine(QPointF *p1, QPointF *p2);
static bool isLinePositivelySloped(const QPointF &p1, const QPointF &p2);
-static QVector<D2D1_GRADIENT_STOP> qGradientStopsToD2DStops(const QGradientStops &qstops)
+static QList<D2D1_GRADIENT_STOP> qGradientStopsToD2DStops(const QGradientStops &qstops)
{
- QVector<D2D1_GRADIENT_STOP> stops(qstops.count());
+ QList<D2D1_GRADIENT_STOP> stops(qstops.count());
for (int i = 0, count = stops.size(); i < count; ++i) {
stops[i].position = FLOAT(qstops.at(i).first);
stops[i].color = to_d2d_color_f(qstops.at(i).second);
@@ -547,7 +510,7 @@ public:
if (newPen.widthF() == 0)
props.transformType = D2D1_STROKE_TRANSFORM_TYPE_HAIRLINE;
- else if (qt_pen_is_cosmetic(newPen, q->state()->renderHints))
+ else if (newPen.isCosmetic())
props.transformType = D2D1_STROKE_TRANSFORM_TYPE_FIXED;
else
props.transformType = D2D1_STROKE_TRANSFORM_TYPE_NORMAL;
@@ -573,8 +536,8 @@ public:
HRESULT hr;
if (props.dashStyle == D2D1_DASH_STYLE_CUSTOM) {
- QVector<qreal> dashes = newPen.dashPattern();
- QVector<FLOAT> converted(dashes.size());
+ QList<qreal> dashes = newPen.dashPattern();
+ QList<FLOAT> converted(dashes.size());
qreal penWidth = pen.qpen.widthF();
qreal brushWidth = 0;
for (int i = 0; i < dashes.size(); i++) {
@@ -697,7 +660,7 @@ public:
linearGradientBrushProperties.startPoint = to_d2d_point_2f(qlinear->start());
linearGradientBrushProperties.endPoint = to_d2d_point_2f(qlinear->finalStop());
- const QVector<D2D1_GRADIENT_STOP> stops = qGradientStopsToD2DStops(qlinear->stops());
+ const QList<D2D1_GRADIENT_STOP> stops = qGradientStopsToD2DStops(qlinear->stops());
hr = dc()->CreateGradientStopCollection(stops.constData(),
UINT32(stops.size()),
@@ -737,7 +700,7 @@ public:
radialGradientBrushProperties.radiusX = FLOAT(qradial->radius());
radialGradientBrushProperties.radiusY = FLOAT(qradial->radius());
- const QVector<D2D1_GRADIENT_STOP> stops = qGradientStopsToD2DStops(qradial->stops());
+ const QList<D2D1_GRADIENT_STOP> stops = qGradientStopsToD2DStops(qradial->stops());
hr = dc()->CreateGradientStopCollection(stops.constData(), stops.size(), &gradientStopCollection);
if (FAILED(hr)) {
@@ -941,16 +904,10 @@ public:
{
Q_Q(QWindowsDirect2DPaintEngine);
-QT_WARNING_PUSH
-QT_WARNING_DISABLE_DEPRECATED
// Default path (no optimization)
if (!(path.shape() == QVectorPath::LinesHint || path.shape() == QVectorPath::PolygonHint)
|| !pen.dashBrush
-#if QT_DEPRECATED_SINCE(5, 14)
- || q->state()->renderHints.testFlag(QPainter::HighQualityAntialiasing)
-#endif
|| q->state()->renderHints.testFlag(QPainter::Antialiasing)) {
-QT_WARNING_POP
ComPtr<ID2D1Geometry> geometry = vectorPathToID2D1PathGeometry(path);
if (!geometry) {
qWarning("%s: Could not convert path to d2d geometry", __FUNCTION__);
@@ -1043,10 +1000,10 @@ QT_WARNING_POP
// Get substitute name
static const char keyC[] = "HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes";
const QString familyName = QString::fromWCharArray(lf.lfFaceName);
- const QString nameSubstitute = QSettings(QLatin1String(keyC), QSettings::NativeFormat).value(familyName, familyName).toString();
+ const QString nameSubstitute = QSettings(QLatin1StringView(keyC), QSettings::NativeFormat).value(familyName, familyName).toString();
if (nameSubstitute != familyName) {
const int nameSubstituteLength = qMin(nameSubstitute.length(), LF_FACESIZE - 1);
- memcpy(lf.lfFaceName, nameSubstitute.utf16(), size_t(nameSubstituteLength) * sizeof(wchar_t));
+ memcpy(lf.lfFaceName, nameSubstitute.data(), size_t(nameSubstituteLength) * sizeof(wchar_t));
lf.lfFaceName[nameSubstituteLength] = 0;
}
@@ -1694,7 +1651,7 @@ void QWindowsDirect2DPaintEngine::rasterFill(const QVectorPath &path, const QBru
p.setPen(state()->pen);
auto *extended = static_cast<QPaintEngineEx *>(engine);
- for (const QPainterClipInfo &info : qAsConst(state()->clipInfo)) {
+ for (const QPainterClipInfo &info : std::as_const(state()->clipInfo)) {
extended->state()->matrix = info.matrix;
extended->transformChanged();
diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.h b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.h
index f61e908bce..f2f54f2e01 100644
--- a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.h
+++ b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QWINDOWSDIRECT2DPAINTENGINE_H
#define QWINDOWSDIRECT2DPAINTENGINE_H
diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dplatformpixmap.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dplatformpixmap.cpp
index fb50e05b3f..54095ba920 100644
--- a/src/plugins/platforms/direct2d/qwindowsdirect2dplatformpixmap.cpp
+++ b/src/plugins/platforms/direct2d/qwindowsdirect2dplatformpixmap.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qwindowsdirect2dcontext.h"
#include "qwindowsdirect2dpaintdevice.h"
@@ -139,8 +103,6 @@ void QWindowsDirect2DPlatformPixmap::fromImage(const QImage &image,
int QWindowsDirect2DPlatformPixmap::metric(QPaintDevice::PaintDeviceMetric metric) const
{
Q_D(const QWindowsDirect2DPlatformPixmap);
-
- Q_GUI_EXPORT int qt_paint_device_metric(const QPaintDevice *device, QPaintDevice::PaintDeviceMetric metric);
return qt_paint_device_metric(d->device.data(), metric);
}
diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dplatformpixmap.h b/src/plugins/platforms/direct2d/qwindowsdirect2dplatformpixmap.h
index 6bd7852ae0..e571fece4e 100644
--- a/src/plugins/platforms/direct2d/qwindowsdirect2dplatformpixmap.h
+++ b/src/plugins/platforms/direct2d/qwindowsdirect2dplatformpixmap.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QWINDOWSDIRECT2DPLATFORMPIXMAP_H
#define QWINDOWSDIRECT2DPLATFORMPIXMAP_H
diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dplatformplugin.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dplatformplugin.cpp
index b2fb4ba551..9f0face1fc 100644
--- a/src/plugins/platforms/direct2d/qwindowsdirect2dplatformplugin.cpp
+++ b/src/plugins/platforms/direct2d/qwindowsdirect2dplatformplugin.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qwindowsdirect2dintegration.h"
@@ -44,17 +8,19 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
class QWindowsDirect2DIntegrationPlugin : public QPlatformIntegrationPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID QPlatformIntegrationFactoryInterface_iid FILE "direct2d.json")
public:
- QPlatformIntegration *create(const QString&, const QStringList&);
+ QPlatformIntegration *create(const QString&, const QStringList&) override;
};
QPlatformIntegration *QWindowsDirect2DIntegrationPlugin::create(const QString& system, const QStringList& paramList)
{
- if (system.compare(system, QLatin1String("direct2d"), Qt::CaseInsensitive) == 0)
+ if (system.compare(system, "direct2d"_L1, Qt::CaseInsensitive) == 0)
return QWindowsDirect2DIntegration::create(paramList);
return nullptr;
}
diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.cpp
index c417daaeae..669166b73d 100644
--- a/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.cpp
+++ b/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qwindowsdirect2dcontext.h"
#include "qwindowsdirect2dbitmap.h"
diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.h b/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.h
index 3ac532d938..bb7d406a33 100644
--- a/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.h
+++ b/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QWINDOWSDIRECT2DWINDOW_H
#define QWINDOWSDIRECT2DWINDOW_H
diff --git a/src/plugins/platforms/directfb/.prev_CMakeLists.txt b/src/plugins/platforms/directfb/.prev_CMakeLists.txt
deleted file mode 100644
index 33beaa3da4..0000000000
--- a/src/plugins/platforms/directfb/.prev_CMakeLists.txt
+++ /dev/null
@@ -1,61 +0,0 @@
-# Generated from directfb.pro.
-
-#####################################################################
-## QDirectFbIntegrationPlugin Plugin:
-#####################################################################
-
-qt_add_plugin(QDirectFbIntegrationPlugin
- OUTPUT_NAME qdirectfb
- TYPE platforms
- SOURCES
- main.cpp
- qdirectfbbackingstore.cpp qdirectfbbackingstore.h
- qdirectfbblitter.cpp qdirectfbblitter.h
- qdirectfbconvenience.cpp qdirectfbconvenience.h
- qdirectfbcursor.cpp qdirectfbcursor.h
- qdirectfbeglhooks.h
- qdirectfbinput.cpp qdirectfbinput.h
- qdirectfbintegration.cpp qdirectfbintegration.h
- qdirectfbscreen.cpp qdirectfbscreen.h
- qdirectfbwindow.cpp qdirectfbwindow.h
- PUBLIC_LIBRARIES
- PkgConfig::DirectFB
- Qt::Core
- Qt::CorePrivate
- Qt::EventDispatcherSupportPrivate
- Qt::FontDatabaseSupportPrivate
- Qt::Gui
- Qt::GuiPrivate
- Qt::ServiceSupportPrivate
-)
-
-#### Keys ignored in scope 1:.:.:directfb.pro:<TRUE>:
-# OTHER_FILES = "directfb.json"
-
-## Scopes:
-#####################################################################
-
-qt_extend_target(QDirectFbIntegrationPlugin CONDITION QT_CONFIG___contains___directfb_egl
- SOURCES
- qdirectfb_egl.cpp qdirectfb_egl.h
- DEFINES
- DIRECTFB_GL_EGL
- PUBLIC_LIBRARIES
- Qt::EglSupportPrivate
-)
-
-qt_extend_target(QDirectFbIntegrationPlugin CONDITION NOT DIRECTFB_PLATFORM_HOOKS_SOURCES_ISEMPTY
- DEFINES
- DIRECTFB_PLATFORM_HOOKS
-)
-
-#### Keys ignored in scope 3:.:.:directfb.pro:NOT DIRECTFB_PLATFORM_HOOKS_SOURCES_ISEMPTY:
-# QMAKE_LIBDIR = "$$DIRECTFB_PLATFORM_HOOKS_LIBDIR"
-
-qt_extend_target(QDirectFbIntegrationPlugin CONDITION DIRECTFB_PLATFORM_HOOKS_SOURCES_ISEMPTY
- SOURCES
- qdirectfbeglhooks_stub.cpp
-)
-
-#### Keys ignored in scope 5:.:.:directfb.pro:NOT TARGET___equals____ss_QT_DEFAULT_QPA_PLUGIN:
-# PLUGIN_EXTENDS = "-"
diff --git a/src/plugins/platforms/directfb/CMakeLists.txt b/src/plugins/platforms/directfb/CMakeLists.txt
index c723ca75f4..7222168a37 100644
--- a/src/plugins/platforms/directfb/CMakeLists.txt
+++ b/src/plugins/platforms/directfb/CMakeLists.txt
@@ -1,16 +1,16 @@
-# Generated from directfb.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
-# begin special case:
qt_find_package(DirectFB)
-# end special case:
+qt_find_package(EGL)
#####################################################################
## QDirectFbIntegrationPlugin Plugin:
#####################################################################
-qt_add_plugin(QDirectFbIntegrationPlugin
+qt_internal_add_plugin(QDirectFbIntegrationPlugin
OUTPUT_NAME qdirectfb
- TYPE platforms
+ PLUGIN_TYPE platforms
SOURCES
main.cpp
qdirectfbbackingstore.cpp qdirectfbbackingstore.h
@@ -22,44 +22,31 @@ qt_add_plugin(QDirectFbIntegrationPlugin
qdirectfbintegration.cpp qdirectfbintegration.h
qdirectfbscreen.cpp qdirectfbscreen.h
qdirectfbwindow.cpp qdirectfbwindow.h
- PUBLIC_LIBRARIES
+ LIBRARIES
PkgConfig::DirectFB
+ EGL::EGL
Qt::Core
Qt::CorePrivate
- Qt::EventDispatcherSupportPrivate
- Qt::FontDatabaseSupportPrivate
Qt::Gui
Qt::GuiPrivate
- Qt::ServiceSupportPrivate
)
-#### Keys ignored in scope 1:.:.:directfb.pro:<TRUE>:
-# OTHER_FILES = "directfb.json"
-
## Scopes:
#####################################################################
-qt_extend_target(QDirectFbIntegrationPlugin CONDITION QT_CONFIG___contains___directfb_egl
+qt_internal_extend_target(QDirectFbIntegrationPlugin CONDITION QT_CONFIG___contains___directfb_egl
SOURCES
qdirectfb_egl.cpp qdirectfb_egl.h
DEFINES
DIRECTFB_GL_EGL
- PUBLIC_LIBRARIES
- Qt::EglSupportPrivate
)
-qt_extend_target(QDirectFbIntegrationPlugin CONDITION NOT DIRECTFB_PLATFORM_HOOKS_SOURCES_ISEMPTY
+qt_internal_extend_target(QDirectFbIntegrationPlugin CONDITION NOT DIRECTFB_PLATFORM_HOOKS_SOURCES_ISEMPTY
DEFINES
DIRECTFB_PLATFORM_HOOKS
)
-#### Keys ignored in scope 3:.:.:directfb.pro:NOT DIRECTFB_PLATFORM_HOOKS_SOURCES_ISEMPTY:
-# QMAKE_LIBDIR = "$$DIRECTFB_PLATFORM_HOOKS_LIBDIR"
-
-qt_extend_target(QDirectFbIntegrationPlugin CONDITION DIRECTFB_PLATFORM_HOOKS_SOURCES_ISEMPTY
+qt_internal_extend_target(QDirectFbIntegrationPlugin CONDITION DIRECTFB_PLATFORM_HOOKS_SOURCES_ISEMPTY
SOURCES
qdirectfbeglhooks_stub.cpp
)
-
-#### Keys ignored in scope 5:.:.:directfb.pro:NOT TARGET___equals____ss_QT_DEFAULT_QPA_PLUGIN:
-# PLUGIN_EXTENDS = "-"
diff --git a/src/plugins/platforms/directfb/directfb.pro b/src/plugins/platforms/directfb/directfb.pro
deleted file mode 100644
index e500d8c419..0000000000
--- a/src/plugins/platforms/directfb/directfb.pro
+++ /dev/null
@@ -1,53 +0,0 @@
-TARGET = qdirectfb
-
-QT += \
- core-private gui-private \
- eventdispatcher_support-private service_support-private \
- fontdatabase_support-private
-
-QMAKE_USE += directfb
-
-SOURCES = main.cpp \
- qdirectfbintegration.cpp \
- qdirectfbbackingstore.cpp \
- qdirectfbblitter.cpp \
- qdirectfbconvenience.cpp \
- qdirectfbinput.cpp \
- qdirectfbcursor.cpp \
- qdirectfbwindow.cpp \
- qdirectfbscreen.cpp
-HEADERS = qdirectfbintegration.h \
- qdirectfbbackingstore.h \
- qdirectfbblitter.h \
- qdirectfbconvenience.h \
- qdirectfbinput.h \
- qdirectfbcursor.h \
- qdirectfbwindow.h \
- qdirectfbscreen.h \
- qdirectfbeglhooks.h
-
-# ### port the GL context
-contains(QT_CONFIG, directfb_egl) {
- QT += egl_support-private
- HEADERS += qdirectfb_egl.h
- SOURCES += qdirectfb_egl.cpp
- DEFINES += DIRECTFB_GL_EGL
-}
-
-!isEmpty(DIRECTFB_PLATFORM_HOOKS_SOURCES) {
- HEADERS += $$DIRECTFB_PLATFORM_HOOKS_HEADERS
- SOURCES += $$DIRECTFB_PLATFORM_HOOKS_SOURCES
- DEFINES += DIRECTFB_PLATFORM_HOOKS
- LIBS += $$DIRECTFB_PLATFORM_HOOKS_LIBS
- QMAKE_LIBDIR += $$DIRECTFB_PLATFORM_HOOKS_LIBDIR
- INCLUDEPATH += $$DIRECTFB_PLATFORM_HOOKS_INCLUDEPATH
-} else {
- SOURCES += qdirectfbeglhooks_stub.cpp
-}
-
-OTHER_FILES += directfb.json
-
-PLUGIN_TYPE = platforms
-PLUGIN_CLASS_NAME = QDirectFbIntegrationPlugin
-!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = -
-load(qt_plugin)
diff --git a/src/plugins/platforms/directfb/main.cpp b/src/plugins/platforms/directfb/main.cpp
index de84827777..4618696154 100644
--- a/src/plugins/platforms/directfb/main.cpp
+++ b/src/plugins/platforms/directfb/main.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <qpa/qplatformintegrationplugin.h>
#include "qdirectfbintegration.h"
@@ -43,6 +7,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
#ifdef DIRECTFB_GL_EGL
#define QT_EGL_BACKEND_STRING(list) list << "directfbegl";
#define QT_EGL_BACKEND_CREATE(list, out) \
@@ -58,15 +24,15 @@ class QDirectFbIntegrationPlugin : public QPlatformIntegrationPlugin
Q_OBJECT
Q_PLUGIN_METADATA(IID QPlatformIntegrationFactoryInterface_iid FILE "directfb.json")
public:
- QPlatformIntegration *create(const QString&, const QStringList&);
+ QPlatformIntegration *create(const QString&, const QStringList&) override;
};
QPlatformIntegration * QDirectFbIntegrationPlugin::create(const QString& system, const QStringList& paramList)
{
Q_UNUSED(paramList);
- QDirectFbIntegration *integration = 0;
+ QDirectFbIntegration *integration = nullptr;
- if (!system.compare(QLatin1String("directfb"), Qt::CaseInsensitive))
+ if (!system.compare("directfb"_L1, Qt::CaseInsensitive))
integration = new QDirectFbIntegration;
QT_EGL_BACKEND_CREATE(system, integration)
diff --git a/src/plugins/platforms/directfb/qdirectfb_egl.cpp b/src/plugins/platforms/directfb/qdirectfb_egl.cpp
index d3c95f0b65..28cf8b610a 100644
--- a/src/plugins/platforms/directfb/qdirectfb_egl.cpp
+++ b/src/plugins/platforms/directfb/qdirectfb_egl.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qdirectfb_egl.h"
#include "qdirectfbwindow.h"
@@ -47,10 +11,10 @@
#include <qpa/qwindowsysteminterface.h>
#include <QtGui/QScreen>
-#include <QtEglSupport/private/qeglplatformcontext_p.h>
-#include <QtEglSupport/private/qeglconvenience_p.h>
+#include <QtGui/private/qeglplatformcontext_p.h>
+#include <QtGui/private/qeglconvenience_p.h>
-#include <QtEglSupport/private/qt_egl_p.h>
+#include <QtGui/private/qt_egl_p.h>
QT_BEGIN_NAMESPACE
@@ -58,7 +22,7 @@ QT_BEGIN_NAMESPACE
extern QDirectFBEGLHooks platform_hook;
static QDirectFBEGLHooks *hooks = &platform_hook;
#else
-static QDirectFBEGLHooks *hooks = 0;
+static QDirectFBEGLHooks *hooks = nullptr;
#endif
/**
diff --git a/src/plugins/platforms/directfb/qdirectfb_egl.h b/src/plugins/platforms/directfb/qdirectfb_egl.h
index 2a8c1268bb..7dfdb4997e 100644
--- a/src/plugins/platforms/directfb/qdirectfb_egl.h
+++ b/src/plugins/platforms/directfb/qdirectfb_egl.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QDIRECTFB_EGL_H
#define QDIRECTFB_EGL_H
diff --git a/src/plugins/platforms/directfb/qdirectfbbackingstore.cpp b/src/plugins/platforms/directfb/qdirectfbbackingstore.cpp
index 8d5e1e50c4..05b7cb09f1 100644
--- a/src/plugins/platforms/directfb/qdirectfbbackingstore.cpp
+++ b/src/plugins/platforms/directfb/qdirectfbbackingstore.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qdirectfbbackingstore.h"
#include "qdirectfbintegration.h"
diff --git a/src/plugins/platforms/directfb/qdirectfbbackingstore.h b/src/plugins/platforms/directfb/qdirectfbbackingstore.h
index af1ce92e64..625b672a40 100644
--- a/src/plugins/platforms/directfb/qdirectfbbackingstore.h
+++ b/src/plugins/platforms/directfb/qdirectfbbackingstore.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QWINDOWSURFACE_DIRECTFB_H
#define QWINDOWSURFACE_DIRECTFB_H
@@ -54,10 +18,10 @@ class QDirectFbBackingStore : public QPlatformBackingStore
public:
QDirectFbBackingStore(QWindow *window);
- QPaintDevice *paintDevice();
- void flush(QWindow *window, const QRegion &region, const QPoint &offset);
- void resize (const QSize &size, const QRegion &staticContents);
- bool scroll(const QRegion &area, int dx, int dy);
+ QPaintDevice *paintDevice() override;
+ void flush(QWindow *window, const QRegion &region, const QPoint &offset) override;
+ void resize (const QSize &size, const QRegion &staticContents) override;
+ bool scroll(const QRegion &area, int dx, int dy) override;
QImage toImage() const override;
diff --git a/src/plugins/platforms/directfb/qdirectfbblitter.cpp b/src/plugins/platforms/directfb/qdirectfbblitter.cpp
index 3e21a1925d..c93e48ead7 100644
--- a/src/plugins/platforms/directfb/qdirectfbblitter.cpp
+++ b/src/plugins/platforms/directfb/qdirectfbblitter.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qdirectfbblitter.h"
#include "qdirectfbconvenience.h"
@@ -252,7 +216,7 @@ bool QDirectFbBlitter::drawCachedGlyphs(const QPaintEngineState *state, QFontEng
for (int i=0; i<numGlyphs; ++i) {
QFixed subPixelPosition = fontEngine->subPixelPositionForX(positions[i].x);
- QTextureGlyphCache::GlyphAndSubPixelPosition glyph(glyphs[i], subPixelPosition);
+ QTextureGlyphCache::GlyphAndSubPixelPosition glyph(glyphs[i], QFixedPoint(subPixelPosition, 0));
const QTextureGlyphCache::Coord &c = cache->coords[glyph];
if (c.isNull())
continue;
@@ -403,7 +367,7 @@ bool QDirectFbBlitterPlatformPixmap::fromFile(const QString &filename, const cha
return QBlittablePlatformPixmap::fromFile(filename, format, flags);
// Deal with resources
- if (filename.startsWith(QLatin1Char(':')))
+ if (filename.startsWith(u':'))
return QBlittablePlatformPixmap::fromFile(filename, format, flags);
// Try to use directfb to load it.
@@ -460,7 +424,7 @@ void QDirectFbBlitter::drawDebugRect(const QRect &rect, const QColor &color)
void QDirectFbTextureGlyphCache::resizeTextureData(int width, int height)
{
- m_surface.reset();;
+ m_surface.reset();
QImageTextureGlyphCache::resizeTextureData(width, height);
}
diff --git a/src/plugins/platforms/directfb/qdirectfbblitter.h b/src/plugins/platforms/directfb/qdirectfbblitter.h
index f8ee92d509..6183859613 100644
--- a/src/plugins/platforms/directfb/qdirectfbblitter.h
+++ b/src/plugins/platforms/directfb/qdirectfbblitter.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QDIRECTFBBLITTER_H
#define QDIRECTFBBLITTER_H
@@ -55,11 +19,20 @@ public:
QDirectFbBlitter(const QSize &size, bool alpha);
virtual ~QDirectFbBlitter();
- virtual void fillRect(const QRectF &rect, const QColor &color);
- virtual void drawPixmap(const QRectF &rect, const QPixmap &pixmap, const QRectF &subrect);
- void alphaFillRect(const QRectF &rect, const QColor &color, QPainter::CompositionMode cmode);
- void drawPixmapOpacity(const QRectF &rect, const QPixmap &pixmap, const QRectF &subrect, QPainter::CompositionMode cmode, qreal opacity);
- virtual bool drawCachedGlyphs(const QPaintEngineState *state, QFontEngine::GlyphFormat glyphFormat, int numGlyphs, const glyph_t *glyphs, const QFixedPoint *positions, QFontEngine *fontEngine);
+ void fillRect(const QRectF &rect, const QColor &color) override;
+ void drawPixmap(const QRectF &rect, const QPixmap &pixmap, const QRectF &subrect) override;
+ void alphaFillRect(const QRectF &rect, const QColor &color, QPainter::CompositionMode cmode) override;
+ void drawPixmapOpacity(const QRectF &rect,
+ const QPixmap &pixmap,
+ const QRectF &subrect,
+ QPainter::CompositionMode cmode,
+ qreal opacity) override;
+ bool drawCachedGlyphs(const QPaintEngineState *state,
+ QFontEngine::GlyphFormat glyphFormat,
+ int numGlyphs,
+ const glyph_t *glyphs,
+ const QFixedPoint *positions,
+ QFontEngine *fontEngine) override;
IDirectFBSurface *dfbSurface() const;
@@ -68,8 +41,8 @@ public:
static DFBSurfacePixelFormat selectPixmapFormat(bool withAlpha);
protected:
- virtual QImage *doLock();
- virtual void doUnlock();
+ QImage *doLock() override;
+ void doUnlock() override;
QDirectFBPointer<IDirectFBSurface> m_surface;
QImage m_image;
@@ -86,12 +59,12 @@ private:
class QDirectFbBlitterPlatformPixmap : public QBlittablePlatformPixmap
{
public:
- QBlittable *createBlittable(const QSize &size, bool alpha) const;
+ QBlittable *createBlittable(const QSize &size, bool alpha) const override;
QDirectFbBlitter *dfbBlitter() const;
- virtual bool fromFile(const QString &filename, const char *format,
- Qt::ImageConversionFlags flags);
+ bool fromFile(const QString &filename, const char *format,
+ Qt::ImageConversionFlags flags) override;
private:
bool fromDataBufferDescription(const DFBDataBufferDescription &);
@@ -119,7 +92,7 @@ public:
: QImageTextureGlyphCache(format, matrix)
{}
- virtual void resizeTextureData(int width, int height);
+ void resizeTextureData(int width, int height) override;
IDirectFBSurface *sourceSurface();
diff --git a/src/plugins/platforms/directfb/qdirectfbconvenience.cpp b/src/plugins/platforms/directfb/qdirectfbconvenience.cpp
index f3e8282101..49ddad8c89 100644
--- a/src/plugins/platforms/directfb/qdirectfbconvenience.cpp
+++ b/src/plugins/platforms/directfb/qdirectfbconvenience.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qdirectfbconvenience.h"
#include "qdirectfbblitter.h"
@@ -50,7 +14,7 @@ QT_BEGIN_NAMESPACE
IDirectFB *QDirectFbConvenience::dfbInterface()
{
- static IDirectFB *dfb = 0;
+ static IDirectFB *dfb = nullptr;
if (!dfb) {
DFBResult result = DirectFBCreate(&dfb);
if (result != DFB_OK) {
@@ -136,7 +100,7 @@ Qt::MouseButton QDirectFbConvenience::mouseButton(DFBInputDeviceButtonIdentifier
case DIBI_RIGHT: // value is 0x01
return Qt::RightButton;
case DIBI_MIDDLE: // value is 0x02
- return Qt::MidButton;
+ return Qt::MiddleButton;
case 0x03:
return Qt::BackButton;
case 0x04:
@@ -198,7 +162,7 @@ Qt::MouseButtons QDirectFbConvenience::mouseButtons(DFBInputDeviceButtonMask mas
buttons |= Qt::LeftButton;
}
if (mask & DIBM_MIDDLE) {
- buttons |= Qt::MidButton;
+ buttons |= Qt::MiddleButton;
}
if (mask & DIBM_RIGHT) {
buttons |= Qt::RightButton;
@@ -247,7 +211,7 @@ QEvent::Type QDirectFbConvenience::eventType(DFBWindowEventType type)
return QEvent::None;
}
}
-QDirectFbKeyMap *QDirectFbConvenience::dfbKeymap = 0;
+QDirectFbKeyMap *QDirectFbConvenience::dfbKeymap = nullptr;
QDirectFbKeyMap *QDirectFbConvenience::keyMap()
{
if (!dfbKeymap)
diff --git a/src/plugins/platforms/directfb/qdirectfbconvenience.h b/src/plugins/platforms/directfb/qdirectfbconvenience.h
index 19fc068307..dc657f384e 100644
--- a/src/plugins/platforms/directfb/qdirectfbconvenience.h
+++ b/src/plugins/platforms/directfb/qdirectfbconvenience.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QDIRECTFBCONVENIENCE_H
#define QDIRECTFBCONVENIENCE_H
@@ -98,13 +62,13 @@ template <typename T>
class QDirectFBPointer : public QScopedPointer<T, QDirectFBInterfaceCleanupHandler<T> >
{
public:
- QDirectFBPointer(T *t = 0)
+ Q_NODISCARD_CTOR QDirectFBPointer(T *t = nullptr)
: QScopedPointer<T, QDirectFBInterfaceCleanupHandler<T> >(t)
{}
T** outPtr()
{
- this->reset(0);
+ this->reset(nullptr);
return &this->d;
}
};
diff --git a/src/plugins/platforms/directfb/qdirectfbcursor.cpp b/src/plugins/platforms/directfb/qdirectfbcursor.cpp
index 7aa9db8066..1e03669498 100644
--- a/src/plugins/platforms/directfb/qdirectfbcursor.cpp
+++ b/src/plugins/platforms/directfb/qdirectfbcursor.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qdirectfbcursor.h"
#include "qdirectfbconvenience.h"
diff --git a/src/plugins/platforms/directfb/qdirectfbcursor.h b/src/plugins/platforms/directfb/qdirectfbcursor.h
index fdb8cd28f5..21a8f4353d 100644
--- a/src/plugins/platforms/directfb/qdirectfbcursor.h
+++ b/src/plugins/platforms/directfb/qdirectfbcursor.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QDIRECTFBCURSOR_H
#define QDIRECTFBCURSOR_H
@@ -55,7 +19,7 @@ class QDirectFBCursor : public QPlatformCursor
public:
QDirectFBCursor(QPlatformScreen *screen);
#ifndef QT_NO_CURSOR
- void changeCursor(QCursor *cursor, QWindow *window);
+ void changeCursor(QCursor *cursor, QWindow *window) override;
#endif
private:
diff --git a/src/plugins/platforms/directfb/qdirectfbeglhooks.h b/src/plugins/platforms/directfb/qdirectfbeglhooks.h
index 7f549e841c..dc3db5fbb5 100644
--- a/src/plugins/platforms/directfb/qdirectfbeglhooks.h
+++ b/src/plugins/platforms/directfb/qdirectfbeglhooks.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QDIRECTFBEGL_HOOKS_H
#define QDIRECTFBEGL_HOOKS_H
diff --git a/src/plugins/platforms/directfb/qdirectfbeglhooks_stub.cpp b/src/plugins/platforms/directfb/qdirectfbeglhooks_stub.cpp
index 890332c268..174ae89d32 100644
--- a/src/plugins/platforms/directfb/qdirectfbeglhooks_stub.cpp
+++ b/src/plugins/platforms/directfb/qdirectfbeglhooks_stub.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qdirectfbeglhooks.h"
diff --git a/src/plugins/platforms/directfb/qdirectfbglcontext.cpp b/src/plugins/platforms/directfb/qdirectfbglcontext.cpp
index 8018433fb6..374df11921 100644
--- a/src/plugins/platforms/directfb/qdirectfbglcontext.cpp
+++ b/src/plugins/platforms/directfb/qdirectfbglcontext.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qdirectfbglcontext.h"
diff --git a/src/plugins/platforms/directfb/qdirectfbglcontext.h b/src/plugins/platforms/directfb/qdirectfbglcontext.h
index f3a706ec94..424b45b034 100644
--- a/src/plugins/platforms/directfb/qdirectfbglcontext.h
+++ b/src/plugins/platforms/directfb/qdirectfbglcontext.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QDIRECTFBGLCONTEXT_H
#define QDIRECTFBGLCONTEXT_H
diff --git a/src/plugins/platforms/directfb/qdirectfbinput.cpp b/src/plugins/platforms/directfb/qdirectfbinput.cpp
index 025edb28b5..c5aacad6cc 100644
--- a/src/plugins/platforms/directfb/qdirectfbinput.cpp
+++ b/src/plugins/platforms/directfb/qdirectfbinput.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qdirectfbinput.h"
#include "qdirectfbconvenience.h"
@@ -162,7 +126,7 @@ void QDirectFbInput::handleMouseEvents(const DFBEvent &event)
long timestamp = (event.window.timestamp.tv_sec*1000) + (event.window.timestamp.tv_usec/1000);
QWindow *tlw = m_tlwMap.value(event.window.window_id);
- QWindowSystemInterface::handleMouseEvent(tlw, timestamp, p, globalPos, buttons);
+ QWindowSystemInterface::handleMouseEvent(tlw, timestamp, p, globalPos, buttons, Qt::NoButton, QEvent::None);
}
void QDirectFbInput::handleWheelEvent(const DFBEvent &event)
@@ -171,9 +135,12 @@ void QDirectFbInput::handleWheelEvent(const DFBEvent &event)
QPoint globalPos(event.window.cx, event.window.cy);
long timestamp = (event.window.timestamp.tv_sec*1000) + (event.window.timestamp.tv_usec/1000);
QWindow *tlw = m_tlwMap.value(event.window.window_id);
- QWindowSystemInterface::handleWheelEvent(tlw, timestamp, p, globalPos,
- event.window.step*120,
- Qt::Vertical);
+ QWindowSystemInterface::handleWheelEvent(tlw,
+ timestamp,
+ p,
+ globalPos,
+ QPoint(),
+ QPoint(0, event.window.step*120));
}
void QDirectFbInput::handleKeyEvents(const DFBEvent &event)
@@ -209,7 +176,7 @@ void QDirectFbInput::handleEnterLeaveEvents(const DFBEvent &event)
void QDirectFbInput::handleGotFocusEvent(const DFBEvent &event)
{
QWindow *tlw = m_tlwMap.value(event.window.window_id);
- QWindowSystemInterface::handleWindowActivated(tlw);
+ QWindowSystemInterface::handleFocusWindowChanged(tlw, Qt::ActiveWindowFocusReason);
}
void QDirectFbInput::handleCloseEvent(const DFBEvent &event)
diff --git a/src/plugins/platforms/directfb/qdirectfbinput.h b/src/plugins/platforms/directfb/qdirectfbinput.h
index 679eaa18a0..02175abc7b 100644
--- a/src/plugins/platforms/directfb/qdirectfbinput.h
+++ b/src/plugins/platforms/directfb/qdirectfbinput.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QDIRECTFBINPUT_H
#define QDIRECTFBINPUT_H
@@ -62,7 +26,7 @@ public:
void stopInputEventLoop();
protected:
- void run();
+ void run() override;
private:
void handleEvents();
diff --git a/src/plugins/platforms/directfb/qdirectfbintegration.cpp b/src/plugins/platforms/directfb/qdirectfbintegration.cpp
index 73e308da53..c52213b161 100644
--- a/src/plugins/platforms/directfb/qdirectfbintegration.cpp
+++ b/src/plugins/platforms/directfb/qdirectfbintegration.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qdirectfbintegration.h"
#include "qdirectfbbackingstore.h"
@@ -44,9 +8,9 @@
#include "qdirectfbcursor.h"
#include "qdirectfbwindow.h"
-#include <QtFontDatabaseSupport/private/qgenericunixfontdatabase_p.h>
-#include <QtEventDispatcherSupport/private/qgenericunixeventdispatcher_p.h>
-#include <QtServiceSupport/private/qgenericunixservices_p.h>
+#include <QtGui/private/qgenericunixfontdatabase_p.h>
+#include <QtGui/private/qgenericunixeventdispatcher_p.h>
+#include <QtGui/private/qgenericunixservices_p.h>
#include <QtGui/private/qpixmap_blitter_p.h>
#include <QtGui/private/qpixmap_raster_p.h>
diff --git a/src/plugins/platforms/directfb/qdirectfbintegration.h b/src/plugins/platforms/directfb/qdirectfbintegration.h
index e6704c91cc..8dd2a4516a 100644
--- a/src/plugins/platforms/directfb/qdirectfbintegration.h
+++ b/src/plugins/platforms/directfb/qdirectfbintegration.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QPLATFORMINTEGRATION_DIRECTFB_H
#define QPLATFORMINTEGRATION_DIRECTFB_H
@@ -61,16 +25,16 @@ public:
void connectToDirectFb();
- bool hasCapability(Capability cap) const;
- QPlatformPixmap *createPlatformPixmap(QPlatformPixmap::PixelType type) const;
- QPlatformWindow *createPlatformWindow(QWindow *window) const;
- QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const;
- QAbstractEventDispatcher *createEventDispatcher() const;
+ bool hasCapability(Capability cap) const override;
+ QPlatformPixmap *createPlatformPixmap(QPlatformPixmap::PixelType type) const override;
+ QPlatformWindow *createPlatformWindow(QWindow *window) const override;
+ QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const override;
+ QAbstractEventDispatcher *createEventDispatcher() const override;
- QPlatformFontDatabase *fontDatabase() const;
- QPlatformServices *services() const;
- QPlatformInputContext *inputContext() const { return m_inputContext; }
- QPlatformNativeInterface *nativeInterface() const;
+ QPlatformFontDatabase *fontDatabase() const override;
+ QPlatformServices *services() const override;
+ QPlatformInputContext *inputContext() const override { return m_inputContext; }
+ QPlatformNativeInterface *nativeInterface() const override;
protected:
virtual void initializeDirectFB();
diff --git a/src/plugins/platforms/directfb/qdirectfbscreen.cpp b/src/plugins/platforms/directfb/qdirectfbscreen.cpp
index c2b5f50989..b98c7b5aec 100644
--- a/src/plugins/platforms/directfb/qdirectfbscreen.cpp
+++ b/src/plugins/platforms/directfb/qdirectfbscreen.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qdirectfbscreen.h"
#include "qdirectfbcursor.h"
diff --git a/src/plugins/platforms/directfb/qdirectfbscreen.h b/src/plugins/platforms/directfb/qdirectfbscreen.h
index c24b8b02a3..cbcb6a55da 100644
--- a/src/plugins/platforms/directfb/qdirectfbscreen.h
+++ b/src/plugins/platforms/directfb/qdirectfbscreen.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QDIRECTFBSCREEN_H
#define QDIRECTFBSCREEN_H
@@ -55,11 +19,11 @@ class QDirectFbScreen : public QPlatformScreen
public:
QDirectFbScreen(int display);
- QRect geometry() const { return m_geometry; }
- int depth() const { return m_depth; }
- QImage::Format format() const { return m_format; }
- QSizeF physicalSize() const { return m_physicalSize; }
- QPlatformCursor *cursor() const { return m_cursor.data(); }
+ QRect geometry() const override { return m_geometry; }
+ int depth() const override { return m_depth; }
+ QImage::Format format() const override { return m_format; }
+ QSizeF physicalSize() const override { return m_physicalSize; }
+ QPlatformCursor *cursor() const override { return m_cursor.data(); }
// DirectFb helpers
IDirectFBDisplayLayer *dfbLayer() const;
diff --git a/src/plugins/platforms/directfb/qdirectfbwindow.cpp b/src/plugins/platforms/directfb/qdirectfbwindow.cpp
index c5458bb720..63fd1f426d 100644
--- a/src/plugins/platforms/directfb/qdirectfbwindow.cpp
+++ b/src/plugins/platforms/directfb/qdirectfbwindow.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qdirectfbwindow.h"
#include "qdirectfbbackingstore.h"
diff --git a/src/plugins/platforms/directfb/qdirectfbwindow.h b/src/plugins/platforms/directfb/qdirectfbwindow.h
index fdf3419ddb..f05038d8ca 100644
--- a/src/plugins/platforms/directfb/qdirectfbwindow.h
+++ b/src/plugins/platforms/directfb/qdirectfbwindow.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QDIRECTFBWINDOW_H
#define QDIRECTFBWINDOW_H
@@ -51,19 +15,19 @@ class QDirectFbWindow : public QPlatformWindow
{
public:
QDirectFbWindow(QWindow *tlw, QDirectFbInput *inputhandler);
- ~QDirectFbWindow();
+ ~QDirectFbWindow() override;
- void setGeometry(const QRect &rect);
- void setOpacity(qreal level);
+ void setGeometry(const QRect &rect) override;
+ void setOpacity(qreal level) override;
- void setVisible(bool visible);
+ void setVisible(bool visible) override;
- void setWindowFlags(Qt::WindowFlags flags);
- bool setKeyboardGrabEnabled(bool grab);
- bool setMouseGrabEnabled(bool grab);
- void raise();
- void lower();
- WId winId() const;
+ void setWindowFlags(Qt::WindowFlags flags) override;
+ bool setKeyboardGrabEnabled(bool grab) override;
+ bool setMouseGrabEnabled(bool grab) override;
+ void raise() override;
+ void lower() override;
+ WId winId() const override;
virtual void createDirectFBWindow();
IDirectFBWindow *dfbWindow() const;
diff --git a/src/plugins/platforms/eglfs/.prev_CMakeLists.txt b/src/plugins/platforms/eglfs/.prev_CMakeLists.txt
deleted file mode 100644
index 4fed525392..0000000000
--- a/src/plugins/platforms/eglfs/.prev_CMakeLists.txt
+++ /dev/null
@@ -1,113 +0,0 @@
-# Generated from eglfs.pro.
-
-#####################################################################
-## EglFSDeviceIntegration Module:
-#####################################################################
-
-qt_add_module(EglFSDeviceIntegration
- INTERNAL_MODULE
- SOURCES
- api/qeglfsdeviceintegration.cpp api/qeglfsdeviceintegration_p.h
- api/qeglfsglobal_p.h
- api/qeglfshooks.cpp api/qeglfshooks_p.h
- api/qeglfsintegration.cpp api/qeglfsintegration_p.h
- api/qeglfsoffscreenwindow.cpp api/qeglfsoffscreenwindow_p.h
- api/qeglfsscreen.cpp api/qeglfsscreen_p.h
- api/qeglfswindow.cpp api/qeglfswindow_p.h
- DEFINES
- QT_BUILD_EGL_DEVICE_LIB
- QT_EGL_NO_X11
- INCLUDE_DIRECTORIES
- api
- PUBLIC_LIBRARIES
- Qt::CorePrivate
- Qt::DeviceDiscoverySupportPrivate
- Qt::EglSupportPrivate
- Qt::EventDispatcherSupportPrivate
- Qt::FbSupportPrivate
- Qt::FontDatabaseSupportPrivate
- Qt::GuiPrivate
- Qt::ServiceSupportPrivate
- Qt::ThemeSupportPrivate
-)
-
-#### Keys ignored in scope 2:.:.:eglfsdeviceintegration.pro:<TRUE>:
-# MODULE = "eglfsdeviceintegration"
-
-## Scopes:
-#####################################################################
-
-qt_extend_target(EglFSDeviceIntegration CONDITION TARGET Qt::InputSupportPrivate
- PUBLIC_LIBRARIES
- Qt::InputSupportPrivate
-)
-
-qt_extend_target(EglFSDeviceIntegration CONDITION TARGET Qt::PlatformCompositorSupportPrivate
- PUBLIC_LIBRARIES
- Qt::PlatformCompositorSupportPrivate
-)
-
-qt_extend_target(EglFSDeviceIntegration CONDITION QT_FEATURE_vulkan
- SOURCES
- api/vulkan/qeglfsvulkaninstance.cpp api/vulkan/qeglfsvulkaninstance_p.h
- api/vulkan/qeglfsvulkanwindow.cpp api/vulkan/qeglfsvulkanwindow_p.h
- PUBLIC_LIBRARIES
- Qt::VulkanSupportPrivate
-)
-
-qt_extend_target(EglFSDeviceIntegration CONDITION NOT EGLFS_PLATFORM_HOOKS_SOURCES_ISEMPTY
- DEFINES
- EGLFS_PLATFORM_HOOKS
-)
-
-qt_extend_target(EglFSDeviceIntegration CONDITION NOT EGLFS_DEVICE_INTEGRATION_ISEMPTY
- DEFINES
- EGLFS_PREFERRED_PLUGIN=
-)
-
-if(QT_FEATURE_cursor)
- # Resources:
- set(cursor_resource_files
- "cursor-atlas.png"
- "cursor.json"
- )
-
- qt_add_resource(EglFSDeviceIntegration "cursor"
- PREFIX
- "/"
- FILES
- ${cursor_resource_files}
- )
-endif()
-
-qt_extend_target(EglFSDeviceIntegration CONDITION QT_FEATURE_opengl
- SOURCES
- api/qeglfscontext.cpp api/qeglfscontext_p.h
- api/qeglfscursor.cpp api/qeglfscursor_p.h
-)
-#####################################################################
-## QEglFSIntegrationPlugin Plugin:
-#####################################################################
-
-qt_add_plugin(QEglFSIntegrationPlugin
- OUTPUT_NAME qeglfs
- TYPE platforms
- SOURCES
- qeglfsmain.cpp
- DEFINES
- QT_EGL_NO_X11
- INCLUDE_DIRECTORIES
- api
- PUBLIC_LIBRARIES
- Qt::EglFSDeviceIntegrationPrivate
-)
-
-#### Keys ignored in scope 13:.:.:eglfs-plugin.pro:<TRUE>:
-# OTHER_FILES = "$$PWD/eglfs.json"
-
-## Scopes:
-#####################################################################
-
-#### Keys ignored in scope 14:.:.:eglfs-plugin.pro:NOT TARGET___equals____ss_QT_DEFAULT_QPA_PLUGIN:
-# PLUGIN_EXTENDS = "-"
-add_subdirectory(deviceintegration)
diff --git a/src/plugins/platforms/eglfs/CMakeLists.txt b/src/plugins/platforms/eglfs/CMakeLists.txt
index 03de79d6f0..a0a6116a45 100644
--- a/src/plugins/platforms/eglfs/CMakeLists.txt
+++ b/src/plugins/platforms/eglfs/CMakeLists.txt
@@ -1,11 +1,27 @@
-# Generated from eglfs.pro.
-qt_find_package(EGL) # special case
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+qt_find_package(EGL)
+
+if(QT_FEATURE_eglfs_gbm)
+ set(_device_integration "eglfs_kms")
+elseif(QT_FEATURE_eglfs_egldevice)
+ set(_device_integration "eglfs_kms_egldevice")
+elseif(QT_FEATURE_eglfs_viv)
+ set(_device_integration "eglfs_viv")
+elseif(QT_FEATURE_eglfs_brcm)
+ set(_device_integration "eglfs_brcm")
+elseif(QT_FEATURE_eglfs_openwfd)
+ set(_device_integration "eglfs_openwfd")
+endif()
+
+set(QT_QPA_DEFAULT_EGLFS_INTEGRATION "${_device_integration}" CACHE STRING "Default EGLFS device integration plugin")
#####################################################################
-## EglFSDeviceIntegration Module:
+## EglFSDeviceIntegrationPrivate Module:
#####################################################################
-qt_add_module(EglFSDeviceIntegration
+qt_internal_add_module(EglFSDeviceIntegrationPrivate
INTERNAL_MODULE
SOURCES
api/qeglfsdeviceintegration.cpp api/qeglfsdeviceintegration_p.h
@@ -18,57 +34,50 @@ qt_add_module(EglFSDeviceIntegration
DEFINES
QT_BUILD_EGL_DEVICE_LIB
QT_EGL_NO_X11
+ QT_NO_FOREACH
+ EGLFS_PREFERRED_PLUGIN=${QT_QPA_DEFAULT_EGLFS_INTEGRATION}
INCLUDE_DIRECTORIES
api
PUBLIC_LIBRARIES
Qt::CorePrivate
Qt::DeviceDiscoverySupportPrivate
- Qt::EglSupportPrivate
- Qt::EventDispatcherSupportPrivate
Qt::FbSupportPrivate
- Qt::FontDatabaseSupportPrivate
Qt::GuiPrivate
- Qt::ServiceSupportPrivate
- Qt::ThemeSupportPrivate
- EGL::EGL # special case
+ EGL::EGL
+ HEADER_SYNC_SOURCE_DIRECTORY
+ "${CMAKE_CURRENT_SOURCE_DIR}/api"
+ NO_GENERATE_CPP_EXPORTS
)
-#### Keys ignored in scope 2:.:.:eglfsdeviceintegration.pro:<TRUE>:
-# MODULE = "eglfsdeviceintegration"
-
## Scopes:
#####################################################################
-qt_extend_target(EglFSDeviceIntegration CONDITION TARGET Qt::InputSupportPrivate
+qt_internal_extend_target(EglFSDeviceIntegrationPrivate CONDITION TARGET Qt::InputSupportPrivate
PUBLIC_LIBRARIES
Qt::InputSupportPrivate
)
-qt_extend_target(EglFSDeviceIntegration CONDITION TARGET Qt::PlatformCompositorSupportPrivate
- PUBLIC_LIBRARIES
- Qt::PlatformCompositorSupportPrivate
+qt_internal_extend_target(EglFSDeviceIntegrationPrivate CONDITION INTEGRITY AND TARGET IntegrityPlatformGraphics::IntegrityPlatformGraphics
+ LIBRARIES
+ IntegrityPlatformGraphics::IntegrityPlatformGraphics
)
-qt_extend_target(EglFSDeviceIntegration CONDITION QT_FEATURE_vulkan
+qt_internal_extend_target(EglFSDeviceIntegrationPrivate CONDITION QT_FEATURE_opengl
SOURCES
- api/vulkan/qeglfsvulkaninstance.cpp api/vulkan/qeglfsvulkaninstance_p.h
- api/vulkan/qeglfsvulkanwindow.cpp api/vulkan/qeglfsvulkanwindow_p.h
+ api/qeglfscontext.cpp api/qeglfscontext_p.h
+ api/qeglfscursor.cpp api/qeglfscursor_p.h
PUBLIC_LIBRARIES
- Qt::VulkanSupportPrivate
+ Qt::OpenGLPrivate
)
-# special case:
-# extend_target(EglFSDeviceIntegration CONDITION NOT EGLFS_PLATFORM_HOOKS_SOURCES_ISEMPTY ...
-# extend_target(EglFSDeviceIntegration CONDITION NOT EGLFS_DEVICE_INTEGRATION_ISEMPTY ...
-
-if(QT_FEATURE_cursor) # special case
+if(QT_FEATURE_cursor)
# Resources:
set(cursor_resource_files
"cursor-atlas.png"
"cursor.json"
)
- qt_add_resource(EglFSDeviceIntegration "cursor"
+ qt_internal_add_resource(EglFSDeviceIntegrationPrivate "cursor"
PREFIX
"/"
FILES
@@ -76,37 +85,22 @@ if(QT_FEATURE_cursor) # special case
)
endif()
-qt_extend_target(EglFSDeviceIntegration CONDITION QT_FEATURE_opengl
- SOURCES
- api/qeglfscontext.cpp api/qeglfscontext_p.h
- api/qeglfscursor.cpp api/qeglfscursor_p.h
-)
#####################################################################
## QEglFSIntegrationPlugin Plugin:
#####################################################################
-qt_add_plugin(QEglFSIntegrationPlugin
+qt_internal_add_plugin(QEglFSIntegrationPlugin
OUTPUT_NAME qeglfs
- TYPE platforms
- DEFAULT_IF ${QT_QPA_DEFAULT_PLATFORM} MATCHES eglfs # special case
+ PLUGIN_TYPE platforms
+ DEFAULT_IF ${QT_QPA_DEFAULT_PLATFORM} MATCHES eglfs
SOURCES
qeglfsmain.cpp
DEFINES
QT_EGL_NO_X11
- INCLUDE_DIRECTORIES
- api
- PUBLIC_LIBRARIES
- Qt::CorePrivate # special case
+ LIBRARIES
+ Qt::CorePrivate
Qt::EglFSDeviceIntegrationPrivate
- EGL::EGL # special case
+ EGL::EGL
)
-#### Keys ignored in scope 13:.:.:eglfs-plugin.pro:<TRUE>:
-# OTHER_FILES = "$$PWD/eglfs.json"
-
-## Scopes:
-#####################################################################
-
-#### Keys ignored in scope 14:.:.:eglfs-plugin.pro:NOT TARGET___equals____ss_QT_DEFAULT_QPA_PLUGIN:
-# PLUGIN_EXTENDS = "-"
add_subdirectory(deviceintegration)
diff --git a/src/plugins/platforms/eglfs/api/api.pri b/src/plugins/platforms/eglfs/api/api.pri
deleted file mode 100644
index 68965b58d8..0000000000
--- a/src/plugins/platforms/eglfs/api/api.pri
+++ /dev/null
@@ -1,35 +0,0 @@
-
-SOURCES += $$PWD/qeglfswindow.cpp \
- $$PWD/qeglfsscreen.cpp \
- $$PWD/qeglfshooks.cpp \
- $$PWD/qeglfsdeviceintegration.cpp \
- $$PWD/qeglfsintegration.cpp \
- $$PWD/qeglfsoffscreenwindow.cpp
-
-HEADERS += $$PWD/qeglfswindow_p.h \
- $$PWD/qeglfsscreen_p.h \
- $$PWD/qeglfshooks_p.h \
- $$PWD/qeglfsdeviceintegration_p.h \
- $$PWD/qeglfsintegration_p.h \
- $$PWD/qeglfsoffscreenwindow_p.h \
- $$PWD/qeglfsglobal_p.h
-
-qtConfig(opengl) {
- SOURCES += \
- $$PWD/qeglfscursor.cpp \
- $$PWD/qeglfscontext.cpp
- HEADERS += \
- $$PWD/qeglfscursor_p.h \
- $$PWD/qeglfscontext_p.h
-}
-
-qtConfig(vulkan) {
- SOURCES += \
- $$PWD/vulkan/qeglfsvulkaninstance.cpp \
- $$PWD/vulkan/qeglfsvulkanwindow.cpp
- HEADERS += \
- $$PWD/vulkan/qeglfsvulkaninstance_p.h \
- $$PWD/vulkan/qeglfsvulkanwindow_p.h
-}
-
-INCLUDEPATH += $$PWD
diff --git a/src/plugins/platforms/eglfs/api/qeglfscontext.cpp b/src/plugins/platforms/eglfs/api/qeglfscontext.cpp
index 48fafbda8d..9c10c1a998 100644
--- a/src/plugins/platforms/eglfs/api/qeglfscontext.cpp
+++ b/src/plugins/platforms/eglfs/api/qeglfscontext.cpp
@@ -1,46 +1,10 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qeglfsglobal_p.h"
#include <QtGui/QSurface>
-#include <QtEglSupport/private/qeglconvenience_p.h>
-#include <QtEglSupport/private/qeglpbuffer_p.h>
+#include <QtGui/private/qeglconvenience_p.h>
+#include <QtGui/private/qeglpbuffer_p.h>
#include "qeglfscontext_p.h"
#include "qeglfswindow_p.h"
@@ -50,19 +14,27 @@
QT_BEGIN_NAMESPACE
QEglFSContext::QEglFSContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, EGLDisplay display,
- EGLConfig *config, const QVariant &nativeHandle)
- : QEGLPlatformContext(format, share, display, config, nativeHandle,
- qt_egl_device_integration()->supportsSurfacelessContexts() ? Flags() : QEGLPlatformContext::NoSurfaceless),
- m_tempWindow(0)
+ EGLConfig *config)
+ : QEGLPlatformContext(format, share, display, config,
+ qt_egl_device_integration()->supportsSurfacelessContexts() ? Flags() : QEGLPlatformContext::NoSurfaceless)
{
}
EGLSurface QEglFSContext::eglSurfaceForPlatformSurface(QPlatformSurface *surface)
{
- if (surface->surface()->surfaceClass() == QSurface::Window)
- return static_cast<QEglFSWindow *>(surface)->surface();
- else
+ if (surface->surface()->surfaceClass() == QSurface::Window) {
+
+ QEglFSWindow *w = static_cast<QEglFSWindow *>(surface);
+ EGLSurface s = w->surface();
+ if (s == EGL_NO_SURFACE) {
+ w->resetSurface();
+ s = w->surface();
+ }
+ return s;
+
+ } else {
return static_cast<QEGLPbuffer *>(surface)->pbuffer();
+ }
}
EGLSurface QEglFSContext::createTemporaryOffscreenSurface()
diff --git a/src/plugins/platforms/eglfs/api/qeglfscontext_p.h b/src/plugins/platforms/eglfs/api/qeglfscontext_p.h
index af8725b6b3..75a4741b1f 100644
--- a/src/plugins/platforms/eglfs/api/qeglfscontext_p.h
+++ b/src/plugins/platforms/eglfs/api/qeglfscontext_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QEGLFSCONTEXT_H
#define QEGLFSCONTEXT_H
@@ -53,7 +17,7 @@
#include "qeglfsglobal_p.h"
#include "qeglfscursor_p.h"
-#include <QtEglSupport/private/qeglplatformcontext_p.h>
+#include <QtGui/private/qeglplatformcontext_p.h>
#include <QtCore/QVariant>
QT_BEGIN_NAMESPACE
@@ -61,8 +25,10 @@ QT_BEGIN_NAMESPACE
class Q_EGLFS_EXPORT QEglFSContext : public QEGLPlatformContext
{
public:
+ using QEGLPlatformContext::QEGLPlatformContext;
+ QEglFSContext() = default; // workaround for INTEGRITY compiler
QEglFSContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, EGLDisplay display,
- EGLConfig *config, const QVariant &nativeHandle);
+ EGLConfig *config);
EGLSurface eglSurfaceForPlatformSurface(QPlatformSurface *surface) override;
EGLSurface createTemporaryOffscreenSurface() override;
void destroyTemporaryOffscreenSurface(EGLSurface surface) override;
@@ -72,7 +38,7 @@ public:
QEglFSCursorData cursorData;
private:
- EGLNativeWindowType m_tempWindow;
+ EGLNativeWindowType m_tempWindow = 0;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/eglfs/api/qeglfscursor.cpp b/src/plugins/platforms/eglfs/api/qeglfscursor.cpp
index 98e05195ee..1e1a7d8269 100644
--- a/src/plugins/platforms/eglfs/api/qeglfscursor.cpp
+++ b/src/plugins/platforms/eglfs/api/qeglfscursor.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qeglfscursor_p.h"
#include "qeglfsintegration_p.h"
@@ -44,13 +8,14 @@
#include <qpa/qwindowsysteminterface.h>
#include <QtGui/QOpenGLContext>
+#include <QtGui/QOpenGLFunctions>
#include <QtCore/QFile>
#include <QtCore/QJsonDocument>
#include <QtCore/QJsonArray>
#include <QtCore/QJsonObject>
#include <QtGui/private/qguiapplication_p.h>
-#include <QtGui/private/qopenglvertexarrayobject_p.h>
+#include <QtOpenGL/private/qopenglvertexarrayobject_p.h>
#ifndef GL_VERTEX_ARRAY_BINDING
#define GL_VERTEX_ARRAY_BINDING 0x85B5
@@ -58,6 +23,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
QEglFSCursor::QEglFSCursor(QPlatformScreen *screen)
: m_visible(true),
m_screen(static_cast<QEglFSScreen *>(screen)),
@@ -151,16 +118,18 @@ void QEglFSCursor::createShaderPrograms()
void QEglFSCursor::createCursorTexture(uint *texture, const QImage &image)
{
+ Q_ASSERT(QOpenGLContext::currentContext());
+ QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions();
if (!*texture)
- glGenTextures(1, texture);
- glBindTexture(GL_TEXTURE_2D, *texture);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-
- glTexImage2D(GL_TEXTURE_2D, 0 /* level */, GL_RGBA, image.width(), image.height(), 0 /* border */,
- GL_RGBA, GL_UNSIGNED_BYTE, image.constBits());
+ f->glGenTextures(1, texture);
+ f->glBindTexture(GL_TEXTURE_2D, *texture);
+ f->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ f->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ f->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ f->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+ f->glTexImage2D(GL_TEXTURE_2D, 0 /* level */, GL_RGBA, image.width(), image.height(), 0 /* border */,
+ GL_RGBA, GL_UNSIGNED_BYTE, image.constBits());
}
void QEglFSCursor::initCursorAtlas()
@@ -178,14 +147,14 @@ void QEglFSCursor::initCursorAtlas()
QJsonDocument doc = QJsonDocument::fromJson(file.readAll());
QJsonObject object = doc.object();
- QString atlas = object.value(QLatin1String("image")).toString();
+ QString atlas = object.value("image"_L1).toString();
Q_ASSERT(!atlas.isEmpty());
- const int cursorsPerRow = object.value(QLatin1String("cursorsPerRow")).toDouble();
+ const int cursorsPerRow = object.value("cursorsPerRow"_L1).toDouble();
Q_ASSERT(cursorsPerRow);
m_cursorAtlas.cursorsPerRow = cursorsPerRow;
- const QJsonArray hotSpots = object.value(QLatin1String("hotSpots")).toArray();
+ const QJsonArray hotSpots = object.value("hotSpots"_L1).toArray();
Q_ASSERT(hotSpots.count() == Qt::LastCursor + 1);
for (int i = 0; i < hotSpots.count(); i++) {
QPoint hotSpot(hotSpots[i].toArray()[0].toDouble(), hotSpots[i].toArray()[1].toDouble());
@@ -323,7 +292,7 @@ void QEglFSCursor::pointerEvent(const QMouseEvent &event)
if (event.type() != QEvent::MouseMove)
return;
const QRect oldCursorRect = cursorRect();
- m_cursor.pos = event.screenPos().toPoint();
+ m_cursor.pos = event.globalPosition().toPoint();
update(oldCursorRect | cursorRect(), false);
for (QPlatformScreen *screen : m_screen->virtualSiblings())
static_cast<QEglFSScreen *>(screen)->handleCursorMove(m_cursor.pos);
@@ -343,8 +312,7 @@ void QEglFSCursor::paintOnScreen()
// screens are siblings of each other. When not enabled, the sibling list
// only contains m_screen itself.
for (QPlatformScreen *screen : m_screen->virtualSiblings()) {
- if (screen->geometry().contains(cr.topLeft().toPoint() + m_cursor.hotSpot)
- && QOpenGLContext::currentContext()->screen() == screen->screen())
+ if (screen->geometry().contains(cr.topLeft().toPoint() + m_cursor.hotSpot))
{
cr.translate(-screen->geometry().topLeft());
const QSize screenSize = screen->geometry().size();
@@ -373,9 +341,9 @@ void QEglFSCursor::paintOnScreen()
// to deal with the changes we make.
struct StateSaver
{
- StateSaver() {
- f = QOpenGLContext::currentContext()->functions();
- vaoHelper = new QOpenGLVertexArrayObjectHelper(QOpenGLContext::currentContext());
+ StateSaver(QOpenGLFunctions* func) {
+ f = func;
+ vaoHelper = QOpenGLVertexArrayObjectHelper::vertexArrayObjectHelperForContext(QOpenGLContext::currentContext());
static bool windowsChecked = false;
static bool shouldSave = true;
@@ -400,6 +368,8 @@ struct StateSaver
f->glGetIntegerv(GL_BLEND_SRC_ALPHA, blendFunc + 1);
f->glGetIntegerv(GL_BLEND_DST_RGB, blendFunc + 2);
f->glGetIntegerv(GL_BLEND_DST_ALPHA, blendFunc + 3);
+ scissor = f->glIsEnabled(GL_SCISSOR_TEST);
+ stencil = f->glIsEnabled(GL_STENCIL_TEST);
f->glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &arrayBuf);
if (vaoHelper->isValid())
f->glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &vao);
@@ -423,17 +393,15 @@ struct StateSaver
f->glFrontFace(frontFace);
if (cull)
f->glEnable(GL_CULL_FACE);
- else
- f->glDisable(GL_CULL_FACE);
if (depthTest)
f->glEnable(GL_DEPTH_TEST);
- else
- f->glDisable(GL_DEPTH_TEST);
- if (blend)
- f->glEnable(GL_BLEND);
- else
+ if (!blend)
f->glDisable(GL_BLEND);
f->glBlendFuncSeparate(blendFunc[0], blendFunc[1], blendFunc[2], blendFunc[3]);
+ if (scissor)
+ f->glEnable(GL_SCISSOR_TEST);
+ if (stencil)
+ f->glEnable(GL_STENCIL_TEST);
f->glBindBuffer(GL_ARRAY_BUFFER, arrayBuf);
if (vaoHelper->isValid())
vaoHelper->glBindVertexArray(vao);
@@ -446,7 +414,6 @@ struct StateSaver
f->glVertexAttribPointer(i, va[i].size, va[i].type, va[i].normalized, va[i].stride, va[i].pointer);
}
}
- delete vaoHelper;
}
QOpenGLFunctions *f;
QOpenGLVertexArrayObjectHelper *vaoHelper;
@@ -459,6 +426,8 @@ struct StateSaver
bool depthTest;
bool blend;
GLint blendFunc[4];
+ bool scissor;
+ bool stencil;
GLint vao;
GLint arrayBuf;
struct { GLint enabled, type, size, normalized, stride, buffer; GLvoid *pointer; } va[2];
@@ -466,13 +435,12 @@ struct StateSaver
void QEglFSCursor::draw(const QRectF &r)
{
- StateSaver stateSaver;
+ Q_ASSERT(QOpenGLContext::currentContext());
+ QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions();
+ StateSaver stateSaver(f);
QEglFSCursorData &gfx = static_cast<QEglFSContext*>(QOpenGLContext::currentContext()->handle())->cursorData;
if (!gfx.program) {
- // one time initialization
- initializeOpenGLFunctions();
-
createShaderPrograms();
if (!gfx.atlasTexture) {
@@ -518,13 +486,13 @@ void QEglFSCursor::draw(const QRectF &r)
s2, t1
};
- glActiveTexture(GL_TEXTURE0);
- glBindTexture(GL_TEXTURE_2D, cursorTexture);
+ f->glActiveTexture(GL_TEXTURE0);
+ f->glBindTexture(GL_TEXTURE_2D, cursorTexture);
if (stateSaver.vaoHelper->isValid())
stateSaver.vaoHelper->glBindVertexArray(0);
- glBindBuffer(GL_ARRAY_BUFFER, 0);
+ f->glBindBuffer(GL_ARRAY_BUFFER, 0);
gfx.program->enableAttributeArray(0);
gfx.program->enableAttributeArray(1);
@@ -534,13 +502,15 @@ void QEglFSCursor::draw(const QRectF &r)
gfx.program->setUniformValue(gfx.textureEntry, 0);
gfx.program->setUniformValue(gfx.matEntry, m_rotationMatrix);
- glDisable(GL_CULL_FACE);
- glFrontFace(GL_CCW);
- glEnable(GL_BLEND);
- glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
- glDisable(GL_DEPTH_TEST); // disable depth testing to make sure cursor is always on top
+ f->glDisable(GL_CULL_FACE);
+ f->glFrontFace(GL_CCW);
+ f->glEnable(GL_BLEND);
+ f->glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ f->glDisable(GL_DEPTH_TEST); // disable depth testing to make sure cursor is always on top
+ f->glDisable(GL_SCISSOR_TEST);
+ f->glDisable(GL_STENCIL_TEST);
- glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+ f->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
gfx.program->disableAttributeArray(0);
gfx.program->disableAttributeArray(1);
@@ -548,3 +518,5 @@ void QEglFSCursor::draw(const QRectF &r)
}
QT_END_NAMESPACE
+
+#include "moc_qeglfscursor_p.cpp"
diff --git a/src/plugins/platforms/eglfs/api/qeglfscursor_p.h b/src/plugins/platforms/eglfs/api/qeglfscursor_p.h
index 8768f9dd8c..88d4ce695a 100644
--- a/src/plugins/platforms/eglfs/api/qeglfscursor_p.h
+++ b/src/plugins/platforms/eglfs/api/qeglfscursor_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QEGLFSCURSOR_H
#define QEGLFSCURSOR_H
@@ -54,12 +18,11 @@
#include "qeglfsglobal_p.h"
#include <qpa/qplatformcursor.h>
#include <qpa/qplatformscreen.h>
+#include <QtOpenGL/QOpenGLShaderProgram>
#include <QtGui/QMatrix4x4>
-#include <QtGui/QOpenGLFunctions>
-#include <QtGui/QOpenGLShaderProgram>
#include <QtGui/private/qinputdevicemanager_p.h>
-#include <QtCore/qvector.h>
+#include <QtCore/qlist.h>
QT_BEGIN_NAMESPACE
@@ -94,7 +57,6 @@ struct QEglFSCursorData {
};
class Q_EGLFS_EXPORT QEglFSCursor : public QPlatformCursor
- , protected QOpenGLFunctions
{
Q_OBJECT
public:
@@ -145,7 +107,7 @@ private:
int cursorsPerRow;
int width, height; // width and height of the atlas
int cursorWidth, cursorHeight; // width and height of cursors inside the atlas
- QVector<QPoint> hotSpots;
+ QList<QPoint> hotSpots;
QImage image; // valid until it's uploaded
} m_cursorAtlas;
diff --git a/src/plugins/platforms/eglfs/api/qeglfsdeviceintegration.cpp b/src/plugins/platforms/eglfs/api/qeglfsdeviceintegration.cpp
index e3145aa0b0..56fda45e90 100644
--- a/src/plugins/platforms/eglfs/api/qeglfsdeviceintegration.cpp
+++ b/src/plugins/platforms/eglfs/api/qeglfsdeviceintegration.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qeglfsdeviceintegration_p.h"
#include "qeglfsintegration_p.h"
@@ -46,7 +10,7 @@
#include "qeglfsscreen_p.h"
#include "qeglfshooks_p.h"
-#include <QtEglSupport/private/qeglconvenience_p.h>
+#include <QtGui/private/qeglconvenience_p.h>
#include <QGuiApplication>
#include <private/qguiapplication_p.h>
#include <QScreen>
@@ -69,52 +33,24 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
Q_LOGGING_CATEGORY(qLcEglDevDebug, "qt.qpa.egldeviceintegration")
Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader,
- (QEglFSDeviceIntegrationFactoryInterface_iid, QLatin1String("/egldeviceintegrations"), Qt::CaseInsensitive))
-
-#if QT_CONFIG(library)
-Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, directLoader,
- (QEglFSDeviceIntegrationFactoryInterface_iid, QLatin1String(""), Qt::CaseInsensitive))
-
-#endif // QT_CONFIG(library)
+ (QEglFSDeviceIntegrationFactoryInterface_iid, "/egldeviceintegrations"_L1, Qt::CaseInsensitive))
-QStringList QEglFSDeviceIntegrationFactory::keys(const QString &pluginPath)
+QStringList QEglFSDeviceIntegrationFactory::keys()
{
QStringList list;
-#if QT_CONFIG(library)
- if (!pluginPath.isEmpty()) {
- QCoreApplication::addLibraryPath(pluginPath);
- list = directLoader()->keyMap().values();
- if (!list.isEmpty()) {
- const QString postFix = QLatin1String(" (from ")
- + QDir::toNativeSeparators(pluginPath)
- + QLatin1Char(')');
- const QStringList::iterator end = list.end();
- for (QStringList::iterator it = list.begin(); it != end; ++it)
- (*it).append(postFix);
- }
- }
-#else
- Q_UNUSED(pluginPath);
-#endif
list.append(loader()->keyMap().values());
qCDebug(qLcEglDevDebug) << "EGL device integration plugin keys:" << list;
return list;
}
-QEglFSDeviceIntegration *QEglFSDeviceIntegrationFactory::create(const QString &key, const QString &pluginPath)
+QEglFSDeviceIntegration *QEglFSDeviceIntegrationFactory::create(const QString &key)
{
QEglFSDeviceIntegration *integration = nullptr;
-#if QT_CONFIG(library)
- if (!pluginPath.isEmpty()) {
- QCoreApplication::addLibraryPath(pluginPath);
- integration = qLoadPlugin<QEglFSDeviceIntegration, QEglFSDeviceIntegrationPlugin>(directLoader(), key);
- }
-#else
- Q_UNUSED(pluginPath);
-#endif
if (!integration)
integration = qLoadPlugin<QEglFSDeviceIntegration, QEglFSDeviceIntegrationPlugin>(loader(), key);
if (integration)
@@ -129,7 +65,7 @@ static int framebuffer = -1;
QByteArray QEglFSDeviceIntegration::fbDeviceName() const
{
-#ifdef Q_OS_LINUX
+#if defined(Q_OS_LINUX) || defined(Q_OS_VXWORKS)
QByteArray fbDev = qgetenv("QT_QPA_EGLFS_FB");
if (fbDev.isEmpty())
fbDev = QByteArrayLiteral("/dev/fb0");
@@ -144,7 +80,7 @@ int QEglFSDeviceIntegration::framebufferIndex() const
{
int fbIndex = 0;
#if QT_CONFIG(regularexpression)
- QRegularExpression fbIndexRx(QLatin1String("fb(\\d+)"));
+ QRegularExpression fbIndexRx("fb(\\d+)"_L1);
QFileInfo fbinfo(QString::fromLocal8Bit(fbDeviceName()));
QRegularExpressionMatch match;
if (fbinfo.isSymLink())
@@ -159,7 +95,7 @@ int QEglFSDeviceIntegration::framebufferIndex() const
void QEglFSDeviceIntegration::platformInit()
{
-#ifdef Q_OS_LINUX
+#if defined(Q_OS_LINUX) || defined(Q_OS_VXWORKS)
QByteArray fbDev = fbDeviceName();
framebuffer = qt_safe_open(fbDev, O_RDONLY);
@@ -177,7 +113,7 @@ void QEglFSDeviceIntegration::platformInit()
void QEglFSDeviceIntegration::platformDestroy()
{
-#ifdef Q_OS_LINUX
+#if defined(Q_OS_LINUX) || defined(Q_OS_VXWORKS)
if (framebuffer != -1)
close(framebuffer);
#endif
@@ -185,7 +121,9 @@ void QEglFSDeviceIntegration::platformDestroy()
EGLNativeDisplayType QEglFSDeviceIntegration::platformDisplay() const
{
- return EGL_DEFAULT_DISPLAY;
+ bool displayOk;
+ const int defaultDisplay = qEnvironmentVariableIntValue("QT_QPA_EGLFS_DEFAULT_DISPLAY", &displayOk);
+ return displayOk ? EGLNativeDisplayType(quintptr(defaultDisplay)) : EGL_DEFAULT_DISPLAY;
}
EGLDisplay QEglFSDeviceIntegration::createDisplay(EGLNativeDisplayType nativeDisplay)
@@ -222,19 +160,12 @@ QSize QEglFSDeviceIntegration::screenSize() const
QDpi QEglFSDeviceIntegration::logicalDpi() const
{
- const QSizeF ps = physicalScreenSize();
- const QSize s = screenSize();
-
- if (!ps.isEmpty() && !s.isEmpty())
- return QDpi(25.4 * s.width() / ps.width(),
- 25.4 * s.height() / ps.height());
- else
- return QDpi(100, 100);
+ return QDpi(100, 100);
}
-qreal QEglFSDeviceIntegration::pixelDensity() const
+QDpi QEglFSDeviceIntegration::logicalBaseDpi() const
{
- return qMax(1, qRound(logicalDpi().first / qreal(100)));
+ return QDpi(100, 100);
}
Qt::ScreenOrientation QEglFSDeviceIntegration::nativeOrientation() const
@@ -381,14 +312,6 @@ void *QEglFSDeviceIntegration::wlDisplay() const
return nullptr;
}
-#if QT_CONFIG(vulkan)
-QPlatformVulkanInstance *QEglFSDeviceIntegration::createPlatformVulkanInstance(QVulkanInstance *instance)
-{
- Q_UNUSED(instance);
- return nullptr;
-}
-#endif
-
EGLConfig QEglFSDeviceIntegration::chooseConfig(EGLDisplay display, const QSurfaceFormat &format)
{
class Chooser : public QEglConfigChooser {
@@ -408,3 +331,5 @@ EGLConfig QEglFSDeviceIntegration::chooseConfig(EGLDisplay display, const QSurfa
}
QT_END_NAMESPACE
+
+#include "moc_qeglfsdeviceintegration_p.cpp"
diff --git a/src/plugins/platforms/eglfs/api/qeglfsdeviceintegration_p.h b/src/plugins/platforms/eglfs/api/qeglfsdeviceintegration_p.h
index 08447a40ea..e0a863c6da 100644
--- a/src/plugins/platforms/eglfs/api/qeglfsdeviceintegration_p.h
+++ b/src/plugins/platforms/eglfs/api/qeglfsdeviceintegration_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QEGLFSDEVICEINTEGRATION_H
#define QEGLFSDEVICEINTEGRATION_H
@@ -80,7 +44,7 @@ public:
virtual QSizeF physicalScreenSize() const;
virtual QSize screenSize() const;
virtual QDpi logicalDpi() const;
- virtual qreal pixelDensity() const;
+ virtual QDpi logicalBaseDpi() const;
virtual Qt::ScreenOrientation nativeOrientation() const;
virtual Qt::ScreenOrientation orientation() const;
virtual int screenDepth() const;
@@ -108,10 +72,6 @@ public:
virtual void *nativeResourceForScreen(const QByteArray &resource, QScreen *screen);
virtual void *wlDisplay() const;
-#if QT_CONFIG(vulkan)
- virtual QPlatformVulkanInstance *createPlatformVulkanInstance(QVulkanInstance *instance);
-#endif
-
static EGLConfig chooseConfig(EGLDisplay display, const QSurfaceFormat &format);
};
@@ -130,8 +90,8 @@ public:
class Q_EGLFS_EXPORT QEglFSDeviceIntegrationFactory
{
public:
- static QStringList keys(const QString &pluginPath = QString());
- static QEglFSDeviceIntegration *create(const QString &name, const QString &platformPluginPath = QString());
+ static QStringList keys();
+ static QEglFSDeviceIntegration *create(const QString &name);
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/eglfs/api/qeglfsglobal_p.h b/src/plugins/platforms/eglfs/api/qeglfsglobal_p.h
index 8d76ff5ee0..488675dbf1 100644
--- a/src/plugins/platforms/eglfs/api/qeglfsglobal_p.h
+++ b/src/plugins/platforms/eglfs/api/qeglfsglobal_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QEGLFSGLOBAL_H
#define QEGLFSGLOBAL_H
@@ -53,7 +17,7 @@
#include <QtCore/qglobal.h>
-#include <QtEglSupport/private/qt_egl_p.h>
+#include <QtGui/private/qt_egl_p.h>
QT_BEGIN_NAMESPACE
diff --git a/src/plugins/platforms/eglfs/api/qeglfshooks.cpp b/src/plugins/platforms/eglfs/api/qeglfshooks.cpp
index ff5c5deee4..4ab40c46fe 100644
--- a/src/plugins/platforms/eglfs/api/qeglfshooks.cpp
+++ b/src/plugins/platforms/eglfs/api/qeglfshooks.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the qmake spec 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qeglfshooks_p.h"
#include <QLoggingCategory>
diff --git a/src/plugins/platforms/eglfs/api/qeglfshooks_p.h b/src/plugins/platforms/eglfs/api/qeglfshooks_p.h
index 4c3149c7c9..5a308b0f68 100644
--- a/src/plugins/platforms/eglfs/api/qeglfshooks_p.h
+++ b/src/plugins/platforms/eglfs/api/qeglfshooks_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QEGLFSHOOKS_H
#define QEGLFSHOOKS_H
diff --git a/src/plugins/platforms/eglfs/api/qeglfsintegration.cpp b/src/plugins/platforms/eglfs/api/qeglfsintegration.cpp
index e26d984cc1..f0b64c475c 100644
--- a/src/plugins/platforms/eglfs/api/qeglfsintegration.cpp
+++ b/src/plugins/platforms/eglfs/api/qeglfsintegration.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtCore/qtextstream.h>
#include <QtGui/private/qguiapplication_p.h>
@@ -61,23 +25,21 @@
#endif
#include "qeglfsoffscreenwindow_p.h"
-#include <QtEglSupport/private/qeglconvenience_p.h>
+#include <QtGui/private/qeglconvenience_p.h>
#ifndef QT_NO_OPENGL
-# include <QtEglSupport/private/qeglplatformcontext_p.h>
-# include <QtEglSupport/private/qeglpbuffer_p.h>
+# include <QtGui/private/qeglplatformcontext_p.h>
+# include <QtGui/private/qeglpbuffer_p.h>
#endif
-#include <QtFontDatabaseSupport/private/qgenericunixfontdatabase_p.h>
-#include <QtServiceSupport/private/qgenericunixservices_p.h>
-#include <QtThemeSupport/private/qgenericunixthemes_p.h>
-#include <QtEventDispatcherSupport/private/qgenericunixeventdispatcher_p.h>
+#include <QtGui/private/qgenericunixfontdatabase_p.h>
+#include <QtGui/private/qgenericunixservices_p.h>
+#include <QtGui/private/qgenericunixthemes_p.h>
+#include <QtGui/private/qgenericunixeventdispatcher_p.h>
#include <QtFbSupport/private/qfbvthandler_p.h>
#ifndef QT_NO_OPENGL
-# include <QtPlatformCompositorSupport/private/qopenglcompositorbackingstore_p.h>
+# include <QtOpenGL/private/qopenglcompositorbackingstore_p.h>
#endif
-#include <QtPlatformHeaders/QEGLNativeContext>
-
#if QT_CONFIG(libinput)
#include <QtInputSupport/private/qlibinputhandler_p.h>
#endif
@@ -96,8 +58,6 @@
#include <QtInputSupport/qintegrityhidmanager.h>
#endif
-#include <QtPlatformHeaders/qeglfsfunctions.h>
-
static void initResources()
{
#ifndef QT_NO_CURSOR
@@ -107,12 +67,14 @@ static void initResources()
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
QEglFSIntegration::QEglFSIntegration()
- : m_display(EGL_NO_DISPLAY),
+ : m_kbdMgr(nullptr),
+ m_display(EGL_NO_DISPLAY),
m_inputContext(nullptr),
m_fontDb(new QGenericUnixFontDatabase),
m_services(new QGenericUnixServices),
- m_kbdMgr(nullptr),
m_disableInputHandlers(false)
{
m_disableInputHandlers = qEnvironmentVariableIntValue("QT_QPA_EGLFS_DISABLE_INPUT");
@@ -148,7 +110,8 @@ void QEglFSIntegration::initialize()
void QEglFSIntegration::destroy()
{
- foreach (QWindow *w, qGuiApp->topLevelWindows())
+ const auto toplevels = qGuiApp->topLevelWindows();
+ for (QWindow *w : toplevels)
w->destroy();
qt_egl_device_integration()->screenDestroy();
@@ -215,22 +178,20 @@ QPlatformOpenGLContext *QEglFSIntegration::createPlatformOpenGLContext(QOpenGLCo
{
EGLDisplay dpy = context->screen() ? static_cast<QEglFSScreen *>(context->screen()->handle())->display() : display();
QPlatformOpenGLContext *share = context->shareHandle();
- QVariant nativeHandle = context->nativeHandle();
QEglFSContext *ctx;
QSurfaceFormat adjustedFormat = qt_egl_device_integration()->surfaceFormatFor(context->format());
- if (nativeHandle.isNull()) {
- EGLConfig config = QEglFSDeviceIntegration::chooseConfig(dpy, adjustedFormat);
- ctx = new QEglFSContext(adjustedFormat, share, dpy, &config, QVariant());
- } else {
- ctx = new QEglFSContext(adjustedFormat, share, dpy, nullptr, nativeHandle);
- }
- nativeHandle = QVariant::fromValue<QEGLNativeContext>(QEGLNativeContext(ctx->eglContext(), dpy));
+ EGLConfig config = QEglFSDeviceIntegration::chooseConfig(dpy, adjustedFormat);
+ ctx = new QEglFSContext(adjustedFormat, share, dpy, &config);
- context->setNativeHandle(nativeHandle);
return ctx;
}
+QOpenGLContext *QEglFSIntegration::createOpenGLContext(EGLContext context, EGLDisplay contextDisplay, QOpenGLContext *shareContext) const
+{
+ return QEGLPlatformContext::createFrom<QEglFSContext>(context, contextDisplay, display(), shareContext);
+}
+
QPlatformOffscreenSurface *QEglFSIntegration::createPlatformOffscreenSurface(QOffscreenSurface *surface) const
{
EGLDisplay dpy = surface->screen() ? static_cast<QEglFSScreen *>(surface->screen()->handle())->display() : display();
@@ -247,13 +208,6 @@ QPlatformOffscreenSurface *QEglFSIntegration::createPlatformOffscreenSurface(QOf
}
#endif // QT_NO_OPENGL
-#if QT_CONFIG(vulkan)
-QPlatformVulkanInstance *QEglFSIntegration::createPlatformVulkanInstance(QVulkanInstance *instance) const
-{
- return qt_egl_device_integration()->createPlatformVulkanInstance(instance);
-}
-#endif
-
bool QEglFSIntegration::hasCapability(QPlatformIntegration::Capability cap) const
{
// We assume that devices will have more and not less capabilities
@@ -373,12 +327,6 @@ void *QEglFSIntegration::nativeResourceForWindow(const QByteArray &resource, QWi
if (window && window->handle())
result = reinterpret_cast<void*>(static_cast<QEglFSWindow *>(window->handle())->surface());
break;
-#if QT_CONFIG(vulkan)
- case VkSurface:
- if (window && window->handle() && window->surfaceType() == QSurface::VulkanSurface)
- result = static_cast<QEglFSWindow *>(window->handle())->vulkanSurfacePtr();
- break;
-#endif
default:
break;
}
@@ -436,45 +384,40 @@ QPlatformNativeInterface::NativeResourceForContextFunction QEglFSIntegration::na
QFunctionPointer QEglFSIntegration::platformFunction(const QByteArray &function) const
{
-#if QT_CONFIG(evdev)
- if (function == QEglFSFunctions::loadKeymapTypeIdentifier())
- return QFunctionPointer(loadKeymapStatic);
- else if (function == QEglFSFunctions::switchLangTypeIdentifier())
- return QFunctionPointer(switchLangStatic);
-#endif
-
return qt_egl_device_integration()->platformFunction(function);
}
-void QEglFSIntegration::loadKeymapStatic(const QString &filename)
+QVariant QEglFSIntegration::styleHint(QPlatformIntegration::StyleHint hint) const
{
+ if (hint == QPlatformIntegration::ShowIsFullScreen)
+ return true;
+
+ return QPlatformIntegration::styleHint(hint);
+}
+
#if QT_CONFIG(evdev)
- QEglFSIntegration *self = static_cast<QEglFSIntegration *>(QGuiApplicationPrivate::platformIntegration());
- if (self->m_kbdMgr)
- self->m_kbdMgr->loadKeymap(filename);
+void QEglFSIntegration::loadKeymap(const QString &filename)
+{
+ if (m_kbdMgr)
+ m_kbdMgr->loadKeymap(filename);
else
qWarning("QEglFSIntegration: Cannot load keymap, no keyboard handler found");
-#else
- Q_UNUSED(filename);
-#endif
}
-void QEglFSIntegration::switchLangStatic()
+void QEglFSIntegration::switchLang()
{
-#if QT_CONFIG(evdev)
- QEglFSIntegration *self = static_cast<QEglFSIntegration *>(QGuiApplicationPrivate::platformIntegration());
- if (self->m_kbdMgr)
- self->m_kbdMgr->switchLang();
+ if (m_kbdMgr)
+ m_kbdMgr->switchLang();
else
qWarning("QEglFSIntegration: Cannot switch language, no keyboard handler found");
-#endif
}
+#endif
void QEglFSIntegration::createInputHandlers()
{
#if QT_CONFIG(libinput)
if (!qEnvironmentVariableIntValue("QT_QPA_EGLFS_NO_LIBINPUT")) {
- new QLibInputHandler(QLatin1String("libinput"), QString());
+ new QLibInputHandler("libinput"_L1, QString());
return;
}
#endif
@@ -482,16 +425,16 @@ void QEglFSIntegration::createInputHandlers()
#if QT_CONFIG(tslib)
bool useTslib = qEnvironmentVariableIntValue("QT_QPA_EGLFS_TSLIB");
if (useTslib)
- new QTsLibMouseHandler(QLatin1String("TsLib"), QString() /* spec */);
+ new QTsLibMouseHandler("TsLib"_L1, QString() /* spec */);
#endif
#if QT_CONFIG(evdev)
- m_kbdMgr = new QEvdevKeyboardManager(QLatin1String("EvdevKeyboard"), QString() /* spec */, this);
- new QEvdevMouseManager(QLatin1String("EvdevMouse"), QString() /* spec */, this);
+ m_kbdMgr = new QEvdevKeyboardManager("EvdevKeyboard"_L1, QString() /* spec */, this);
+ new QEvdevMouseManager("EvdevMouse"_L1, QString() /* spec */, this);
#if QT_CONFIG(tslib)
if (!useTslib)
#endif
- new QEvdevTouchManager(QLatin1String("EvdevTouch"), QString() /* spec */, this);
+ new QEvdevTouchManager("EvdevTouch"_L1, QString() /* spec */, this);
#endif
#if QT_CONFIG(integrityhid)
diff --git a/src/plugins/platforms/eglfs/api/qeglfsintegration_p.h b/src/plugins/platforms/eglfs/api/qeglfsintegration_p.h
index b293651ce7..8007167ec7 100644
--- a/src/plugins/platforms/eglfs/api/qeglfsintegration_p.h
+++ b/src/plugins/platforms/eglfs/api/qeglfsintegration_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QEGLFSINTEGRATION_H
#define QEGLFSINTEGRATION_H
@@ -52,10 +16,14 @@
//
#include "qeglfsglobal_p.h"
+#include <QtCore/QPointer>
#include <QtCore/QVariant>
+#include <QtGui/QWindow>
#include <qpa/qplatformintegration.h>
#include <qpa/qplatformnativeinterface.h>
+#include <qpa/qplatformopenglcontext.h>
#include <qpa/qplatformscreen.h>
+#include <QtGui/private/qkeymapper_p.h>
QT_BEGIN_NAMESPACE
@@ -65,6 +33,12 @@ class QFbVtHandler;
class QEvdevKeyboardManager;
class Q_EGLFS_EXPORT QEglFSIntegration : public QPlatformIntegration, public QPlatformNativeInterface
+#if QT_CONFIG(evdev)
+ , public QNativeInterface::Private::QEvdevKeyMapper
+#endif
+#ifndef QT_NO_OPENGL
+ , public QNativeInterface::Private::QEGLIntegration
+#endif
{
public:
QEglFSIntegration();
@@ -84,11 +58,9 @@ public:
QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const override;
#ifndef QT_NO_OPENGL
QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const override;
+ QOpenGLContext *createOpenGLContext(EGLContext context, EGLDisplay display, QOpenGLContext *shareContext) const override;
QPlatformOffscreenSurface *createPlatformOffscreenSurface(QOffscreenSurface *surface) const override;
#endif
-#if QT_CONFIG(vulkan)
- QPlatformVulkanInstance *createPlatformVulkanInstance(QVulkanInstance *instance) const override;
-#endif
bool hasCapability(QPlatformIntegration::Capability cap) const override;
QPlatformNativeInterface *nativeInterface() const override;
@@ -104,20 +76,31 @@ public:
QFunctionPointer platformFunction(const QByteArray &function) const override;
+ QVariant styleHint(QPlatformIntegration::StyleHint hint) const override;
+
QFbVtHandler *vtHandler() { return m_vtHandler.data(); }
+ QPointer<QWindow> pointerWindow() { return m_pointerWindow; }
+ void setPointerWindow(QWindow *pointerWindow) { m_pointerWindow = pointerWindow; }
+
+#if QT_CONFIG(evdev)
+ void loadKeymap(const QString &filename) override;
+ void switchLang() override;
+#endif
+
+protected:
+ virtual void createInputHandlers();
+ QEvdevKeyboardManager *m_kbdMgr;
+
private:
EGLNativeDisplayType nativeDisplay() const;
- void createInputHandlers();
- static void loadKeymapStatic(const QString &filename);
- static void switchLangStatic();
EGLDisplay m_display;
QPlatformInputContext *m_inputContext;
QScopedPointer<QPlatformFontDatabase> m_fontDb;
QScopedPointer<QPlatformServices> m_services;
QScopedPointer<QFbVtHandler> m_vtHandler;
- QEvdevKeyboardManager *m_kbdMgr;
+ QPointer<QWindow> m_pointerWindow;
bool m_disableInputHandlers;
};
diff --git a/src/plugins/platforms/eglfs/api/qeglfsoffscreenwindow.cpp b/src/plugins/platforms/eglfs/api/qeglfsoffscreenwindow.cpp
index c96e329816..cf926529c2 100644
--- a/src/plugins/platforms/eglfs/api/qeglfsoffscreenwindow.cpp
+++ b/src/plugins/platforms/eglfs/api/qeglfsoffscreenwindow.cpp
@@ -1,46 +1,10 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qeglfsoffscreenwindow_p.h"
#include "qeglfshooks_p.h"
#include <QtGui/QOffscreenSurface>
-#include <QtEglSupport/private/qeglconvenience_p.h>
+#include <QtGui/private/qeglconvenience_p.h>
QT_BEGIN_NAMESPACE
diff --git a/src/plugins/platforms/eglfs/api/qeglfsoffscreenwindow_p.h b/src/plugins/platforms/eglfs/api/qeglfsoffscreenwindow_p.h
index 9fdb81efdd..568302d298 100644
--- a/src/plugins/platforms/eglfs/api/qeglfsoffscreenwindow_p.h
+++ b/src/plugins/platforms/eglfs/api/qeglfsoffscreenwindow_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QEGLFSOFFSCREENWINDOW_H
#define QEGLFSOFFSCREENWINDOW_H
diff --git a/src/plugins/platforms/eglfs/api/qeglfsscreen.cpp b/src/plugins/platforms/eglfs/api/qeglfsscreen.cpp
index 8a8e8cd563..c5108be04a 100644
--- a/src/plugins/platforms/eglfs/api/qeglfsscreen.cpp
+++ b/src/plugins/platforms/eglfs/api/qeglfsscreen.cpp
@@ -1,48 +1,13 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtCore/qtextstream.h>
#include <QtGui/qwindow.h>
+#include <QtGui/private/qguiapplication_p.h>
#include <qpa/qwindowsysteminterface.h>
#include <qpa/qplatformcursor.h>
#ifndef QT_NO_OPENGL
-# include <QtPlatformCompositorSupport/private/qopenglcompositor_p.h>
+# include <QtOpenGL/private/qopenglcompositor_p.h>
#endif
#include "qeglfsscreen_p.h"
@@ -114,9 +79,9 @@ QDpi QEglFSScreen::logicalDpi() const
return qt_egl_device_integration()->logicalDpi();
}
-qreal QEglFSScreen::pixelDensity() const
+QDpi QEglFSScreen::logicalBaseDpi() const
{
- return qt_egl_device_integration()->pixelDensity();
+ return qt_egl_device_integration()->logicalBaseDpi();
}
Qt::ScreenOrientation QEglFSScreen::nativeOrientation() const
@@ -149,37 +114,43 @@ void QEglFSScreen::handleCursorMove(const QPoint &pos)
#ifndef QT_NO_OPENGL
const QOpenGLCompositor *compositor = QOpenGLCompositor::instance();
const QList<QOpenGLCompositorWindow *> windows = compositor->windows();
+ QEglFSIntegration *platformIntegration = static_cast<QEglFSIntegration *>(QGuiApplicationPrivate::platformIntegration());
// Generate enter and leave events like a real windowing system would do.
if (windows.isEmpty())
return;
// First window is always fullscreen.
- if (windows.count() == 1) {
+ if (windows.size() == 1) {
QWindow *window = windows[0]->sourceWindow();
- if (m_pointerWindow != window) {
- m_pointerWindow = window;
+ if (platformIntegration->pointerWindow() != window) {
+ platformIntegration->setPointerWindow(window);
QWindowSystemInterface::handleEnterEvent(window, window->mapFromGlobal(pos), pos);
}
return;
}
QWindow *enter = nullptr, *leave = nullptr;
- for (int i = windows.count() - 1; i >= 0; --i) {
+ for (int i = windows.size() - 1; i >= 0; --i) {
QWindow *window = windows[i]->sourceWindow();
const QRect geom = window->geometry();
if (geom.contains(pos)) {
- if (m_pointerWindow != window) {
- leave = m_pointerWindow;
- m_pointerWindow = window;
+ if (platformIntegration->pointerWindow() != window) {
+ leave = platformIntegration->pointerWindow();
+ platformIntegration->setPointerWindow(window);
enter = window;
}
break;
}
}
- if (enter && leave)
+ if (enter && leave) {
QWindowSystemInterface::handleEnterLeaveEvent(enter, leave, enter->mapFromGlobal(pos), pos);
+ } else if (enter) {
+ QWindowSystemInterface::handleEnterEvent(enter, enter->mapFromGlobal(pos), pos);
+ } else if (leave) {
+ QWindowSystemInterface::handleLeaveEvent(leave);
+ }
#else
Q_UNUSED(pos);
#endif
@@ -194,7 +165,8 @@ QPixmap QEglFSScreen::grabWindow(WId wid, int x, int y, int width, int height) c
QImage img;
- if (static_cast<QEglFSWindow *>(windows.first()->sourceWindow()->handle())->isRaster()) {
+ QEglFSWindow *primaryWin = static_cast<QEglFSWindow *>(windows.first()->sourceWindow()->handle());
+ if (primaryWin->isRaster() || primaryWin->backingStore()) {
// Request the compositor to render everything into an FBO and read it back. This
// is of course slow, but it's safe and reliable. It will not include the mouse
// cursor, which is a plus.
@@ -217,7 +189,7 @@ QPixmap QEglFSScreen::grabWindow(WId wid, int x, int y, int width, int height) c
return QPixmap::fromImage(img).copy(x, y, width, height);
}
- foreach (QOpenGLCompositorWindow *w, windows) {
+ for (QOpenGLCompositorWindow *w : windows) {
const QWindow *window = w->sourceWindow();
if (window->winId() == wid) {
const QRect geom = window->geometry();
@@ -240,4 +212,22 @@ QPixmap QEglFSScreen::grabWindow(WId wid, int x, int y, int width, int height) c
return QPixmap();
}
+QWindow *QEglFSScreen::topLevelAt(const QPoint &point) const
+{
+#ifndef QT_NO_OPENGL
+ QOpenGLCompositor *compositor = QOpenGLCompositor::instance();
+ const QList<QOpenGLCompositorWindow *> windows = compositor->windows();
+ const int windowCount = windows.size();
+
+ // Higher z-order is at the end of the list
+ for (int i = windowCount - 1; i >= 0; i--) {
+ QWindow *window = windows[i]->sourceWindow();
+ if (window->isVisible() && window->geometry().contains(point))
+ return window;
+ }
+#endif
+
+ return QPlatformScreen::topLevelAt(point);
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/eglfs/api/qeglfsscreen_p.h b/src/plugins/platforms/eglfs/api/qeglfsscreen_p.h
index bea7b4c8ef..bbfc9a9259 100644
--- a/src/plugins/platforms/eglfs/api/qeglfsscreen_p.h
+++ b/src/plugins/platforms/eglfs/api/qeglfsscreen_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QEGLFSSCREEN_H
#define QEGLFSSCREEN_H
@@ -74,7 +38,7 @@ public:
QSizeF physicalSize() const override;
QDpi logicalDpi() const override;
- qreal pixelDensity() const override;
+ QDpi logicalBaseDpi() const override;
Qt::ScreenOrientation nativeOrientation() const override;
Qt::ScreenOrientation orientation() const override;
@@ -90,11 +54,12 @@ public:
void handleCursorMove(const QPoint &pos);
+ QWindow *topLevelAt(const QPoint &point) const override;
+
private:
void setPrimarySurface(EGLSurface surface);
EGLDisplay m_dpy;
- QPointer<QWindow> m_pointerWindow;
EGLSurface m_surface;
QPlatformCursor *m_cursor;
diff --git a/src/plugins/platforms/eglfs/api/qeglfswindow.cpp b/src/plugins/platforms/eglfs/api/qeglfswindow.cpp
index f7e116eb88..306d121cfb 100644
--- a/src/plugins/platforms/eglfs/api/qeglfswindow.cpp
+++ b/src/plugins/platforms/eglfs/api/qeglfswindow.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtCore/qtextstream.h>
#include <qpa/qwindowsysteminterface.h>
@@ -45,9 +9,9 @@
#ifndef QT_NO_OPENGL
# include <QtGui/private/qopenglcontext_p.h>
# include <QtGui/QOpenGLContext>
-# include <QtPlatformCompositorSupport/private/qopenglcompositorbackingstore_p.h>
+# include <QtOpenGL/private/qopenglcompositorbackingstore_p.h>
#endif
-#include <QtEglSupport/private/qeglconvenience_p.h>
+#include <QtGui/private/qeglconvenience_p.h>
#include "qeglfswindow_p.h"
#ifndef QT_NO_OPENGL
@@ -58,6 +22,8 @@
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(qLcEglDevDebug)
+
QEglFSWindow::QEglFSWindow(QWindow *w)
: QPlatformWindow(w),
#ifndef QT_NO_OPENGL
@@ -110,12 +76,12 @@ void QEglFSWindow::create()
#ifndef QT_NO_OPENGL
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)
+ if (Q_UNLIKELY(isRaster() != (compositor->targetWindow() != nullptr))) {
+# 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();
@@ -137,25 +103,30 @@ void QEglFSWindow::create()
screen->setPrimarySurface(m_surface);
#ifndef QT_NO_OPENGL
- if (isRaster()) {
+ compositor->setTargetWindow(window(), screen->rawGeometry());
+ compositor->setRotation(qEnvironmentVariableIntValue("QT_QPA_EGLFS_ROTATION"));
+#endif
+}
+
+void QEglFSWindow::setBackingStore(QOpenGLCompositorBackingStore *backingStore)
+{
+#ifndef QT_NO_OPENGL
+ if (!m_rasterCompositingContext) {
m_rasterCompositingContext = new QOpenGLContext;
m_rasterCompositingContext->setShareContext(qt_gl_global_share_context());
m_rasterCompositingContext->setFormat(m_format);
m_rasterCompositingContext->setScreen(window()->screen());
if (Q_UNLIKELY(!m_rasterCompositingContext->create()))
qFatal("EGLFS: Failed to create compositing context");
- compositor->setTarget(m_rasterCompositingContext, window(), screen->rawGeometry());
- compositor->setRotation(qEnvironmentVariableIntValue("QT_QPA_EGLFS_ROTATION"));
// If there is a "root" window into which raster and QOpenGLWidget content is
// composited, all other contexts must share with its context.
- if (!qt_gl_global_share_context()) {
+ if (!qt_gl_global_share_context())
qt_gl_set_global_share_context(m_rasterCompositingContext);
- // What we set up here is in effect equivalent to the application setting
- // AA_ShareOpenGLContexts. Set the attribute to be fully consistent.
- QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts);
- }
}
-#endif // QT_NO_OPENGL
+ QOpenGLCompositor *compositor = QOpenGLCompositor::instance();
+ compositor->setTargetContext(m_rasterCompositingContext);
+#endif
+ m_backingStore = backingStore;
}
void QEglFSWindow::destroy()
@@ -181,6 +152,8 @@ void QEglFSWindow::destroy()
#ifndef QT_NO_OPENGL
QOpenGLCompositor::destroy();
+ if (qt_gl_global_share_context() == m_rasterCompositingContext)
+ qt_gl_set_global_share_context(nullptr);
delete m_rasterCompositingContext;
#endif
}
@@ -191,8 +164,29 @@ void QEglFSWindow::destroy()
void QEglFSWindow::invalidateSurface()
{
if (m_surface != EGL_NO_SURFACE) {
- eglDestroySurface(screen()->display(), m_surface);
+ qCDebug(qLcEglDevDebug) << Q_FUNC_INFO << " about to destroy EGLSurface: " << m_surface;
+
+ bool ok = eglDestroySurface(screen()->display(), m_surface);
+
+ if (!ok) {
+ qCWarning(qLcEglDevDebug, "QEglFSWindow::invalidateSurface() eglDestroySurface failed!"
+ " Follow-up errors or memory leaks are possible."
+ " eglGetError(): %x", eglGetError());
+ }
+
+ if (eglGetCurrentSurface(EGL_READ) == m_surface ||
+ eglGetCurrentSurface(EGL_DRAW) == m_surface) {
+ bool ok = eglMakeCurrent(eglGetCurrentDisplay(), EGL_NO_DISPLAY, EGL_NO_DISPLAY, EGL_NO_CONTEXT);
+ qCDebug(qLcEglDevDebug) << Q_FUNC_INFO << " due to eglDestroySurface on *currently* bound surface"
+ << "we just called eglMakeCurrent(..,0,0,0)! It returned: " << ok;
+ }
+
+ if (screen()->primarySurface() == m_surface)
+ screen()->setPrimarySurface(EGL_NO_SURFACE);
+
+
m_surface = EGL_NO_SURFACE;
+ m_flags = m_flags & ~Created;
}
qt_egl_device_integration()->destroyNativeWindow(m_window);
m_window = 0;
@@ -269,7 +263,7 @@ void QEglFSWindow::requestActivateWindow()
QOpenGLCompositor::instance()->moveToTop(this);
#endif
QWindow *wnd = window();
- QWindowSystemInterface::handleWindowActivated(wnd);
+ QWindowSystemInterface::handleFocusWindowChanged(wnd, Qt::ActiveWindowFocusReason);
QWindowSystemInterface::handleExposeEvent(wnd, QRect(QPoint(0, 0), wnd->geometry().size()));
}
@@ -289,7 +283,7 @@ void QEglFSWindow::lower()
#ifndef QT_NO_OPENGL
QOpenGLCompositor *compositor = QOpenGLCompositor::instance();
QList<QOpenGLCompositorWindow *> windows = compositor->windows();
- if (window()->type() != Qt::Desktop && windows.count() > 1) {
+ if (window()->type() != Qt::Desktop && windows.size() > 1) {
int idx = windows.indexOf(this);
if (idx > 0) {
compositor->changeWindowIndex(this, idx - 1);
@@ -354,7 +348,7 @@ WId QEglFSWindow::winId() const
void QEglFSWindow::setOpacity(qreal)
{
- if (!isRaster())
+ if (!isRaster() && !backingStore())
qWarning("QEglFSWindow: Cannot set opacity for non-raster windows");
// Nothing to do here. The opacity is stored in the QWindow.
diff --git a/src/plugins/platforms/eglfs/api/qeglfswindow_p.h b/src/plugins/platforms/eglfs/api/qeglfswindow_p.h
index 7bf74c25ee..e51cd69f3d 100644
--- a/src/plugins/platforms/eglfs/api/qeglfswindow_p.h
+++ b/src/plugins/platforms/eglfs/api/qeglfswindow_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QEGLFSWINDOW_H
#define QEGLFSWINDOW_H
@@ -57,7 +21,7 @@
#include <qpa/qplatformwindow.h>
#ifndef QT_NO_OPENGL
-# include <QtPlatformCompositorSupport/private/qopenglcompositor_p.h>
+# include <QtOpenGL/private/qopenglcompositor_p.h>
#endif
QT_BEGIN_NAMESPACE
@@ -97,21 +61,17 @@ public:
EGLNativeWindowType eglWindow() const;
EGLSurface surface() const;
QEglFSScreen *screen() const override;
-#if QT_CONFIG(vulkan)
- virtual void *vulkanSurfacePtr() { return nullptr; }
-#endif
bool hasNativeWindow() const { return m_flags.testFlag(HasNativeWindow); }
void invalidateSurface() override;
virtual void resetSurface();
-#ifndef QT_NO_OPENGL
- QOpenGLCompositorBackingStore *backingStore() { return m_backingStore; }
- void setBackingStore(QOpenGLCompositorBackingStore *backingStore) { m_backingStore = backingStore; }
-#endif
bool isRaster() const;
+
#ifndef QT_NO_OPENGL
+ QOpenGLCompositorBackingStore *backingStore() const override { return m_backingStore; }
+ void setBackingStore(QOpenGLCompositorBackingStore *backingStore) override;
QWindow *sourceWindow() const override;
const QPlatformTextureList *textures() const override;
void endCompositing() override;
diff --git a/src/plugins/platforms/eglfs/api/vulkan/qeglfsvulkaninstance_p.h b/src/plugins/platforms/eglfs/api/vulkan/qeglfsvulkaninstance_p.h
deleted file mode 100644
index 9d6d47f439..0000000000
--- a/src/plugins/platforms/eglfs/api/vulkan/qeglfsvulkaninstance_p.h
+++ /dev/null
@@ -1,88 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 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 QEGLFSVULKANINSTANCE_H
-#define QEGLFSVULKANINSTANCE_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 "qeglfsglobal_p.h"
-#include <QtVulkanSupport/private/qbasicvulkanplatforminstance_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class QEglFSWindow;
-
-class Q_EGLFS_EXPORT QEglFSVulkanInstance : public QBasicPlatformVulkanInstance
-{
-public:
- QEglFSVulkanInstance(QVulkanInstance *instance);
-
- void createOrAdoptInstance() override;
- bool supportsPresent(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, QWindow *window) override;
- void presentAboutToBeQueued(QWindow *window) override;
-
- VkSurfaceKHR createSurface(QEglFSWindow *window);
-
-private:
- QVulkanInstance *m_instance;
- VkPhysicalDevice m_physDev = VK_NULL_HANDLE;
- PFN_vkEnumeratePhysicalDevices m_enumeratePhysicalDevices = nullptr;
-#if VK_KHR_display
- PFN_vkGetPhysicalDeviceDisplayPropertiesKHR m_getPhysicalDeviceDisplayPropertiesKHR = nullptr;
- PFN_vkGetDisplayModePropertiesKHR m_getDisplayModePropertiesKHR = nullptr;
- PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR m_getPhysicalDeviceDisplayPlanePropertiesKHR = nullptr;
- PFN_vkGetDisplayPlaneSupportedDisplaysKHR m_getDisplayPlaneSupportedDisplaysKHR = nullptr;
- PFN_vkGetDisplayPlaneCapabilitiesKHR m_getDisplayPlaneCapabilitiesKHR = nullptr;
- PFN_vkCreateDisplayPlaneSurfaceKHR m_createDisplayPlaneSurfaceKHR = nullptr;
-#endif
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/plugins/platforms/eglfs/api/vulkan/qeglfsvulkanwindow.cpp b/src/plugins/platforms/eglfs/api/vulkan/qeglfsvulkanwindow.cpp
deleted file mode 100644
index ae41ca00b6..0000000000
--- a/src/plugins/platforms/eglfs/api/vulkan/qeglfsvulkanwindow.cpp
+++ /dev/null
@@ -1,75 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 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 "qeglfsvulkanwindow_p.h"
-
-QT_BEGIN_NAMESPACE
-
-QEglFSVulkanWindow::QEglFSVulkanWindow(QWindow *window)
- : QEglFSWindow(window),
- m_surface(VK_NULL_HANDLE)
-{
-}
-
-QEglFSVulkanWindow::~QEglFSVulkanWindow()
-{
- if (m_surface) {
- QVulkanInstance *inst = window()->vulkanInstance();
- if (inst)
- static_cast<QEglFSVulkanInstance *>(inst->handle())->destroySurface(m_surface);
- }
-}
-
-void *QEglFSVulkanWindow::vulkanSurfacePtr()
-{
- if (m_surface)
- return &m_surface;
-
- QVulkanInstance *inst = window()->vulkanInstance();
- if (!inst) {
- qWarning("Attempted to create Vulkan surface without an instance; was QWindow::setVulkanInstance() called?");
- return nullptr;
- }
- QEglFSVulkanInstance *eglfsInst = static_cast<QEglFSVulkanInstance *>(inst->handle());
- m_surface = eglfsInst->createSurface(this);
-
- return &m_surface;
-}
-
-QT_END_NAMESPACE
diff --git a/src/plugins/platforms/eglfs/api/vulkan/qeglfsvulkanwindow_p.h b/src/plugins/platforms/eglfs/api/vulkan/qeglfsvulkanwindow_p.h
deleted file mode 100644
index 492fb41ca4..0000000000
--- a/src/plugins/platforms/eglfs/api/vulkan/qeglfsvulkanwindow_p.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 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 QEGLFSVULKANWINDOW_H
-#define QEGLFSVULKANWINDOW_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 "qeglfsglobal_p.h"
-#include "qeglfswindow_p.h"
-#include "qeglfsvulkaninstance_p.h"
-
-QT_BEGIN_NAMESPACE
-
-class Q_EGLFS_EXPORT QEglFSVulkanWindow : public QEglFSWindow
-{
-public:
- QEglFSVulkanWindow(QWindow *window);
- ~QEglFSVulkanWindow();
-
- void *vulkanSurfacePtr() override;
-
-private:
- VkSurfaceKHR m_surface;
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/plugins/platforms/eglfs/cursor.qrc b/src/plugins/platforms/eglfs/cursor.qrc
deleted file mode 100644
index 8ea6e86587..0000000000
--- a/src/plugins/platforms/eglfs/cursor.qrc
+++ /dev/null
@@ -1,7 +0,0 @@
-<!DOCTYPE RCC><RCC version="1.0">
-<qresource>
- <file>cursor-atlas.png</file>
- <file>cursor.json</file>
-</qresource>
-</RCC>
-
diff --git a/src/plugins/platforms/eglfs/deviceintegration/.prev_CMakeLists.txt b/src/plugins/platforms/eglfs/deviceintegration/.prev_CMakeLists.txt
deleted file mode 100644
index d08bf6bc20..0000000000
--- a/src/plugins/platforms/eglfs/deviceintegration/.prev_CMakeLists.txt
+++ /dev/null
@@ -1,38 +0,0 @@
-# Generated from deviceintegration.pro.
-
-if(QT_FEATURE_eglfs_x11)
- add_subdirectory(eglfs_x11)
-endif()
-if(QT_FEATURE_eglfs_egldevice OR QT_FEATURE_eglfs_gbm)
- add_subdirectory(eglfs_kms_support)
-endif()
-if(QT_FEATURE_eglfs_gbm)
- add_subdirectory(eglfs_kms)
-endif()
-if(QT_FEATURE_eglfs_egldevice)
- add_subdirectory(eglfs_kms_egldevice)
-endif()
-if(QT_FEATURE_eglfs_vsp2)
- add_subdirectory(eglfs_kms_vsp2)
-endif()
-if(QT_FEATURE_eglfs_brcm)
- add_subdirectory(eglfs_brcm)
-endif()
-if(QT_FEATURE_eglfs_mali)
- add_subdirectory(eglfs_mali)
-endif()
-if(QT_FEATURE_eglfs_viv)
- add_subdirectory(eglfs_viv)
-endif()
-if(QT_FEATURE_eglfs_rcar)
- add_subdirectory(eglfs_rcar)
-endif()
-if(QT_FEATURE_eglfs_viv_wl)
- add_subdirectory(eglfs_viv_wl)
-endif()
-if(QT_FEATURE_eglfs_openwfd)
- add_subdirectory(eglfs_openwfd)
-endif()
-if(QT_FEATURE_opengl)
- add_subdirectory(eglfs_emu)
-endif()
diff --git a/src/plugins/platforms/eglfs/deviceintegration/CMakeLists.txt b/src/plugins/platforms/eglfs/deviceintegration/CMakeLists.txt
index 7ddcb8993f..bb50216f23 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/CMakeLists.txt
+++ b/src/plugins/platforms/eglfs/deviceintegration/CMakeLists.txt
@@ -1,4 +1,5 @@
-# Generated from deviceintegration.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
if(QT_FEATURE_eglfs_x11)
add_subdirectory(eglfs_x11)
@@ -13,25 +14,25 @@ if(QT_FEATURE_eglfs_egldevice)
add_subdirectory(eglfs_kms_egldevice)
endif()
if(QT_FEATURE_eglfs_vsp2)
- # add_subdirectory(eglfs_kms_vsp2) # special case TODO
+ # add_subdirectory(eglfs_kms_vsp2) # TODO: QTBUG-112769
endif()
if(QT_FEATURE_eglfs_brcm)
- # add_subdirectory(eglfs_brcm) # special case TODO
+ # add_subdirectory(eglfs_brcm) # TODO: QTBUG-112769
endif()
if(QT_FEATURE_eglfs_mali)
- # add_subdirectory(eglfs_mali) # special case TODO
+ add_subdirectory(eglfs_mali)
endif()
if(QT_FEATURE_eglfs_viv)
- # add_subdirectory(eglfs_viv) # special case TODO
+ add_subdirectory(eglfs_viv)
endif()
if(QT_FEATURE_eglfs_rcar)
- # add_subdirectory(eglfs_rcar) # special case TODO
+ # add_subdirectory(eglfs_rcar) # TODO: QTBUG-112769
endif()
if(QT_FEATURE_eglfs_viv_wl)
- # add_subdirectory(eglfs_viv_wl) # special case TODO
+ add_subdirectory(eglfs_viv_wl)
endif()
if(QT_FEATURE_eglfs_openwfd)
- # add_subdirectory(eglfs_openwfd) # special case TODO
+ add_subdirectory(eglfs_openwfd)
endif()
if(QT_FEATURE_opengl)
add_subdirectory(eglfs_emu)
diff --git a/src/plugins/platforms/eglfs/deviceintegration/deviceintegration.pro b/src/plugins/platforms/eglfs/deviceintegration/deviceintegration.pro
deleted file mode 100644
index 360536d22f..0000000000
--- a/src/plugins/platforms/eglfs/deviceintegration/deviceintegration.pro
+++ /dev/null
@@ -1,17 +0,0 @@
-TEMPLATE = subdirs
-QT_FOR_CONFIG += gui-private
-
-qtConfig(eglfs_x11): SUBDIRS += eglfs_x11
-qtConfig(eglfs_gbm): SUBDIRS *= eglfs_kms_support eglfs_kms
-qtConfig(eglfs_egldevice): SUBDIRS *= eglfs_kms_support eglfs_kms_egldevice
-qtConfig(eglfs_vsp2): SUBDIRS += eglfs_kms_vsp2
-qtConfig(eglfs_brcm): SUBDIRS += eglfs_brcm
-qtConfig(eglfs_mali): SUBDIRS += eglfs_mali
-qtConfig(eglfs_viv): SUBDIRS += eglfs_viv
-qtConfig(eglfs_rcar): SUBDIRS += eglfs_rcar
-qtConfig(eglfs_viv_wl): SUBDIRS += eglfs_viv_wl
-qtConfig(eglfs_openwfd): SUBDIRS += eglfs_openwfd
-qtConfig(opengl): SUBDIRS += eglfs_emu
-
-eglfs_kms_egldevice.depends = eglfs_kms_support
-eglfs_kms.depends = eglfs_kms_support
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_brcm/eglfs_brcm.pro b/src/plugins/platforms/eglfs/deviceintegration/eglfs_brcm/eglfs_brcm.pro
deleted file mode 100644
index aa487be8c0..0000000000
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_brcm/eglfs_brcm.pro
+++ /dev/null
@@ -1,22 +0,0 @@
-TARGET = qeglfs-brcm-integration
-
-QT += core-private gui-private eglfsdeviceintegration-private
-
-INCLUDEPATH += $$PWD/../../api
-CONFIG += egl
-
-LIBS += -lbcm_host
-
-# Avoid X11 header collision, use generic EGL native types
-DEFINES += QT_EGL_NO_X11
-
-SOURCES += $$PWD/qeglfsbrcmmain.cpp \
- $$PWD/qeglfsbrcmintegration.cpp
-
-HEADERS += $$PWD/qeglfsbrcmintegration.h
-
-OTHER_FILES += $$PWD/eglfs_brcm.json
-
-PLUGIN_TYPE = egldeviceintegrations
-PLUGIN_CLASS_NAME = QEglFSBrcmIntegrationPlugin
-load(qt_plugin)
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_brcm/qeglfsbrcmintegration.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_brcm/qeglfsbrcmintegration.cpp
index 4e811a1dfe..8dd3eb8681 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_brcm/qeglfsbrcmintegration.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_brcm/qeglfsbrcmintegration.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qeglfsbrcmintegration.h"
#include <bcm_host.h>
@@ -127,7 +91,7 @@ QSize QEglFSBrcmIntegration::screenSize() const
EGLNativeWindowType QEglFSBrcmIntegration::createNativeWindow(QPlatformWindow *window, const QSize &size, const QSurfaceFormat &format)
{
- Q_UNUSED(window)
+ Q_UNUSED(window);
return createDispmanxLayer(QPoint(0, 0), size, 1, format.hasAlpha() ? DISPMANX_FLAGS_ALPHA_FROM_SOURCE : DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS);
}
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_brcm/qeglfsbrcmintegration.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_brcm/qeglfsbrcmintegration.h
index 83bcc487af..1cd4bfd672 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_brcm/qeglfsbrcmintegration.h
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_brcm/qeglfsbrcmintegration.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QEGLFSBRCMINTEGRATION_H
#define QEGLFSBRCMINTEGRATION_H
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_brcm/qeglfsbrcmmain.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_brcm/qeglfsbrcmmain.cpp
index fd6665e560..58028d37d1 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_brcm/qeglfsbrcmmain.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_brcm/qeglfsbrcmmain.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "private/qeglfsdeviceintegration_p.h"
#include "qeglfsbrcmintegration.h"
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/CMakeLists.txt b/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/CMakeLists.txt
index a62b8bbb2b..fa744be033 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/CMakeLists.txt
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/CMakeLists.txt
@@ -1,12 +1,13 @@
-# Generated from eglfs_emu.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## QEglFSEmulatorIntegrationPlugin Plugin:
#####################################################################
-qt_add_plugin(QEglFSEmulatorIntegrationPlugin
+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,14 +16,10 @@ qt_add_plugin(QEglFSEmulatorIntegrationPlugin
QT_EGL_NO_X11
INCLUDE_DIRECTORIES
../../api
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Core
Qt::CorePrivate
Qt::EglFSDeviceIntegrationPrivate
Qt::Gui
Qt::GuiPrivate
)
-
-#### Keys ignored in scope 1:.:.:eglfs_emu.pro:<TRUE>:
-# DISTFILES = "eglfs_emu.json"
-# OTHER_FILES = "$$PWD/eglfs_emu.json"
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/eglfs_emu.pro b/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/eglfs_emu.pro
deleted file mode 100644
index 609f04e8a9..0000000000
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/eglfs_emu.pro
+++ /dev/null
@@ -1,27 +0,0 @@
-TARGET = qeglfs-emu-integration
-
-QT += core-private gui-private eglfsdeviceintegration-private
-
-INCLUDEPATH += $$PWD/../../api
-CONFIG += egl
-
-# Avoid X11 header collision
-DEFINES += QT_EGL_NO_X11
-
-OTHER_FILES += $$PWD/eglfs_emu.json
-
-PLUGIN_TYPE = egldeviceintegrations
-PLUGIN_CLASS_NAME = QEglFSEmulatorIntegrationPlugin
-load(qt_plugin)
-
-DISTFILES += \
- eglfs_emu.json
-
-SOURCES += \
- qeglfsemumain.cpp \
- qeglfsemulatorintegration.cpp \
- qeglfsemulatorscreen.cpp
-
-HEADERS += \
- qeglfsemulatorintegration.h \
- qeglfsemulatorscreen.h
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/qeglfsemulatorintegration.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/qeglfsemulatorintegration.cpp
index cb7844aff0..a63aafa242 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/qeglfsemulatorintegration.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/qeglfsemulatorintegration.cpp
@@ -1,49 +1,13 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qeglfsemulatorintegration.h"
#include "qeglfsemulatorscreen.h"
#include "private/qeglfsintegration_p.h"
#include <private/qguiapplication_p.h>
-#include <QtEglSupport/private/qeglconvenience_p.h>
-#include <QtEglSupport/private/qeglplatformcontext_p.h>
+#include <QtGui/private/qeglconvenience_p.h>
+#include <QtGui/private/qeglplatformcontext_p.h>
#include <qpa/qwindowsysteminterface.h>
@@ -129,7 +93,7 @@ EGLNativeWindowType QEglFSEmulatorIntegration::createNativeWindow(QPlatformWindo
// Let the emulator know which screen the window surface is attached to
setDisplay(screen->id());
}
- static QBasicAtomicInt uniqueWindowId = Q_BASIC_ATOMIC_INITIALIZER(0);
+ Q_CONSTINIT static QBasicAtomicInt uniqueWindowId = Q_BASIC_ATOMIC_INITIALIZER(0);
return EGLNativeWindowType(qintptr(1 + uniqueWindowId.fetchAndAddRelaxed(1)));
}
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/qeglfsemulatorintegration.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/qeglfsemulatorintegration.h
index be5524cba3..24bda7b9ca 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/qeglfsemulatorintegration.h
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/qeglfsemulatorintegration.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QEGLFSEMULATORINTEGRATION_H
#define QEGLFSEMULATORINTEGRATION_H
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/qeglfsemulatorscreen.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/qeglfsemulatorscreen.cpp
index 7654034f85..ff2f966477 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/qeglfsemulatorscreen.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/qeglfsemulatorscreen.cpp
@@ -1,46 +1,12 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qeglfsemulatorscreen.h"
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
QEglFSEmulatorScreen::QEglFSEmulatorScreen(const QJsonObject &screenDescription)
: QEglFSScreen(eglGetDisplay(EGL_DEFAULT_DISPLAY))
, m_id(0)
@@ -75,19 +41,12 @@ QSizeF QEglFSEmulatorScreen::physicalSize() const
QDpi QEglFSEmulatorScreen::logicalDpi() const
{
- const QSizeF ps = m_physicalSize;
- const QSize s = m_geometry.size();
-
- if (!ps.isEmpty() && !s.isEmpty())
- return QDpi(25.4 * s.width() / ps.width(),
- 25.4 * s.height() / ps.height());
- else
- return QDpi(100, 100);
+ return logicalBaseDpi();
}
-qreal QEglFSEmulatorScreen::pixelDensity() const
+QDpi QEglFSEmulatorScreen::logicalBaseDpi() const
{
- return m_pixelDensity;
+ return QDpi(100, 100);
}
qreal QEglFSEmulatorScreen::refreshRate() const
@@ -119,63 +78,60 @@ void QEglFSEmulatorScreen::initFromJsonObject(const QJsonObject &description)
{
QJsonValue value;
- value = description.value(QLatin1String("id"));
+ value = description.value("id"_L1);
if (!value.isUndefined() && value.isDouble())
m_id = value.toInt();
- value = description.value(QLatin1String("description"));
+ value = description.value("description"_L1);
if (!value.isUndefined() && value.isString())
m_description = value.toString();
- value = description.value(QLatin1String("geometry"));
+ value = description.value("geometry"_L1);
if (!value.isUndefined() && value.isObject()) {
QJsonObject geometryObject = value.toObject();
- value = geometryObject.value(QLatin1String("x"));
+ value = geometryObject.value("x"_L1);
if (!value.isUndefined() && value.isDouble())
m_geometry.setX(value.toInt());
- value = geometryObject.value(QLatin1String("y"));
+ value = geometryObject.value("y"_L1);
if (!value.isUndefined() && value.isDouble())
m_geometry.setY(value.toInt());
- value = geometryObject.value(QLatin1String("width"));
+ value = geometryObject.value("width"_L1);
if (!value.isUndefined() && value.isDouble())
m_geometry.setWidth(value.toInt());
- value = geometryObject.value(QLatin1String("height"));
+ value = geometryObject.value("height"_L1);
if (!value.isUndefined() && value.isDouble())
m_geometry.setHeight(value.toInt());
}
- value = description.value(QLatin1String("depth"));
+ value = description.value("depth"_L1);
if (!value.isUndefined() && value.isDouble())
m_depth = value.toInt();
- value = description.value(QLatin1String("format"));
+ value = description.value("format"_L1);
if (!value.isUndefined() && value.isDouble())
m_format = static_cast<QImage::Format>(value.toInt());
- value = description.value(QLatin1String("physicalSize"));
+ value = description.value("physicalSize"_L1);
if (!value.isUndefined() && value.isObject()) {
QJsonObject physicalSizeObject = value.toObject();
- value = physicalSizeObject.value(QLatin1String("width"));
+ value = physicalSizeObject.value("width"_L1);
if (!value.isUndefined() && value.isDouble())
m_physicalSize.setWidth(value.toInt());
- value = physicalSizeObject.value(QLatin1String("height"));
+ value = physicalSizeObject.value("height"_L1);
if (!value.isUndefined() && value.isDouble())
m_physicalSize.setHeight(value.toInt());
}
- value = description.value(QLatin1String("pixelDensity"));
- if (!value.isUndefined() && value.isDouble())
- m_pixelDensity = value.toDouble();
- value = description.value(QLatin1String("refreshRate"));
+ value = description.value("refreshRate"_L1);
if (!value.isUndefined() && value.isDouble())
m_refreshRate = value.toDouble();
- value = description.value(QLatin1String("nativeOrientation"));
+ value = description.value("nativeOrientation"_L1);
if (!value.isUndefined() && value.isDouble())
m_nativeOrientation = static_cast<Qt::ScreenOrientation>(value.toInt());
- value = description.value(QLatin1String("orientation"));
+ value = description.value("orientation"_L1);
if (!value.isUndefined() && value.isDouble())
m_orientation = static_cast<Qt::ScreenOrientation>(value.toInt());
}
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/qeglfsemulatorscreen.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/qeglfsemulatorscreen.h
index c4994720fa..570a14079c 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/qeglfsemulatorscreen.h
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/qeglfsemulatorscreen.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QEGLFSEMULATORSCREEN_H
#define QEGLFSEMULATORSCREEN_H
@@ -58,7 +22,7 @@ public:
QImage::Format format() const override;
QSizeF physicalSize() const override;
QDpi logicalDpi() const override;
- qreal pixelDensity() const override;
+ QDpi logicalBaseDpi() const override;
qreal refreshRate() const override;
Qt::ScreenOrientation nativeOrientation() const override;
Qt::ScreenOrientation orientation() const override;
@@ -74,7 +38,6 @@ private:
int m_depth;
QImage::Format m_format;
QSizeF m_physicalSize;
- float m_pixelDensity;
float m_refreshRate;
Qt::ScreenOrientation m_nativeOrientation;
Qt::ScreenOrientation m_orientation;
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/qeglfsemumain.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/qeglfsemumain.cpp
index a9923851ef..22fe6ad40f 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/qeglfsemumain.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/qeglfsemumain.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "private/qeglfsdeviceintegration_p.h"
#include "qeglfsemulatorintegration.h"
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/CMakeLists.txt b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/CMakeLists.txt
index 55a1d71c07..9f9d315202 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/CMakeLists.txt
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/CMakeLists.txt
@@ -1,36 +1,49 @@
-# Generated from eglfs_kms.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
+## EglFsKmsGbmSupportPrivate Module:
+#####################################################################
+
+qt_internal_add_module(EglFsKmsGbmSupportPrivate
+ CONFIG_MODULE_NAME eglfs_kms_gbm_support
+ INTERNAL_MODULE
+ SOURCES
+ qeglfskmsgbmcursor.cpp qeglfskmsgbmcursor_p.h
+ qeglfskmsgbmdevice.cpp qeglfskmsgbmdevice_p.h
+ qeglfskmsgbmintegration.cpp qeglfskmsgbmintegration_p.h
+ qeglfskmsgbmscreen.cpp qeglfskmsgbmscreen_p.h
+ qeglfskmsgbmwindow.cpp qeglfskmsgbmwindow_p.h
+ DEFINES
+ QT_EGL_NO_X11
+ PUBLIC_LIBRARIES
+ Libdrm::Libdrm
+ Qt::CorePrivate
+ Qt::EglFSDeviceIntegrationPrivate
+ Qt::EglFsKmsSupportPrivate
+ Qt::GuiPrivate
+ Qt::KmsSupportPrivate
+ gbm::gbm
+ NO_GENERATE_CPP_EXPORTS
+)
+#####################################################################
## QEglFSKmsGbmIntegrationPlugin Plugin:
#####################################################################
-qt_add_plugin(QEglFSKmsGbmIntegrationPlugin
+qt_internal_add_plugin(QEglFSKmsGbmIntegrationPlugin
OUTPUT_NAME qeglfs-kms-integration
- TYPE egldeviceintegrations
+ PLUGIN_TYPE egldeviceintegrations
SOURCES
- qeglfskmsgbmcursor.cpp qeglfskmsgbmcursor.h
- qeglfskmsgbmdevice.cpp qeglfskmsgbmdevice.h
- qeglfskmsgbmintegration.cpp qeglfskmsgbmintegration.h
qeglfskmsgbmmain.cpp
- qeglfskmsgbmscreen.cpp qeglfskmsgbmscreen.h
- qeglfskmsgbmwindow.cpp qeglfskmsgbmwindow.h
DEFINES
QT_EGL_NO_X11
- INCLUDE_DIRECTORIES
- ../../api
- ../eglfs_kms_support
- PUBLIC_LIBRARIES
+ LIBRARIES
Libdrm::Libdrm
- Qt::Core
Qt::CorePrivate
- Qt::EdidSupportPrivate
Qt::EglFSDeviceIntegrationPrivate
+ Qt::EglFsKmsGbmSupportPrivate
Qt::EglFsKmsSupportPrivate
- Qt::Gui
Qt::GuiPrivate
Qt::KmsSupportPrivate
gbm::gbm
)
-
-#### Keys ignored in scope 1:.:.:eglfs_kms.pro:<TRUE>:
-# OTHER_FILES = "$$PWD/eglfs_kms.json"
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/eglfs_kms.pro b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/eglfs_kms.pro
deleted file mode 100644
index f5c2c0ed89..0000000000
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/eglfs_kms.pro
+++ /dev/null
@@ -1,30 +0,0 @@
-TARGET = qeglfs-kms-integration
-
-PLUGIN_TYPE = egldeviceintegrations
-PLUGIN_CLASS_NAME = QEglFSKmsGbmIntegrationPlugin
-load(qt_plugin)
-
-QT += core-private gui-private eglfsdeviceintegration-private eglfs_kms_support-private kms_support-private edid_support-private
-
-INCLUDEPATH += $$PWD/../../api $$PWD/../eglfs_kms_support
-
-# Avoid X11 header collision, use generic EGL native types
-DEFINES += QT_EGL_NO_X11
-
-QMAKE_USE += gbm drm
-CONFIG += egl
-
-SOURCES += $$PWD/qeglfskmsgbmmain.cpp \
- $$PWD/qeglfskmsgbmintegration.cpp \
- $$PWD/qeglfskmsgbmdevice.cpp \
- $$PWD/qeglfskmsgbmscreen.cpp \
- $$PWD/qeglfskmsgbmcursor.cpp \
- $$PWD/qeglfskmsgbmwindow.cpp
-
-HEADERS += $$PWD/qeglfskmsgbmintegration.h \
- $$PWD/qeglfskmsgbmdevice.h \
- $$PWD/qeglfskmsgbmscreen.h \
- $$PWD/qeglfskmsgbmcursor.h \
- $$PWD/qeglfskmsgbmwindow.h
-
-OTHER_FILES += $$PWD/eglfs_kms.json
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmcursor.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmcursor.cpp
index dc98cdce4b..d171715e72 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmcursor.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmcursor.cpp
@@ -1,48 +1,13 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2016 Pelagicore AG
-** 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 "qeglfskmsgbmcursor.h"
-#include "qeglfskmsgbmscreen.h"
-#include "qeglfskmsgbmdevice.h"
+// Copyright (C) 2015 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2016 Pelagicore AG
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+#include "qeglfskmsgbmcursor_p.h"
+#include "qeglfskmsgbmscreen_p.h"
+#include "qeglfskmsgbmdevice_p.h"
+
+#include <QtCore/QFile>
#include <QtCore/QJsonDocument>
#include <QtCore/QJsonObject>
#include <QtCore/QJsonArray>
@@ -63,6 +28,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
Q_DECLARE_LOGGING_CATEGORY(qLcEglfsKmsDebug)
QEglFSKmsGbmCursor::QEglFSKmsGbmCursor(QEglFSKmsGbmScreen *screen)
@@ -111,7 +78,7 @@ QEglFSKmsGbmCursor::~QEglFSKmsGbmCursor()
{
delete m_deviceListener;
- Q_FOREACH (QPlatformScreen *screen, m_screen->virtualSiblings()) {
+ for (QPlatformScreen *screen : m_screen->virtualSiblings()) {
QEglFSKmsScreen *kmsScreen = static_cast<QEglFSKmsScreen *>(screen);
drmModeSetCursor(kmsScreen->device()->fd(), kmsScreen->output().crtc_id, 0, 0, 0);
drmModeMoveCursor(kmsScreen->device()->fd(), kmsScreen->output().crtc_id, 0, 0);
@@ -150,7 +117,7 @@ void QEglFSKmsGbmCursorDeviceListener::onDeviceListChanged(QInputDeviceManager::
void QEglFSKmsGbmCursor::pointerEvent(const QMouseEvent &event)
{
- setPos(event.screenPos().toPoint());
+ setPos(event.globalPosition().toPoint());
}
#ifndef QT_NO_CURSOR
@@ -163,7 +130,7 @@ void QEglFSKmsGbmCursor::changeCursor(QCursor *windowCursor, QWindow *window)
if (m_state == CursorPendingHidden) {
m_state = CursorHidden;
- Q_FOREACH (QPlatformScreen *screen, m_screen->virtualSiblings()) {
+ for (QPlatformScreen *screen : m_screen->virtualSiblings()) {
QEglFSKmsScreen *kmsScreen = static_cast<QEglFSKmsScreen *>(screen);
drmModeSetCursor(kmsScreen->device()->fd(), kmsScreen->output().crtc_id, 0, 0, 0);
}
@@ -212,7 +179,7 @@ void QEglFSKmsGbmCursor::changeCursor(QCursor *windowCursor, QWindow *window)
if (m_state == CursorPendingVisible)
m_state = CursorVisible;
- Q_FOREACH (QPlatformScreen *screen, m_screen->virtualSiblings()) {
+ for (QPlatformScreen *screen : m_screen->virtualSiblings()) {
QEglFSKmsScreen *kmsScreen = static_cast<QEglFSKmsScreen *>(screen);
if (kmsScreen->isCursorOutOfRange())
continue;
@@ -231,7 +198,7 @@ QPoint QEglFSKmsGbmCursor::pos() const
void QEglFSKmsGbmCursor::setPos(const QPoint &pos)
{
- Q_FOREACH (QPlatformScreen *screen, m_screen->virtualSiblings()) {
+ for (QPlatformScreen *screen : m_screen->virtualSiblings()) {
QEglFSKmsScreen *kmsScreen = static_cast<QEglFSKmsScreen *>(screen);
const QRect screenGeom = kmsScreen->geometry();
const QPoint origin = screenGeom.topLeft();
@@ -247,7 +214,7 @@ void QEglFSKmsGbmCursor::setPos(const QPoint &pos)
}
} else {
int ret;
- if (kmsScreen->isCursorOutOfRange()) {
+ if (kmsScreen->isCursorOutOfRange() && m_bo) {
kmsScreen->setCursorOutOfRange(false);
uint32_t handle = gbm_bo_get_handle(m_bo).u32;
ret = drmModeSetCursor(kmsScreen->device()->fd(), kmsScreen->output().crtc_id,
@@ -276,7 +243,7 @@ void QEglFSKmsGbmCursor::initCursorAtlas()
QFile file(QString::fromUtf8(json));
if (!file.open(QFile::ReadOnly)) {
- Q_FOREACH (QPlatformScreen *screen, m_screen->virtualSiblings()) {
+ for (QPlatformScreen *screen : m_screen->virtualSiblings()) {
QEglFSKmsScreen *kmsScreen = static_cast<QEglFSKmsScreen *>(screen);
drmModeSetCursor(kmsScreen->device()->fd(), kmsScreen->output().crtc_id, 0, 0, 0);
drmModeMoveCursor(kmsScreen->device()->fd(), kmsScreen->output().crtc_id, 0, 0);
@@ -288,14 +255,14 @@ void QEglFSKmsGbmCursor::initCursorAtlas()
QJsonDocument doc = QJsonDocument::fromJson(file.readAll());
QJsonObject object = doc.object();
- QString atlas = object.value(QLatin1String("image")).toString();
+ QString atlas = object.value("image"_L1).toString();
Q_ASSERT(!atlas.isEmpty());
- const int cursorsPerRow = object.value(QLatin1String("cursorsPerRow")).toDouble();
+ const int cursorsPerRow = object.value("cursorsPerRow"_L1).toDouble();
Q_ASSERT(cursorsPerRow);
m_cursorAtlas.cursorsPerRow = cursorsPerRow;
- const QJsonArray hotSpots = object.value(QLatin1String("hotSpots")).toArray();
+ const QJsonArray hotSpots = object.value("hotSpots"_L1).toArray();
Q_ASSERT(hotSpots.count() == Qt::LastCursor + 1);
for (int i = 0; i < hotSpots.count(); i++) {
QPoint hotSpot(hotSpots[i].toArray()[0].toDouble(), hotSpots[i].toArray()[1].toDouble());
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmcursor.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmcursor.h
deleted file mode 100644
index 5d2dfedba2..0000000000
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmcursor.h
+++ /dev/null
@@ -1,122 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 QEGLFSKMSGBMCURSOR_H
-#define QEGLFSKMSGBMCURSOR_H
-
-#include <qpa/qplatformcursor.h>
-#include <QtCore/QVector>
-#include <QtGui/QImage>
-#include <QtGui/private/qinputdevicemanager_p.h>
-
-#include <gbm.h>
-
-QT_BEGIN_NAMESPACE
-
-class QEglFSKmsGbmScreen;
-class QEglFSKmsGbmCursor;
-
-class QEglFSKmsGbmCursorDeviceListener : public QObject
-{
- Q_OBJECT
-
-public:
- QEglFSKmsGbmCursorDeviceListener(QEglFSKmsGbmCursor *cursor) : m_cursor(cursor) { }
- bool hasMouse() const;
-
-public slots:
- void onDeviceListChanged(QInputDeviceManager::DeviceType type);
-
-private:
- QEglFSKmsGbmCursor *m_cursor;
-};
-
-class QEglFSKmsGbmCursor : public QPlatformCursor
-{
- Q_OBJECT
-
-public:
- QEglFSKmsGbmCursor(QEglFSKmsGbmScreen *screen);
- ~QEglFSKmsGbmCursor();
-
- // input methods
- void pointerEvent(const QMouseEvent & event) override;
-#ifndef QT_NO_CURSOR
- void changeCursor(QCursor * windowCursor, QWindow * window) override;
-#endif
- QPoint pos() const override;
- void setPos(const QPoint &pos) override;
-
- void updateMouseStatus();
-
- void reevaluateVisibilityForScreens() { setPos(pos()); }
-
-private:
- void initCursorAtlas();
-
- enum CursorState {
- CursorDisabled,
- CursorPendingHidden,
- CursorHidden,
- CursorPendingVisible,
- CursorVisible
- };
-
- QEglFSKmsGbmScreen *m_screen;
- QSize m_cursorSize;
- gbm_bo *m_bo;
- QPoint m_pos;
- QPlatformCursorImage m_cursorImage;
- CursorState m_state;
- QEglFSKmsGbmCursorDeviceListener *m_deviceListener;
-
- // cursor atlas information
- struct CursorAtlas {
- CursorAtlas() : cursorsPerRow(0), cursorWidth(0), cursorHeight(0) { }
- int cursorsPerRow;
- int width, height; // width and height of the atlas
- int cursorWidth, cursorHeight; // width and height of cursors inside the atlas
- QVector<QPoint> hotSpots;
- QImage image;
- } m_cursorAtlas;
-};
-
-QT_END_NAMESPACE
-
-#endif // QEGLFSKMSGBMCURSOR_H
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmcursor_p.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmcursor_p.h
new file mode 100644
index 0000000000..a0f78bb310
--- /dev/null
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmcursor_p.h
@@ -0,0 +1,97 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QEGLFSKMSGBMCURSOR_H
+#define QEGLFSKMSGBMCURSOR_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 <qpa/qplatformcursor.h>
+#include <QtCore/QList>
+#include <QtGui/QImage>
+#include <QtGui/private/qinputdevicemanager_p.h>
+
+#include <gbm.h>
+
+QT_BEGIN_NAMESPACE
+
+class QEglFSKmsGbmScreen;
+class QEglFSKmsGbmCursor;
+
+class QEglFSKmsGbmCursorDeviceListener : public QObject
+{
+ Q_OBJECT
+
+public:
+ QEglFSKmsGbmCursorDeviceListener(QEglFSKmsGbmCursor *cursor) : m_cursor(cursor) { }
+ bool hasMouse() const;
+
+public slots:
+ void onDeviceListChanged(QInputDeviceManager::DeviceType type);
+
+private:
+ QEglFSKmsGbmCursor *m_cursor;
+};
+
+class QEglFSKmsGbmCursor : public QPlatformCursor
+{
+ Q_OBJECT
+
+public:
+ QEglFSKmsGbmCursor(QEglFSKmsGbmScreen *screen);
+ ~QEglFSKmsGbmCursor();
+
+ // input methods
+ void pointerEvent(const QMouseEvent & event) override;
+#ifndef QT_NO_CURSOR
+ void changeCursor(QCursor * windowCursor, QWindow * window) override;
+#endif
+ QPoint pos() const override;
+ void setPos(const QPoint &pos) override;
+
+ void updateMouseStatus();
+
+ void reevaluateVisibilityForScreens() { setPos(pos()); }
+
+private:
+ void initCursorAtlas();
+
+ enum CursorState {
+ CursorDisabled,
+ CursorPendingHidden,
+ CursorHidden,
+ CursorPendingVisible,
+ CursorVisible
+ };
+
+ QEglFSKmsGbmScreen *m_screen;
+ QSize m_cursorSize;
+ gbm_bo *m_bo;
+ QPoint m_pos;
+ QPlatformCursorImage m_cursorImage;
+ CursorState m_state;
+ QEglFSKmsGbmCursorDeviceListener *m_deviceListener;
+
+ // cursor atlas information
+ struct CursorAtlas {
+ CursorAtlas() : cursorsPerRow(0), cursorWidth(0), cursorHeight(0) { }
+ int cursorsPerRow;
+ int width, height; // width and height of the atlas
+ int cursorWidth, cursorHeight; // width and height of cursors inside the atlas
+ QList<QPoint> hotSpots;
+ QImage image;
+ } m_cursorAtlas;
+};
+
+QT_END_NAMESPACE
+
+#endif // QEGLFSKMSGBMCURSOR_H
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice.cpp
index 503419cf91..89479fc250 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice.cpp
@@ -1,48 +1,12 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2016 Pelagicore AG
-** 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 "qeglfskmsgbmdevice.h"
-#include "qeglfskmsgbmscreen.h"
-
-#include "qeglfsintegration_p.h"
+// Copyright (C) 2015 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2016 Pelagicore AG
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qeglfskmsgbmdevice_p.h"
+#include "qeglfskmsgbmscreen_p.h"
+
+#include <private/qeglfsintegration_p.h>
#include <QtCore/QLoggingCategory>
#include <QtCore/private/qcore_unix_p.h>
@@ -83,7 +47,13 @@ bool QEglFSKmsGbmDevice::open()
setFd(fd);
- m_eventReader.create(this);
+ if (usesEventReader()) {
+ qCDebug(qLcEglfsKmsDebug, "Using dedicated drm event reading thread");
+ m_eventReader.create(this);
+ } else {
+ qCDebug(qLcEglfsKmsDebug, "Not using dedicated drm event reading thread; "
+ "threaded multi-screen setups may experience problems");
+ }
return true;
}
@@ -92,7 +62,8 @@ void QEglFSKmsGbmDevice::close()
{
// Note: screens are gone at this stage.
- m_eventReader.destroy();
+ if (usesEventReader())
+ m_eventReader.destroy();
if (m_gbm_device) {
gbm_device_destroy(m_gbm_device);
@@ -131,14 +102,19 @@ void QEglFSKmsGbmDevice::destroyGlobalCursor()
}
}
-QPlatformScreen *QEglFSKmsGbmDevice::createScreen(const QKmsOutput &output)
+void QEglFSKmsGbmDevice::createGlobalCursor(QEglFSKmsGbmScreen *screen)
{
- QEglFSKmsGbmScreen *screen = new QEglFSKmsGbmScreen(this, output, false);
-
if (!m_globalCursor && screenConfig()->hwCursor()) {
qCDebug(qLcEglfsKmsDebug, "Creating new global GBM mouse cursor");
m_globalCursor = new QEglFSKmsGbmCursor(screen);
}
+}
+
+QPlatformScreen *QEglFSKmsGbmDevice::createScreen(const QKmsOutput &output)
+{
+ QEglFSKmsGbmScreen *screen = new QEglFSKmsGbmScreen(this, output, false);
+
+ createGlobalCursor(screen);
return screen;
}
@@ -150,7 +126,7 @@ QPlatformScreen *QEglFSKmsGbmDevice::createHeadlessScreen()
void QEglFSKmsGbmDevice::registerScreenCloning(QPlatformScreen *screen,
QPlatformScreen *screenThisScreenClones,
- const QVector<QPlatformScreen *> &screensCloningThisScreen)
+ const QList<QPlatformScreen *> &screensCloningThisScreen)
{
if (!screenThisScreenClones && screensCloningThisScreen.isEmpty())
return;
@@ -169,4 +145,10 @@ void QEglFSKmsGbmDevice::registerScreen(QPlatformScreen *screen,
m_globalCursor->reevaluateVisibilityForScreens();
}
+bool QEglFSKmsGbmDevice::usesEventReader() const
+{
+ static const bool eventReaderThreadDisabled = qEnvironmentVariableIntValue("QT_QPA_EGLFS_KMS_NO_EVENT_READER_THREAD");
+ return !eventReaderThreadDisabled;
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice.h
deleted file mode 100644
index f1476f8ffa..0000000000
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice.h
+++ /dev/null
@@ -1,88 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2016 Pelagicore AG
-** 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 QEGLFSKMSGBMDEVICE_H
-#define QEGLFSKMSGBMDEVICE_H
-
-#include "qeglfskmsgbmcursor.h"
-#include <qeglfskmsdevice.h>
-
-#include <gbm.h>
-
-QT_BEGIN_NAMESPACE
-
-class QEglFSKmsScreen;
-
-class QEglFSKmsGbmDevice: public QEglFSKmsDevice
-{
-public:
- QEglFSKmsGbmDevice(QKmsScreenConfig *screenConfig, const QString &path);
-
- bool open() override;
- void close() override;
-
- void *nativeDisplay() const override;
- gbm_device *gbmDevice() const;
-
- QPlatformCursor *globalCursor() const;
- void destroyGlobalCursor();
-
- QPlatformScreen *createScreen(const QKmsOutput &output) override;
- QPlatformScreen *createHeadlessScreen() override;
- void registerScreenCloning(QPlatformScreen *screen,
- QPlatformScreen *screenThisScreenClones,
- const QVector<QPlatformScreen *> &screensCloningThisScreen) override;
- void registerScreen(QPlatformScreen *screen,
- bool isPrimary,
- const QPoint &virtualPos,
- const QList<QPlatformScreen *> &virtualSiblings) override;
-
-private:
- Q_DISABLE_COPY(QEglFSKmsGbmDevice)
-
- gbm_device *m_gbm_device;
-
- QEglFSKmsGbmCursor *m_globalCursor;
-};
-
-QT_END_NAMESPACE
-
-#endif // QEGLFSKMSGBMDEVICE_H
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice_p.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice_p.h
new file mode 100644
index 0000000000..e00992ed29
--- /dev/null
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice_p.h
@@ -0,0 +1,68 @@
+// Copyright (C) 2015 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2016 Pelagicore AG
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QEGLFSKMSGBMDEVICE_H
+#define QEGLFSKMSGBMDEVICE_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 "qeglfskmsgbmcursor_p.h"
+#include <private/qeglfskmsdevice_p.h>
+#include <private/qeglfskmseventreader_p.h>
+
+#include <gbm.h>
+
+QT_BEGIN_NAMESPACE
+
+class QEglFSKmsScreen;
+
+class Q_EGLFS_EXPORT QEglFSKmsGbmDevice: public QEglFSKmsDevice
+{
+public:
+ QEglFSKmsGbmDevice(QKmsScreenConfig *screenConfig, const QString &path);
+
+ bool open() override;
+ void close() override;
+
+ void *nativeDisplay() const override;
+ gbm_device *gbmDevice() const;
+
+ QPlatformCursor *globalCursor() const;
+ void destroyGlobalCursor();
+ void createGlobalCursor(QEglFSKmsGbmScreen *screen);
+
+ QPlatformScreen *createScreen(const QKmsOutput &output) override;
+ QPlatformScreen *createHeadlessScreen() override;
+ void registerScreenCloning(QPlatformScreen *screen,
+ QPlatformScreen *screenThisScreenClones,
+ const QList<QPlatformScreen *> &screensCloningThisScreen) override;
+ void registerScreen(QPlatformScreen *screen,
+ bool isPrimary,
+ const QPoint &virtualPos,
+ const QList<QPlatformScreen *> &virtualSiblings) override;
+
+ bool usesEventReader() const;
+ QEglFSKmsEventReader *eventReader() { return &m_eventReader; }
+
+private:
+ Q_DISABLE_COPY(QEglFSKmsGbmDevice)
+
+ gbm_device *m_gbm_device;
+ QEglFSKmsEventReader m_eventReader;
+ QEglFSKmsGbmCursor *m_globalCursor;
+};
+
+QT_END_NAMESPACE
+
+#endif // QEGLFSKMSGBMDEVICE_H
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmintegration.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmintegration.cpp
index caa1187b40..05ffb3b212 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmintegration.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmintegration.cpp
@@ -1,49 +1,13 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2016 Pelagicore AG
-** 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 "qeglfskmsgbmintegration.h"
-#include "qeglfskmsgbmdevice.h"
-#include "qeglfskmsgbmscreen.h"
-#include "qeglfskmsgbmcursor.h"
-#include "qeglfskmsgbmwindow.h"
+// Copyright (C) 2015 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2016 Pelagicore AG
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qeglfskmsgbmintegration_p.h"
+#include "qeglfskmsgbmdevice_p.h"
+#include "qeglfskmsgbmscreen_p.h"
+#include "qeglfskmsgbmcursor_p.h"
+#include "qeglfskmsgbmwindow_p.h"
#include "private/qeglfscursor_p.h"
#include <QtCore/QLoggingCategory>
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmintegration.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmintegration.h
deleted file mode 100644
index 71f232abf9..0000000000
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmintegration.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2016 Pelagicore AG
-** 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 QEGLFSKMSGBMINTEGRATION_H
-#define QEGLFSKMSGBMINTEGRATION_H
-
-#include "qeglfskmsintegration.h"
-#include <QtCore/QMap>
-#include <QtCore/QVariant>
-
-QT_BEGIN_NAMESPACE
-
-class QEglFSKmsDevice;
-
-class QEglFSKmsGbmIntegration : public QEglFSKmsIntegration
-{
-public:
- QEglFSKmsGbmIntegration();
-
- EGLDisplay createDisplay(EGLNativeDisplayType nativeDisplay) override;
- EGLNativeWindowType createNativeOffscreenWindow(const QSurfaceFormat &format) override;
- void destroyNativeWindow(EGLNativeWindowType window) override;
-
- QPlatformCursor *createCursor(QPlatformScreen *screen) const override;
- void presentBuffer(QPlatformSurface *surface) override;
- QEglFSWindow *createWindow(QWindow *window) const override;
-
-protected:
- QKmsDevice *createDevice() override;
-
-private:
-};
-
-QT_END_NAMESPACE
-
-#endif // QEGLFSKMSGBMINTEGRATION_H
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmintegration_p.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmintegration_p.h
new file mode 100644
index 0000000000..fb118438d2
--- /dev/null
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmintegration_p.h
@@ -0,0 +1,49 @@
+// Copyright (C) 2015 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2016 Pelagicore AG
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QEGLFSKMSGBMINTEGRATION_H
+#define QEGLFSKMSGBMINTEGRATION_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 <private/qeglfskmsintegration_p.h>
+#include <QtCore/QMap>
+#include <QtCore/QVariant>
+
+QT_BEGIN_NAMESPACE
+
+class QEglFSKmsDevice;
+
+class Q_EGLFS_EXPORT QEglFSKmsGbmIntegration : public QEglFSKmsIntegration
+{
+public:
+ QEglFSKmsGbmIntegration();
+
+ EGLDisplay createDisplay(EGLNativeDisplayType nativeDisplay) override;
+ EGLNativeWindowType createNativeOffscreenWindow(const QSurfaceFormat &format) override;
+ void destroyNativeWindow(EGLNativeWindowType window) override;
+
+ QPlatformCursor *createCursor(QPlatformScreen *screen) const override;
+ void presentBuffer(QPlatformSurface *surface) override;
+ QEglFSWindow *createWindow(QWindow *window) const override;
+
+protected:
+ QKmsDevice *createDevice() override;
+
+private:
+};
+
+QT_END_NAMESPACE
+
+#endif // QEGLFSKMSGBMINTEGRATION_H
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmmain.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmmain.cpp
index 945c8b4255..9d6a694f03 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmmain.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmmain.cpp
@@ -1,45 +1,9 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2016 Pelagicore AG
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the qmake spec 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2016 Pelagicore AG
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "private/qeglfsdeviceintegration_p.h"
-#include "qeglfskmsgbmintegration.h"
+#include "qeglfskmsgbmintegration_p.h"
QT_BEGIN_NAMESPACE
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp
index 6f5c3b6953..8dcfed04db 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp
@@ -1,48 +1,12 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Copyright (C) 2015 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
-** Copyright (C) 2016 Pelagicore AG
-** 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 "qeglfskmsgbmscreen.h"
-#include "qeglfskmsgbmdevice.h"
-#include "qeglfskmsgbmcursor.h"
-#include "qeglfsintegration_p.h"
+// Copyright (C) 2017 The Qt Company Ltd.
+// Copyright (C) 2015 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
+// Copyright (C) 2016 Pelagicore AG
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qeglfskmsgbmscreen_p.h"
+#include "qeglfskmsgbmdevice_p.h"
+#include "qeglfskmsgbmcursor_p.h"
+#include <private/qeglfsintegration_p.h>
#include <QtCore/QLoggingCategory>
@@ -56,6 +20,8 @@ QT_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(qLcEglfsKmsDebug)
+QMutex QEglFSKmsGbmScreen::m_nonThreadedFlipMutex;
+
static inline uint32_t drmFormatToGbmFormat(uint32_t drmFormat)
{
Q_ASSERT(DRM_FORMAT_XRGB8888 == GBM_FORMAT_XRGB8888);
@@ -95,8 +61,9 @@ QEglFSKmsGbmScreen::FrameBuffer *QEglFSKmsGbmScreen::framebufferForBufferObject(
uint32_t offsets[4] = { 0 };
uint32_t pixelFormat = gbmFormatToDrmFormat(gbm_bo_get_format(bo));
- QScopedPointer<FrameBuffer> fb(new FrameBuffer);
- qCDebug(qLcEglfsKmsDebug, "Adding FB, size %ux%u, DRM format 0x%x", width, height, pixelFormat);
+ auto fb = std::make_unique<FrameBuffer>();
+ qCDebug(qLcEglfsKmsDebug, "Adding FB, size %ux%u, DRM format 0x%x, stride %u, handle %u",
+ width, height, pixelFormat, strides[0], handles[0]);
int ret = drmModeAddFB2(device()->fd(), width, height, pixelFormat,
handles, strides, offsets, &fb->fb, 0);
@@ -106,8 +73,9 @@ QEglFSKmsGbmScreen::FrameBuffer *QEglFSKmsGbmScreen::framebufferForBufferObject(
return nullptr;
}
- gbm_bo_set_user_data(bo, fb.data(), bufferDestroyedHandler);
- return fb.take();
+ auto res = fb.get();
+ gbm_bo_set_user_data(bo, fb.release(), bufferDestroyedHandler);
+ return res;
}
QEglFSKmsGbmScreen::QEglFSKmsGbmScreen(QEglFSKmsDevice *device, const QKmsOutput &output, bool headless)
@@ -169,36 +137,63 @@ gbm_surface *QEglFSKmsGbmScreen::createSurface(EGLConfig eglConfig)
rawGeometry().width(),
rawGeometry().height(),
native_format,
- GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
+ gbmFlags());
if (m_gbm_surface)
m_output.drm_format = gbmFormatToDrmFormat(native_format);
}
}
+ const uint32_t gbmFormat = drmFormatToGbmFormat(m_output.drm_format);
+
// Fallback for older drivers, and when "format" is explicitly specified
// in the output config. (not guaranteed that the requested format works
// of course, but do what we are told to)
if (!m_gbm_surface) {
- uint32_t gbmFormat = drmFormatToGbmFormat(m_output.drm_format);
if (queryFromEgl)
qCDebug(qLcEglfsKmsDebug, "Could not create surface with EGL_NATIVE_VISUAL_ID, falling back to format %x", gbmFormat);
m_gbm_surface = gbm_surface_create(gbmDevice,
rawGeometry().width(),
rawGeometry().height(),
gbmFormat,
- GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
+ gbmFlags());
+ }
+
+ // Fallback for some drivers, its required to request with modifiers
+ if (!m_gbm_surface) {
+ uint64_t modifier = DRM_FORMAT_MOD_LINEAR;
+
+ m_gbm_surface = gbm_surface_create_with_modifiers(gbmDevice,
+ rawGeometry().width(),
+ rawGeometry().height(),
+ gbmFormat,
+ &modifier, 1);
}
+ // Fail here, as it would fail with the next usage of the GBM surface, which is very unexpected
+ if (!m_gbm_surface)
+ qFatal("Could not create GBM surface!");
}
return m_gbm_surface; // not owned, gets destroyed in QEglFSKmsGbmIntegration::destroyNativeWindow() via QEglFSKmsGbmWindow::invalidateSurface()
}
void QEglFSKmsGbmScreen::resetSurface()
{
+ m_flipPending = false; // not necessarily true but enough to keep bo_next
+ m_gbm_bo_current = nullptr;
m_gbm_surface = nullptr;
+
+ // Leave m_gbm_bo_next untouched. waitForFlip() should
+ // still do its work, when called. Otherwise we end up
+ // in device-is-busy errors if there is a new QWindow
+ // created afterwards. (QTBUG-122663)
+
+ // If not using atomic, will need a new drmModeSetCrtc if a new window
+ // gets created later on (and so there's a new fb).
+ if (!device()->hasAtomicSupport())
+ needsNewModeSetForNextFb = true;
}
void QEglFSKmsGbmScreen::initCloning(QPlatformScreen *screenThisScreenClones,
- const QVector<QPlatformScreen *> &screensCloningThisScreen)
+ const QList<QPlatformScreen *> &screensCloningThisScreen)
{
// clone destinations need to know the clone source
const bool clonesAnother = screenThisScreenClones != nullptr;
@@ -206,8 +201,10 @@ void QEglFSKmsGbmScreen::initCloning(QPlatformScreen *screenThisScreenClones,
qWarning("QEglFSKmsGbmScreen %s cannot be clone source and destination at the same time", qPrintable(name()));
return;
}
- if (clonesAnother)
+ if (clonesAnother) {
m_cloneSource = static_cast<QEglFSKmsGbmScreen *>(screenThisScreenClones);
+ qCDebug(qLcEglfsKmsDebug, "Screen %s clones %s", qPrintable(name()), qPrintable(m_cloneSource->name()));
+ }
// clone sources need to know their additional destinations
for (QPlatformScreen *s : screensCloningThisScreen) {
@@ -222,21 +219,17 @@ void QEglFSKmsGbmScreen::ensureModeSet(uint32_t fb)
QKmsOutput &op(output());
const int fd = device()->fd();
- if (!op.mode_set) {
+ if (!op.mode_set || needsNewModeSetForNextFb) {
op.mode_set = true;
+ needsNewModeSetForNextFb = false;
bool doModeSet = true;
drmModeCrtcPtr currentMode = drmModeGetCrtc(fd, op.crtc_id);
- const bool alreadySet = currentMode && !memcmp(&currentMode->mode, &op.modes[op.mode], sizeof(drmModeModeInfo));
+ const bool alreadySet = currentMode && currentMode->buffer_id == fb && !memcmp(&currentMode->mode, &op.modes[op.mode], sizeof(drmModeModeInfo));
if (currentMode)
drmModeFreeCrtc(currentMode);
- if (alreadySet) {
- static bool alwaysDoSet = qEnvironmentVariableIntValue("QT_QPA_EGLFS_ALWAYS_SET_MODE");
- if (!alwaysDoSet) {
- qCDebug(qLcEglfsKmsDebug, "Mode already set, skipping modesetting for screen %s", qPrintable(name()));
- doModeSet = false;
- }
- }
+ if (alreadySet)
+ doModeSet = false;
if (doModeSet) {
qCDebug(qLcEglfsKmsDebug, "Setting mode for screen %s", qPrintable(name()));
@@ -267,6 +260,29 @@ void QEglFSKmsGbmScreen::ensureModeSet(uint32_t fb)
}
}
+void QEglFSKmsGbmScreen::nonThreadedPageFlipHandler(int fd,
+ unsigned int sequence,
+ unsigned int tv_sec,
+ unsigned int tv_usec,
+ void *user_data)
+{
+ // note that with cloning involved this callback is called also for screens that clone another one
+ Q_UNUSED(fd);
+ QEglFSKmsGbmScreen *screen = static_cast<QEglFSKmsGbmScreen *>(user_data);
+ screen->flipFinished();
+ screen->pageFlipped(sequence, tv_sec, tv_usec);
+}
+
+void QEglFSKmsGbmScreen::waitForFlipWithEventReader(QEglFSKmsGbmScreen *screen)
+{
+ m_flipMutex.lock();
+ QEglFSKmsGbmDevice *dev = static_cast<QEglFSKmsGbmDevice *>(device());
+ dev->eventReader()->startWaitFlip(screen, &m_flipMutex, &m_flipCond);
+ m_flipCond.wait(&m_flipMutex);
+ m_flipMutex.unlock();
+ screen->flipFinished();
+}
+
void QEglFSKmsGbmScreen::waitForFlip()
{
if (m_headless || m_cloneSource)
@@ -276,18 +292,69 @@ void QEglFSKmsGbmScreen::waitForFlip()
if (!m_gbm_bo_next)
return;
- m_flipMutex.lock();
- device()->eventReader()->startWaitFlip(this, &m_flipMutex, &m_flipCond);
- m_flipCond.wait(&m_flipMutex);
- m_flipMutex.unlock();
-
- flipFinished();
+ QEglFSKmsGbmDevice *dev = static_cast<QEglFSKmsGbmDevice *>(device());
+ if (dev->usesEventReader()) {
+ waitForFlipWithEventReader(this);
+ // Now, unlike on the other code path, we need to ensure the
+ // flips have completed for the screens that just scan out
+ // this one's content, because the eventReader's wait is
+ // per-output.
+ for (CloneDestination &d : m_cloneDests) {
+ if (d.screen != this)
+ waitForFlipWithEventReader(d.screen);
+ }
+ } else {
+ QMutexLocker lock(&m_nonThreadedFlipMutex);
+ while (m_gbm_bo_next) {
+ drmEventContext drmEvent;
+ memset(&drmEvent, 0, sizeof(drmEvent));
+ drmEvent.version = 2;
+ drmEvent.vblank_handler = nullptr;
+ drmEvent.page_flip_handler = nonThreadedPageFlipHandler;
+ drmHandleEvent(device()->fd(), &drmEvent);
+ }
+ }
#if QT_CONFIG(drm_atomic)
device()->threadLocalAtomicReset();
#endif
}
+#if QT_CONFIG(drm_atomic)
+static void addAtomicFlip(drmModeAtomicReq *request, const QKmsOutput &output, uint32_t fb)
+{
+ drmModeAtomicAddProperty(request, output.eglfs_plane->id,
+ output.eglfs_plane->framebufferPropertyId, fb);
+
+ drmModeAtomicAddProperty(request, output.eglfs_plane->id,
+ output.eglfs_plane->crtcPropertyId, output.crtc_id);
+
+ drmModeAtomicAddProperty(request, output.eglfs_plane->id,
+ output.eglfs_plane->srcwidthPropertyId, output.size.width() << 16);
+
+ drmModeAtomicAddProperty(request, output.eglfs_plane->id,
+ output.eglfs_plane->srcXPropertyId, 0);
+
+ drmModeAtomicAddProperty(request, output.eglfs_plane->id,
+ output.eglfs_plane->srcYPropertyId, 0);
+
+ drmModeAtomicAddProperty(request, output.eglfs_plane->id,
+ output.eglfs_plane->srcheightPropertyId, output.size.height() << 16);
+
+ drmModeAtomicAddProperty(request, output.eglfs_plane->id,
+ output.eglfs_plane->crtcXPropertyId, 0);
+
+ drmModeAtomicAddProperty(request, output.eglfs_plane->id,
+ output.eglfs_plane->crtcYPropertyId, 0);
+
+ drmModeAtomicAddProperty(request, output.eglfs_plane->id,
+ output.eglfs_plane->crtcwidthPropertyId, output.modes[output.mode].hdisplay);
+
+ drmModeAtomicAddProperty(request, output.eglfs_plane->id,
+ output.eglfs_plane->crtcheightPropertyId, output.modes[output.mode].vdisplay);
+}
+#endif
+
void QEglFSKmsGbmScreen::flip()
{
// For headless screen just return silently. It is not necessarily an error
@@ -307,14 +374,24 @@ void QEglFSKmsGbmScreen::flip()
m_gbm_bo_next = gbm_surface_lock_front_buffer(m_gbm_surface);
if (!m_gbm_bo_next) {
- qWarning("Could not lock GBM surface front buffer!");
+ qWarning("Could not lock GBM surface front buffer for screen %s", qPrintable(name()));
return;
}
+ auto gbmRelease = qScopeGuard([this]{
+ m_flipPending = false;
+ gbm_surface_release_buffer(m_gbm_surface, m_gbm_bo_next);
+ m_gbm_bo_next = nullptr;
+ });
+
FrameBuffer *fb = framebufferForBufferObject(m_gbm_bo_next);
+ if (!fb) {
+ qWarning("FrameBuffer not available. Cannot flip");
+ return;
+ }
ensureModeSet(fb->fb);
- QKmsOutput &op(output());
+ const QKmsOutput &thisOutput(output());
const int fd = device()->fd();
m_flipPending = true;
@@ -322,40 +399,27 @@ void QEglFSKmsGbmScreen::flip()
#if QT_CONFIG(drm_atomic)
drmModeAtomicReq *request = device()->threadLocalAtomicRequest();
if (request) {
- drmModeAtomicAddProperty(request, op.eglfs_plane->id, op.eglfs_plane->framebufferPropertyId, fb->fb);
- drmModeAtomicAddProperty(request, op.eglfs_plane->id, op.eglfs_plane->crtcPropertyId, op.crtc_id);
- drmModeAtomicAddProperty(request, op.eglfs_plane->id, op.eglfs_plane->srcwidthPropertyId,
- op.size.width() << 16);
- drmModeAtomicAddProperty(request, op.eglfs_plane->id, op.eglfs_plane->srcXPropertyId, 0);
- drmModeAtomicAddProperty(request, op.eglfs_plane->id, op.eglfs_plane->srcYPropertyId, 0);
- drmModeAtomicAddProperty(request, op.eglfs_plane->id, op.eglfs_plane->srcheightPropertyId,
- op.size.height() << 16);
- drmModeAtomicAddProperty(request, op.eglfs_plane->id, op.eglfs_plane->crtcXPropertyId, 0);
- drmModeAtomicAddProperty(request, op.eglfs_plane->id, op.eglfs_plane->crtcYPropertyId, 0);
- drmModeAtomicAddProperty(request, op.eglfs_plane->id, op.eglfs_plane->crtcwidthPropertyId,
- m_output.modes[m_output.mode].hdisplay);
- drmModeAtomicAddProperty(request, op.eglfs_plane->id, op.eglfs_plane->crtcheightPropertyId,
- m_output.modes[m_output.mode].vdisplay);
-
+ addAtomicFlip(request, thisOutput, fb->fb);
static int zpos = qEnvironmentVariableIntValue("QT_QPA_EGLFS_KMS_ZPOS");
- if (zpos)
- drmModeAtomicAddProperty(request, op.eglfs_plane->id, op.eglfs_plane->zposPropertyId, zpos);
+ if (zpos) {
+ drmModeAtomicAddProperty(request, thisOutput.eglfs_plane->id,
+ thisOutput.eglfs_plane->zposPropertyId, zpos);
+ }
static uint blendOp = uint(qEnvironmentVariableIntValue("QT_QPA_EGLFS_KMS_BLEND_OP"));
- if (blendOp)
- drmModeAtomicAddProperty(request, op.eglfs_plane->id, op.eglfs_plane->blendOpPropertyId, blendOp);
+ if (blendOp) {
+ drmModeAtomicAddProperty(request, thisOutput.eglfs_plane->id,
+ thisOutput.eglfs_plane->blendOpPropertyId, blendOp);
+ }
}
#endif
} else {
int ret = drmModePageFlip(fd,
- op.crtc_id,
- fb->fb,
- DRM_MODE_PAGE_FLIP_EVENT,
- this);
+ thisOutput.crtc_id,
+ fb->fb,
+ DRM_MODE_PAGE_FLIP_EVENT,
+ this);
if (ret) {
qErrnoWarning("Could not queue DRM page flip on screen %s", qPrintable(name()));
- m_flipPending = false;
- gbm_surface_release_buffer(m_gbm_surface, m_gbm_bo_next);
- m_gbm_bo_next = nullptr;
return;
}
}
@@ -364,34 +428,46 @@ void QEglFSKmsGbmScreen::flip()
if (d.screen != this) {
d.screen->ensureModeSet(fb->fb);
d.cloneFlipPending = true;
+ const QKmsOutput &destOutput(d.screen->output());
if (device()->hasAtomicSupport()) {
#if QT_CONFIG(drm_atomic)
drmModeAtomicReq *request = device()->threadLocalAtomicRequest();
- if (request) {
- drmModeAtomicAddProperty(request, d.screen->output().eglfs_plane->id,
- d.screen->output().eglfs_plane->framebufferPropertyId, fb->fb);
- drmModeAtomicAddProperty(request, d.screen->output().eglfs_plane->id,
- d.screen->output().eglfs_plane->crtcPropertyId, op.crtc_id);
- }
+ if (request)
+ addAtomicFlip(request, destOutput, fb->fb);
+
+ // ### This path is broken. On the other branch we can easily
+ // pass in d.screen as the user_data for drmModePageFlip, but
+ // using one atomic request breaks down here since we get events
+ // with the same user_data passed to drmModeAtomicCommit. Until
+ // this gets reworked (multiple requests?) screen cloning is not
+ // compatible with atomic.
#endif
} else {
int ret = drmModePageFlip(fd,
- d.screen->output().crtc_id,
+ destOutput.crtc_id,
fb->fb,
DRM_MODE_PAGE_FLIP_EVENT,
d.screen);
if (ret) {
- qErrnoWarning("Could not queue DRM page flip for clone screen %s", qPrintable(name()));
+ qErrnoWarning("Could not queue DRM page flip for screen %s (clones screen %s)",
+ qPrintable(d.screen->name()),
+ qPrintable(name()));
d.cloneFlipPending = false;
}
}
}
}
+ if (device()->hasAtomicSupport()) {
#if QT_CONFIG(drm_atomic)
- device()->threadLocalAtomicCommit(this);
+ if (!device()->threadLocalAtomicCommit(this)) {
+ return;
+ }
#endif
+ }
+
+ gbmRelease.dismiss();
}
void QEglFSKmsGbmScreen::flipFinished()
@@ -418,19 +494,23 @@ void QEglFSKmsGbmScreen::cloneDestFlipFinished(QEglFSKmsGbmScreen *cloneDestScre
void QEglFSKmsGbmScreen::updateFlipStatus()
{
- Q_ASSERT(!m_cloneSource);
+ // only for 'real' outputs that own the color buffer, i.e. that are not cloning another one
+ if (m_cloneSource)
+ return;
+ // proceed only if flips for both this and all others that clone this have finished
if (m_flipPending)
return;
- for (const CloneDestination &d : qAsConst(m_cloneDests)) {
+ for (const CloneDestination &d : std::as_const(m_cloneDests)) {
if (d.cloneFlipPending)
return;
}
- if (m_gbm_bo_current)
+ if (m_gbm_bo_current) {
gbm_surface_release_buffer(m_gbm_surface,
m_gbm_bo_current);
+ }
m_gbm_bo_current = m_gbm_bo_next;
m_gbm_bo_next = nullptr;
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.h
deleted file mode 100644
index 69feeee703..0000000000
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.h
+++ /dev/null
@@ -1,106 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2016 Pelagicore AG
-** 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 QEGLFSKMSGBMSCREEN_H
-#define QEGLFSKMSGBMSCREEN_H
-
-#include "qeglfskmsscreen.h"
-#include <QMutex>
-#include <QWaitCondition>
-
-#include <gbm.h>
-
-QT_BEGIN_NAMESPACE
-
-class QEglFSKmsGbmCursor;
-
-class QEglFSKmsGbmScreen : public QEglFSKmsScreen
-{
-public:
- QEglFSKmsGbmScreen(QEglFSKmsDevice *device, const QKmsOutput &output, bool headless);
- ~QEglFSKmsGbmScreen();
-
- QPlatformCursor *cursor() const override;
-
- gbm_surface *createSurface(EGLConfig eglConfig);
- void resetSurface();
-
- void initCloning(QPlatformScreen *screenThisScreenClones,
- const QVector<QPlatformScreen *> &screensCloningThisScreen);
-
- void waitForFlip() override;
-
- void flip();
-
-private:
- void flipFinished();
- void ensureModeSet(uint32_t fb);
- void cloneDestFlipFinished(QEglFSKmsGbmScreen *cloneDestScreen);
- void updateFlipStatus();
-
- gbm_surface *m_gbm_surface;
-
- gbm_bo *m_gbm_bo_current;
- gbm_bo *m_gbm_bo_next;
- bool m_flipPending;
-
- QMutex m_flipMutex;
- QWaitCondition m_flipCond;
-
- QScopedPointer<QEglFSKmsGbmCursor> m_cursor;
-
- struct FrameBuffer {
- uint32_t fb = 0;
- };
- static void bufferDestroyedHandler(gbm_bo *bo, void *data);
- FrameBuffer *framebufferForBufferObject(gbm_bo *bo);
-
- QEglFSKmsGbmScreen *m_cloneSource;
- struct CloneDestination {
- QEglFSKmsGbmScreen *screen = nullptr;
- bool cloneFlipPending = false;
- };
- QVector<CloneDestination> m_cloneDests;
-};
-
-QT_END_NAMESPACE
-
-#endif // QEGLFSKMSGBMSCREEN_H
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen_p.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen_p.h
new file mode 100644
index 0000000000..aca34fcae2
--- /dev/null
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen_p.h
@@ -0,0 +1,92 @@
+// Copyright (C) 2015 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2016 Pelagicore AG
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QEGLFSKMSGBMSCREEN_H
+#define QEGLFSKMSGBMSCREEN_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 <private/qeglfskmsscreen_p.h>
+#include <QMutex>
+#include <QWaitCondition>
+
+#include <gbm.h>
+
+QT_BEGIN_NAMESPACE
+
+class QEglFSKmsGbmCursor;
+
+class Q_EGLFS_EXPORT QEglFSKmsGbmScreen : public QEglFSKmsScreen
+{
+public:
+ QEglFSKmsGbmScreen(QEglFSKmsDevice *device, const QKmsOutput &output, bool headless);
+ ~QEglFSKmsGbmScreen();
+
+ QPlatformCursor *cursor() const override;
+
+ gbm_surface *createSurface(EGLConfig eglConfig);
+ void resetSurface();
+
+ void initCloning(QPlatformScreen *screenThisScreenClones,
+ const QList<QPlatformScreen *> &screensCloningThisScreen);
+
+ void waitForFlip() override;
+
+ virtual void flip();
+ virtual void updateFlipStatus();
+
+ virtual uint32_t gbmFlags() { return GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING; }
+
+protected:
+ void flipFinished();
+ void ensureModeSet(uint32_t fb);
+ void cloneDestFlipFinished(QEglFSKmsGbmScreen *cloneDestScreen);
+ void waitForFlipWithEventReader(QEglFSKmsGbmScreen *screen);
+ static void nonThreadedPageFlipHandler(int fd,
+ unsigned int sequence,
+ unsigned int tv_sec,
+ unsigned int tv_usec,
+ void *user_data);
+
+ gbm_surface *m_gbm_surface;
+
+ gbm_bo *m_gbm_bo_current;
+ gbm_bo *m_gbm_bo_next;
+ bool m_flipPending;
+
+ QMutex m_flipMutex;
+ QWaitCondition m_flipCond;
+ static QMutex m_nonThreadedFlipMutex;
+
+ QScopedPointer<QEglFSKmsGbmCursor> m_cursor;
+
+ struct FrameBuffer {
+ uint32_t fb = 0;
+ };
+ static void bufferDestroyedHandler(gbm_bo *bo, void *data);
+ FrameBuffer *framebufferForBufferObject(gbm_bo *bo);
+
+ QEglFSKmsGbmScreen *m_cloneSource;
+ struct CloneDestination {
+ QEglFSKmsGbmScreen *screen = nullptr;
+ bool cloneFlipPending = false;
+ };
+ QList<CloneDestination> m_cloneDests;
+
+ bool needsNewModeSetForNextFb = false;
+};
+
+QT_END_NAMESPACE
+
+#endif // QEGLFSKMSGBMSCREEN_H
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmwindow.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmwindow.cpp
index a93762e5b4..f2e23061be 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmwindow.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmwindow.cpp
@@ -1,47 +1,11 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#include "qeglfskmsgbmwindow.h"
-#include "qeglfskmsgbmintegration.h"
-#include "qeglfskmsgbmscreen.h"
+#include "qeglfskmsgbmwindow_p.h"
+#include "qeglfskmsgbmintegration_p.h"
+#include "qeglfskmsgbmscreen_p.h"
-#include <QtEglSupport/private/qeglconvenience_p.h>
+#include <QtGui/private/qeglconvenience_p.h>
QT_BEGIN_NAMESPACE
@@ -67,7 +31,21 @@ void QEglFSKmsGbmWindow::resetSurface()
}
if (createPlatformWindowSurface) {
- m_surface = createPlatformWindowSurface(display, m_config, reinterpret_cast<void *>(m_window), nullptr);
+ QVector<EGLint> contextAttributes;
+#ifdef EGL_EXT_protected_content
+ if (platformFormat.testOption(QSurfaceFormat::ProtectedContent)) {
+ if (q_hasEglExtension(display, "EGL_EXT_protected_content")) {
+ contextAttributes.append(EGL_PROTECTED_CONTENT_EXT);
+ contextAttributes.append(EGL_TRUE);
+ qCDebug(qLcEglfsKmsDebug, "Enabled EGL_PROTECTED_CONTENT_EXT for eglCreatePlatformWindowSurfaceEXT");
+ } else {
+ m_format.setOption(QSurfaceFormat::ProtectedContent, false);
+ }
+ }
+#endif
+ contextAttributes.append(EGL_NONE);
+
+ m_surface = createPlatformWindowSurface(display, m_config, reinterpret_cast<void *>(m_window), contextAttributes.constData());
} else {
qCDebug(qLcEglfsKmsDebug, "No eglCreatePlatformWindowSurface for GBM, falling back to eglCreateWindowSurface");
m_surface = eglCreateWindowSurface(display, m_config, m_window, nullptr);
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmwindow.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmwindow.h
deleted file mode 100644
index ee4b7978f1..0000000000
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmwindow.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2016 Pelagicore AG
-** 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 QEGLFSKMSGBMWINDOW_H
-#define QEGLFSKMSGBMWINDOW_H
-
-#include "private/qeglfswindow_p.h"
-
-QT_BEGIN_NAMESPACE
-
-class QEglFSKmsGbmIntegration;
-
-class QEglFSKmsGbmWindow : public QEglFSWindow
-{
-public:
- QEglFSKmsGbmWindow(QWindow *w, const QEglFSKmsGbmIntegration *integration)
- : QEglFSWindow(w),
- m_integration(integration)
- { }
-
- ~QEglFSKmsGbmWindow() { destroy(); }
-
- void resetSurface() override;
- void invalidateSurface() override;
-
-private:
- const QEglFSKmsGbmIntegration *m_integration;
-};
-
-QT_END_NAMESPACE
-
-#endif // QEGLFSKMSGBMWINDOW_H
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmwindow_p.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmwindow_p.h
new file mode 100644
index 0000000000..2d225b0314
--- /dev/null
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmwindow_p.h
@@ -0,0 +1,45 @@
+// Copyright (C) 2015 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2016 Pelagicore AG
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QEGLFSKMSGBMWINDOW_H
+#define QEGLFSKMSGBMWINDOW_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 "private/qeglfswindow_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QEglFSKmsGbmIntegration;
+
+class Q_EGLFS_EXPORT QEglFSKmsGbmWindow : public QEglFSWindow
+{
+public:
+ QEglFSKmsGbmWindow(QWindow *w, const QEglFSKmsGbmIntegration *integration)
+ : QEglFSWindow(w),
+ m_integration(integration)
+ { }
+
+ ~QEglFSKmsGbmWindow() { destroy(); }
+
+ void resetSurface() override;
+ void invalidateSurface() override;
+
+private:
+ const QEglFSKmsGbmIntegration *m_integration;
+};
+
+QT_END_NAMESPACE
+
+#endif // QEGLFSKMSGBMWINDOW_H
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 a0b405c90c..3c3e5a8a6c 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/CMakeLists.txt
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/CMakeLists.txt
@@ -1,12 +1,13 @@
-# Generated from eglfs_kms_egldevice.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## QEglFSKmsEglDeviceIntegrationPlugin Plugin:
#####################################################################
-qt_add_plugin(QEglFSKmsEglDeviceIntegrationPlugin
+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,20 +15,13 @@ qt_add_plugin(QEglFSKmsEglDeviceIntegrationPlugin
qeglfskmsegldevicescreen.cpp qeglfskmsegldevicescreen.h
DEFINES
QT_EGL_NO_X11
- INCLUDE_DIRECTORIES
- ../../api
- ../eglfs_kms_support
- PUBLIC_LIBRARIES
+ LIBRARIES
Libdrm::Libdrm
Qt::Core
Qt::CorePrivate
- Qt::EdidSupportPrivate
Qt::EglFSDeviceIntegrationPrivate
Qt::EglFsKmsSupportPrivate
Qt::Gui
Qt::GuiPrivate
Qt::KmsSupportPrivate
)
-
-#### Keys ignored in scope 1:.:.:eglfs_kms_egldevice.pro:<TRUE>:
-# OTHER_FILES = "$$PWD/eglfs_kms_egldevice.json"
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/eglfs_kms_egldevice.pro b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/eglfs_kms_egldevice.pro
deleted file mode 100644
index a6145c07e6..0000000000
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/eglfs_kms_egldevice.pro
+++ /dev/null
@@ -1,26 +0,0 @@
-TARGET = qeglfs-kms-egldevice-integration
-
-QT += core-private gui-private eglfsdeviceintegration-private eglfs_kms_support-private kms_support-private edid_support-private
-
-INCLUDEPATH += $$PWD/../../api $$PWD/../eglfs_kms_support
-
-# Avoid X11 header collision, use generic EGL native types
-DEFINES += QT_EGL_NO_X11
-
-QMAKE_USE += drm
-CONFIG += egl
-
-SOURCES += $$PWD/qeglfskmsegldevicemain.cpp \
- $$PWD/qeglfskmsegldeviceintegration.cpp \
- qeglfskmsegldevice.cpp \
- qeglfskmsegldevicescreen.cpp
-
-HEADERS += $$PWD/qeglfskmsegldeviceintegration.h \
- qeglfskmsegldevice.h \
- qeglfskmsegldevicescreen.h
-
-OTHER_FILES += $$PWD/eglfs_kms_egldevice.json
-
-PLUGIN_TYPE = egldeviceintegrations
-PLUGIN_CLASS_NAME = QEglFSKmsEglDeviceIntegrationPlugin
-load(qt_plugin)
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevice.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevice.cpp
index 8c8e6260f1..3e2c93d8e5 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevice.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevice.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Pelagicore AG
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 Pelagicore AG
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qeglfskmsegldevice.h"
#include "qeglfskmsegldevicescreen.h"
@@ -58,7 +22,12 @@ bool QEglFSKmsEglDevice::open()
{
Q_ASSERT(fd() == -1);
- int fd = drmOpen(devicePath().toLocal8Bit().constData(), nullptr);
+ int fd = -1;
+
+ if (devicePath().compare("drm-nvdc") == 0)
+ fd = drmOpen(devicePath().toLocal8Bit().constData(), nullptr);
+ else
+ fd = qt_safe_open(devicePath().toLocal8Bit().constData(), O_RDWR);
if (Q_UNLIKELY(fd < 0))
qFatal("Could not open DRM (NV) device");
@@ -71,7 +40,7 @@ void QEglFSKmsEglDevice::close()
{
// Note: screens are gone at this stage.
- if (qt_safe_close(fd()) == -1)
+ if (drmClose(fd()) == -1)
qErrnoWarning("Could not close DRM (NV) device");
setFd(-1);
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevice.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevice.h
index 8d469879ab..824cae0906 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevice.h
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevice.h
@@ -1,46 +1,10 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Pelagicore AG
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 Pelagicore AG
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QEGLFSKMSEGLDEVICE_H
#define QEGLFSKMSEGLDEVICE_H
-#include <qeglfskmsdevice.h>
+#include <private/qeglfskmsdevice_p.h>
QT_BEGIN_NAMESPACE
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.cpp
index 3e78196227..a213bc9bba 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.cpp
@@ -1,47 +1,11 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2016 Pelagicore AG
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2016 Pelagicore AG
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qeglfskmsegldeviceintegration.h"
#include "qeglfskmsegldevice.h"
#include "qeglfskmsegldevicescreen.h"
-#include <QtEglSupport/private/qeglconvenience_p.h>
+#include <QtGui/private/qeglconvenience_p.h>
#include "private/qeglfswindow_p.h"
#include "private/qeglfscursor_p.h"
#include <QLoggingCategory>
@@ -74,8 +38,11 @@ EGLDisplay QEglFSKmsEglDeviceIntegration::createDisplay(EGLNativeDisplayType nat
EGLDisplay display;
+ EGLint egldevice_fd = device()->fd();
+
+ const EGLint attribs[] = { EGL_DRM_MASTER_FD_EXT, egldevice_fd, EGL_NONE };
if (m_funcs->has_egl_platform_device) {
- display = m_funcs->get_platform_display(EGL_PLATFORM_DEVICE_EXT, nativeDisplay, nullptr);
+ display = m_funcs->get_platform_display(EGL_PLATFORM_DEVICE_EXT, nativeDisplay, attribs);
} else {
qWarning("EGL_EXT_platform_device not available, falling back to legacy path!");
display = eglGetDisplay(nativeDisplay);
@@ -171,7 +138,7 @@ void QEglFSKmsEglDeviceWindow::resetSurface()
qCDebug(qLcEglfsKmsDebug, "Output has %d layers", count);
- QVector<EGLOutputLayerEXT> layers;
+ QList<EGLOutputLayerEXT> layers;
layers.resize(count);
EGLint actualCount;
if (!m_integration->m_funcs->get_output_layers(display, nullptr, layers.data(), count, &actualCount)) {
@@ -204,7 +171,7 @@ void QEglFSKmsEglDeviceWindow::resetSurface()
QByteArray reqLayerIndex = qgetenv("QT_QPA_EGLFS_LAYER_INDEX");
if (!reqLayerIndex.isEmpty()) {
int idx = reqLayerIndex.toInt();
- if (idx >= 0 && idx < layers.count()) {
+ if (idx >= 0 && idx < layers.size()) {
qCDebug(qLcEglfsKmsDebug, "EGLOutput layer index override = %d", idx);
layer = layers[idx];
}
@@ -262,7 +229,7 @@ QKmsDevice *QEglFSKmsEglDeviceIntegration::createDevice()
if (Q_UNLIKELY(!deviceName))
qFatal("Failed to query device name from EGLDevice");
- return new QEglFSKmsEglDevice(this, screenConfig(), QLatin1String(deviceName));
+ return new QEglFSKmsEglDevice(this, screenConfig(), QLatin1StringView(deviceName));
}
bool QEglFSKmsEglDeviceIntegration::query_egl_device()
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.h
index 5819d82ebf..4c4bdc5f1b 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.h
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.h
@@ -1,52 +1,16 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2016 Pelagicore AG
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2016 Pelagicore AG
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QEGLFSKMSEGLDEVICEINTEGRATION_H
#define QEGLFSKMSEGLDEVICEINTEGRATION_H
-#include <qeglfskmsintegration.h>
+#include <private/qeglfskmsintegration_p.h>
#include <xf86drm.h>
#include <xf86drmMode.h>
-#include <QtEglSupport/private/qeglstreamconvenience_p.h>
+#include <QtGui/private/qeglstreamconvenience_p.h>
QT_BEGIN_NAMESPACE
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicemain.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicemain.cpp
index 5763ab45cc..c8c5bb789e 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicemain.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicemain.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the qmake spec 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qeglfskmsegldeviceintegration.h"
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicescreen.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicescreen.cpp
index 5a62e437c4..3fc46cd224 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicescreen.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicescreen.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Pelagicore AG
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 Pelagicore AG
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qeglfskmsegldevicescreen.h"
#include "qeglfskmsegldevice.h"
@@ -49,12 +13,63 @@ Q_DECLARE_LOGGING_CATEGORY(qLcEglfsKmsDebug)
QEglFSKmsEglDeviceScreen::QEglFSKmsEglDeviceScreen(QEglFSKmsDevice *device, const QKmsOutput &output)
: QEglFSKmsScreen(device, output)
+ , m_default_fb_handle(uint32_t(-1))
+ , m_default_fb_id(uint32_t(-1))
{
+ const int fd = device->fd();
+
+ struct drm_mode_create_dumb createRequest;
+ createRequest.width = output.size.width();
+ createRequest.height = output.size.height();
+ createRequest.bpp = 32;
+ createRequest.flags = 0;
+
+ qCDebug(qLcEglfsKmsDebug, "Creating dumb fb %dx%d", createRequest.width, createRequest.height);
+
+ int ret = drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &createRequest);
+ if (ret < 0)
+ qFatal("Unable to create dumb buffer.\n");
+
+ m_default_fb_handle = createRequest.handle;
+
+ uint32_t handles[4] = { 0, 0, 0, 0 };
+ uint32_t pitches[4] = { 0, 0, 0, 0 };
+ uint32_t offsets[4] = { 0, 0, 0, 0 };
+
+ handles[0] = createRequest.handle;
+ pitches[0] = createRequest.pitch;
+ offsets[0] = 0;
+
+ ret = drmModeAddFB2(fd, createRequest.width, createRequest.height, DRM_FORMAT_ARGB8888, handles,
+ pitches, offsets, &m_default_fb_id, 0);
+ if (ret)
+ qFatal("Unable to add fb\n");
+
+ qCDebug(qLcEglfsKmsDebug, "Added dumb fb %dx%d handle:%u pitch:%d id:%u", createRequest.width, createRequest.height,
+ createRequest.handle, createRequest.pitch, m_default_fb_id);
}
QEglFSKmsEglDeviceScreen::~QEglFSKmsEglDeviceScreen()
{
- const int remainingScreenCount = qGuiApp->screens().count();
+ int ret;
+ const int fd = device()->fd();
+
+ if (m_default_fb_id != uint32_t(-1)) {
+ ret = drmModeRmFB(fd, m_default_fb_id);
+ if (ret)
+ qErrnoWarning("drmModeRmFB failed");
+ }
+
+ if (m_default_fb_handle != uint32_t(-1)) {
+ struct drm_mode_destroy_dumb destroyRequest;
+ destroyRequest.handle = m_default_fb_handle;
+
+ ret = drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroyRequest);
+ if (ret)
+ qErrnoWarning("DRM_IOCTL_MODE_DESTROY_DUMB failed");
+ }
+
+ const int remainingScreenCount = qGuiApp->screens().size();
qCDebug(qLcEglfsKmsDebug, "Screen dtor. Remaining screens: %d", remainingScreenCount);
if (!remainingScreenCount && !device()->screenConfig()->separateScreens())
static_cast<QEglFSKmsEglDevice *>(device())->destroyGlobalCursor();
@@ -89,8 +104,11 @@ void QEglFSKmsEglDeviceScreen::waitForFlip()
if (alreadySet) {
// Maybe detecting the DPMS mode could help here, but there are no properties
// exposed on the connector apparently. So rely on an env var for now.
- static bool alwaysDoSet = qEnvironmentVariableIntValue("QT_QPA_EGLFS_ALWAYS_SET_MODE");
- if (!alwaysDoSet) {
+ // Note that typically, we need to set crtc with the default fb even if the
+ // mode did not change, unless QT_QPA_EGLFS_ALWAYS_SET_MODE is explicitly specified.
+ static bool envVarSet = false;
+ static bool alwaysDoSet = qEnvironmentVariableIntValue("QT_QPA_EGLFS_ALWAYS_SET_MODE", &envVarSet);
+ if (envVarSet && !alwaysDoSet) {
qCDebug(qLcEglfsKmsDebug, "Mode already set");
return;
}
@@ -98,7 +116,7 @@ void QEglFSKmsEglDeviceScreen::waitForFlip()
qCDebug(qLcEglfsKmsDebug, "Setting mode");
int ret = drmModeSetCrtc(fd, op.crtc_id,
- uint32_t(-1), 0, 0,
+ m_default_fb_id, 0, 0,
&op.connector_id, 1,
&op.modes[op.mode]);
if (ret)
@@ -110,7 +128,7 @@ void QEglFSKmsEglDeviceScreen::waitForFlip()
if (op.wants_forced_plane) {
qCDebug(qLcEglfsKmsDebug, "Setting plane %u", op.forced_plane_id);
- int ret = drmModeSetPlane(fd, op.forced_plane_id, op.crtc_id, uint32_t(-1), 0,
+ int ret = drmModeSetPlane(fd, op.forced_plane_id, op.crtc_id, m_default_fb_id, 0,
0, 0, w, h,
0 << 16, 0 << 16, op.size.width() << 16, op.size.height() << 16);
if (ret == -1)
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicescreen.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicescreen.h
index 961398ba3e..8779499bef 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicescreen.h
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicescreen.h
@@ -1,46 +1,10 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Pelagicore AG
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 Pelagicore AG
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QEGLFSKMSEGLDEVICESCREEN_H
#define QEGLFSKMSEGLDEVICESCREEN_H
-#include <qeglfskmsscreen.h>
+#include <private/qeglfskmsscreen_p.h>
QT_BEGIN_NAMESPACE
@@ -53,6 +17,9 @@ public:
QPlatformCursor *cursor() const override;
void waitForFlip() override;
+private:
+ uint32_t m_default_fb_handle;
+ uint32_t m_default_fb_id;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/CMakeLists.txt b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/CMakeLists.txt
index abaad3930d..5fcc0e1b18 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/CMakeLists.txt
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/CMakeLists.txt
@@ -1,29 +1,28 @@
-# Generated from eglfs_kms_support.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
-## EglFsKmsSupport Module:
+## EglFsKmsSupportPrivate Module:
#####################################################################
-qt_add_module(EglFsKmsSupport
+qt_internal_add_module(EglFsKmsSupportPrivate
+ CONFIG_MODULE_NAME eglfs_kms_support
INTERNAL_MODULE
- NO_MODULE_HEADERS
SOURCES
- qeglfskmsdevice.cpp qeglfskmsdevice.h
- qeglfskmseventreader.cpp qeglfskmseventreader.h
- qeglfskmshelpers.h
- qeglfskmsintegration.cpp qeglfskmsintegration.h
- qeglfskmsscreen.cpp qeglfskmsscreen.h
+ qeglfskmsdevice.cpp qeglfskmsdevice_p.h
+ qeglfskmseventreader.cpp qeglfskmseventreader_p.h
+ qeglfskmshelpers_p.h
+ qeglfskmsintegration.cpp qeglfskmsintegration_p.h
+ qeglfskmsscreen.cpp qeglfskmsscreen_p.h
DEFINES
QT_EGL_NO_X11
- INCLUDE_DIRECTORIES
- ../../api
PUBLIC_LIBRARIES
Libdrm::Libdrm
Qt::Core
Qt::CorePrivate
- Qt::EdidSupportPrivate
Qt::EglFSDeviceIntegrationPrivate
Qt::Gui
Qt::GuiPrivate
Qt::KmsSupportPrivate
+ NO_GENERATE_CPP_EXPORTS
)
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/eglfs_kms_support.pro b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/eglfs_kms_support.pro
deleted file mode 100644
index e51903ed96..0000000000
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/eglfs_kms_support.pro
+++ /dev/null
@@ -1,24 +0,0 @@
-TARGET = QtEglFsKmsSupport
-CONFIG += no_module_headers internal_module
-load(qt_module)
-
-QT += core-private gui-private eglfsdeviceintegration-private kms_support-private edid_support-private
-
-INCLUDEPATH += $$PWD/../../api
-
-# Avoid X11 header collision, use generic EGL native types
-DEFINES += QT_EGL_NO_X11
-
-QMAKE_USE += drm
-CONFIG += egl
-
-SOURCES += $$PWD/qeglfskmsintegration.cpp \
- $$PWD/qeglfskmsdevice.cpp \
- $$PWD/qeglfskmsscreen.cpp \
- $$PWD/qeglfskmseventreader.cpp
-
-HEADERS += $$PWD/qeglfskmsintegration.h \
- $$PWD/qeglfskmsdevice.h \
- $$PWD/qeglfskmsscreen.h \
- $$PWD/qeglfskmshelpers.h \
- $$PWD/qeglfskmseventreader.h
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice.cpp
index 4f0b0d7725..037b26f023 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice.cpp
@@ -1,45 +1,9 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2016 Pelagicore AG
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2016 Pelagicore AG
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#include "qeglfskmsdevice.h"
-#include "qeglfskmsscreen.h"
+#include "qeglfskmsdevice_p.h"
+#include "qeglfskmsscreen_p.h"
#include "private/qeglfsintegration_p.h"
#include <QtGui/private/qguiapplication_p.h>
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice.h
deleted file mode 100644
index 34908aa60f..0000000000
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2016 Pelagicore AG
-** 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 QEGLFSKMSDEVICE_H
-#define QEGLFSKMSDEVICE_H
-
-#include "private/qeglfsglobal_p.h"
-#include "qeglfskmseventreader.h"
-#include <QtKmsSupport/private/qkmsdevice_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class Q_EGLFS_EXPORT QEglFSKmsDevice : public QKmsDevice
-{
-public:
- QEglFSKmsDevice(QKmsScreenConfig *screenConfig, const QString &path);
-
- void registerScreen(QPlatformScreen *screen,
- bool isPrimary,
- const QPoint &virtualPos,
- const QList<QPlatformScreen *> &virtualSiblings) override;
-
- QEglFSKmsEventReader *eventReader() { return &m_eventReader; }
-
-protected:
- QEglFSKmsEventReader m_eventReader;
-};
-
-QT_END_NAMESPACE
-
-#endif // QEGLFSKMSDEVICE_H
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice_p.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice_p.h
new file mode 100644
index 0000000000..6e11953a69
--- /dev/null
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice_p.h
@@ -0,0 +1,37 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2016 Pelagicore AG
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QEGLFSKMSDEVICE_H
+#define QEGLFSKMSDEVICE_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 "private/qeglfsglobal_p.h"
+#include <QtKmsSupport/private/qkmsdevice_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_EGLFS_EXPORT QEglFSKmsDevice : public QKmsDevice
+{
+public:
+ QEglFSKmsDevice(QKmsScreenConfig *screenConfig, const QString &path);
+
+ void registerScreen(QPlatformScreen *screen,
+ bool isPrimary,
+ const QPoint &virtualPos,
+ const QList<QPlatformScreen *> &virtualSiblings) override;
+};
+
+QT_END_NAMESPACE
+
+#endif // QEGLFSKMSDEVICE_H
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmseventreader.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmseventreader.cpp
index 645a0ae2e9..96cdcd8947 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmseventreader.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmseventreader.cpp
@@ -1,44 +1,9 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 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 "qeglfskmseventreader.h"
-#include "qeglfskmsdevice.h"
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qeglfskmseventreader_p.h"
+#include "qeglfskmsdevice_p.h"
+#include "qeglfskmsscreen_p.h"
#include <QSocketNotifier>
#include <QCoreApplication>
#include <QLoggingCategory>
@@ -50,12 +15,12 @@ Q_DECLARE_LOGGING_CATEGORY(qLcEglfsKmsDebug)
static void pageFlipHandler(int fd, unsigned int sequence, unsigned int tv_sec, unsigned int tv_usec, void *user_data)
{
Q_UNUSED(fd);
- Q_UNUSED(sequence);
- Q_UNUSED(tv_sec);
- Q_UNUSED(tv_usec);
QEglFSKmsEventReaderThread *t = static_cast<QEglFSKmsEventReaderThread *>(QThread::currentThread());
t->eventHost()->handlePageFlipCompleted(user_data);
+
+ QEglFSKmsScreen *screen = static_cast<QEglFSKmsScreen *>(user_data);
+ screen->pageFlipped(sequence, tv_sec, tv_usec);
}
class RegisterWaitFlipEvent : public QEvent
@@ -179,7 +144,7 @@ void QEglFSKmsEventReader::create(QEglFSKmsDevice *device)
m_device = device;
- qCDebug(qLcEglfsKmsDebug, "Initalizing event reader for device %p fd %d",
+ qCDebug(qLcEglfsKmsDebug, "Initializing event reader for device %p fd %d",
m_device, m_device->fd());
m_thread = new QEglFSKmsEventReaderThread(m_device->fd());
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmseventreader.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmseventreader.h
deleted file mode 100644
index 4aa285b0fe..0000000000
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmseventreader.h
+++ /dev/null
@@ -1,99 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 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 QEGLFSKKMSEVENTREADER_H
-#define QEGLFSKKMSEVENTREADER_H
-
-#include "private/qeglfsglobal_p.h"
-#include <QObject>
-#include <QThread>
-#include <QMutex>
-#include <QWaitCondition>
-
-QT_BEGIN_NAMESPACE
-
-class QEglFSKmsDevice;
-
-struct QEglFSKmsEventHost : public QObject
-{
- struct PendingFlipWait {
- void *key;
- QMutex *mutex;
- QWaitCondition *cond;
- };
-
- static const int MAX_FLIPS = 32;
- void *completedFlips[MAX_FLIPS] = {};
- QEglFSKmsEventHost::PendingFlipWait pendingFlipWaits[MAX_FLIPS] = {};
-
- bool event(QEvent *event) override;
- void updateStatus();
- void handlePageFlipCompleted(void *key);
-};
-
-class QEglFSKmsEventReaderThread : public QThread
-{
-public:
- QEglFSKmsEventReaderThread(int fd) : m_fd(fd) { }
- void run() override;
- QEglFSKmsEventHost *eventHost() { return &m_ev; }
-
-private:
- int m_fd;
- QEglFSKmsEventHost m_ev;
-};
-
-class Q_EGLFS_EXPORT QEglFSKmsEventReader
-{
-public:
- ~QEglFSKmsEventReader();
-
- void create(QEglFSKmsDevice *device);
- void destroy();
-
- void startWaitFlip(void *key, QMutex *mutex, QWaitCondition *cond);
-
-private:
- QEglFSKmsDevice *m_device = nullptr;
- QEglFSKmsEventReaderThread *m_thread = nullptr;
-};
-
-QT_END_NAMESPACE
-
-#endif // QEGLFSKKMSEVENTREADER_H
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmseventreader_p.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmseventreader_p.h
new file mode 100644
index 0000000000..295e5c4407
--- /dev/null
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmseventreader_p.h
@@ -0,0 +1,74 @@
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QEGLFSKKMSEVENTREADER_H
+#define QEGLFSKKMSEVENTREADER_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 "private/qeglfsglobal_p.h"
+#include <QObject>
+#include <QThread>
+#include <QMutex>
+#include <QWaitCondition>
+
+QT_BEGIN_NAMESPACE
+
+class QEglFSKmsDevice;
+
+struct QEglFSKmsEventHost : public QObject
+{
+ struct PendingFlipWait {
+ void *key;
+ QMutex *mutex;
+ QWaitCondition *cond;
+ };
+
+ static const int MAX_FLIPS = 32;
+ void *completedFlips[MAX_FLIPS] = {};
+ QEglFSKmsEventHost::PendingFlipWait pendingFlipWaits[MAX_FLIPS] = {};
+
+ bool event(QEvent *event) override;
+ void updateStatus();
+ void handlePageFlipCompleted(void *key);
+};
+
+class QEglFSKmsEventReaderThread : public QThread
+{
+public:
+ QEglFSKmsEventReaderThread(int fd) : m_fd(fd) { }
+ void run() override;
+ QEglFSKmsEventHost *eventHost() { return &m_ev; }
+
+private:
+ int m_fd;
+ QEglFSKmsEventHost m_ev;
+};
+
+class Q_EGLFS_EXPORT QEglFSKmsEventReader
+{
+public:
+ ~QEglFSKmsEventReader();
+
+ void create(QEglFSKmsDevice *device);
+ void destroy();
+
+ void startWaitFlip(void *key, QMutex *mutex, QWaitCondition *cond);
+
+private:
+ QEglFSKmsDevice *m_device = nullptr;
+ QEglFSKmsEventReaderThread *m_thread = nullptr;
+};
+
+QT_END_NAMESPACE
+
+#endif // QEGLFSKKMSEVENTREADER_H
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmshelpers.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmshelpers.h
deleted file mode 100644
index c9e5f04a7b..0000000000
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmshelpers.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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 QEGLFSKMSHELPERS_H
-#define QEGLFSKMSHELPERS_H
-
-#include <QString>
-
-QT_BEGIN_NAMESPACE
-
-inline QString q_fourccToString(uint code)
-{
- QString s;
- s.reserve(4);
- s.append(code & 0xff);
- s.append((code >> 8) & 0xff);
- s.append((code >> 16) & 0xff);
- s.append((code >> 24) & 0xff);
- return s;
-}
-
-QT_END_NAMESPACE
-
-#endif // QEGLFSKMSHELPERS_H
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmshelpers_p.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmshelpers_p.h
new file mode 100644
index 0000000000..5f9935e93b
--- /dev/null
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmshelpers_p.h
@@ -0,0 +1,35 @@
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QEGLFSKMSHELPERS_H
+#define QEGLFSKMSHELPERS_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 <QString>
+
+QT_BEGIN_NAMESPACE
+
+inline QString q_fourccToString(uint code)
+{
+ QString s;
+ s.reserve(4);
+ s.append(code & 0xff);
+ s.append((code >> 8) & 0xff);
+ s.append((code >> 16) & 0xff);
+ s.append((code >> 24) & 0xff);
+ return s;
+}
+
+QT_END_NAMESPACE
+
+#endif // QEGLFSKMSHELPERS_H
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsintegration.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsintegration.cpp
index 28b6b7df63..26420b441f 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsintegration.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsintegration.cpp
@@ -1,46 +1,10 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2016 Pelagicore AG
-** 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 "qeglfskmsintegration.h"
-#include "qeglfskmsscreen.h"
+// Copyright (C) 2015 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2016 Pelagicore AG
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qeglfskmsintegration_p.h"
+#include "qeglfskmsscreen_p.h"
#include <QtKmsSupport/private/qkmsdevice_p.h>
@@ -55,18 +19,19 @@ QT_BEGIN_NAMESPACE
Q_LOGGING_CATEGORY(qLcEglfsKmsDebug, "qt.qpa.eglfs.kms")
QEglFSKmsIntegration::QEglFSKmsIntegration()
- : m_device(nullptr),
- m_screenConfig(new QKmsScreenConfig)
+ : m_device(nullptr)
{
}
QEglFSKmsIntegration::~QEglFSKmsIntegration()
{
- delete m_screenConfig;
}
void QEglFSKmsIntegration::platformInit()
{
+ qCDebug(qLcEglfsKmsDebug, "platformInit: Load Screen Config");
+ m_screenConfig = createScreenConfig();
+
qCDebug(qLcEglfsKmsDebug, "platformInit: Opening DRM device");
m_device = createDevice();
if (Q_UNLIKELY(!m_device->open()))
@@ -79,6 +44,8 @@ void QEglFSKmsIntegration::platformDestroy()
m_device->close();
delete m_device;
m_device = nullptr;
+ delete m_screenConfig;
+ m_screenConfig = nullptr;
}
EGLNativeDisplayType QEglFSKmsIntegration::platformDisplay() const
@@ -167,4 +134,12 @@ QKmsScreenConfig *QEglFSKmsIntegration::screenConfig() const
return m_screenConfig;
}
+QKmsScreenConfig *QEglFSKmsIntegration::createScreenConfig()
+{
+ QKmsScreenConfig *screenConfig = new QKmsScreenConfig;
+ screenConfig->loadConfig();
+
+ return screenConfig;
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsintegration.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsintegration.h
deleted file mode 100644
index e2c37f60fc..0000000000
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsintegration.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2016 Pelagicore AG
-** 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 QEGLFSKMSINTEGRATION_H
-#define QEGLFSKMSINTEGRATION_H
-
-#include "private/qeglfsdeviceintegration_p.h"
-#include <QtCore/QMap>
-#include <QtCore/QVariant>
-#include <QtCore/QLoggingCategory>
-
-QT_BEGIN_NAMESPACE
-
-class QKmsDevice;
-class QKmsScreenConfig;
-
-Q_EGLFS_EXPORT Q_DECLARE_LOGGING_CATEGORY(qLcEglfsKmsDebug)
-
-class Q_EGLFS_EXPORT QEglFSKmsIntegration : public QEglFSDeviceIntegration
-{
-public:
- QEglFSKmsIntegration();
- ~QEglFSKmsIntegration();
-
- void platformInit() override;
- void platformDestroy() override;
- EGLNativeDisplayType platformDisplay() const override;
- bool usesDefaultScreen() override;
- void screenInit() override;
- QSurfaceFormat surfaceFormatFor(const QSurfaceFormat &inputFormat) const override;
- bool hasCapability(QPlatformIntegration::Capability cap) const override;
- void waitForVSync(QPlatformSurface *surface) const override;
- bool supportsPBuffers() const override;
- void *nativeResourceForIntegration(const QByteArray &name) override;
- void *nativeResourceForScreen(const QByteArray &resource, QScreen *screen) override;
-
- QKmsDevice *device() const;
- QKmsScreenConfig *screenConfig() const;
-
-protected:
- virtual QKmsDevice *createDevice() = 0;
-
- QKmsDevice *m_device;
- QKmsScreenConfig *m_screenConfig;
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsintegration_p.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsintegration_p.h
new file mode 100644
index 0000000000..36e65a0bd4
--- /dev/null
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsintegration_p.h
@@ -0,0 +1,63 @@
+// Copyright (C) 2015 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2016 Pelagicore AG
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QEGLFSKMSINTEGRATION_H
+#define QEGLFSKMSINTEGRATION_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 "private/qeglfsdeviceintegration_p.h"
+#include <QtCore/QMap>
+#include <QtCore/QVariant>
+#include <QtCore/QLoggingCategory>
+
+QT_BEGIN_NAMESPACE
+
+class QKmsDevice;
+class QKmsScreenConfig;
+
+Q_DECLARE_EXPORTED_LOGGING_CATEGORY(qLcEglfsKmsDebug, Q_EGLFS_EXPORT)
+
+class Q_EGLFS_EXPORT QEglFSKmsIntegration : public QEglFSDeviceIntegration
+{
+public:
+ QEglFSKmsIntegration();
+ ~QEglFSKmsIntegration();
+
+ void platformInit() override;
+ void platformDestroy() override;
+ EGLNativeDisplayType platformDisplay() const override;
+ bool usesDefaultScreen() override;
+ void screenInit() override;
+ QSurfaceFormat surfaceFormatFor(const QSurfaceFormat &inputFormat) const override;
+ bool hasCapability(QPlatformIntegration::Capability cap) const override;
+ void waitForVSync(QPlatformSurface *surface) const override;
+ bool supportsPBuffers() const override;
+ void *nativeResourceForIntegration(const QByteArray &name) override;
+ void *nativeResourceForScreen(const QByteArray &resource, QScreen *screen) override;
+
+ QKmsDevice *device() const;
+ QKmsScreenConfig *screenConfig() const;
+
+protected:
+ virtual QKmsDevice *createDevice() = 0;
+ virtual QKmsScreenConfig *createScreenConfig();
+
+ QKmsDevice *m_device;
+ QKmsScreenConfig *m_screenConfig = nullptr;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen.cpp
index 959f17eba3..369356b761 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen.cpp
@@ -1,47 +1,11 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Copyright (C) 2017 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
-** Copyright (C) 2016 Pelagicore AG
-** 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 "qeglfskmsscreen.h"
-#include "qeglfskmsdevice.h"
-#include "qeglfsintegration_p.h"
+// Copyright (C) 2017 The Qt Company Ltd.
+// Copyright (C) 2017 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
+// Copyright (C) 2016 Pelagicore AG
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qeglfskmsscreen_p.h"
+#include "qeglfskmsdevice_p.h"
+#include <private/qeglfsintegration_p.h>
#include <QtCore/QLoggingCategory>
@@ -160,14 +124,12 @@ QSizeF QEglFSKmsScreen::physicalSize() const
QDpi QEglFSKmsScreen::logicalDpi() const
{
- const QSizeF ps = physicalSize();
- const QSize s = geometry().size();
-
- if (!ps.isEmpty() && !s.isEmpty())
- return QDpi(25.4 * s.width() / ps.width(),
- 25.4 * s.height() / ps.height());
- else
- return QDpi(100, 100);
+ return logicalBaseDpi();
+}
+
+QDpi QEglFSKmsScreen::logicalBaseDpi() const
+{
+ return QDpi(100, 100);
}
Qt::ScreenOrientation QEglFSKmsScreen::nativeOrientation() const
@@ -218,12 +180,12 @@ qreal QEglFSKmsScreen::refreshRate() const
return refresh > 0 ? refresh : 60;
}
-QVector<QPlatformScreen::Mode> QEglFSKmsScreen::modes() const
+QList<QPlatformScreen::Mode> QEglFSKmsScreen::modes() const
{
- QVector<QPlatformScreen::Mode> list;
+ QList<QPlatformScreen::Mode> list;
list.reserve(m_output.modes.size());
- for (const drmModeModeInfo &info : qAsConst(m_output.modes))
+ for (const drmModeModeInfo &info : std::as_const(m_output.modes))
list.append({QSize(info.hdisplay, info.vdisplay),
qreal(info.vrefresh > 0 ? info.vrefresh : 60)});
@@ -256,4 +218,13 @@ void QEglFSKmsScreen::setPowerState(QPlatformScreen::PowerState state)
m_powerState = state;
}
+/* Informs exact page flip timing which can be used rendering optimization.
+ Consider this is from drm event reader thread. */
+void QEglFSKmsScreen::pageFlipped(unsigned int sequence, unsigned int tv_sec, unsigned int tv_usec)
+{
+ Q_UNUSED(sequence);
+ Q_UNUSED(tv_sec);
+ Q_UNUSED(tv_usec);
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen.h
deleted file mode 100644
index a5c8f5b4e8..0000000000
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen.h
+++ /dev/null
@@ -1,125 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2016 Pelagicore AG
-** 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 QEGLFSKMSSCREEN_H
-#define QEGLFSKMSSCREEN_H
-
-#include "private/qeglfsscreen_p.h"
-#include <QtCore/QList>
-#include <QtCore/QMutex>
-
-#include <QtKmsSupport/private/qkmsdevice_p.h>
-#include <QtEdidSupport/private/qedidparser_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class QEglFSKmsDevice;
-class QEglFSKmsInterruptHandler;
-
-class Q_EGLFS_EXPORT QEglFSKmsScreen : public QEglFSScreen
-{
-public:
- QEglFSKmsScreen(QEglFSKmsDevice *device, const QKmsOutput &output, bool headless = false);
- ~QEglFSKmsScreen();
-
- void setVirtualPosition(const QPoint &pos);
-
- QRect rawGeometry() const override;
-
- int depth() const override;
- QImage::Format format() const override;
-
- QSizeF physicalSize() const override;
- QDpi logicalDpi() const override;
- Qt::ScreenOrientation nativeOrientation() const override;
- Qt::ScreenOrientation orientation() const override;
-
- QString name() const override;
-
- QString manufacturer() const override;
- QString model() const override;
- QString serialNumber() const override;
-
- qreal refreshRate() const override;
-
- QList<QPlatformScreen *> virtualSiblings() const override { return m_siblings; }
- void setVirtualSiblings(QList<QPlatformScreen *> sl) { m_siblings = sl; }
-
- QVector<QPlatformScreen::Mode> modes() const override;
-
- int currentMode() const override;
- int preferredMode() const override;
-
- QEglFSKmsDevice *device() const { return m_device; }
-
- virtual void waitForFlip();
-
- QKmsOutput &output() { return m_output; }
- void restoreMode();
-
- SubpixelAntialiasingType subpixelAntialiasingTypeHint() const override;
-
- QPlatformScreen::PowerState powerState() const override;
- void setPowerState(QPlatformScreen::PowerState state) override;
-
- bool isCursorOutOfRange() const { return m_cursorOutOfRange; }
- void setCursorOutOfRange(bool b) { m_cursorOutOfRange = b; }
-
-protected:
- QEglFSKmsDevice *m_device;
-
- QKmsOutput m_output;
- QEdidParser m_edid;
- QPoint m_pos;
- bool m_cursorOutOfRange;
-
- QList<QPlatformScreen *> m_siblings;
-
- PowerState m_powerState;
-
- QEglFSKmsInterruptHandler *m_interruptHandler;
-
- bool m_headless;
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen_p.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen_p.h
new file mode 100644
index 0000000000..6fb1f9a134
--- /dev/null
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen_p.h
@@ -0,0 +1,102 @@
+// Copyright (C) 2015 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2016 Pelagicore AG
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QEGLFSKMSSCREEN_H
+#define QEGLFSKMSSCREEN_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 "private/qeglfsscreen_p.h"
+#include <QtCore/QList>
+#include <QtCore/QMutex>
+
+#include <QtKmsSupport/private/qkmsdevice_p.h>
+#include <QtGui/private/qedidparser_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QEglFSKmsDevice;
+class QEglFSKmsInterruptHandler;
+
+class Q_EGLFS_EXPORT QEglFSKmsScreen : public QEglFSScreen
+{
+public:
+ QEglFSKmsScreen(QEglFSKmsDevice *device, const QKmsOutput &output, bool headless = false);
+ ~QEglFSKmsScreen();
+
+ void setVirtualPosition(const QPoint &pos);
+
+ QRect rawGeometry() const override;
+
+ int depth() const override;
+ QImage::Format format() const override;
+
+ QSizeF physicalSize() const override;
+ QDpi logicalDpi() const override;
+ QDpi logicalBaseDpi() const override;
+ Qt::ScreenOrientation nativeOrientation() const override;
+ Qt::ScreenOrientation orientation() const override;
+
+ QString name() const override;
+
+ QString manufacturer() const override;
+ QString model() const override;
+ QString serialNumber() const override;
+
+ qreal refreshRate() const override;
+
+ QList<QPlatformScreen *> virtualSiblings() const override { return m_siblings; }
+ void setVirtualSiblings(QList<QPlatformScreen *> sl) { m_siblings = sl; }
+
+ QList<QPlatformScreen::Mode> modes() const override;
+
+ int currentMode() const override;
+ int preferredMode() const override;
+
+ QEglFSKmsDevice *device() const { return m_device; }
+
+ virtual void waitForFlip();
+
+ QKmsOutput &output() { return m_output; }
+ void restoreMode();
+
+ SubpixelAntialiasingType subpixelAntialiasingTypeHint() const override;
+
+ QPlatformScreen::PowerState powerState() const override;
+ void setPowerState(QPlatformScreen::PowerState state) override;
+
+ bool isCursorOutOfRange() const { return m_cursorOutOfRange; }
+ void setCursorOutOfRange(bool b) { m_cursorOutOfRange = b; }
+
+ virtual void pageFlipped(unsigned int sequence, unsigned int tv_sec, unsigned int tv_usec);
+protected:
+ QEglFSKmsDevice *m_device;
+
+ QKmsOutput m_output;
+ QEdidParser m_edid;
+ QPoint m_pos;
+ bool m_cursorOutOfRange;
+
+ QList<QPlatformScreen *> m_siblings;
+
+ PowerState m_powerState;
+
+ QEglFSKmsInterruptHandler *m_interruptHandler;
+
+ bool m_headless;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/eglfs_kms_vsp2.pro b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/eglfs_kms_vsp2.pro
deleted file mode 100644
index f63b768a38..0000000000
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/eglfs_kms_vsp2.pro
+++ /dev/null
@@ -1,30 +0,0 @@
-TARGET = qeglfs-kms-vsp2-integration
-
-PLUGIN_TYPE = egldeviceintegrations
-PLUGIN_CLASS_NAME = QEglFSKmsVsp2IntegrationPlugin
-load(qt_plugin)
-
-QT += core-private gui-private eglfsdeviceintegration-private eglfs_kms_support-private kms_support-private edid_support-private
-
-INCLUDEPATH += $$PWD/../../api $$PWD/../eglfs_kms_support
-
-# Avoid X11 header collision, use generic EGL native types
-DEFINES += QT_EGL_NO_X11
-
-QMAKE_USE += gbm drm v4l2
-CONFIG += egl
-
-SOURCES += $$PWD/qeglfskmsvsp2main.cpp \
- $$PWD/qeglfskmsvsp2integration.cpp \
- $$PWD/qeglfskmsvsp2device.cpp \
- $$PWD/qeglfskmsvsp2screen.cpp \
- $$PWD/qlinuxmediadevice.cpp \
- $$PWD/qvsp2blendingdevice.cpp
-
-HEADERS += $$PWD/qeglfskmsvsp2integration.h \
- $$PWD/qeglfskmsvsp2device.h \
- $$PWD/qeglfskmsvsp2screen.h \
- $$PWD/qlinuxmediadevice.h \
- $$PWD/qvsp2blendingdevice.h
-
-OTHER_FILES += $$PWD/eglfs_kms.json
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qeglfskmsvsp2device.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qeglfskmsvsp2device.cpp
index 44f855910c..e1ac1127b7 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qeglfskmsvsp2device.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qeglfskmsvsp2device.cpp
@@ -1,43 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
-** Copyright (C) 2017 The Qt Company Ltd.
-** Copyright (C) 2016 Pelagicore AG
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2015 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
+// Copyright (C) 2017 The Qt Company Ltd.
+// Copyright (C) 2016 Pelagicore AG
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qeglfskmsvsp2device.h"
#include "qeglfskmsvsp2screen.h"
@@ -122,7 +86,7 @@ QPlatformScreen *QEglFSKmsVsp2Device::createHeadlessScreen()
void QEglFSKmsVsp2Device::registerScreenCloning(QPlatformScreen *screen,
QPlatformScreen *screenThisScreenClones,
- const QVector<QPlatformScreen *> &screensCloningThisScreen)
+ const QList<QPlatformScreen *> &screensCloningThisScreen)
{
Q_UNUSED(screen);
qWarning() << Q_FUNC_INFO << "Not implemented yet";
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qeglfskmsvsp2device.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qeglfskmsvsp2device.h
index c795fa4005..7826ffd4e3 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qeglfskmsvsp2device.h
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qeglfskmsvsp2device.h
@@ -1,48 +1,12 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
-** Copyright (C) 2017 The Qt Company Ltd.
-** Copyright (C) 2016 Pelagicore AG
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2015 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
+// Copyright (C) 2017 The Qt Company Ltd.
+// Copyright (C) 2016 Pelagicore AG
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QEGLFSKMSVSP2DEVICE_H
#define QEGLFSKMSVSP2DEVICE_H
-#include <qeglfskmsdevice.h>
+#include <qeglfskmsdevice_p.h>
#include <gbm.h>
@@ -65,7 +29,7 @@ public:
QPlatformScreen *createHeadlessScreen() override;
void registerScreenCloning(QPlatformScreen *screen,
QPlatformScreen *screenThisScreenClones,
- const QVector<QPlatformScreen *> &screensCloningThisScreen) override;
+ const QList<QPlatformScreen *> &screensCloningThisScreen) override;
private:
Q_DISABLE_COPY(QEglFSKmsVsp2Device)
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qeglfskmsvsp2integration.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qeglfskmsvsp2integration.cpp
index d1250ec9bf..9150eeb870 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qeglfskmsvsp2integration.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qeglfskmsvsp2integration.cpp
@@ -1,43 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
-** Copyright (C) 2017 The Qt Company Ltd.
-** Copyright (C) 2016 Pelagicore AG
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2015 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
+// Copyright (C) 2017 The Qt Company Ltd.
+// Copyright (C) 2016 Pelagicore AG
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qeglfskmsvsp2integration.h"
#include "qeglfskmsvsp2device.h"
@@ -45,14 +9,13 @@
#include "private/qeglfswindow_p.h"
#include <QtDeviceDiscoverySupport/private/qdevicediscovery_p.h>
-#include <QtEglSupport/private/qeglconvenience_p.h>
+#include <QtGui/private/qeglconvenience_p.h>
#include <QtCore/QLoggingCategory>
#include <QtCore/QJsonDocument>
#include <QtCore/QJsonObject>
#include <QtCore/QJsonArray>
#include <QtGui/qpa/qplatformwindow.h>
#include <QtGui/QScreen>
-#include <QtPlatformHeaders/qeglfsfunctions.h>
#include <xf86drm.h>
#include <xf86drmMode.h>
@@ -123,24 +86,6 @@ void QEglFSKmsVsp2Integration::presentBuffer(QPlatformSurface *surface)
screen->flip();
}
-QFunctionPointer QEglFSKmsVsp2Integration::platformFunction(const QByteArray &function) const
-{
- if (function == QEglFSFunctions::vsp2AddLayerTypeIdentifier())
- return QFunctionPointer(addLayerStatic);
- if (function == QEglFSFunctions::vsp2RemoveLayerTypeIdentifier())
- return QFunctionPointer(removeLayerStatic);
- if (function == QEglFSFunctions::vsp2SetLayerBufferTypeIdentifier())
- return QFunctionPointer(setLayerBufferStatic);
- if (function == QEglFSFunctions::vsp2SetLayerPositionTypeIdentifier())
- return QFunctionPointer(setLayerPositionStatic);
- if (function == QEglFSFunctions::vsp2SetLayerAlphaTypeIdentifier())
- return QFunctionPointer(setLayerAlphaStatic);
- if (function == QEglFSFunctions::vsp2AddBlendListenerTypeIdentifier())
- return QFunctionPointer(addBlendListenerStatic);
-
- return nullptr;
-}
-
QKmsDevice *QEglFSKmsVsp2Integration::createDevice()
{
QString path = screenConfig()->devicePath();
@@ -162,42 +107,6 @@ QKmsDevice *QEglFSKmsVsp2Integration::createDevice()
return new QEglFSKmsVsp2Device(screenConfig(), path);
}
-int QEglFSKmsVsp2Integration::addLayerStatic(const QScreen *screen, int dmabufFd, const QSize &size, const QPoint &position, uint pixelFormat, uint bytesPerLine)
-{
- auto vsp2Screen = static_cast<QEglFSKmsVsp2Screen *>(screen->handle());
- return vsp2Screen->addLayer(dmabufFd, size, position, pixelFormat, bytesPerLine);
-}
-
-bool QEglFSKmsVsp2Integration::removeLayerStatic(const QScreen *screen, int id)
-{
- auto vsp2Screen = static_cast<QEglFSKmsVsp2Screen *>(screen->handle());
- return vsp2Screen->removeLayer(id);
-}
-
-void QEglFSKmsVsp2Integration::setLayerBufferStatic(const QScreen *screen, int id, int dmabufFd)
-{
- auto vsp2Screen = static_cast<QEglFSKmsVsp2Screen *>(screen->handle());
- vsp2Screen->setLayerBuffer(id, dmabufFd);
-}
-
-void QEglFSKmsVsp2Integration::setLayerPositionStatic(const QScreen *screen, int id, const QPoint &position)
-{
- auto vsp2Screen = static_cast<QEglFSKmsVsp2Screen *>(screen->handle());
- vsp2Screen->setLayerPosition(id, position);
-}
-
-void QEglFSKmsVsp2Integration::setLayerAlphaStatic(const QScreen *screen, int id, qreal alpha)
-{
- auto vsp2Screen = static_cast<QEglFSKmsVsp2Screen *>(screen->handle());
- vsp2Screen->setLayerAlpha(id, alpha);
-}
-
-void QEglFSKmsVsp2Integration::addBlendListenerStatic(const QScreen *screen, void(*callback)())
-{
- auto vsp2Screen = static_cast<QEglFSKmsVsp2Screen *>(screen->handle());
- vsp2Screen->addBlendListener(callback);
-}
-
class QEglFSKmsVsp2Window : public QEglFSWindow
{
public:
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qeglfskmsvsp2integration.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qeglfskmsvsp2integration.h
index b1a8a2edf3..10e74eea13 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qeglfskmsvsp2integration.h
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qeglfskmsvsp2integration.h
@@ -1,48 +1,12 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
-** Copyright (C) 2017 The Qt Company Ltd.
-** Copyright (C) 2016 Pelagicore AG
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2015 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
+// Copyright (C) 2017 The Qt Company Ltd.
+// Copyright (C) 2016 Pelagicore AG
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QEGLFSKMSVSP2INTEGRATION_H
#define QEGLFSKMSVSP2INTEGRATION_H
-#include "qeglfskmsintegration.h"
+#include "qeglfskmsintegration_p.h"
#include <QtCore/QMap>
#include <QtCore/QVariant>
@@ -62,18 +26,8 @@ public:
void presentBuffer(QPlatformSurface *surface) override;
QEglFSWindow *createWindow(QWindow *window) const override;
- QFunctionPointer platformFunction(const QByteArray &function) const override;
-
protected:
QKmsDevice *createDevice() override;
-
-private:
- static int addLayerStatic(const QScreen *screen, int dmabufFd, const QSize &size, const QPoint &position, uint pixelFormat, uint bytesPerLine);
- static bool removeLayerStatic(const QScreen *screen, int id);
- static void setLayerBufferStatic(const QScreen *screen, int id, int dmabufFd);
- static void setLayerPositionStatic(const QScreen *screen, int id, const QPoint &position);
- static void setLayerAlphaStatic(const QScreen *screen, int id, qreal alpha);
- static void addBlendListenerStatic(const QScreen *screen, void(*callback)());
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qeglfskmsvsp2main.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qeglfskmsvsp2main.cpp
index 1345d38359..24240a19d3 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qeglfskmsvsp2main.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qeglfskmsvsp2main.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the qmake spec 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "private/qeglfsdeviceintegration_p.h"
#include "qeglfskmsvsp2integration.h"
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qeglfskmsvsp2screen.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qeglfskmsvsp2screen.cpp
index c255bc84b7..e5996271bb 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qeglfskmsvsp2screen.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qeglfskmsvsp2screen.cpp
@@ -1,47 +1,11 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Copyright (C) 2015 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
-** Copyright (C) 2016 Pelagicore AG
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// Copyright (C) 2015 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
+// Copyright (C) 2016 Pelagicore AG
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qeglfskmsvsp2screen.h"
#include "qeglfskmsvsp2device.h"
-#include <qeglfskmshelpers.h>
+#include <qeglfskmshelpers_p.h>
#include <QtCore/QLoggingCategory>
#include <QtGui/private/qguiapplication_p.h>
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qeglfskmsvsp2screen.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qeglfskmsvsp2screen.h
index 378786643d..b865522697 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qeglfskmsvsp2screen.h
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qeglfskmsvsp2screen.h
@@ -1,56 +1,23 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
-** Copyright (C) 2017 The Qt Company Ltd.
-** Copyright (C) 2016 Pelagicore AG
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2015 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
+// Copyright (C) 2017 The Qt Company Ltd.
+// Copyright (C) 2016 Pelagicore AG
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QEGLFSKMSVSP2SCREEN_H
#define QEGLFSKMSVSP2SCREEN_H
-#include "qeglfskmsscreen.h"
+#include "qeglfskmsscreen_p.h"
#include "qvsp2blendingdevice.h"
#include <QtCore/QMutex>
+#include <qpa/qplatformscreen_p.h>
+
#include <gbm.h>
QT_BEGIN_NAMESPACE
class QEglFSKmsVsp2Screen : public QEglFSKmsScreen
+ , public QNativeInterface::Private::QVsp2Screen
{
public:
QEglFSKmsVsp2Screen(QEglFSKmsDevice *device, const QKmsOutput &output);
@@ -63,12 +30,12 @@ public:
void initQtLayer();
//TODO: use a fixed index API instead of auto increment?
- int addLayer(int dmabufFd, const QSize &size, const QPoint &position, uint drmPixelFormat, uint bytesPerLine);
- void setLayerBuffer(int id, int dmabufFd);
- void setLayerPosition(int id, const QPoint &position);
- void setLayerAlpha(int id, qreal alpha);
- bool removeLayer(int id);
- void addBlendListener(void (*callback)());
+ int addLayer(int dmabufFd, const QSize &size, const QPoint &position, uint drmPixelFormat, uint bytesPerLine) override;
+ void setLayerBuffer(int id, int dmabufFd) override;
+ void setLayerPosition(int id, const QPoint &position) override;
+ void setLayerAlpha(int id, qreal alpha) override;
+ bool removeLayer(int id) override;
+ void addBlendListener(void (*callback)()) override;
void flip();
void blendAndFlipDrm();
@@ -97,7 +64,7 @@ private:
std::array<FrameBuffer, 2> m_frameBuffers;
uint m_backFb = 0;
void initDumbFrameBuffer(FrameBuffer &fb);
- QVector<void (*)()> m_blendFinishedCallbacks;
+ QList<void (*)()> m_blendFinishedCallbacks;
struct DmaBuffer { //these are for qt buffers before blending with additional layers (gbm buffer data)
int dmabufFd = -1;
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qlinuxmediadevice.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qlinuxmediadevice.cpp
index f77430d7a0..5d2900097e 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qlinuxmediadevice.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qlinuxmediadevice.cpp
@@ -1,45 +1,9 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qeglfsintegration_p.h"
#include "qlinuxmediadevice.h"
-#include <qeglfskmshelpers.h>
+#include <qeglfskmshelpers_p.h>
#include <QtCore/QLoggingCategory>
#include <QtCore/QSize>
@@ -236,7 +200,7 @@ bool QLinuxMediaDevice::resetLinks()
struct media_link *QLinuxMediaDevice::parseLink(const QString &link)
{
- char *endp = nullptr;;
+ char *endp = nullptr;
struct media_link *mediaLink = media_parse_link(m_mediaDevice, link.toStdString().c_str(), &endp);
if (!mediaLink)
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qlinuxmediadevice.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qlinuxmediadevice.h
index 26f863214b..c0998916c6 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qlinuxmediadevice.h
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qlinuxmediadevice.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QLINUXMEDIADEVICE_H
#define QLINUXMEDIADEVICE_H
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qvsp2blendingdevice.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qvsp2blendingdevice.cpp
index 132806a2e3..e7e3c76190 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qvsp2blendingdevice.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qvsp2blendingdevice.cpp
@@ -1,44 +1,8 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qvsp2blendingdevice.h"
-#include <qeglfskmshelpers.h>
+#include <qeglfskmshelpers_p.h>
#include <QDebug>
#include <QtCore/QLoggingCategory>
@@ -241,7 +205,7 @@ bool QVsp2BlendingDevice::blend(int outputDmabufFd)
if (queueingFailed) {
qWarning() << "Vsp2: Trying to clean up queued buffers";
- for (auto &input : qAsConst(m_inputs)) {
+ for (auto &input : std::as_const(m_inputs)) {
if (input.enabled) {
if (!input.rpfInput->clearBuffers())
qWarning() << "Vsp2: Failed to remove buffers after an aborted blend";
@@ -284,7 +248,7 @@ int QVsp2BlendingDevice::numInputs() const
bool QVsp2BlendingDevice::hasContinuousLayers() const
{
bool seenDisabled = false;
- for (auto &input : qAsConst(m_inputs)) {
+ for (auto &input : std::as_const(m_inputs)) {
if (seenDisabled && input.enabled)
return false;
seenDisabled |= !input.enabled;
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qvsp2blendingdevice.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qvsp2blendingdevice.h
index ee34ae654a..3b8e662eb4 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qvsp2blendingdevice.h
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qvsp2blendingdevice.h
@@ -1,47 +1,11 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QVSP2BLENDINGDEVICE_H
#define QVSP2BLENDINGDEVICE_H
+#include <QtCore/QList>
#include <QtCore/QRect>
-#include <QtCore/QVector>
#include <QtCore/qglobal.h>
#include "qlinuxmediadevice.h"
@@ -86,7 +50,7 @@ private:
struct media_pad *bruInputFormatPad = nullptr; // bru:x
QLinuxMediaDevice::OutputSubDevice *rpfInput = nullptr; // rpf.x input
};
- QVector<struct Input> m_inputs;
+ QList<struct Input> m_inputs;
const QSize m_screenSize;
bool m_dirty = true;
};
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_mali/CMakeLists.txt b/src/plugins/platforms/eglfs/deviceintegration/eglfs_mali/CMakeLists.txt
new file mode 100644
index 0000000000..38981f87b9
--- /dev/null
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_mali/CMakeLists.txt
@@ -0,0 +1,24 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## QEglFSMaliIntegrationPlugin Plugin:
+#####################################################################
+
+qt_internal_add_plugin(QEglFSMaliIntegrationPlugin
+ OUTPUT_NAME qeglfs-mali-integration
+ PLUGIN_TYPE egldeviceintegrations
+ SOURCES
+ qeglfsmaliintegration.cpp qeglfsmaliintegration.h
+ qeglfsmalimain.cpp
+ DEFINES
+ QT_EGL_NO_X11
+ INCLUDE_DIRECTORIES
+ ../../api
+ LIBRARIES
+ Qt::Core
+ Qt::CorePrivate
+ Qt::EglFSDeviceIntegrationPrivate
+ Qt::Gui
+ Qt::GuiPrivate
+)
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_mali/eglfs_mali.pro b/src/plugins/platforms/eglfs/deviceintegration/eglfs_mali/eglfs_mali.pro
deleted file mode 100644
index 3261a6dbba..0000000000
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_mali/eglfs_mali.pro
+++ /dev/null
@@ -1,20 +0,0 @@
-TARGET = qeglfs-mali-integration
-
-QT += core-private gui-private eglfsdeviceintegration-private
-
-# Avoid X11 header collision, use generic EGL native types
-DEFINES += QT_EGL_NO_X11
-
-INCLUDEPATH += $$PWD/../../api
-CONFIG += egl
-
-SOURCES += $$PWD/qeglfsmalimain.cpp \
- $$PWD/qeglfsmaliintegration.cpp
-
-HEADERS += $$PWD/qeglfsmaliintegration.h
-
-OTHER_FILES += $$PWD/eglfs_mali.json
-
-PLUGIN_TYPE = egldeviceintegrations
-PLUGIN_CLASS_NAME = QEglFSMaliIntegrationPlugin
-load(qt_plugin)
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_mali/qeglfsmaliintegration.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_mali/qeglfsmaliintegration.cpp
index 8eb07d727b..36768f6ff2 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_mali/qeglfsmaliintegration.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_mali/qeglfsmaliintegration.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qeglfsmaliintegration.h"
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_mali/qeglfsmaliintegration.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_mali/qeglfsmaliintegration.h
index 85eda4889f..24b97a933f 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_mali/qeglfsmaliintegration.h
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_mali/qeglfsmaliintegration.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QEGLFSMALIINTEGRATION_H
#define QEGLFSMALIINTEGRATION_H
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_mali/qeglfsmalimain.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_mali/qeglfsmalimain.cpp
index 4f87dab967..0a62a67a28 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_mali/qeglfsmalimain.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_mali/qeglfsmalimain.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "private/qeglfsdeviceintegration_p.h"
#include "qeglfsmaliintegration.h"
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_openwfd/CMakeLists.txt b/src/plugins/platforms/eglfs/deviceintegration/eglfs_openwfd/CMakeLists.txt
new file mode 100644
index 0000000000..7e2362e627
--- /dev/null
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_openwfd/CMakeLists.txt
@@ -0,0 +1,22 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## QEglFSOpenWFDIntegrationPlugin Plugin:
+#####################################################################
+
+qt_internal_add_plugin(QEglFSOpenWFDIntegrationPlugin
+ OUTPUT_NAME qeglfs-openwfd-integration
+ PLUGIN_TYPE egldeviceintegrations
+ SOURCES
+ qeglfsopenwfdintegration.cpp qeglfsopenwfdintegration.h
+ qeglfsopenwfdmain.cpp
+ INCLUDE_DIRECTORIES
+ ../../api
+ LIBRARIES
+ Qt::Core
+ Qt::CorePrivate
+ Qt::EglFSDeviceIntegrationPrivate
+ Qt::Gui
+ Qt::GuiPrivate
+)
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_openwfd/eglfs_openwfd.pro b/src/plugins/platforms/eglfs/deviceintegration/eglfs_openwfd/eglfs_openwfd.pro
deleted file mode 100644
index 448b4cbe21..0000000000
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_openwfd/eglfs_openwfd.pro
+++ /dev/null
@@ -1,17 +0,0 @@
-TARGET = qeglfs-openwfd-integration
-
-QT += core-private gui-private eglfsdeviceintegration-private
-
-INCLUDEPATH += $$PWD/../../api
-CONFIG += egl
-
-SOURCES += $$PWD/qeglfsopenwfdmain.cpp \
- $$PWD/qeglfsopenwfdintegration.cpp
-
-HEADERS += $$PWD/qeglfsopenwfdintegration.h
-
-OTHER_FILES += $$PWD/eglfs_openwfd.json
-
-PLUGIN_TYPE = egldeviceintegrations
-PLUGIN_CLASS_NAME = QEglFSOpenWFDIntegrationPlugin
-load(qt_plugin)
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_openwfd/qeglfsopenwfdintegration.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_openwfd/qeglfsopenwfdintegration.cpp
index b8f04cf978..c23ae7caa1 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_openwfd/qeglfsopenwfdintegration.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_openwfd/qeglfsopenwfdintegration.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qeglfsopenwfdintegration.h"
@@ -154,23 +118,23 @@ EGLNativeWindowType QEglFSOpenWFDIntegration::createNativeWindow(QPlatformWindow
if (!ok)
pipelineId = pipelineIds[0];
- WFDPipeline pipeline = wfdCreatePipeline(mDevice, pipelineId, nullptr);
- if (WFD_INVALID_HANDLE == pipeline)
+ mPipeline = wfdCreatePipeline(mDevice, pipelineId, nullptr);
+ if (WFD_INVALID_HANDLE == mPipeline)
qFatal("Failed to create wfd pipeline");
- wfdSetPipelineAttribi(mDevice, pipeline, WFD_PIPELINE_TRANSPARENCY_ENABLE,
+ wfdSetPipelineAttribi(mDevice, mPipeline, WFD_PIPELINE_TRANSPARENCY_ENABLE,
(WFD_TRANSPARENCY_SOURCE_ALPHA|WFD_TRANSPARENCY_GLOBAL_ALPHA));
WFDErrorCode eError = wfdGetError(mDevice);
if (WFD_ERROR_NONE != eError)
qFatal("Failed to set WFD_PIPELINE_TRANSPARENCY_ENABLE");
- wfdSetPipelineAttribi(mDevice, pipeline, WFD_PIPELINE_GLOBAL_ALPHA, 255);
+ wfdSetPipelineAttribi(mDevice, mPipeline, WFD_PIPELINE_GLOBAL_ALPHA, 255);
eError = wfdGetError(mDevice);
if (WFD_ERROR_NONE != eError)
qFatal("Failed to set WFD_PIPELINE_GLOBAL_ALPHA");
- wfdBindPipelineToPort(mDevice, mPort, pipeline);
+ wfdBindPipelineToPort(mDevice, mPort, mPipeline);
eError = wfdGetError(mDevice);
if (WFD_ERROR_NONE != eError)
qFatal("Failed to bind port to pipeline");
@@ -190,7 +154,7 @@ EGLNativeWindowType QEglFSOpenWFDIntegration::createNativeWindow(QPlatformWindow
if (WFD_INVALID_HANDLE == wfdEglImages[i])
qFatal("Failed to create WDFEGLImages");
- source[i] = wfdCreateSourceFromImage(mDevice, pipeline, eglImageHandles[i], nullptr);
+ source[i] = wfdCreateSourceFromImage(mDevice, mPipeline, eglImageHandles[i], nullptr);
if (WFD_INVALID_HANDLE == source[i])
qFatal("Failed to create source from EGLImage");
}
@@ -208,14 +172,13 @@ EGLNativeWindowType QEglFSOpenWFDIntegration::createNativeWindow(QPlatformWindow
nativeWindow->dev = mDevice;
nativeWindow->port = mPort;
- nativeWindow->pipeline = pipeline;
+ nativeWindow->pipeline = mPipeline;
nativeWindow->numBuffers = MAX_NUM_OF_WFD_BUFFERS;
for (int i = 0; i < MAX_NUM_OF_WFD_BUFFERS; i++) {
nativeWindow->buffers[i].image = wfdEglImages[i];
nativeWindow->buffers[i].source = source[i];
}
-
return (EGLNativeWindowType)nativeWindow;
}
@@ -231,7 +194,16 @@ QSurfaceFormat QEglFSOpenWFDIntegration::surfaceFormatFor(const QSurfaceFormat &
void QEglFSOpenWFDIntegration::destroyNativeWindow(EGLNativeWindowType window)
{
+ wfdDestroyPipeline(mDevice, mPipeline);
free((void*)window);
}
+void QEglFSOpenWFDIntegration::platformDestroy()
+{
+ wfdDestroyPort(mDevice, mPort);
+ WFDErrorCode error = wfdDestroyDevice(mDevice);
+ if (error != WFD_ERROR_NONE)
+ qWarning() << "Failed to release wfd device! Error = " << error;
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_openwfd/qeglfsopenwfdintegration.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_openwfd/qeglfsopenwfdintegration.h
index 189ddd4d7a..c6ff282b5c 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_openwfd/qeglfsopenwfdintegration.h
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_openwfd/qeglfsopenwfdintegration.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QEGLFSOPENWFDINTEGRATION_H
#define QEGLFSOPENWFDINTEGRATION_H
@@ -51,6 +15,7 @@ class QEglFSOpenWFDIntegration : public QEglFSDeviceIntegration
{
public:
void platformInit() override;
+ void platformDestroy() override;
QSize screenSize() const override;
EGLNativeWindowType createNativeWindow(QPlatformWindow *window, const QSize &size, const QSurfaceFormat &format) override;
void destroyNativeWindow(EGLNativeWindowType window) override;
@@ -62,6 +27,7 @@ private:
EGLNativeDisplayType mNativeDisplay;
WFDDevice mDevice;
WFDPort mPort;
+ WFDPipeline mPipeline;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_openwfd/qeglfsopenwfdmain.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_openwfd/qeglfsopenwfdmain.cpp
index 1d6132b55e..70f2d694f1 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_openwfd/qeglfsopenwfdmain.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_openwfd/qeglfsopenwfdmain.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "private/qeglfsdeviceintegration_p.h"
#include "qeglfsopenwfdintegration.h"
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_rcar/eglfs_rcar.pro b/src/plugins/platforms/eglfs/deviceintegration/eglfs_rcar/eglfs_rcar.pro
deleted file mode 100644
index 62acd51cea..0000000000
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_rcar/eglfs_rcar.pro
+++ /dev/null
@@ -1,18 +0,0 @@
-TARGET = qeglfs-rcar-integration
-
-QT += core-private gui-private eglfsdeviceintegration-private
-
-INCLUDEPATH += $$PWD/../../api
-CONFIG += egl
-DEFINES += LINUX=1 EGL_API_FB=1
-
-SOURCES += $$PWD/qeglfsrcarmain.cpp \
- $$PWD/qeglfsrcarintegration.cpp
-
-HEADERS += $$PWD/qeglfsrcarintegration.h
-
-OTHER_FILES += $$PWD/eglfs_rcar.json
-
-PLUGIN_TYPE = egldeviceintegrations
-PLUGIN_CLASS_NAME = QEglFSRcarIntegrationPlugin
-load(qt_plugin)
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_rcar/qeglfsrcarintegration.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_rcar/qeglfsrcarintegration.cpp
index 212ebde05a..a805795bab 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_rcar/qeglfsrcarintegration.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_rcar/qeglfsrcarintegration.cpp
@@ -1,44 +1,8 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QDebug>
-#include <QtEglSupport/private/qeglconvenience_p.h>
+#include <QtGui/private/qeglconvenience_p.h>
#include <EGL/egl.h>
#include "INTEGRITY.h"
#include "qeglfsrcarintegration.h"
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_rcar/qeglfsrcarintegration.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_rcar/qeglfsrcarintegration.h
index 08911594f9..dba6bdfa40 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_rcar/qeglfsrcarintegration.h
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_rcar/qeglfsrcarintegration.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QEGLFSVIVINTEGRATION_H
#define QEGLFSVIVINTEGRATION_H
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_rcar/qeglfsrcarmain.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_rcar/qeglfsrcarmain.cpp
index 6cf3e1387d..2fcadad4ff 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_rcar/qeglfsrcarmain.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_rcar/qeglfsrcarmain.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "INTEGRITY.h"
#include "private/qeglfsdeviceintegration_p.h"
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/CMakeLists.txt b/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/CMakeLists.txt
new file mode 100644
index 0000000000..01defc9242
--- /dev/null
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/CMakeLists.txt
@@ -0,0 +1,25 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## QEglFSVivIntegrationPlugin Plugin:
+#####################################################################
+
+qt_internal_add_plugin(QEglFSVivIntegrationPlugin
+ OUTPUT_NAME qeglfs-viv-integration
+ PLUGIN_TYPE egldeviceintegrations
+ SOURCES
+ qeglfsvivintegration.cpp qeglfsvivintegration.h
+ qeglfsvivmain.cpp
+ DEFINES
+ EGL_API_FB=1
+ LINUX=1
+ INCLUDE_DIRECTORIES
+ ../../api
+ LIBRARIES
+ Qt::Core
+ Qt::CorePrivate
+ Qt::EglFSDeviceIntegrationPrivate
+ Qt::Gui
+ Qt::GuiPrivate
+)
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/eglfs_viv.pro b/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/eglfs_viv.pro
deleted file mode 100644
index 8d3be9c2ac..0000000000
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/eglfs_viv.pro
+++ /dev/null
@@ -1,18 +0,0 @@
-TARGET = qeglfs-viv-integration
-
-QT += core-private gui-private eglfsdeviceintegration-private
-
-INCLUDEPATH += $$PWD/../../api
-CONFIG += egl
-DEFINES += LINUX=1 EGL_API_FB=1
-
-SOURCES += $$PWD/qeglfsvivmain.cpp \
- $$PWD/qeglfsvivintegration.cpp
-
-HEADERS += $$PWD/qeglfsvivintegration.h
-
-OTHER_FILES += $$PWD/eglfs_viv.json
-
-PLUGIN_TYPE = egldeviceintegrations
-PLUGIN_CLASS_NAME = QEglFSVivIntegrationPlugin
-load(qt_plugin)
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/qeglfsvivintegration.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/qeglfsvivintegration.cpp
index 5e1d28a353..c8b08f95a4 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/qeglfsvivintegration.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/qeglfsvivintegration.cpp
@@ -1,51 +1,10 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qeglfsvivintegration.h"
#include <EGL/eglvivante.h>
#include <QDebug>
-#if QT_CONFIG(vulkan)
-#include "private/qeglfsvulkaninstance_p.h"
-#include "private/qeglfsvulkanwindow_p.h"
-#endif
-
#ifdef Q_OS_INTEGRITY
extern "C" void VivanteInit(void);
#endif
@@ -90,8 +49,8 @@ EGLNativeDisplayType QEglFSVivIntegration::platformDisplay() const
EGLNativeWindowType QEglFSVivIntegration::createNativeWindow(QPlatformWindow *window, const QSize &size, const QSurfaceFormat &format)
{
- Q_UNUSED(window)
- Q_UNUSED(format)
+ Q_UNUSED(window);
+ Q_UNUSED(format);
EGLNativeWindowType eglWindow = static_cast<EGLNativeWindowType>(fbCreateWindow(mNativeDisplay, 0, 0, size.width(), size.height()));
return eglWindow;
@@ -102,20 +61,4 @@ void QEglFSVivIntegration::destroyNativeWindow(EGLNativeWindowType window)
fbDestroyWindow(window);
}
-#if QT_CONFIG(vulkan)
-
-QEglFSWindow *QEglFSVivIntegration::createWindow(QWindow *window) const
-{
- if (window->surfaceType() == QSurface::VulkanSurface)
- return new QEglFSVulkanWindow(window);
- return QEglFSDeviceIntegration::createWindow(window);
-}
-
-QPlatformVulkanInstance *QEglFSVivIntegration::createPlatformVulkanInstance(QVulkanInstance *instance)
-{
- return new QEglFSVulkanInstance(instance);
-}
-
-#endif // vulkan
-
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/qeglfsvivintegration.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/qeglfsvivintegration.h
index 02b59c16b5..abee5e623d 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/qeglfsvivintegration.h
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/qeglfsvivintegration.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QEGLFSVIVINTEGRATION_H
#define QEGLFSVIVINTEGRATION_H
@@ -53,12 +17,6 @@ public:
void destroyNativeWindow(EGLNativeWindowType window) override;
EGLNativeDisplayType platformDisplay() const override;
- // Vulkan support with VK_KHR_display
-#if QT_CONFIG(vulkan)
- QEglFSWindow *createWindow(QWindow *window) const override;
- QPlatformVulkanInstance *createPlatformVulkanInstance(QVulkanInstance *instance) override;
-#endif
-
private:
QSize mScreenSize;
EGLNativeDisplayType mNativeDisplay;
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/qeglfsvivmain.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/qeglfsvivmain.cpp
index 0736637b6b..2db12e0e71 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/qeglfsvivmain.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/qeglfsvivmain.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "private/qeglfsdeviceintegration_p.h"
#include "qeglfsvivintegration.h"
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv_wl/CMakeLists.txt b/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv_wl/CMakeLists.txt
new file mode 100644
index 0000000000..6052e98ab8
--- /dev/null
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv_wl/CMakeLists.txt
@@ -0,0 +1,26 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## QEglFSVivWaylandIntegrationPlugin Plugin:
+#####################################################################
+
+qt_internal_add_plugin(QEglFSVivWaylandIntegrationPlugin
+ OUTPUT_NAME qeglfs-viv-wl-integration
+ PLUGIN_TYPE egldeviceintegrations
+ SOURCES
+ qeglfsvivwlintegration.cpp qeglfsvivwlintegration.h
+ qeglfsvivwlmain.cpp
+ DEFINES
+ EGL_API_FB=1
+ LINUX=1
+ INCLUDE_DIRECTORIES
+ ../../api
+ LIBRARIES
+ Wayland::Server
+ Qt::Core
+ Qt::CorePrivate
+ Qt::EglFSDeviceIntegrationPrivate
+ Qt::Gui
+ Qt::GuiPrivate
+)
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv_wl/eglfs_viv_wl.pro b/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv_wl/eglfs_viv_wl.pro
deleted file mode 100644
index 45d73e1eb8..0000000000
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv_wl/eglfs_viv_wl.pro
+++ /dev/null
@@ -1,20 +0,0 @@
-TARGET = qeglfs-viv-wl-integration
-
-QT += core-private gui-private eglfsdeviceintegration-private
-
-INCLUDEPATH += $$PWD/../../api
-CONFIG += egl
-DEFINES += LINUX=1 EGL_API_FB=1
-
-SOURCES += $$PWD/qeglfsvivwlmain.cpp \
- $$PWD/qeglfsvivwlintegration.cpp
-
-HEADERS += $$PWD/qeglfsvivwlintegration.h
-
-OTHER_FILES += $$PWD/eglfs_viv_wl.json
-
-QMAKE_USE_PRIVATE += wayland_server
-
-PLUGIN_TYPE = egldeviceintegrations
-PLUGIN_CLASS_NAME = QEglFSVivWaylandIntegrationPlugin
-load(qt_plugin)
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv_wl/qeglfsvivwlintegration.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv_wl/qeglfsvivwlintegration.cpp
index 296e301f07..898ea96e1f 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv_wl/qeglfsvivwlintegration.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv_wl/qeglfsvivwlintegration.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qeglfsvivwlintegration.h"
#include <EGL/eglvivante.h>
@@ -83,8 +47,8 @@ EGLNativeDisplayType QEglFSVivWaylandIntegration::platformDisplay() const
EGLNativeWindowType QEglFSVivWaylandIntegration::createNativeWindow(QPlatformWindow *window, const QSize &size, const QSurfaceFormat &format)
{
- Q_UNUSED(window)
- Q_UNUSED(format)
+ Q_UNUSED(window);
+ Q_UNUSED(format);
EGLNativeWindowType eglWindow = static_cast<EGLNativeWindowType>(fbCreateWindow(mNativeDisplay, 0, 0, size.width(), size.height()));
return eglWindow;
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv_wl/qeglfsvivwlintegration.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv_wl/qeglfsvivwlintegration.h
index bee23dfb3e..84cdfe34db 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv_wl/qeglfsvivwlintegration.h
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv_wl/qeglfsvivwlintegration.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QEGLFSVIVINTEGRATION_H
#define QEGLFSVIVINTEGRATION_H
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv_wl/qeglfsvivwlmain.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv_wl/qeglfsvivwlmain.cpp
index 6cdc9346c0..357265d708 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv_wl/qeglfsvivwlmain.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv_wl/qeglfsvivwlmain.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "private/qeglfsdeviceintegration_p.h"
#include "qeglfsvivwlintegration.h"
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/CMakeLists.txt b/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/CMakeLists.txt
index 29dcd0dab7..9dde3090c8 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/CMakeLists.txt
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/CMakeLists.txt
@@ -1,12 +1,13 @@
-# Generated from eglfs_x11.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## QEglFSX11IntegrationPlugin Plugin:
#####################################################################
-qt_add_plugin(QEglFSX11IntegrationPlugin
+qt_internal_add_plugin(QEglFSX11IntegrationPlugin
OUTPUT_NAME qeglfs-x11-integration
- TYPE egldeviceintegrations
+ PLUGIN_TYPE egldeviceintegrations
SOURCES
qeglfsx11integration.cpp qeglfsx11integration.h
qeglfsx11main.cpp
@@ -14,15 +15,14 @@ qt_add_plugin(QEglFSX11IntegrationPlugin
QT_EGL_NO_X11
INCLUDE_DIRECTORIES
../../api
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Core
Qt::CorePrivate
Qt::EglFSDeviceIntegrationPrivate
Qt::Gui
Qt::GuiPrivate
+ X11::X11
X11::XCB
XCB::XCB
+ NO_UNITY_BUILD # X11 define clashes
)
-
-#### Keys ignored in scope 1:.:.:eglfs_x11.pro:<TRUE>:
-# OTHER_FILES = "$$PWD/eglfs_x11.json"
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/eglfs_x11.pro b/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/eglfs_x11.pro
deleted file mode 100644
index 6b55918f03..0000000000
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/eglfs_x11.pro
+++ /dev/null
@@ -1,22 +0,0 @@
-TARGET = qeglfs-x11-integration
-
-QT += core-private gui-private eglfsdeviceintegration-private
-
-# Avoid X11 header collision, use generic EGL native types
-DEFINES += QT_EGL_NO_X11
-
-INCLUDEPATH += $$PWD/../../api
-
-CONFIG += egl
-QMAKE_USE += xcb_xlib xcb xlib
-
-SOURCES += $$PWD/qeglfsx11main.cpp \
- $$PWD/qeglfsx11integration.cpp
-
-HEADERS += $$PWD/qeglfsx11integration.h
-
-OTHER_FILES += $$PWD/eglfs_x11.json
-
-PLUGIN_TYPE = egldeviceintegrations
-PLUGIN_CLASS_NAME = QEglFSX11IntegrationPlugin
-load(qt_plugin)
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/qeglfsx11integration.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/qeglfsx11integration.cpp
index ce5a721906..8f491274d5 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/qeglfsx11integration.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/qeglfsx11integration.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qeglfsx11integration.h"
#include <QThread>
@@ -61,7 +25,7 @@ private:
QEglFSX11Integration *m_integration;
};
-QAtomicInt running;
+Q_CONSTINIT static QBasicAtomicInt running = Q_BASIC_ATOMIC_INITIALIZER(0);
void EventReader::run()
{
@@ -151,7 +115,7 @@ QSize QEglFSX11Integration::screenSize() const
{
if (m_screenSize.isEmpty()) {
QList<QByteArray> env = qgetenv("EGLFS_X11_SIZE").split('x');
- if (env.length() == 2) {
+ if (env.size() == 2) {
m_screenSize = QSize(env.at(0).toInt(), env.at(1).toInt());
} else {
XWindowAttributes a;
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/qeglfsx11integration.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/qeglfsx11integration.h
index ebcc19b682..e083c157cd 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/qeglfsx11integration.h
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/qeglfsx11integration.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QEGLFSX11INTEGRATION_H
#define QEGLFSX11INTEGRATION_H
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/qeglfsx11main.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/qeglfsx11main.cpp
index 39ab54ae5a..b46e88843f 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/qeglfsx11main.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/qeglfsx11main.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the qmake spec 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "private/qeglfsdeviceintegration_p.h"
#include "qeglfsx11integration.h"
diff --git a/src/plugins/platforms/eglfs/eglfs-plugin.pro b/src/plugins/platforms/eglfs/eglfs-plugin.pro
deleted file mode 100644
index ec229796e5..0000000000
--- a/src/plugins/platforms/eglfs/eglfs-plugin.pro
+++ /dev/null
@@ -1,19 +0,0 @@
-TARGET = qeglfs
-
-QT += eglfsdeviceintegration-private
-
-CONFIG += egl
-
-# Avoid X11 header collision, use generic EGL native types
-DEFINES += QT_EGL_NO_X11
-
-SOURCES += $$PWD/qeglfsmain.cpp
-
-OTHER_FILES += $$PWD/eglfs.json
-
-INCLUDEPATH += $$PWD/api
-
-PLUGIN_TYPE = platforms
-PLUGIN_CLASS_NAME = QEglFSIntegrationPlugin
-!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = -
-load(qt_plugin)
diff --git a/src/plugins/platforms/eglfs/eglfs.pro b/src/plugins/platforms/eglfs/eglfs.pro
deleted file mode 100644
index d91ffd60a1..0000000000
--- a/src/plugins/platforms/eglfs/eglfs.pro
+++ /dev/null
@@ -1,6 +0,0 @@
-TEMPLATE = subdirs
-CONFIG += ordered
-
-SUBDIRS += eglfsdeviceintegration.pro
-SUBDIRS += eglfs-plugin.pro
-SUBDIRS += deviceintegration
diff --git a/src/plugins/platforms/eglfs/eglfsdeviceintegration.pro b/src/plugins/platforms/eglfs/eglfsdeviceintegration.pro
deleted file mode 100644
index bd02aea4d3..0000000000
--- a/src/plugins/platforms/eglfs/eglfsdeviceintegration.pro
+++ /dev/null
@@ -1,52 +0,0 @@
-# The device integration plugin base class has to live in a shared library,
-# placing it into a static lib like platformsupport is not sufficient since we
-# have to keep the QObject magic like qobject_cast working.
-# Hence this private-only module.
-# By having _p headers, it also enables developing out-of-tree integration plugins.
-
-TARGET = QtEglFSDeviceIntegration
-CONFIG += internal_module
-MODULE = eglfsdeviceintegration
-
-QT += \
- core-private gui-private \
- devicediscovery_support-private eventdispatcher_support-private \
- service_support-private theme_support-private fontdatabase_support-private \
- fb_support-private egl_support-private
-
-qtHaveModule(input_support-private): \
- QT += input_support-private
-
-qtHaveModule(platformcompositor_support-private): \
- QT += platformcompositor_support-private
-
-qtConfig(vulkan): \
- QT += vulkan_support-private
-
-# Avoid X11 header collision, use generic EGL native types
-DEFINES += QT_EGL_NO_X11
-
-DEFINES += QT_BUILD_EGL_DEVICE_LIB
-
-include($$PWD/api/api.pri)
-
-!isEmpty(EGLFS_PLATFORM_HOOKS_SOURCES) {
- HEADERS += $$EGLFS_PLATFORM_HOOKS_HEADERS
- SOURCES += $$EGLFS_PLATFORM_HOOKS_SOURCES
- LIBS += $$EGLFS_PLATFORM_HOOKS_LIBS
- DEFINES += EGLFS_PLATFORM_HOOKS
-}
-
-!isEmpty(EGLFS_DEVICE_INTEGRATION) {
- DEFINES += EGLFS_PREFERRED_PLUGIN=$$EGLFS_DEVICE_INTEGRATION
-}
-
-CONFIG += egl
-
-# Prevent gold linker from crashing.
-# This started happening when QtPlatformSupport was modularized.
-use_gold_linker: CONFIG += no_linker_version_script
-
-!contains(DEFINES, QT_NO_CURSOR): RESOURCES += $$PWD/cursor.qrc
-
-load(qt_module)
diff --git a/src/plugins/platforms/eglfs/qeglfsmain.cpp b/src/plugins/platforms/eglfs/qeglfsmain.cpp
index b41bbec27d..13e4199f45 100644
--- a/src/plugins/platforms/eglfs/qeglfsmain.cpp
+++ b/src/plugins/platforms/eglfs/qeglfsmain.cpp
@@ -1,47 +1,13 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <qpa/qplatformintegrationplugin.h>
-#include "qeglfsintegration_p.h"
+#include <private/qeglfsintegration_p.h>
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
class QEglFSIntegrationPlugin : public QPlatformIntegrationPlugin
{
Q_OBJECT
@@ -53,7 +19,7 @@ public:
QPlatformIntegration* QEglFSIntegrationPlugin::create(const QString& system, const QStringList& paramList)
{
Q_UNUSED(paramList);
- if (!system.compare(QLatin1String("eglfs"), Qt::CaseInsensitive))
+ if (!system.compare("eglfs"_L1, Qt::CaseInsensitive))
return new QEglFSIntegration;
return nullptr;
diff --git a/src/plugins/platforms/haiku/haiku.pro b/src/plugins/platforms/haiku/haiku.pro
deleted file mode 100644
index e7702361ee..0000000000
--- a/src/plugins/platforms/haiku/haiku.pro
+++ /dev/null
@@ -1,41 +0,0 @@
-TARGET = qhaiku
-
-QT += core-private gui-private eventdispatcher_support-private
-
-SOURCES = \
- main.cpp \
- qhaikuapplication.cpp \
- qhaikubuffer.cpp \
- qhaikuclipboard.cpp \
- qhaikucursor.cpp \
- qhaikuintegration.cpp \
- qhaikukeymapper.cpp \
- qhaikurasterbackingstore.cpp \
- qhaikurasterwindow.cpp \
- qhaikuscreen.cpp \
- qhaikuservices.cpp \
- qhaikuutils.cpp \
- qhaikuwindow.cpp
-
-HEADERS = \
- main.h \
- qhaikuapplication.h \
- qhaikubuffer.h \
- qhaikuclipboard.h \
- qhaikucursor.h \
- qhaikuintegration.h \
- qhaikukeymapper.h \
- qhaikurasterbackingstore.h \
- qhaikurasterwindow.h \
- qhaikuscreen.h \
- qhaikuservices.h \
- qhaikuutils.h \
- qhaikuwindow.h
-
-LIBS += -lbe
-
-OTHER_FILES += haiku.json
-
-PLUGIN_TYPE = platforms
-PLUGIN_CLASS_NAME = QHaikuIntegrationPlugin
-load(qt_plugin)
diff --git a/src/plugins/platforms/haiku/main.cpp b/src/plugins/platforms/haiku/main.cpp
index 841891970d..e845f60586 100644
--- a/src/plugins/platforms/haiku/main.cpp
+++ b/src/plugins/platforms/haiku/main.cpp
@@ -1,50 +1,16 @@
-/***************************************************************************
-**
-** Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias Koenig <tobias.koenig@kdab.com>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias Koenig <tobias.koenig@kdab.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "main.h"
#include "qhaikuintegration.h"
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
QPlatformIntegration *QHaikuIntegrationPlugin::create(const QString& system, const QStringList& paramList)
{
- if (!system.compare(QLatin1String("haiku"), Qt::CaseInsensitive))
+ if (!system.compare("haiku"_L1, Qt::CaseInsensitive))
return new QHaikuIntegration(paramList);
return nullptr;
diff --git a/src/plugins/platforms/haiku/main.h b/src/plugins/platforms/haiku/main.h
index e316b79d7c..e2eeea7a9c 100644
--- a/src/plugins/platforms/haiku/main.h
+++ b/src/plugins/platforms/haiku/main.h
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias Koenig <tobias.koenig@kdab.com>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias Koenig <tobias.koenig@kdab.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <qpa/qplatformintegrationplugin.h>
diff --git a/src/plugins/platforms/haiku/qhaikuapplication.cpp b/src/plugins/platforms/haiku/qhaikuapplication.cpp
index de4acdfd4a..c42e38c5ce 100644
--- a/src/plugins/platforms/haiku/qhaikuapplication.cpp
+++ b/src/plugins/platforms/haiku/qhaikuapplication.cpp
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias Koenig <tobias.koenig@kdab.com>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias Koenig <tobias.koenig@kdab.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qhaikuapplication.h"
diff --git a/src/plugins/platforms/haiku/qhaikuapplication.h b/src/plugins/platforms/haiku/qhaikuapplication.h
index a9ea442691..a65e9b6b81 100644
--- a/src/plugins/platforms/haiku/qhaikuapplication.h
+++ b/src/plugins/platforms/haiku/qhaikuapplication.h
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias Koenig <tobias.koenig@kdab.com>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias Koenig <tobias.koenig@kdab.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QHAIKUAPPLICATION_H
#define QHAIKUAPPLICATION_H
diff --git a/src/plugins/platforms/haiku/qhaikubuffer.cpp b/src/plugins/platforms/haiku/qhaikubuffer.cpp
index f25ddef86b..e668c019c3 100644
--- a/src/plugins/platforms/haiku/qhaikubuffer.cpp
+++ b/src/plugins/platforms/haiku/qhaikubuffer.cpp
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias Koenig <tobias.koenig@kdab.com>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias Koenig <tobias.koenig@kdab.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qhaikubuffer.h"
diff --git a/src/plugins/platforms/haiku/qhaikubuffer.h b/src/plugins/platforms/haiku/qhaikubuffer.h
index bc88e6ad5a..018b032322 100644
--- a/src/plugins/platforms/haiku/qhaikubuffer.h
+++ b/src/plugins/platforms/haiku/qhaikubuffer.h
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias Koenig <tobias.koenig@kdab.com>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias Koenig <tobias.koenig@kdab.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QHAIKUBUFFER_H
#define QHAIKUBUFFER_H
diff --git a/src/plugins/platforms/haiku/qhaikuclipboard.cpp b/src/plugins/platforms/haiku/qhaikuclipboard.cpp
index 20519e21d0..4080f9a121 100644
--- a/src/plugins/platforms/haiku/qhaikuclipboard.cpp
+++ b/src/plugins/platforms/haiku/qhaikuclipboard.cpp
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias Koenig <tobias.koenig@kdab.com>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias Koenig <tobias.koenig@kdab.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#if !defined(QT_NO_CLIPBOARD)
@@ -46,6 +10,8 @@
#include <Clipboard.h>
+using namespace Qt::StringLiterals;
+
QHaikuClipboard::QHaikuClipboard()
: m_systemMimeData(nullptr)
, m_userMimeData(nullptr)
@@ -91,10 +57,10 @@ QMimeData *QHaikuClipboard::mimeData(QClipboard::Mode mode)
const status_t status = clipboard->FindData(name, B_MIME_TYPE, &data, &dataLen);
if (dataLen && (status == B_OK)) {
- const QLatin1String format(name);
- if (format == QLatin1String("text/plain")) {
+ const QLatin1StringView format(name);
+ if (format == "text/plain"_L1) {
m_systemMimeData->setText(QString::fromLocal8Bit(reinterpret_cast<const char*>(data), dataLen));
- } else if (format == QLatin1String("text/html")) {
+ } else if (format == "text/html"_L1) {
m_systemMimeData->setHtml(QString::fromLocal8Bit(reinterpret_cast<const char*>(data), dataLen));
} else {
m_systemMimeData->setData(format, QByteArray(reinterpret_cast<const char*>(data), dataLen));
diff --git a/src/plugins/platforms/haiku/qhaikuclipboard.h b/src/plugins/platforms/haiku/qhaikuclipboard.h
index b6eb3f591f..332368ffc7 100644
--- a/src/plugins/platforms/haiku/qhaikuclipboard.h
+++ b/src/plugins/platforms/haiku/qhaikuclipboard.h
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias Koenig <tobias.koenig@kdab.com>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias Koenig <tobias.koenig@kdab.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QHAIKUCLIPBOARD_H
#define QHAIKUCLIPBOARD_H
diff --git a/src/plugins/platforms/haiku/qhaikucursor.cpp b/src/plugins/platforms/haiku/qhaikucursor.cpp
index d8e79f180a..6b06cef030 100644
--- a/src/plugins/platforms/haiku/qhaikucursor.cpp
+++ b/src/plugins/platforms/haiku/qhaikucursor.cpp
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias Koenig <tobias.koenig@kdab.com>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias Koenig <tobias.koenig@kdab.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qhaikucursor.h"
diff --git a/src/plugins/platforms/haiku/qhaikucursor.h b/src/plugins/platforms/haiku/qhaikucursor.h
index 73a1d2c492..89531c3049 100644
--- a/src/plugins/platforms/haiku/qhaikucursor.h
+++ b/src/plugins/platforms/haiku/qhaikucursor.h
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias Koenig <tobias.koenig@kdab.com>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias Koenig <tobias.koenig@kdab.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QHAIKUCURSOR_H
#define QHAIKUCURSOR_H
diff --git a/src/plugins/platforms/haiku/qhaikuintegration.cpp b/src/plugins/platforms/haiku/qhaikuintegration.cpp
index 44df6ae8f5..2b0672e363 100644
--- a/src/plugins/platforms/haiku/qhaikuintegration.cpp
+++ b/src/plugins/platforms/haiku/qhaikuintegration.cpp
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias Koenig <tobias.koenig@kdab.com>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias Koenig <tobias.koenig@kdab.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qhaikuintegration.h"
@@ -50,12 +14,14 @@
#include <QFileInfo>
#include <qpa/qplatformwindow.h>
#include <qpa/qwindowsysteminterface.h>
-#include <QtEventDispatcherSupport/private/qgenericunixeventdispatcher_p.h>
+#include <QtGui/private/qgenericunixeventdispatcher_p.h>
#include <Application.h>
QT_BEGIN_NAMESPACE
+using namespace Qt::Literals::StringLiterals;
+
static long int startApplicationThread(void *data)
{
QHaikuApplication *app = static_cast<QHaikuApplication*>(data);
@@ -68,7 +34,7 @@ QHaikuIntegration::QHaikuIntegration(const QStringList &parameters)
{
Q_UNUSED(parameters);
- const QString signature = QStringLiteral("application/x-vnd.Qt.%1").arg(QFileInfo(QCoreApplication::applicationFilePath()).fileName());
+ const QString signature = "application/x-vnd.Qt.%1"_L1.arg(QFileInfo(QCoreApplication::applicationFilePath()).fileName());
QHaikuApplication *app = new QHaikuApplication(signature.toLocal8Bit());
be_app = app;
diff --git a/src/plugins/platforms/haiku/qhaikuintegration.h b/src/plugins/platforms/haiku/qhaikuintegration.h
index 5c7a173c91..8e5f3d52f1 100644
--- a/src/plugins/platforms/haiku/qhaikuintegration.h
+++ b/src/plugins/platforms/haiku/qhaikuintegration.h
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias Koenig <tobias.koenig@kdab.com>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias Koenig <tobias.koenig@kdab.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QHAIKUINTEGRATION_H
#define QHAIKUINTEGRATION_H
diff --git a/src/plugins/platforms/haiku/qhaikukeymapper.cpp b/src/plugins/platforms/haiku/qhaikukeymapper.cpp
index 3862fac69a..131450385e 100644
--- a/src/plugins/platforms/haiku/qhaikukeymapper.cpp
+++ b/src/plugins/platforms/haiku/qhaikukeymapper.cpp
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias Koenig <tobias.koenig@kdab.com>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias Koenig <tobias.koenig@kdab.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qhaikukeymapper.h"
diff --git a/src/plugins/platforms/haiku/qhaikukeymapper.h b/src/plugins/platforms/haiku/qhaikukeymapper.h
index 73d1794b41..a3acca3fc4 100644
--- a/src/plugins/platforms/haiku/qhaikukeymapper.h
+++ b/src/plugins/platforms/haiku/qhaikukeymapper.h
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias Koenig <tobias.koenig@kdab.com>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias Koenig <tobias.koenig@kdab.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QHAIKUKEYMAPPER_H
#define QHAIKUKEYMAPPER_H
diff --git a/src/plugins/platforms/haiku/qhaikurasterbackingstore.cpp b/src/plugins/platforms/haiku/qhaikurasterbackingstore.cpp
index 613ae471cb..842e472b66 100644
--- a/src/plugins/platforms/haiku/qhaikurasterbackingstore.cpp
+++ b/src/plugins/platforms/haiku/qhaikurasterbackingstore.cpp
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias Koenig <tobias.koenig@kdab.com>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias Koenig <tobias.koenig@kdab.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qhaikurasterbackingstore.h"
#include "qhaikurasterwindow.h"
diff --git a/src/plugins/platforms/haiku/qhaikurasterbackingstore.h b/src/plugins/platforms/haiku/qhaikurasterbackingstore.h
index 060ab27126..e2e1506fef 100644
--- a/src/plugins/platforms/haiku/qhaikurasterbackingstore.h
+++ b/src/plugins/platforms/haiku/qhaikurasterbackingstore.h
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias Koenig <tobias.koenig@kdab.com>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias Koenig <tobias.koenig@kdab.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QHAIKURASTERWINDOWSURFACE_H
#define QHAIKURASTERWINDOWSURFACE_H
diff --git a/src/plugins/platforms/haiku/qhaikurasterwindow.cpp b/src/plugins/platforms/haiku/qhaikurasterwindow.cpp
index 7e57e67bab..4392bf8553 100644
--- a/src/plugins/platforms/haiku/qhaikurasterwindow.cpp
+++ b/src/plugins/platforms/haiku/qhaikurasterwindow.cpp
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias Koenig <tobias.koenig@kdab.com>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias Koenig <tobias.koenig@kdab.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qhaikurasterwindow.h"
diff --git a/src/plugins/platforms/haiku/qhaikurasterwindow.h b/src/plugins/platforms/haiku/qhaikurasterwindow.h
index 24b13aa122..750775a8d0 100644
--- a/src/plugins/platforms/haiku/qhaikurasterwindow.h
+++ b/src/plugins/platforms/haiku/qhaikurasterwindow.h
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias Koenig <tobias.koenig@kdab.com>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias Koenig <tobias.koenig@kdab.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QHAIKURASTERWINDOW_H
#define QHAIKURASTERWINDOW_H
diff --git a/src/plugins/platforms/haiku/qhaikuscreen.cpp b/src/plugins/platforms/haiku/qhaikuscreen.cpp
index 2c8abba8aa..b8c21a0308 100644
--- a/src/plugins/platforms/haiku/qhaikuscreen.cpp
+++ b/src/plugins/platforms/haiku/qhaikuscreen.cpp
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias Koenig <tobias.koenig@kdab.com>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias Koenig <tobias.koenig@kdab.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qhaikuscreen.h"
diff --git a/src/plugins/platforms/haiku/qhaikuscreen.h b/src/plugins/platforms/haiku/qhaikuscreen.h
index 98de6fdd03..22cfd82c76 100644
--- a/src/plugins/platforms/haiku/qhaikuscreen.h
+++ b/src/plugins/platforms/haiku/qhaikuscreen.h
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias Koenig <tobias.koenig@kdab.com>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias Koenig <tobias.koenig@kdab.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QHAIKUSCREEN_H
#define QHAIKUSCREEN_H
diff --git a/src/plugins/platforms/haiku/qhaikuservices.cpp b/src/plugins/platforms/haiku/qhaikuservices.cpp
index cc7e588b82..d7a101942c 100644
--- a/src/plugins/platforms/haiku/qhaikuservices.cpp
+++ b/src/plugins/platforms/haiku/qhaikuservices.cpp
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias Koenig <tobias.koenig@kdab.com>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias Koenig <tobias.koenig@kdab.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qhaikuservices.h"
diff --git a/src/plugins/platforms/haiku/qhaikuservices.h b/src/plugins/platforms/haiku/qhaikuservices.h
index 59ff6395fb..5cf2195e71 100644
--- a/src/plugins/platforms/haiku/qhaikuservices.h
+++ b/src/plugins/platforms/haiku/qhaikuservices.h
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias Koenig <tobias.koenig@kdab.com>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias Koenig <tobias.koenig@kdab.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QHAIKUSERVICES_H
#define QHAIKUSERVICES_H
diff --git a/src/plugins/platforms/haiku/qhaikuutils.cpp b/src/plugins/platforms/haiku/qhaikuutils.cpp
index 1173de82bc..202b05c7ac 100644
--- a/src/plugins/platforms/haiku/qhaikuutils.cpp
+++ b/src/plugins/platforms/haiku/qhaikuutils.cpp
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias Koenig <tobias.koenig@kdab.com>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias Koenig <tobias.koenig@kdab.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qhaikuutils.h"
diff --git a/src/plugins/platforms/haiku/qhaikuutils.h b/src/plugins/platforms/haiku/qhaikuutils.h
index d726426d89..c96b4b9f26 100644
--- a/src/plugins/platforms/haiku/qhaikuutils.h
+++ b/src/plugins/platforms/haiku/qhaikuutils.h
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias Koenig <tobias.koenig@kdab.com>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias Koenig <tobias.koenig@kdab.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QHAIKUUTILS_H
#define QHAIKUUTILS_H
diff --git a/src/plugins/platforms/haiku/qhaikuwindow.cpp b/src/plugins/platforms/haiku/qhaikuwindow.cpp
index f8fdf3f92d..3f2c6a889a 100644
--- a/src/plugins/platforms/haiku/qhaikuwindow.cpp
+++ b/src/plugins/platforms/haiku/qhaikuwindow.cpp
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias Koenig <tobias.koenig@kdab.com>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias Koenig <tobias.koenig@kdab.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qhaikuwindow.h"
@@ -330,7 +294,7 @@ void QHaikuWindow::haikuWindowResized(const QSize &size, bool zoomInProgress)
void QHaikuWindow::haikuWindowActivated(bool activated)
{
- QWindowSystemInterface::handleWindowActivated(activated ? window() : nullptr);
+ QWindowSystemInterface::handleFocusWindowChanged(activated ? window() : nullptr);
}
void QHaikuWindow::haikuWindowMinimized(bool minimize)
diff --git a/src/plugins/platforms/haiku/qhaikuwindow.h b/src/plugins/platforms/haiku/qhaikuwindow.h
index bb57742087..4ec645daa3 100644
--- a/src/plugins/platforms/haiku/qhaikuwindow.h
+++ b/src/plugins/platforms/haiku/qhaikuwindow.h
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias Koenig <tobias.koenig@kdab.com>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias Koenig <tobias.koenig@kdab.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QHAIKUWINDOW_H
#define QHAIKUWINDOW_H
diff --git a/src/plugins/platforms/integrity/integrity.pro b/src/plugins/platforms/integrity/integrity.pro
deleted file mode 100644
index 54438707eb..0000000000
--- a/src/plugins/platforms/integrity/integrity.pro
+++ /dev/null
@@ -1,29 +0,0 @@
-TARGET = integrityfb
-
-QT += \
- core-private gui-private \
- eventdispatcher_support-private service_support-private \
- fontdatabase_support-private fb_support-private
-
-SOURCES = \
- main.cpp \
- qintegrityfbintegration.cpp \
- qintegrityfbscreen.cpp
-
-HEADERS = \
- qintegrityfbintegration.h \
- qintegrityfbscreen.h
-
-qtConfig(integrityhid) {
- SOURCES += \
- qintegrityhidmanager.cpp
- HEADERS += \
- qintegrityhidmanager.h
-}
-
-OTHER_FILES += integrity.json
-
-PLUGIN_TYPE = platforms
-PLUGIN_CLASS_NAME = QIntegrityFbIntegrationPlugin
-!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = -
-load(qt_plugin)
diff --git a/src/plugins/platforms/integrity/main.cpp b/src/plugins/platforms/integrity/main.cpp
index 6313aa47e5..3cf7af3dc7 100644
--- a/src/plugins/platforms/integrity/main.cpp
+++ b/src/plugins/platforms/integrity/main.cpp
@@ -1,47 +1,13 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <qpa/qplatformintegrationplugin.h>
#include "qintegrityfbintegration.h"
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
class QIntegrityFbIntegrationPlugin : public QPlatformIntegrationPlugin
{
Q_OBJECT
@@ -53,7 +19,7 @@ public:
QPlatformIntegration* QIntegrityFbIntegrationPlugin::create(const QString& system, const QStringList& paramList)
{
Q_UNUSED(paramList);
- if (!system.compare(QLatin1String("integrityfb"), Qt::CaseInsensitive))
+ if (!system.compare("integrityfb"_L1, Qt::CaseInsensitive))
return new QIntegrityFbIntegration(paramList);
return 0;
diff --git a/src/plugins/platforms/integrity/qintegrityfbintegration.cpp b/src/plugins/platforms/integrity/qintegrityfbintegration.cpp
index 3ad31dc562..e57ad83cf8 100644
--- a/src/plugins/platforms/integrity/qintegrityfbintegration.cpp
+++ b/src/plugins/platforms/integrity/qintegrityfbintegration.cpp
@@ -1,49 +1,13 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qintegrityfbintegration.h"
#include "qintegrityfbscreen.h"
#include "qintegrityhidmanager.h"
-#include <QtFontDatabaseSupport/private/qgenericunixfontdatabase_p.h>
-#include <QtServiceSupport/private/qgenericunixservices_p.h>
-#include <QtEventDispatcherSupport/private/qgenericunixeventdispatcher_p.h>
+#include <QtGui/private/qgenericunixfontdatabase_p.h>
+#include <QtGui/private/qgenericunixservices_p.h>
+#include <QtGui/private/qgenericunixeventdispatcher_p.h>
#include <QtFbSupport/private/qfbbackingstore_p.h>
#include <QtFbSupport/private/qfbwindow_p.h>
diff --git a/src/plugins/platforms/integrity/qintegrityfbintegration.h b/src/plugins/platforms/integrity/qintegrityfbintegration.h
index d0cd5417ab..5c0d16516d 100644
--- a/src/plugins/platforms/integrity/qintegrityfbintegration.h
+++ b/src/plugins/platforms/integrity/qintegrityfbintegration.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QINTEGRITYFBINTEGRATION_H
#define QINTEGRITYFBINTEGRATION_H
diff --git a/src/plugins/platforms/integrity/qintegrityfbscreen.cpp b/src/plugins/platforms/integrity/qintegrityfbscreen.cpp
index d64b96ca4c..bfa05b1b47 100644
--- a/src/plugins/platforms/integrity/qintegrityfbscreen.cpp
+++ b/src/plugins/platforms/integrity/qintegrityfbscreen.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qintegrityfbscreen.h"
#include <QtFbSupport/private/qfbcursor_p.h>
@@ -51,6 +15,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
static QImage::Format determineFormat(const FBInfo *fbinfo)
{
QImage::Format format = QImage::Format_Invalid;
@@ -109,9 +75,9 @@ QIntegrityFbScreen::~QIntegrityFbScreen()
bool QIntegrityFbScreen::initialize()
{
Error err;
- QRegularExpression fbRx(QLatin1String("fb=(.*)"));
- QRegularExpression sizeRx(QLatin1String("size=(\\d+)x(\\d+)"));
- QRegularExpression offsetRx(QLatin1String("offset=(\\d+)x(\\d+)"));
+ QRegularExpression fbRx("fb=(.*)"_L1);
+ QRegularExpression sizeRx("size=(\\d+)x(\\d+)"_L1);
+ QRegularExpression offsetRx("offset=(\\d+)x(\\d+)"_L1);
QString fbDevice;
QRect userGeometry;
diff --git a/src/plugins/platforms/integrity/qintegrityfbscreen.h b/src/plugins/platforms/integrity/qintegrityfbscreen.h
index c38b4f073d..30ac10f94c 100644
--- a/src/plugins/platforms/integrity/qintegrityfbscreen.h
+++ b/src/plugins/platforms/integrity/qintegrityfbscreen.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QINTEGRITYFBSCREEN_H
#define QINTEGRITYFBSCREEN_H
diff --git a/src/plugins/platforms/integrity/qintegrityhidmanager.cpp b/src/plugins/platforms/integrity/qintegrityhidmanager.cpp
index 3570b90134..e79180b659 100644
--- a/src/plugins/platforms/integrity/qintegrityhidmanager.cpp
+++ b/src/plugins/platforms/integrity/qintegrityhidmanager.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 Green Hills Software
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2015 Green Hills Software
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qintegrityhidmanager.h"
#include <QList>
diff --git a/src/plugins/platforms/integrity/qintegrityhidmanager.h b/src/plugins/platforms/integrity/qintegrityhidmanager.h
index c8780b2dc2..99433f4e93 100644
--- a/src/plugins/platforms/integrity/qintegrityhidmanager.h
+++ b/src/plugins/platforms/integrity/qintegrityhidmanager.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 Green Hills Software
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2015 Green Hills Software
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QINTEGRITYHIDMANAGER_P_H
#define QINTEGRITYHIDMANAGER_P_H
@@ -52,7 +16,7 @@ class QIntegrityHIDManager : public QThread
{
Q_OBJECT
public:
- QIntegrityHIDManager(const QString &key, const QString &specification, QObject *parent = 0);
+ QIntegrityHIDManager(const QString &key, const QString &specification, QObject *parent = nullptr);
~QIntegrityHIDManager();
void run(void);
diff --git a/src/plugins/platforms/ios/.prev_CMakeLists.txt b/src/plugins/platforms/ios/.prev_CMakeLists.txt
deleted file mode 100644
index d7ff160ee0..0000000000
--- a/src/plugins/platforms/ios/.prev_CMakeLists.txt
+++ /dev/null
@@ -1,65 +0,0 @@
-# Generated from ios.pro.
-
-#####################################################################
-## QIOSIntegrationPlugin Plugin:
-#####################################################################
-
-add_qt_plugin(QIOSIntegrationPlugin
- OUTPUT_NAME qios
- TYPE platforms
- SOURCES
- plugin.mm
- qiosapplicationdelegate.h qiosapplicationdelegate.mm
- qiosapplicationstate.h qiosapplicationstate.mm
- qiosbackingstore.h qiosbackingstore.mm
- qioscontext.h qioscontext.mm
- qioseventdispatcher.h qioseventdispatcher.mm
- qiosglobal.h qiosglobal.mm
- qiosinputcontext.h qiosinputcontext.mm
- qiosintegration.h qiosintegration.mm
- qiosplatformaccessibility.h qiosplatformaccessibility.mm
- qiosscreen.h qiosscreen.mm
- qiosservices.h qiosservices.mm
- qiostextresponder.h qiostextresponder.mm
- qiostheme.h qiostheme.mm
- qiosviewcontroller.h qiosviewcontroller.mm
- qioswindow.h qioswindow.mm
- quiaccessibilityelement.h quiaccessibilityelement.mm
- quiview.h quiview.mm
- PUBLIC_LIBRARIES
- ${FWAudioToolbox}
- ${FWFoundation}
- ${FWQuartzCore}
- ${FWUIKit}
- Qt::ClipboardSupportPrivate
- Qt::CorePrivate
- Qt::FontDatabaseSupportPrivate
- Qt::GraphicsSupportPrivate
- Qt::GuiPrivate
-)
-
-#### Keys ignored in scope 2:.:.:kernel.pro:<TRUE>:
-# OTHER_FILES = "quiview_textinput.mm" "quiview_accessibility.mm"
-
-## Scopes:
-#####################################################################
-
-extend_target(QIOSIntegrationPlugin CONDITION TARGET Qt::PlatformCompositorSupportPrivate
- PUBLIC_LIBRARIES
- Qt::PlatformCompositorSupportPrivate
-)
-
-extend_target(QIOSIntegrationPlugin CONDITION NOT APPLE_TVOS
- SOURCES
- qiosclipboard.h qiosclipboard.mm
- qiosfiledialog.h qiosfiledialog.mm
- qiosmenu.h qiosmenu.mm
- qiosmessagedialog.h qiosmessagedialog.mm
- qiostextinputoverlay.h qiostextinputoverlay.mm
- PUBLIC_LIBRARIES
- ${FWAssetsLibrary}
-)
-
-#### Keys ignored in scope 6:.:.:kernel.pro:NOT TARGET___equals____ss_QT_DEFAULT_QPA_PLUGIN:
-# PLUGIN_EXTENDS = "-"
-add_subdirectory(optional)
diff --git a/src/plugins/platforms/ios/CMakeLists.txt b/src/plugins/platforms/ios/CMakeLists.txt
index d7ff160ee0..4cc3efc91e 100644
--- a/src/plugins/platforms/ios/CMakeLists.txt
+++ b/src/plugins/platforms/ios/CMakeLists.txt
@@ -1,18 +1,19 @@
-# Generated from ios.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## QIOSIntegrationPlugin Plugin:
#####################################################################
-add_qt_plugin(QIOSIntegrationPlugin
+qt_internal_add_plugin(QIOSIntegrationPlugin
OUTPUT_NAME qios
- TYPE platforms
+ STATIC # Force static, even in shared builds
+ DEFAULT_IF ${QT_QPA_DEFAULT_PLATFORM} MATCHES ios
+ PLUGIN_TYPE platforms
SOURCES
plugin.mm
qiosapplicationdelegate.h qiosapplicationdelegate.mm
qiosapplicationstate.h qiosapplicationstate.mm
- qiosbackingstore.h qiosbackingstore.mm
- qioscontext.h qioscontext.mm
qioseventdispatcher.h qioseventdispatcher.mm
qiosglobal.h qiosglobal.mm
qiosinputcontext.h qiosinputcontext.mm
@@ -26,40 +27,62 @@ add_qt_plugin(QIOSIntegrationPlugin
qioswindow.h qioswindow.mm
quiaccessibilityelement.h quiaccessibilityelement.mm
quiview.h quiview.mm
- PUBLIC_LIBRARIES
+ quiwindow.mm quiwindow.h
+ uistrings_p.h uistrings.cpp
+ NO_PCH_SOURCES
+ qioscontext.mm # undef QT_NO_FOREACH
+ qiosintegration.mm # undef QT_NO_FOREACH
+ qiosplatformaccessibility.mm # undef QT_NO_FOREACH
+ qiosscreen.mm # undef QT_NO_FOREACH
+ LIBRARIES
${FWAudioToolbox}
${FWFoundation}
+ ${FWMetal}
${FWQuartzCore}
${FWUIKit}
- Qt::ClipboardSupportPrivate
+ ${FWCoreGraphics}
Qt::CorePrivate
- Qt::FontDatabaseSupportPrivate
- Qt::GraphicsSupportPrivate
Qt::GuiPrivate
)
-#### Keys ignored in scope 2:.:.:kernel.pro:<TRUE>:
-# OTHER_FILES = "quiview_textinput.mm" "quiview_accessibility.mm"
+qt_disable_apple_app_extension_api_only(QIOSIntegrationPlugin)
## Scopes:
#####################################################################
+qt_internal_find_apple_system_framework(FWUniformTypeIdentifiers UniformTypeIdentifiers)
-extend_target(QIOSIntegrationPlugin CONDITION TARGET Qt::PlatformCompositorSupportPrivate
- PUBLIC_LIBRARIES
- Qt::PlatformCompositorSupportPrivate
+qt_internal_extend_target(QIOSIntegrationPlugin CONDITION QT_FEATURE_opengl
+ SOURCES
+ qioscontext.h qioscontext.mm
+ LIBRARIES
+ Qt::OpenGLPrivate
)
-extend_target(QIOSIntegrationPlugin CONDITION NOT APPLE_TVOS
+qt_internal_extend_target(QIOSIntegrationPlugin CONDITION QT_FEATURE_clipboard
SOURCES
qiosclipboard.h qiosclipboard.mm
+)
+
+qt_internal_extend_target(QIOSIntegrationPlugin CONDITION NOT TVOS
+ SOURCES
qiosfiledialog.h qiosfiledialog.mm
- qiosmenu.h qiosmenu.mm
+ qiosdocumentpickercontroller.h qiosdocumentpickercontroller.mm
+ LIBRARIES
+ ${FWUniformTypeIdentifiers}
+ ${FWPhotos}
+)
+
+qt_internal_extend_target(QIOSIntegrationPlugin CONDITION NOT TVOS
+ SOURCES
+ qioscolordialog.h qioscolordialog.mm
+ qiosfontdialog.h qiosfontdialog.mm
qiosmessagedialog.h qiosmessagedialog.mm
+)
+
+qt_internal_extend_target(QIOSIntegrationPlugin CONDITION NOT (TVOS OR VISIONOS)
+ SOURCES
+ qiosmenu.h qiosmenu.mm
qiostextinputoverlay.h qiostextinputoverlay.mm
- PUBLIC_LIBRARIES
- ${FWAssetsLibrary}
)
-#### Keys ignored in scope 6:.:.:kernel.pro:NOT TARGET___equals____ss_QT_DEFAULT_QPA_PLUGIN:
-# PLUGIN_EXTENDS = "-"
add_subdirectory(optional)
diff --git a/src/plugins/platforms/ios/ios.pro b/src/plugins/platforms/ios/ios.pro
deleted file mode 100644
index 594ccefcf1..0000000000
--- a/src/plugins/platforms/ios/ios.pro
+++ /dev/null
@@ -1,2 +0,0 @@
-TEMPLATE = subdirs
-SUBDIRS = kernel.pro optional
diff --git a/src/plugins/platforms/ios/kernel.pro b/src/plugins/platforms/ios/kernel.pro
deleted file mode 100644
index 01e0105223..0000000000
--- a/src/plugins/platforms/ios/kernel.pro
+++ /dev/null
@@ -1,78 +0,0 @@
-TARGET = qios
-
-# QTBUG-42937: Work around linker errors caused by circular
-# dependencies between the iOS platform plugin and the user
-# application's main() when the plugin is a shared library.
-qtConfig(shared): CONFIG += static
-
-QT += \
- core-private gui-private \
- clipboard_support-private fontdatabase_support-private graphics_support-private
-
-qtHaveModule(platformcompositor_support-private): QT += platformcompositor_support-private
-
-LIBS += -framework Foundation -framework UIKit -framework QuartzCore -framework AudioToolbox
-
-OBJECTIVE_SOURCES = \
- plugin.mm \
- qiosintegration.mm \
- qioseventdispatcher.mm \
- qioswindow.mm \
- qiosscreen.mm \
- qiosbackingstore.mm \
- qiosapplicationdelegate.mm \
- qiosapplicationstate.mm \
- qiosviewcontroller.mm \
- qioscontext.mm \
- qiosinputcontext.mm \
- qiostheme.mm \
- qiosglobal.mm \
- qiosservices.mm \
- quiview.mm \
- quiaccessibilityelement.mm \
- qiosplatformaccessibility.mm \
- qiostextresponder.mm
-
-HEADERS = \
- qiosintegration.h \
- qioseventdispatcher.h \
- qioswindow.h \
- qiosscreen.h \
- qiosbackingstore.h \
- qiosapplicationdelegate.h \
- qiosapplicationstate.h \
- qiosviewcontroller.h \
- qioscontext.h \
- qiosinputcontext.h \
- qiostheme.h \
- qiosglobal.h \
- qiosservices.h \
- quiview.h \
- quiaccessibilityelement.h \
- qiosplatformaccessibility.h \
- qiostextresponder.h
-
-!tvos {
- LIBS += -framework AssetsLibrary
- OBJECTIVE_SOURCES += \
- qiosclipboard.mm \
- qiosmenu.mm \
- qiosfiledialog.mm \
- qiosmessagedialog.mm \
- qiostextinputoverlay.mm
- HEADERS += \
- qiosclipboard.h \
- qiosmenu.h \
- qiosfiledialog.h \
- qiosmessagedialog.h \
- qiostextinputoverlay.h
-}
-
-OTHER_FILES = \
- quiview_textinput.mm \
- quiview_accessibility.mm
-
-PLUGIN_TYPE = platforms
-PLUGIN_CLASS_NAME = QIOSIntegrationPlugin
-!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = -
-load(qt_plugin)
diff --git a/src/plugins/platforms/ios/optional/CMakeLists.txt b/src/plugins/platforms/ios/optional/CMakeLists.txt
index 3c84e61f26..a01d7a6441 100644
--- a/src/plugins/platforms/ios/optional/CMakeLists.txt
+++ b/src/plugins/platforms/ios/optional/CMakeLists.txt
@@ -1,5 +1,6 @@
-# Generated from optional.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
-if(APPLE_IOS)
+if(IOS)
add_subdirectory(nsphotolibrarysupport)
endif()
diff --git a/src/plugins/platforms/ios/optional/nsphotolibrarysupport/CMakeLists.txt b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/CMakeLists.txt
index 0fbb0fdbd8..663878bde7 100644
--- a/src/plugins/platforms/ios/optional/nsphotolibrarysupport/CMakeLists.txt
+++ b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/CMakeLists.txt
@@ -1,18 +1,22 @@
-# Generated from nsphotolibrarysupport.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## QIosOptionalPlugin_NSPhotoLibrary Plugin:
#####################################################################
-add_qt_plugin(QIosOptionalPlugin_NSPhotoLibrary
+qt_internal_add_plugin(QIosOptionalPlugin_NSPhotoLibraryPlugin
OUTPUT_NAME qiosnsphotolibrarysupport
- TYPE platforms/darwin
+ STATIC # Force static, even in shared builds
+ PLUGIN_TYPE platforms/darwin
+ CLASS_NAME QIosOptionalPlugin_NSPhotoLibrary
+ DEFAULT_IF FALSE
SOURCES
plugin.mm
qiosfileengineassetslibrary.h qiosfileengineassetslibrary.mm
qiosfileenginefactory.h
qiosimagepickercontroller.h qiosimagepickercontroller.mm
- PUBLIC_LIBRARIES
+ LIBRARIES
${FWAssetsLibrary}
${FWFoundation}
${FWUIKit}
@@ -21,9 +25,7 @@ add_qt_plugin(QIosOptionalPlugin_NSPhotoLibrary
Qt::GuiPrivate
)
-#### Keys ignored in scope 1:.:.:nsphotolibrarysupport.pro:<TRUE>:
-# OTHER_FILES = "plugin.json"
-# PLUGIN_EXTENDS = "-"
-
-## Scopes:
-#####################################################################
+set_target_properties(QIosOptionalPlugin_NSPhotoLibraryPlugin
+ PROPERTIES
+ DISABLE_PRECOMPILE_HEADERS ON
+)
diff --git a/src/plugins/platforms/ios/optional/nsphotolibrarysupport/nsphotolibrarysupport.pro b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/nsphotolibrarysupport.pro
deleted file mode 100644
index 7379765599..0000000000
--- a/src/plugins/platforms/ios/optional/nsphotolibrarysupport/nsphotolibrarysupport.pro
+++ /dev/null
@@ -1,26 +0,0 @@
-TARGET = qiosnsphotolibrarysupport
-
-# QTBUG-42937: Since the iOS plugin (kernel) is
-# static, this plugin needs to be static as well.
-qtConfig(shared): CONFIG += static
-
-QT += core gui gui-private
-LIBS += -framework Foundation -framework UIKit -framework AssetsLibrary
-
-HEADERS = \
- qiosfileengineassetslibrary.h \
- qiosfileenginefactory.h \
- qiosimagepickercontroller.h
-
-OBJECTIVE_SOURCES = \
- plugin.mm \
- qiosfileengineassetslibrary.mm \
- qiosimagepickercontroller.mm \
-
-OTHER_FILES = \
- plugin.json
-
-PLUGIN_CLASS_NAME = QIosOptionalPlugin_NSPhotoLibrary
-PLUGIN_EXTENDS = -
-PLUGIN_TYPE = platforms/darwin
-load(qt_plugin)
diff --git a/src/plugins/platforms/ios/optional/nsphotolibrarysupport/plugin.mm b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/plugin.mm
index 8b372b8749..693b9e4345 100644
--- a/src/plugins/platforms/ios/optional/nsphotolibrarysupport/plugin.mm
+++ b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/plugin.mm
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "../../qiosoptionalplugininterface.h"
#include "../../qiosfiledialog.h"
@@ -52,7 +16,7 @@ class QIosOptionalPlugin_NSPhotoLibrary : public QObject, QIosOptionalPluginInte
Q_INTERFACES(QIosOptionalPluginInterface)
public:
- explicit QIosOptionalPlugin_NSPhotoLibrary(QObject* = 0) {};
+ explicit QIosOptionalPlugin_NSPhotoLibrary(QObject * = nullptr) {};
~QIosOptionalPlugin_NSPhotoLibrary() {}
UIViewController* createImagePickerController(QIOSFileDialog *fileDialog) const override
diff --git a/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosfileengineassetslibrary.h b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosfileengineassetslibrary.h
index 8d7cabf15b..0ad54a9e11 100644
--- a/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosfileengineassetslibrary.h
+++ b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosfileengineassetslibrary.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QIOSFILEENGINEASSETSLIBRARY_H
#define QIOSFILEENGINEASSETSLIBRARY_H
@@ -54,7 +18,7 @@ public:
QIOSFileEngineAssetsLibrary(const QString &fileName);
~QIOSFileEngineAssetsLibrary();
- bool open(QIODevice::OpenMode openMode) override;
+ bool open(QIODevice::OpenMode openMode, std::optional<QFile::Permissions> permissions) override;
bool close() override;
FileFlags fileFlags(FileFlags type) const override;
qint64 size() const override;
@@ -63,11 +27,10 @@ public:
bool seek(qint64 pos) override;
QString fileName(FileName file) const override;
void setFileName(const QString &file) override;
- QStringList entryList(QDir::Filters filters, const QStringList &filterNames) const override;
#ifndef QT_NO_FILESYSTEMITERATOR
- Iterator *beginEntryList(QDir::Filters filters, const QStringList &filterNames) override;
- Iterator *endEntryList() override;
+ IteratorUniquePtr beginEntryList(const QString &path, QDir::Filters filters,
+ const QStringList &filterNames) override;
#endif
void setError(QFile::FileError error, const QString &str) { QAbstractFileEngine::setError(error, str); }
diff --git a/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosfileengineassetslibrary.mm b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosfileengineassetslibrary.mm
index c5244a51ad..f7e112ab81 100644
--- a/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosfileengineassetslibrary.mm
+++ b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosfileengineassetslibrary.mm
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qiosfileengineassetslibrary.h"
@@ -47,14 +11,18 @@
#include <QtCore/qurl.h>
#include <QtCore/qset.h>
#include <QtCore/qthreadstorage.h>
+#include <QtCore/qfileselector.h>
+#include <QtCore/qpointer.h>
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
static QThreadStorage<QString> g_iteratorCurrentUrl;
static QThreadStorage<QPointer<QIOSAssetData> > g_assetDataCache;
static const int kBufferSize = 10;
-static ALAsset *kNoAsset = 0;
+static ALAsset *kNoAsset = nullptr;
static bool ensureAuthorizationDialogNotBlocked()
{
@@ -222,7 +190,7 @@ public:
// We can only load images from the asset library async. And this might take time, since it
// involves showing the authorization dialog. But the QFile API is synchronuous, so we need to
- // wait until we have access to the data. [ALAssetLibrary assetForUrl:] will shedule a block on
+ // wait until we have access to the data. [ALAssetLibrary assetForUrl:] will schedule a block on
// the current thread. But instead of spinning the event loop to force the block to execute, we
// wrap the call inside a synchronuous dispatch queue so that it executes on another thread.
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
@@ -249,7 +217,7 @@ public:
}
if (!asset)
- engine->setError(QFile::OpenError, QLatin1String("could not open image"));
+ engine->setError(QFile::OpenError, "could not open image"_L1);
m_asset = [asset retain];
dispatch_semaphore_signal(semaphore);
@@ -290,8 +258,8 @@ public:
QIOSAssetEnumerator *m_enumerator;
QIOSFileEngineIteratorAssetsLibrary(
- QDir::Filters filters, const QStringList &nameFilters)
- : QAbstractFileEngineIterator(filters, nameFilters)
+ const QString &path, QDir::Filters filters, const QStringList &nameFilters)
+ : QAbstractFileEngineIterator(path, filters, nameFilters)
, m_enumerator(new QIOSAssetEnumerator([[[ALAssetsLibrary alloc] init] autorelease], ALAssetsGroupAll))
{
}
@@ -302,8 +270,11 @@ public:
g_iteratorCurrentUrl.setLocalData(QString());
}
- QString next() override
+ bool advance() override
{
+ if (!m_enumerator->hasNext())
+ return false;
+
// Cache the URL that we are about to return, since QDir will immediately create a
// new file engine on the file and ask if it exists. Unless we do this, we end up
// creating a new ALAsset just to verify its existence, which will be especially
@@ -311,12 +282,7 @@ public:
ALAsset *asset = m_enumerator->next();
QString url = QUrl::fromNSURL([asset valueForProperty:ALAssetPropertyAssetURL]).toString();
g_iteratorCurrentUrl.setLocalData(url);
- return url;
- }
-
- bool hasNext() const override
- {
- return m_enumerator->hasNext();
+ return true;
}
QString currentFileName() const override
@@ -353,8 +319,11 @@ ALAsset *QIOSFileEngineAssetsLibrary::loadAsset() const
return m_data->m_asset;
}
-bool QIOSFileEngineAssetsLibrary::open(QIODevice::OpenMode openMode)
+bool QIOSFileEngineAssetsLibrary::open(QIODevice::OpenMode openMode,
+ std::optional<QFile::Permissions> permissions)
{
+ Q_UNUSED(permissions);
+
if (openMode & (QIODevice::WriteOnly | QIODevice::Text))
return false;
return loadAsset();
@@ -366,7 +335,7 @@ bool QIOSFileEngineAssetsLibrary::close()
// Delete later, so that we can reuse the asset if a QFile is
// opened with the same path during the same event loop cycle.
m_data->deleteLater();
- m_data = 0;
+ m_data = nullptr;
}
return true;
}
@@ -374,7 +343,18 @@ bool QIOSFileEngineAssetsLibrary::close()
QAbstractFileEngine::FileFlags QIOSFileEngineAssetsLibrary::fileFlags(QAbstractFileEngine::FileFlags type) const
{
QAbstractFileEngine::FileFlags flags;
- const bool isDir = (m_assetUrl == QLatin1String("assets-library://"));
+ const bool isDir = (m_assetUrl == "assets-library://"_L1);
+ if (!isDir) {
+ static const QFileSelector fileSelector;
+ static const auto selectors = fileSelector.allSelectors();
+ if (m_assetUrl.startsWith("assets-library://"_L1)) {
+ for (const auto &selector : selectors) {
+ if (m_assetUrl.endsWith(selector))
+ return flags;
+ }
+ }
+ }
+
const bool exists = isDir || m_assetUrl == g_iteratorCurrentUrl.localData() || loadAsset();
if (!exists)
@@ -410,7 +390,7 @@ qint64 QIOSFileEngineAssetsLibrary::read(char *data, qint64 maxlen)
if (!bytesRead)
return 0;
- NSError *error = 0;
+ NSError *error = nullptr;
[[asset defaultRepresentation] getBytes:(uint8_t *)data fromOffset:m_offset length:bytesRead error:&error];
if (error) {
@@ -449,29 +429,20 @@ void QIOSFileEngineAssetsLibrary::setFileName(const QString &file)
// QUrl::fromLocalFile() will remove double slashes. Since the asset url is
// passed around as a file name in the app (and converted to/from a file url, e.g
// in QFileDialog), we need to ensure that m_assetUrl ends up being valid.
- int index = file.indexOf(QLatin1String("/asset"));
+ qsizetype index = file.indexOf("/asset"_L1);
if (index == -1)
- m_assetUrl = QLatin1String("assets-library://");
+ m_assetUrl = "assets-library://"_L1;
else
- m_assetUrl = QLatin1String("assets-library:/") + file.mid(index);
-}
-
-QStringList QIOSFileEngineAssetsLibrary::entryList(QDir::Filters filters, const QStringList &filterNames) const
-{
- return QAbstractFileEngine::entryList(filters, filterNames);
+ m_assetUrl = "assets-library:/"_L1 + file.mid(index);
}
#ifndef QT_NO_FILESYSTEMITERATOR
-QAbstractFileEngine::Iterator *QIOSFileEngineAssetsLibrary::beginEntryList(
- QDir::Filters filters, const QStringList &filterNames)
+QAbstractFileEngine::IteratorUniquePtr
+QIOSFileEngineAssetsLibrary::beginEntryList(
+ const QString &path, QDir::Filters filters, const QStringList &filterNames)
{
- return new QIOSFileEngineIteratorAssetsLibrary(filters, filterNames);
-}
-
-QAbstractFileEngine::Iterator *QIOSFileEngineAssetsLibrary::endEntryList()
-{
- return 0;
+ return std::make_unique<QIOSFileEngineIteratorAssetsLibrary>(path, filters, filterNames);
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosfileenginefactory.h b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosfileenginefactory.h
index b143357aa5..136716f792 100644
--- a/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosfileenginefactory.h
+++ b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosfileenginefactory.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QIOSFILEENGINEFACTORY_H
#define QIOSFILEENGINEFACTORY_H
@@ -49,18 +13,18 @@ QT_BEGIN_NAMESPACE
class QIOSFileEngineFactory : public QAbstractFileEngineHandler
{
public:
- QAbstractFileEngine* create(const QString &fileName) const
+ std::unique_ptr<QAbstractFileEngine> create(const QString &fileName) const
{
- static QLatin1String assetsScheme("assets-library:");
+ Q_CONSTINIT static QLatin1StringView assetsScheme("assets-library:");
#ifndef Q_OS_TVOS
if (fileName.toLower().startsWith(assetsScheme))
- return new QIOSFileEngineAssetsLibrary(fileName);
+ return std::make_unique<QIOSFileEngineAssetsLibrary>(fileName);
#else
Q_UNUSED(fileName);
#endif
- return 0;
+ return {};
}
};
diff --git a/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosimagepickercontroller.h b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosimagepickercontroller.h
index 201b277494..bd5c0ae350 100644
--- a/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosimagepickercontroller.h
+++ b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosimagepickercontroller.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#import <UIKit/UIKit.h>
diff --git a/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosimagepickercontroller.mm b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosimagepickercontroller.mm
index 79d4ecf83f..2ebd75549f 100644
--- a/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosimagepickercontroller.mm
+++ b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosimagepickercontroller.mm
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#import <UIKit/UIKit.h>
@@ -67,7 +31,7 @@
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker
{
- Q_UNUSED(picker)
+ Q_UNUSED(picker);
emit m_fileDialog->reject();
}
diff --git a/src/plugins/platforms/ios/optional/optional.pro b/src/plugins/platforms/ios/optional/optional.pro
deleted file mode 100644
index 6b4ae1ef5e..0000000000
--- a/src/plugins/platforms/ios/optional/optional.pro
+++ /dev/null
@@ -1,2 +0,0 @@
-TEMPLATE = subdirs
-ios: SUBDIRS = nsphotolibrarysupport
diff --git a/src/plugins/platforms/ios/plugin.mm b/src/plugins/platforms/ios/plugin.mm
index 83760f2f39..4fba69eb85 100644
--- a/src/plugins/platforms/ios/plugin.mm
+++ b/src/plugins/platforms/ios/plugin.mm
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <qpa/qplatformintegrationplugin.h>
#include <qpa/qplatformthemeplugin.h>
@@ -43,6 +7,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
class QIOSIntegrationPlugin : public QPlatformIntegrationPlugin
{
Q_OBJECT
@@ -54,8 +20,8 @@ class QIOSIntegrationPlugin : public QPlatformIntegrationPlugin
QPlatformIntegration * QIOSIntegrationPlugin::create(const QString& system, const QStringList& paramList)
{
Q_UNUSED(paramList);
- if (!system.compare(QLatin1String("ios"), Qt::CaseInsensitive)
- || !system.compare(QLatin1String("tvos"), Qt::CaseInsensitive)) {
+ if (!system.compare("ios"_L1, Qt::CaseInsensitive)
+ || !system.compare("tvos"_L1, Qt::CaseInsensitive)) {
return new QIOSIntegration;
}
diff --git a/src/plugins/platforms/ios/qiosapplicationdelegate.h b/src/plugins/platforms/ios/qiosapplicationdelegate.h
index 722c0801a0..39bb9fdedb 100644
--- a/src/plugins/platforms/ios/qiosapplicationdelegate.h
+++ b/src/plugins/platforms/ios/qiosapplicationdelegate.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#import <UIKit/UIKit.h>
#import <QtGui/QtGui>
diff --git a/src/plugins/platforms/ios/qiosapplicationdelegate.mm b/src/plugins/platforms/ios/qiosapplicationdelegate.mm
index a56c1e4568..a017fef457 100644
--- a/src/plugins/platforms/ios/qiosapplicationdelegate.mm
+++ b/src/plugins/platforms/ios/qiosapplicationdelegate.mm
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qiosapplicationdelegate.h"
@@ -50,6 +14,26 @@
@implementation QIOSApplicationDelegate
+- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray<id<UIUserActivityRestoring>> *restorableObjects))restorationHandler
+{
+ Q_UNUSED(application);
+ Q_UNUSED(restorationHandler);
+
+ if (!QGuiApplication::instance())
+ return NO;
+
+ if ([userActivity.activityType isEqualToString:NSUserActivityTypeBrowsingWeb]) {
+ QIOSIntegration *iosIntegration = QIOSIntegration::instance();
+ Q_ASSERT(iosIntegration);
+
+ QIOSServices *iosServices = static_cast<QIOSServices *>(iosIntegration->services());
+
+ return iosServices->handleUrl(QUrl::fromNSURL(userActivity.webpageURL));
+ }
+
+ return NO;
+}
+
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey, id> *)options
{
Q_UNUSED(application);
diff --git a/src/plugins/platforms/ios/qiosapplicationstate.h b/src/plugins/platforms/ios/qiosapplicationstate.h
index 8a15a4a51b..ddac0b69de 100644
--- a/src/plugins/platforms/ios/qiosapplicationstate.h
+++ b/src/plugins/platforms/ios/qiosapplicationstate.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QIOSAPPLICATIONSTATE_H
#define QIOSAPPLICATIONSTATE_H
diff --git a/src/plugins/platforms/ios/qiosapplicationstate.mm b/src/plugins/platforms/ios/qiosapplicationstate.mm
index bf4e9cc900..fdc2c70df7 100644
--- a/src/plugins/platforms/ios/qiosapplicationstate.mm
+++ b/src/plugins/platforms/ios/qiosapplicationstate.mm
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qiosapplicationstate.h"
@@ -50,6 +14,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
static void qRegisterApplicationStateNotifications()
{
NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
@@ -83,11 +49,11 @@ static void qRegisterApplicationStateNotifications()
if (qt_apple_isApplicationExtension()) {
// Extensions are not allowed to access UIApplication, so we assume the state is active
QIOSApplicationState::handleApplicationStateChanged(UIApplicationStateActive,
- QLatin1String("Extension loaded, assuming state is active"));
+ "Extension loaded, assuming state is active"_L1);
} else {
// Initialize correct startup state, which may not be the Qt default (inactive)
UIApplicationState startupState = qt_apple_sharedApplication().applicationState;
- QIOSApplicationState::handleApplicationStateChanged(startupState, QLatin1String("Application loaded"));
+ QIOSApplicationState::handleApplicationStateChanged(startupState, "Application loaded"_L1);
}
}
Q_CONSTRUCTOR_FUNCTION(qRegisterApplicationStateNotifications)
@@ -96,7 +62,7 @@ QIOSApplicationState::QIOSApplicationState()
{
if (!qt_apple_isApplicationExtension()) {
UIApplicationState startupState = qt_apple_sharedApplication().applicationState;
- QIOSApplicationState::handleApplicationStateChanged(startupState, QLatin1String("Application launched"));
+ QIOSApplicationState::handleApplicationStateChanged(startupState, "Application launched"_L1);
}
}
diff --git a/src/plugins/platforms/ios/qiosbackingstore.h b/src/plugins/platforms/ios/qiosbackingstore.h
deleted file mode 100644
index 38006ba90b..0000000000
--- a/src/plugins/platforms/ios/qiosbackingstore.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 QIOSBACKINGSTORE_H
-#define QIOSBACKINGSTORE_H
-
-#include <qpa/qplatformbackingstore.h>
-
-#include <QtGraphicsSupport/private/qrasterbackingstore_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class QOpenGLPaintDevice;
-
-class QIOSBackingStore : public QRasterBackingStore
-{
-public:
- QIOSBackingStore(QWindow *window);
- ~QIOSBackingStore();
-
- void flush(QWindow *window, const QRegion &region, const QPoint &offset) override;
-};
-
-QT_END_NAMESPACE
-
-#endif // QIOSBACKINGSTORE_H
diff --git a/src/plugins/platforms/ios/qiosbackingstore.mm b/src/plugins/platforms/ios/qiosbackingstore.mm
deleted file mode 100644
index db4dd81b2e..0000000000
--- a/src/plugins/platforms/ios/qiosbackingstore.mm
+++ /dev/null
@@ -1,91 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 "qiosbackingstore.h"
-#include "qioswindow.h"
-
-#include <QtGui/QOpenGLContext>
-#include <QtGui/private/qwindow_p.h>
-
-#include <QtDebug>
-
-QT_BEGIN_NAMESPACE
-
-/*!
- \class QIOSBackingStore
-
- QBackingStore enables the use of QPainter to paint on a QWindow, as opposed
- to rendering to a QWindow through the use of OpenGL with QOpenGLContext.
-*/
-QIOSBackingStore::QIOSBackingStore(QWindow *window)
- : QRasterBackingStore(window)
-{
- // We use the surface both for raster operations and for GL drawing (when
- // we blit the raster image), so the type needs to cover both use cases.
- if (window->surfaceType() == QSurface::RasterSurface)
- window->setSurfaceType(QSurface::RasterGLSurface);
-
- Q_ASSERT_X(window->surfaceType() != QSurface::OpenGLSurface, "QIOSBackingStore",
- "QBackingStore on iOS can only be used with raster-enabled surfaces.");
-}
-
-QIOSBackingStore::~QIOSBackingStore()
-{
-}
-
-void QIOSBackingStore::flush(QWindow *window, const QRegion &region, const QPoint &offset)
-{
- Q_ASSERT(!qt_window_private(window)->compositing);
-
- Q_UNUSED(region);
- Q_UNUSED(offset);
-
- if (window != this->window()) {
- // We skip flushing raster-based child windows, to avoid the extra cost of copying from the
- // parent FBO into the child FBO. Since the child is already drawn inside the parent FBO, it
- // will become visible when flushing the parent. The only case we end up not supporting is if
- // the child window overlaps a sibling window that's draws using a separate QOpenGLContext.
- return;
- }
-
- static QPlatformTextureList emptyTextureList;
- composeAndFlush(window, region, offset, &emptyTextureList, false);
-}
-
-QT_END_NAMESPACE
diff --git a/src/plugins/platforms/ios/qiosclipboard.h b/src/plugins/platforms/ios/qiosclipboard.h
index 3fe9b29b71..0e46a65223 100644
--- a/src/plugins/platforms/ios/qiosclipboard.h
+++ b/src/plugins/platforms/ios/qiosclipboard.h
@@ -1,45 +1,10 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QIOSCLIPBOARD_H
#define QIOSCLIPBOARD_H
+#include <QtCore/qmap.h>
#include <qpa/qplatformclipboard.h>
#ifndef QT_NO_CLIPBOARD
diff --git a/src/plugins/platforms/ios/qiosclipboard.mm b/src/plugins/platforms/ios/qiosclipboard.mm
index 6bdbf94d3f..de8ab69dff 100644
--- a/src/plugins/platforms/ios/qiosclipboard.mm
+++ b/src/plugins/platforms/ios/qiosclipboard.mm
@@ -1,62 +1,16 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qiosclipboard.h"
#ifndef QT_NO_CLIPBOARD
-#include <QtClipboardSupport/private/qmacmime_p.h>
+#include <QtCore/qurl.h>
+#include <QtGui/private/qmacmimeregistry_p.h>
+#include <QtGui/qutimimeconverter.h>
#include <QtCore/QMimeData>
#include <QtGui/QGuiApplication>
-@interface UIPasteboard (QUIPasteboard)
-+ (instancetype)pasteboardWithQClipboardMode:(QClipboard::Mode)mode;
-@end
-
-@implementation UIPasteboard (QUIPasteboard)
-+ (instancetype)pasteboardWithQClipboardMode:(QClipboard::Mode)mode
-{
- NSString *name = (mode == QClipboard::Clipboard) ? UIPasteboardNameGeneral : UIPasteboardNameFind;
- return [UIPasteboard pasteboardWithName:name create:NO];
-}
-@end
-
// --------------------------------------------------------------------
@interface QUIClipboard : NSObject
@@ -65,7 +19,6 @@
@implementation QUIClipboard {
QIOSClipboard *m_qiosClipboard;
NSInteger m_changeCountClipboard;
- NSInteger m_changeCountFindBuffer;
}
- (instancetype)initWithQIOSClipboard:(QIOSClipboard *)qiosClipboard
@@ -73,8 +26,7 @@
self = [super init];
if (self) {
m_qiosClipboard = qiosClipboard;
- m_changeCountClipboard = [UIPasteboard pasteboardWithQClipboardMode:QClipboard::Clipboard].changeCount;
- m_changeCountFindBuffer = [UIPasteboard pasteboardWithQClipboardMode:QClipboard::FindBuffer].changeCount;
+ m_changeCountClipboard = UIPasteboard.generalPasteboard.changeCount;
[[NSNotificationCenter defaultCenter]
addObserver:self
@@ -111,18 +63,12 @@
- (void)updatePasteboardChanged:(NSNotification *)notification
{
Q_UNUSED(notification);
- NSInteger changeCountClipboard = [UIPasteboard pasteboardWithQClipboardMode:QClipboard::Clipboard].changeCount;
- NSInteger changeCountFindBuffer = [UIPasteboard pasteboardWithQClipboardMode:QClipboard::FindBuffer].changeCount;
+ NSInteger changeCountClipboard = UIPasteboard.generalPasteboard.changeCount;
if (m_changeCountClipboard != changeCountClipboard) {
m_changeCountClipboard = changeCountClipboard;
m_qiosClipboard->emitChanged(QClipboard::Clipboard);
}
-
- if (m_changeCountFindBuffer != changeCountFindBuffer) {
- m_changeCountFindBuffer = changeCountFindBuffer;
- m_qiosClipboard->emitChanged(QClipboard::FindBuffer);
- }
}
@end
@@ -133,25 +79,22 @@ QT_BEGIN_NAMESPACE
class QIOSMimeData : public QMimeData {
public:
- QIOSMimeData(QClipboard::Mode mode) : QMimeData(), m_mode(mode) { }
+ QIOSMimeData() : QMimeData() { }
~QIOSMimeData() { }
QStringList formats() const override;
- QVariant retrieveData(const QString &mimeType, QVariant::Type type) const override;
-
-private:
- const QClipboard::Mode m_mode;
+ QVariant retrieveData(const QString &mimeType, QMetaType type) const override;
};
QStringList QIOSMimeData::formats() const
{
QStringList foundMimeTypes;
- UIPasteboard *pb = [UIPasteboard pasteboardWithQClipboardMode:m_mode];
+ UIPasteboard *pb = UIPasteboard.generalPasteboard;
NSArray<NSString *> *pasteboardTypes = [pb pasteboardTypes];
for (NSUInteger i = 0; i < [pasteboardTypes count]; ++i) {
- QString uti = QString::fromNSString([pasteboardTypes objectAtIndex:i]);
- QString mimeType = QMacInternalPasteboardMime::flavorToMime(QMacInternalPasteboardMime::MIME_ALL, uti);
+ const QString uti = QString::fromNSString([pasteboardTypes objectAtIndex:i]);
+ const QString mimeType = QMacMimeRegistry::flavorToMime(QUtiMimeConverter::HandlerScopeFlag::All, uti);
if (!mimeType.isEmpty() && !foundMimeTypes.contains(mimeType))
foundMimeTypes << mimeType;
}
@@ -159,19 +102,16 @@ QStringList QIOSMimeData::formats() const
return foundMimeTypes;
}
-QVariant QIOSMimeData::retrieveData(const QString &mimeType, QVariant::Type) const
+QVariant QIOSMimeData::retrieveData(const QString &mimeType, QMetaType) const
{
- UIPasteboard *pb = [UIPasteboard pasteboardWithQClipboardMode:m_mode];
+ UIPasteboard *pb = UIPasteboard.generalPasteboard;
NSArray<NSString *> *pasteboardTypes = [pb pasteboardTypes];
- foreach (QMacInternalPasteboardMime *converter,
- QMacInternalPasteboardMime::all(QMacInternalPasteboardMime::MIME_ALL)) {
- if (!converter->canConvert(mimeType, converter->flavorFor(mimeType)))
- continue;
-
+ const auto converters = QMacMimeRegistry::all(QUtiMimeConverter::HandlerScopeFlag::All);
+ for (QUtiMimeConverter *converter : converters) {
for (NSUInteger i = 0; i < [pasteboardTypes count]; ++i) {
NSString *availableUtiNSString = [pasteboardTypes objectAtIndex:i];
- QString availableUti = QString::fromNSString(availableUtiNSString);
+ const QString availableUti = QString::fromNSString(availableUtiNSString);
if (!converter->canConvert(mimeType, availableUti))
continue;
@@ -201,7 +141,7 @@ QMimeData *QIOSClipboard::mimeData(QClipboard::Mode mode)
{
Q_ASSERT(supportsMode(mode));
if (!m_mimeData.contains(mode))
- return *m_mimeData.insert(mode, new QIOSMimeData(mode));
+ return *m_mimeData.insert(mode, new QIOSMimeData);
return m_mimeData[mode];
}
@@ -209,7 +149,7 @@ void QIOSClipboard::setMimeData(QMimeData *mimeData, QClipboard::Mode mode)
{
Q_ASSERT(supportsMode(mode));
- UIPasteboard *pb = [UIPasteboard pasteboardWithQClipboardMode:mode];
+ UIPasteboard *pb = UIPasteboard.generalPasteboard;
if (!mimeData) {
pb.items = [NSArray<NSDictionary<NSString *, id> *> array];
return;
@@ -218,26 +158,29 @@ void QIOSClipboard::setMimeData(QMimeData *mimeData, QClipboard::Mode mode)
mimeData->deleteLater();
NSMutableDictionary<NSString *, id> *pbItem = [NSMutableDictionary<NSString *, id> dictionaryWithCapacity:mimeData->formats().size()];
- foreach (const QString &mimeType, mimeData->formats()) {
- foreach (QMacInternalPasteboardMime *converter,
- QMacInternalPasteboardMime::all(QMacInternalPasteboardMime::MIME_ALL)) {
- QString uti = converter->flavorFor(mimeType);
- if (uti.isEmpty() || !converter->canConvert(mimeType, uti))
+ const auto formats = mimeData->formats();
+ for (const QString &mimeType : formats) {
+ const auto converters = QMacMimeRegistry::all(QUtiMimeConverter::HandlerScopeFlag::All);
+ for (const QUtiMimeConverter *converter : converters) {
+ const QString uti = converter->utiForMime(mimeType);
+ if (uti.isEmpty())
continue;
QVariant mimeDataAsVariant;
if (mimeData->hasImage()) {
mimeDataAsVariant = mimeData->imageData();
} else if (mimeData->hasUrls()) {
+ const auto urls = mimeData->urls();
QVariantList urlList;
- for (QUrl url : mimeData->urls())
+ urlList.reserve(urls.size());
+ for (const QUrl& url : urls)
urlList << url;
mimeDataAsVariant = QVariant(urlList);
} else {
mimeDataAsVariant = QVariant(mimeData->data(mimeType));
}
- QByteArray byteArray = converter->convertFromMime(mimeType, mimeDataAsVariant, uti).first();
+ QByteArray byteArray = converter->convertFromMime(mimeType, mimeDataAsVariant, uti).constFirst();
NSData *nsData = [NSData dataWithBytes:byteArray.constData() length:byteArray.size()];
[pbItem setValue:nsData forKey:uti.toNSString()];
break;
@@ -249,7 +192,7 @@ void QIOSClipboard::setMimeData(QMimeData *mimeData, QClipboard::Mode mode)
bool QIOSClipboard::supportsMode(QClipboard::Mode mode) const
{
- return (mode == QClipboard::Clipboard || mode == QClipboard::FindBuffer);
+ return mode == QClipboard::Clipboard;
}
bool QIOSClipboard::ownsMode(QClipboard::Mode mode) const
diff --git a/src/plugins/platforms/ios/qioscolordialog.h b/src/plugins/platforms/ios/qioscolordialog.h
new file mode 100644
index 0000000000..1af718949b
--- /dev/null
+++ b/src/plugins/platforms/ios/qioscolordialog.h
@@ -0,0 +1,38 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QIOSCOLORDIALOG_H
+#define QIOSCOLORDIALOG_H
+
+#include <QtCore/qeventloop.h>
+#include <qpa/qplatformdialoghelper.h>
+
+Q_FORWARD_DECLARE_OBJC_CLASS(QIOSColorDialogController);
+
+QT_BEGIN_NAMESPACE
+
+class QIOSColorDialog : public QPlatformColorDialogHelper
+{
+public:
+ QIOSColorDialog();
+ ~QIOSColorDialog();
+
+ void exec() override;
+ bool show(Qt::WindowFlags windowFlags, Qt::WindowModality windowModality, QWindow *parent) override;
+ void hide() override;
+
+ void setCurrentColor(const QColor&) override;
+ QColor currentColor() const override;
+
+ void updateColor(const QColor&);
+
+private:
+ QEventLoop m_eventLoop;
+ QIOSColorDialogController *m_viewController;
+ QColor m_currentColor;
+};
+
+QT_END_NAMESPACE
+
+#endif // QIOSCOLORDIALOG_H
+
diff --git a/src/plugins/platforms/ios/qioscolordialog.mm b/src/plugins/platforms/ios/qioscolordialog.mm
new file mode 100644
index 0000000000..6651b1791d
--- /dev/null
+++ b/src/plugins/platforms/ios/qioscolordialog.mm
@@ -0,0 +1,159 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#import <UIKit/UIKit.h>
+
+#include <QtGui/qwindow.h>
+#include <QDebug>
+
+#include <QtCore/private/qcore_mac_p.h>
+
+#include "qiosglobal.h"
+#include "qioscolordialog.h"
+#include "qiosintegration.h"
+
+@interface QIOSColorDialogController : UIColorPickerViewController <UIColorPickerViewControllerDelegate,
+ UIAdaptivePresentationControllerDelegate>
+@end
+
+@implementation QIOSColorDialogController {
+ QIOSColorDialog *m_colorDialog;
+}
+
+- (instancetype)initWithQIOSColorDialog:(QIOSColorDialog *)dialog
+{
+ if (self = [super init]) {
+ m_colorDialog = dialog;
+ self.delegate = self;
+ self.presentationController.delegate = self;
+ self.supportsAlpha = dialog->options()->testOption(QColorDialogOptions::ShowAlphaChannel);
+ }
+ return self;
+}
+
+- (void)setQColor:(const QColor &)qColor
+{
+ UIColor *uiColor;
+ const QColor::Spec spec = qColor.spec();
+ if (spec == QColor::Hsv) {
+ uiColor = [UIColor colorWithHue:qColor.hsvHueF()
+ saturation:qColor.hsvSaturationF()
+ brightness:qColor.valueF()
+ alpha:qColor.alphaF()];
+ } else {
+ uiColor = [UIColor colorWithRed:qColor.redF()
+ green:qColor.greenF()
+ blue:qColor.blueF()
+ alpha:qColor.alphaF()];
+ }
+ self.selectedColor = uiColor;
+}
+
+- (void)updateQColor
+{
+ UIColor *color = self.selectedColor;
+ CGFloat red = 0, green = 0, blue = 0, alpha = 0;
+
+ QColor newColor;
+ if ([color getRed:&red green:&green blue:&blue alpha:&alpha])
+ newColor.setRgbF(red, green, blue, alpha);
+ else
+ qWarning() << "Incompatible color space";
+
+
+ if (m_colorDialog) {
+ m_colorDialog->updateColor(newColor);
+ emit m_colorDialog->currentColorChanged(newColor);
+ }
+}
+
+// ----------------------UIColorPickerViewControllerDelegate--------------------------
+- (void)colorPickerViewControllerDidSelectColor:(UIColorPickerViewController *)viewController
+{
+ Q_UNUSED(viewController);
+ [self updateQColor];
+}
+
+- (void)colorPickerViewControllerDidFinish:(UIColorPickerViewController *)viewController
+{
+ Q_UNUSED(viewController);
+ [self updateQColor];
+ emit m_colorDialog->accept();
+}
+
+// ----------------------UIAdaptivePresentationControllerDelegate--------------------------
+- (void)presentationControllerDidDismiss:(UIPresentationController *)presentationController
+{
+ Q_UNUSED(presentationController);
+ emit m_colorDialog->reject();
+}
+
+@end
+
+QIOSColorDialog::QIOSColorDialog()
+ : m_viewController(nullptr)
+{
+}
+
+QIOSColorDialog::~QIOSColorDialog()
+{
+ hide();
+}
+
+void QIOSColorDialog::exec()
+{
+ m_eventLoop.exec(QEventLoop::DialogExec);
+}
+
+bool QIOSColorDialog::show(Qt::WindowFlags windowFlags, Qt::WindowModality windowModality, QWindow *parent)
+{
+ Q_UNUSED(windowFlags);
+
+ if (!m_viewController) {
+ m_viewController = [[QIOSColorDialogController alloc] initWithQIOSColorDialog:this];
+ if (m_currentColor.isValid())
+ [m_viewController setQColor:m_currentColor];
+ }
+
+ if (windowModality == Qt::ApplicationModal || windowModality == Qt::WindowModal)
+ m_viewController.modalInPresentation = YES;
+
+ UIWindow *window = presentationWindow(parent);
+ if (!window)
+ return false;
+
+ // We can't present from view controller if already presenting
+ if (window.rootViewController.presentedViewController)
+ return false;
+
+ [window.rootViewController presentViewController:m_viewController animated:YES completion:nil];
+
+ return true;
+}
+
+void QIOSColorDialog::hide()
+{
+ [m_viewController dismissViewControllerAnimated:YES completion:nil];
+ [m_viewController release];
+ m_viewController = nullptr;
+ m_eventLoop.exit();
+}
+
+void QIOSColorDialog::setCurrentColor(const QColor &color)
+{
+ updateColor(color);
+ if (m_viewController)
+ [m_viewController setQColor:color];
+}
+
+QColor QIOSColorDialog::currentColor() const
+{
+ return m_currentColor;
+}
+
+void QIOSColorDialog::updateColor(const QColor &color)
+{
+ m_currentColor = color;
+}
+
+
diff --git a/src/plugins/platforms/ios/qioscontext.h b/src/plugins/platforms/ios/qioscontext.h
index a2595877dc..99786951cb 100644
--- a/src/plugins/platforms/ios/qioscontext.h
+++ b/src/plugins/platforms/ios/qioscontext.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QIOSCONTEXT_H
#define QIOSCONTEXT_H
diff --git a/src/plugins/platforms/ios/qioscontext.mm b/src/plugins/platforms/ios/qioscontext.mm
index cb1a8a96f8..499adea0fe 100644
--- a/src/plugins/platforms/ios/qioscontext.mm
+++ b/src/plugins/platforms/ios/qioscontext.mm
@@ -1,41 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#undef QT_NO_FOREACH // this file contains unported legacy Q_FOREACH uses
#include "qioscontext.h"
@@ -118,7 +84,7 @@ QSurfaceFormat QIOSContext::format() const
return m_format;
}
-#define QT_IOS_GL_STATUS_CASE(val) case val: return QLatin1String(#val)
+#define QT_IOS_GL_STATUS_CASE(val) case val: return QLatin1StringView(#val)
static QString fboStatusString(GLenum status)
{
@@ -368,6 +334,6 @@ bool QIOSContext::isSharing() const
return m_sharedContext;
}
-#include "moc_qioscontext.cpp"
-
QT_END_NAMESPACE
+
+#include "moc_qioscontext.cpp"
diff --git a/src/plugins/platforms/ios/qiosdocumentpickercontroller.h b/src/plugins/platforms/ios/qiosdocumentpickercontroller.h
new file mode 100644
index 0000000000..f0b7472539
--- /dev/null
+++ b/src/plugins/platforms/ios/qiosdocumentpickercontroller.h
@@ -0,0 +1,13 @@
+// Copyright (C) 2020 Harald Meyer.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#import <UIKit/UIKit.h>
+#import <UniformTypeIdentifiers/UniformTypeIdentifiers.h>
+
+#include "qiosfiledialog.h"
+
+@interface QIOSDocumentPickerController : UIDocumentPickerViewController <UIDocumentPickerDelegate,
+ UINavigationControllerDelegate,
+ UIAdaptivePresentationControllerDelegate>
+- (instancetype)initWithQIOSFileDialog:(QIOSFileDialog *)fileDialog;
+@end
diff --git a/src/plugins/platforms/ios/qiosdocumentpickercontroller.mm b/src/plugins/platforms/ios/qiosdocumentpickercontroller.mm
new file mode 100644
index 0000000000..fca0432426
--- /dev/null
+++ b/src/plugins/platforms/ios/qiosdocumentpickercontroller.mm
@@ -0,0 +1,115 @@
+// Copyright (C) 2020 Harald Meyer.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#import <UIKit/UIKit.h>
+#import <MobileCoreServices/MobileCoreServices.h>
+
+#include "qiosdocumentpickercontroller.h"
+
+@implementation QIOSDocumentPickerController {
+ QIOSFileDialog *m_fileDialog;
+}
+
+- (instancetype)initWithQIOSFileDialog:(QIOSFileDialog *)fileDialog
+{
+ NSMutableArray <UTType *> *docTypes = [[[NSMutableArray alloc] init] autorelease];
+
+ QStringList nameFilters = fileDialog->options()->nameFilters();
+ if (!nameFilters.isEmpty() && (fileDialog->options()->fileMode() != QFileDialogOptions::Directory
+ || fileDialog->options()->fileMode() != QFileDialogOptions::DirectoryOnly))
+ {
+ QStringList results;
+ for (const QString &filter : nameFilters)
+ results.append(QPlatformFileDialogHelper::cleanFilterList(filter));
+
+ docTypes = [self computeAllowedFileTypes:results];
+ }
+
+ if (!docTypes.count) {
+ switch (fileDialog->options()->fileMode()) {
+ case QFileDialogOptions::AnyFile:
+ case QFileDialogOptions::ExistingFile:
+ case QFileDialogOptions::ExistingFiles:
+ [docTypes addObject:[UTType typeWithIdentifier:(__bridge NSString *)UTTypeContent]];
+ [docTypes addObject:[UTType typeWithIdentifier:(__bridge NSString *)UTTypeItem]];
+ [docTypes addObject:[UTType typeWithIdentifier:(__bridge NSString *)UTTypeData]];
+ break;
+ // Showing files is not supported in Directory mode in iOS
+ case QFileDialogOptions::Directory:
+ case QFileDialogOptions::DirectoryOnly:
+ [docTypes addObject:[UTType typeWithIdentifier:(__bridge NSString *)UTTypeFolder]];
+ break;
+ }
+ }
+
+ if (self = [super initForOpeningContentTypes:docTypes]) {
+ m_fileDialog = fileDialog;
+ self.modalPresentationStyle = UIModalPresentationFormSheet;
+ self.delegate = self;
+ self.presentationController.delegate = self;
+
+ if (m_fileDialog->options()->fileMode() == QFileDialogOptions::ExistingFiles)
+ self.allowsMultipleSelection = YES;
+
+ self.directoryURL = m_fileDialog->options()->initialDirectory().toNSURL();
+ }
+ return self;
+}
+
+- (void)documentPicker:(UIDocumentPickerViewController *)controller didPickDocumentsAtURLs:(NSArray <NSURL *>*)urls
+{
+ Q_UNUSED(controller);
+
+ QList<QUrl> files;
+ for (NSURL* url in urls)
+ files.append(QUrl::fromNSURL(url));
+
+ m_fileDialog->selectedFilesChanged(files);
+ emit m_fileDialog->accept();
+}
+
+- (void)documentPickerWasCancelled:(UIDocumentPickerViewController *)controller
+{
+ Q_UNUSED(controller);
+ emit m_fileDialog->reject();
+}
+
+- (void)presentationControllerDidDismiss:(UIPresentationController *)presentationController
+{
+ Q_UNUSED(presentationController);
+
+ // "Called on the delegate when the user has taken action to dismiss the
+ // presentation successfully, after all animations are finished.
+ // This is not called if the presentation is dismissed programmatically."
+
+ // So if document picker's view was dismissed, for example by swiping it away,
+ // we got this method called. But not if the dialog was cancelled or a file
+ // was selected.
+ emit m_fileDialog->reject();
+}
+
+- (NSMutableArray<UTType*>*)computeAllowedFileTypes:(QStringList)filters
+{
+ QStringList fileTypes;
+ for (const QString &filter : filters) {
+ if (filter == (QLatin1String("*")))
+ continue;
+
+ if (filter.contains(u'?'))
+ continue;
+
+ if (filter.count(u'*') != 1)
+ continue;
+
+ auto extensions = filter.split('.', Qt::SkipEmptyParts);
+ fileTypes += extensions.last();
+ }
+
+ NSMutableArray<UTType *> *result = [NSMutableArray<UTType *> arrayWithCapacity:fileTypes.size()];
+ for (const QString &string : fileTypes)
+ [result addObject:[UTType typeWithFilenameExtension:string.toNSString()]];
+
+ return result;
+}
+
+@end
diff --git a/src/plugins/platforms/ios/qioseventdispatcher.h b/src/plugins/platforms/ios/qioseventdispatcher.h
index 1f4c78dc74..b40024ec19 100644
--- a/src/plugins/platforms/ios/qioseventdispatcher.h
+++ b/src/plugins/platforms/ios/qioseventdispatcher.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QIOSEVENTDISPATCHER_H
#define QIOSEVENTDISPATCHER_H
@@ -53,7 +17,7 @@ public:
bool processPostedEvents() override;
protected:
- explicit QIOSEventDispatcher(QObject *parent = 0);
+ explicit QIOSEventDispatcher(QObject *parent = nullptr);
};
class QIOSJumpingEventDispatcher : public QIOSEventDispatcher
@@ -61,7 +25,7 @@ class QIOSJumpingEventDispatcher : public QIOSEventDispatcher
Q_OBJECT
public:
- QIOSJumpingEventDispatcher(QObject *parent = 0);
+ QIOSJumpingEventDispatcher(QObject *parent = nullptr);
bool processEvents(QEventLoop::ProcessEventsFlags flags) override;
// Public since we can't friend Objective-C methods
@@ -76,4 +40,4 @@ private:
QT_END_NAMESPACE
-#endif // QIOSEVENTDISPATCHER_H \ No newline at end of file
+#endif // QIOSEVENTDISPATCHER_H
diff --git a/src/plugins/platforms/ios/qioseventdispatcher.mm b/src/plugins/platforms/ios/qioseventdispatcher.mm
index c5856051de..24d9d88294 100644
--- a/src/plugins/platforms/ios/qioseventdispatcher.mm
+++ b/src/plugins/platforms/ios/qioseventdispatcher.mm
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qioseventdispatcher.h"
#include "qiosapplicationdelegate.h"
@@ -473,7 +437,8 @@ bool QIOSEventDispatcher::processPostedEvents()
return false;
QT_APPLE_SCOPED_LOG_ACTIVITY(lcEventDispatcher().isDebugEnabled(), "sendWindowSystemEvents");
- QEventLoop::ProcessEventsFlags flags = QEventLoop::ProcessEventsFlags(m_processEvents.flags.load());
+ QEventLoop::ProcessEventsFlags flags
+ = QEventLoop::ProcessEventsFlags(m_processEvents.flags.loadRelaxed());
qCDebug(lcEventDispatcher) << "Sending window system events for" << flags;
QWindowSystemInterface::sendWindowSystemEvents(flags);
diff --git a/src/plugins/platforms/ios/qiosfiledialog.h b/src/plugins/platforms/ios/qiosfiledialog.h
index 5cb1b45e20..f00c154c03 100644
--- a/src/plugins/platforms/ios/qiosfiledialog.h
+++ b/src/plugins/platforms/ios/qiosfiledialog.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QIOSFILEDIALOG_H
#define QIOSFILEDIALOG_H
@@ -65,7 +29,7 @@ public:
void selectNameFilter(const QString &) override {}
QString selectedNameFilter() const override { return QString(); }
- void selectedFilesChanged(QList<QUrl> selection);
+ void selectedFilesChanged(const QList<QUrl> &selection);
private:
QUrl m_directory;
@@ -74,6 +38,8 @@ private:
UIViewController *m_viewController;
bool showImagePickerDialog(QWindow *parent);
+ bool showNativeDocumentPickerDialog(QWindow *parent);
+ void showImagePickerDialog_helper(QWindow *parent);
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/ios/qiosfiledialog.mm b/src/plugins/platforms/ios/qiosfiledialog.mm
index e8a3f5b30e..cf9580c17e 100644
--- a/src/plugins/platforms/ios/qiosfiledialog.mm
+++ b/src/plugins/platforms/ios/qiosfiledialog.mm
@@ -1,53 +1,25 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#import <UIKit/UIKit.h>
+#import <Photos/Photos.h>
+
#include <QtCore/qstandardpaths.h>
#include <QtGui/qwindow.h>
#include <QDebug>
#include <QtCore/private/qcore_mac_p.h>
+#include "qiosglobal.h"
#include "qiosfiledialog.h"
#include "qiosintegration.h"
#include "qiosoptionalplugininterface.h"
+#include "qiosdocumentpickercontroller.h"
+
+#include <QtCore/qpointer.h>
+
+using namespace Qt::StringLiterals;
QIOSFileDialog::QIOSFileDialog()
: m_viewController(nullptr)
@@ -69,20 +41,35 @@ bool QIOSFileDialog::show(Qt::WindowFlags windowFlags, Qt::WindowModality window
Q_UNUSED(windowFlags);
Q_UNUSED(windowModality);
- bool acceptOpen = options()->acceptMode() == QFileDialogOptions::AcceptOpen;
- QString directory = options()->initialDirectory().toLocalFile();
-
- if (acceptOpen && directory.startsWith(QLatin1String("assets-library:")))
- return showImagePickerDialog(parent);
+ const bool acceptOpen = options()->acceptMode() == QFileDialogOptions::AcceptOpen;
+ const auto initialDir = options()->initialDirectory();
+ const QString directory = initialDir.toLocalFile();
+ // We manually add assets-library:// to the list of paths,
+ // when converted to QUrl, it becames a scheme.
+ const QString scheme = initialDir.scheme();
+
+ if (acceptOpen) {
+ if (directory.startsWith("assets-library:"_L1) || scheme == "assets-library"_L1)
+ return showImagePickerDialog(parent);
+ else
+ return showNativeDocumentPickerDialog(parent);
+ }
return false;
}
+void QIOSFileDialog::showImagePickerDialog_helper(QWindow *parent)
+{
+ UIWindow *window = presentationWindow(parent);
+ [window.rootViewController presentViewController:m_viewController animated:YES completion:nil];
+}
+
bool QIOSFileDialog::showImagePickerDialog(QWindow *parent)
{
if (!m_viewController) {
QFactoryLoader *plugins = QIOSIntegration::instance()->optionalPlugins();
- for (int i = 0; i < plugins->metaData().size(); ++i) {
+ qsizetype size = QList<QPluginParsedMetaData>(plugins->metaData()).size();
+ for (qsizetype i = 0; i < size; ++i) {
QIosOptionalPluginInterface *plugin = qobject_cast<QIosOptionalPluginInterface *>(plugins->instance(i));
m_viewController = [plugin->createImagePickerController(this) retain];
if (m_viewController)
@@ -95,11 +82,54 @@ bool QIOSFileDialog::showImagePickerDialog(QWindow *parent)
return false;
}
- UIWindow *window = parent ? reinterpret_cast<UIView *>(parent->winId()).window
- : qt_apple_sharedApplication().keyWindow;
+ // "Old style" authorization (deprecated, but we have to work with AssetsLibrary anyway).
+ //
+ // From the documentation:
+ // "The authorizationStatus and requestAuthorization: methods aren’t compatible with the
+ // limited library and return PHAuthorizationStatusAuthorized when the user authorizes your
+ // app for limited access only."
+ //
+ // This is good enough for us.
+
+ const auto authStatus = [PHPhotoLibrary authorizationStatus];
+ if (authStatus == PHAuthorizationStatusAuthorized) {
+ showImagePickerDialog_helper(parent);
+ } else if (authStatus == PHAuthorizationStatusNotDetermined) {
+ QPointer<QWindow> winGuard(parent);
+ QPointer<QIOSFileDialog> thisGuard(this);
+ [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ if (status == PHAuthorizationStatusAuthorized) {
+ if (thisGuard && winGuard)
+ thisGuard->showImagePickerDialog_helper(winGuard);
+
+ } else if (thisGuard) {
+ emit thisGuard->reject();
+ }
+ });
+ }];
+ } else {
+ // Treat 'Limited' (we don't know how to deal with anyway) and 'Denied' as errors.
+ // FIXME: logging category?
+ qWarning() << "QIOSFileDialog: insufficient permission, cannot pick images";
+ return false;
+ }
+
+ return true;
+}
+
+bool QIOSFileDialog::showNativeDocumentPickerDialog(QWindow *parent)
+{
+#ifndef Q_OS_TVOS
+ m_viewController = [[QIOSDocumentPickerController alloc] initWithQIOSFileDialog:this];
+
+ UIWindow *window = presentationWindow(parent);
[window.rootViewController presentViewController:m_viewController animated:YES completion:nil];
return true;
+#else
+ return false;
+#endif
}
void QIOSFileDialog::hide()
@@ -123,7 +153,7 @@ QList<QUrl> QIOSFileDialog::selectedFiles() const
return m_selection;
}
-void QIOSFileDialog::selectedFilesChanged(QList<QUrl> selection)
+void QIOSFileDialog::selectedFilesChanged(const QList<QUrl> &selection)
{
m_selection = selection;
emit filesSelected(m_selection);
diff --git a/src/plugins/platforms/ios/qiosfontdialog.h b/src/plugins/platforms/ios/qiosfontdialog.h
new file mode 100644
index 0000000000..f0a92d0d6f
--- /dev/null
+++ b/src/plugins/platforms/ios/qiosfontdialog.h
@@ -0,0 +1,41 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QIOSFONTDIALOG_H
+#define QIOSFONTDIALOG_H
+
+#include <QtCore/qeventloop.h>
+#include <qpa/qplatformdialoghelper.h>
+
+@interface QIOSFontDialogController : UIFontPickerViewController <UIFontPickerViewControllerDelegate,
+ UIAdaptivePresentationControllerDelegate>
+@end
+
+QT_BEGIN_NAMESPACE
+
+class QIOSFontDialog : public QPlatformFontDialogHelper
+{
+public:
+ QIOSFontDialog();
+ ~QIOSFontDialog();
+
+ void exec() override;
+
+ bool show(Qt::WindowFlags windowFlags, Qt::WindowModality windowModality, QWindow *parent) override;
+ void hide() override;
+
+ void setCurrentFont(const QFont &) override;
+ QFont currentFont() const override;
+
+ void updateCurrentFont(const QFont &);
+
+private:
+ QEventLoop m_eventLoop;
+ QIOSFontDialogController *m_viewController;
+ QFont m_currentFont;
+
+};
+
+QT_END_NAMESPACE
+
+#endif // QIOSFONTDIALOG_H
diff --git a/src/plugins/platforms/ios/qiosfontdialog.mm b/src/plugins/platforms/ios/qiosfontdialog.mm
new file mode 100644
index 0000000000..25d0197195
--- /dev/null
+++ b/src/plugins/platforms/ios/qiosfontdialog.mm
@@ -0,0 +1,190 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#import <UIKit/UIKit.h>
+
+#include <QtGui/qwindow.h>
+#include <QtGui/qfontdatabase.h>
+#include <QDebug>
+
+#include <QtCore/private/qcore_mac_p.h>
+#include <QtGui/private/qfont_p.h>
+#include <QtGui/private/qfontengine_p.h>
+
+#include "qiosglobal.h"
+#include "qiosfontdialog.h"
+#include "qiosintegration.h"
+
+@implementation QIOSFontDialogController {
+ QIOSFontDialog *m_fontDialog;
+}
+
+- (instancetype)initWithQIOSFontDialog:(QIOSFontDialog *)dialog
+{
+ UIFontPickerViewControllerConfiguration *configuration = [[UIFontPickerViewControllerConfiguration alloc] init];
+ if (dialog->options()->testOption(QFontDialogOptions::MonospacedFonts)) {
+ UIFontDescriptorSymbolicTraits traits = {};
+ traits |= UIFontDescriptorTraitMonoSpace;
+ configuration.filteredTraits = traits;
+ }
+ configuration.includeFaces = YES;
+ if (self = [super initWithConfiguration:configuration]) {
+ m_fontDialog = dialog;
+ self.delegate = self;
+ self.presentationController.delegate = self;
+ }
+ [configuration release];
+ return self;
+}
+
+- (void)setQFont:(const QFont &)font
+{
+ QFontInfo fontInfo(font);
+ auto family = fontInfo.family().toNSString();
+ auto size = fontInfo.pointSize();
+
+ NSDictionary *dictionary = @{
+ static_cast<NSString *>(UIFontDescriptorFamilyAttribute): family,
+ static_cast<NSString *>(UIFontDescriptorSizeAttribute): [NSNumber numberWithInt:size]
+ };
+ UIFontDescriptor *fd = [UIFontDescriptor fontDescriptorWithFontAttributes:dictionary];
+
+ UIFontDescriptorSymbolicTraits traits = 0;
+ if (font.style() == QFont::StyleItalic)
+ traits |= UIFontDescriptorTraitItalic;
+ if (font.weight() == QFont::Bold)
+ traits |= UIFontDescriptorTraitBold;
+ fd = [fd fontDescriptorWithSymbolicTraits:traits];
+
+ self.selectedFontDescriptor = fd;
+}
+
+- (void)updateQFont
+{
+ UIFontDescriptor *font = self.selectedFontDescriptor;
+ if (!font)
+ return;
+
+ NSDictionary *attributes = font.fontAttributes;
+ UIFontDescriptorSymbolicTraits traits = font.symbolicTraits;
+
+ QFont newFont;
+ int size = qRound(font.pointSize);
+ QString family = QString::fromNSString([attributes objectForKey:UIFontDescriptorFamilyAttribute]);
+ if (family.isEmpty()) {
+ // If includeFaces is true, then the font descriptor won't
+ // have the UIFontDescriptorFamilyAttribute key set so we
+ // need to create a UIFont to get the font family
+ UIFont *f = [UIFont fontWithDescriptor:font size:size];
+ family = QString::fromNSString(f.familyName);
+ }
+
+ QString style;
+ if ((traits & (UIFontDescriptorTraitItalic | UIFontDescriptorTraitBold)) == (UIFontDescriptorTraitItalic | UIFontDescriptorTraitBold))
+ style = "Bold Italic";
+ else if (traits & UIFontDescriptorTraitItalic)
+ style = "Italic";
+ else if (traits & UIFontDescriptorTraitBold)
+ style = "Bold";
+
+ newFont = QFontDatabase::font(family, style, size);
+
+ if (m_fontDialog) {
+ m_fontDialog->updateCurrentFont(newFont);
+ emit m_fontDialog->currentFontChanged(newFont);
+ }
+}
+
+// ----------------------UIFontPickerViewControllerDelegate--------------------------
+- (void)fontPickerViewControllerDidPickFont:(UIFontPickerViewController *)viewController
+{
+ [self updateQFont];
+ emit m_fontDialog->accept();
+}
+
+- (void)fontPickerViewControllerDidCancel:(UIFontPickerViewController *)viewController
+{
+ Q_UNUSED(viewController);
+ emit m_fontDialog->reject();
+}
+
+// ----------------------UIAdaptivePresentationControllerDelegate--------------------------
+- (void)presentationControllerDidDismiss:(UIPresentationController *)presentationController
+{
+ Q_UNUSED(presentationController);
+ emit m_fontDialog->reject();
+}
+
+@end
+
+QIOSFontDialog::QIOSFontDialog()
+ : m_viewController(nullptr)
+{
+}
+
+QIOSFontDialog::~QIOSFontDialog()
+{
+ hide();
+}
+
+void QIOSFontDialog::exec()
+{
+ m_eventLoop.exec(QEventLoop::DialogExec);
+}
+
+bool QIOSFontDialog::show(Qt::WindowFlags windowFlags, Qt::WindowModality windowModality, QWindow *parent)
+{
+ Q_UNUSED(windowFlags);
+ Q_UNUSED(windowModality);
+
+ if (!m_viewController) {
+ m_viewController = [[QIOSFontDialogController alloc] initWithQIOSFontDialog:this];
+ [m_viewController setQFont:m_currentFont];
+ }
+
+ if (windowModality == Qt::ApplicationModal || windowModality == Qt::WindowModal)
+ m_viewController.modalInPresentation = YES;
+
+ UIWindow *window = presentationWindow(parent);
+ if (!window)
+ return false;
+
+ // We can't present from view controller if already presenting
+ if (window.rootViewController.presentedViewController)
+ return false;
+
+ [window.rootViewController presentViewController:m_viewController animated:YES completion:nil];
+
+ return true;
+}
+
+void QIOSFontDialog::hide()
+{
+ [m_viewController dismissViewControllerAnimated:YES completion:nil];
+ [m_viewController release];
+ m_viewController = nullptr;
+ if (m_eventLoop.isRunning())
+ m_eventLoop.exit();
+}
+
+void QIOSFontDialog::setCurrentFont(const QFont &font)
+{
+ if (m_currentFont == font)
+ return;
+
+ m_currentFont = font;
+ if (m_viewController)
+ [m_viewController setQFont:font];
+}
+
+QFont QIOSFontDialog::currentFont() const
+{
+ return m_currentFont;
+}
+
+void QIOSFontDialog::updateCurrentFont(const QFont &font)
+{
+ m_currentFont = font;
+}
+
+
diff --git a/src/plugins/platforms/ios/qiosglobal.h b/src/plugins/platforms/ios/qiosglobal.h
index 8b39aded06..0fafbe1936 100644
--- a/src/plugins/platforms/ios/qiosglobal.h
+++ b/src/plugins/platforms/ios/qiosglobal.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QIOSGLOBAL_H
#define QIOSGLOBAL_H
@@ -62,6 +26,7 @@ Q_DECLARE_LOGGING_CATEGORY(lcQpaWindow);
class QPlatformScreen;
bool isQtApplication();
+bool isRunningOnVisionOS();
#ifndef Q_OS_TVOS
Qt::ScreenOrientation toQtScreenOrientation(UIDeviceOrientation uiDeviceOrientation);
@@ -70,10 +35,13 @@ UIDeviceOrientation fromQtScreenOrientation(Qt::ScreenOrientation qtOrientation)
int infoPlistValue(NSString* key, int defaultValue);
+class QWindow;
+UIWindow *presentationWindow(QWindow *);
+
QT_END_NAMESPACE
@interface UIResponder (QtFirstResponder)
-+ (id)currentFirstResponder;
++ (id)qt_currentFirstResponder;
@end
QT_BEGIN_NAMESPACE
diff --git a/src/plugins/platforms/ios/qiosglobal.mm b/src/plugins/platforms/ios/qiosglobal.mm
index a523d1be45..eb9e713b0d 100644
--- a/src/plugins/platforms/ios/qiosglobal.mm
+++ b/src/plugins/platforms/ios/qiosglobal.mm
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qiosglobal.h"
#include "qiosapplicationdelegate.h"
@@ -65,6 +29,15 @@ bool isQtApplication()
return isQt;
}
+bool isRunningOnVisionOS()
+{
+ static bool result = []{
+ // This class is documented to only be available on visionOS
+ return NSClassFromString(@"UIWindowSceneGeometryPreferencesVision");
+ }();
+ return result;
+}
+
#ifndef Q_OS_TVOS
Qt::ScreenOrientation toQtScreenOrientation(UIDeviceOrientation uiDeviceOrientation)
{
@@ -121,6 +94,21 @@ int infoPlistValue(NSString* key, int defaultValue)
return value ? [value intValue] : defaultValue;
}
+UIWindow *presentationWindow(QWindow *window)
+{
+ UIWindow *uiWindow = window ? reinterpret_cast<UIView *>(window->winId()).window : nullptr;
+ if (!uiWindow) {
+ auto *scenes = [qt_apple_sharedApplication().connectedScenes allObjects];
+ if (scenes.count > 0) {
+ auto *windowScene = static_cast<UIWindowScene*>(scenes[0]);
+ uiWindow = windowScene.keyWindow;
+ if (!uiWindow && windowScene.windows.count)
+ uiWindow = windowScene.windows[0];
+ }
+ }
+ return uiWindow;
+}
+
QT_END_NAMESPACE
// -------------------------------------------------------------------------
@@ -155,7 +143,7 @@ QT_END_NAMESPACE
@implementation UIResponder (QtFirstResponder)
-+ (id)currentFirstResponder
++ (id)qt_currentFirstResponder
{
if (qt_apple_isApplicationExtension()) {
qWarning() << "can't get first responder in application extensions!";
@@ -185,7 +173,7 @@ FirstResponderCandidate::FirstResponderCandidate(UIResponder *responder)
{
}
-UIResponder *FirstResponderCandidate::s_firstResponderCandidate = 0;
+UIResponder *FirstResponderCandidate::s_firstResponderCandidate = nullptr;
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/ios/qiosinputcontext.h b/src/plugins/platforms/ios/qiosinputcontext.h
index 255cf8bca9..370032a1f8 100644
--- a/src/plugins/platforms/ios/qiosinputcontext.h
+++ b/src/plugins/platforms/ios/qiosinputcontext.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QIOSINPUTCONTEXT_H
#define QIOSINPUTCONTEXT_H
@@ -54,7 +18,7 @@ const char kImePlatformDataReturnKeyType[] = "returnKeyType";
@class QIOSLocaleListener;
@class QIOSKeyboardListener;
-@class QIOSTextInputResponder;
+@class QIOSTextResponder;
@protocol KeyboardState;
QT_BEGIN_NAMESPACE
@@ -76,10 +40,10 @@ struct KeyboardState
struct ImeState
{
- ImeState() : currentState(0), focusObject(0) {}
+ ImeState() = default;
Qt::InputMethodQueries update(Qt::InputMethodQueries properties);
- QInputMethodQueryEvent currentState;
- QObject *focusObject;
+ QInputMethodQueryEvent currentState = QInputMethodQueryEvent({});
+ QObject *focusObject = nullptr;
};
class QIOSInputContext : public QPlatformInputContext
@@ -111,10 +75,10 @@ public:
void scrollToCursor();
void scroll(int y);
- void updateKeyboardState(NSNotification *notification = 0);
+ void updateKeyboardState(NSNotification *notification = nullptr);
- const ImeState &imeState() { return m_imeState; };
- const KeyboardState &keyboardState() { return m_keyboardState; };
+ const ImeState &imeState() { return m_imeState; }
+ const KeyboardState &keyboardState() { return m_keyboardState; }
bool inputMethodAccepted() const;
@@ -125,7 +89,7 @@ private:
QIOSLocaleListener *m_localeListener;
QIOSKeyboardListener *m_keyboardHideGesture;
- QIOSTextInputResponder *m_textResponder;
+ QIOSTextResponder *m_textResponder;
KeyboardState m_keyboardState;
ImeState m_imeState;
};
diff --git a/src/plugins/platforms/ios/qiosinputcontext.mm b/src/plugins/platforms/ios/qiosinputcontext.mm
index d2229df133..5716ad041e 100644
--- a/src/plugins/platforms/ios/qiosinputcontext.mm
+++ b/src/plugins/platforms/ios/qiosinputcontext.mm
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qiosinputcontext.h"
@@ -54,6 +18,8 @@
#include <QGuiApplication>
#include <QtGui/private/qwindow_p.h>
+#include <QtCore/qpointer.h>
+
// -------------------------------------------------------------------------
static QUIView *focusView()
@@ -155,12 +121,12 @@ static QUIView *focusView()
{
[self keyboardWillOrDidChange:notification];
- UIResponder *firstResponder = [UIResponder currentFirstResponder];
+ UIResponder *firstResponder = [UIResponder qt_currentFirstResponder];
if (![firstResponder isKindOfClass:[QIOSTextInputResponder class]])
return;
// Enable hide-keyboard gesture
- self.enabled = YES;
+ self.enabled = m_context->isInputPanelVisible();
m_context->scrollToCursor();
}
@@ -210,7 +176,11 @@ static QUIView *focusView()
{
[super touchesBegan:touches withEvent:event];
- Q_ASSERT(m_context->isInputPanelVisible());
+ if (!m_context->isInputPanelVisible()) {
+ qImDebug("keyboard was hidden by sliding it down, disabling hide-keyboard gesture");
+ self.enabled = NO;
+ return;
+ }
if ([touches count] != 1)
self.state = UIGestureRecognizerStateFailed;
@@ -264,7 +234,7 @@ static QUIView *focusView()
if (self.state == UIGestureRecognizerStateBegan) {
qImDebug("hide keyboard gesture was triggered");
- UIResponder *firstResponder = [UIResponder currentFirstResponder];
+ UIResponder *firstResponder = [UIResponder qt_currentFirstResponder];
Q_ASSERT([firstResponder isKindOfClass:[QIOSTextInputResponder class]]);
[firstResponder resignFirstResponder];
}
@@ -297,7 +267,7 @@ QT_BEGIN_NAMESPACE
Qt::InputMethodQueries ImeState::update(Qt::InputMethodQueries properties)
{
if (!properties)
- return 0;
+ return {};
QInputMethodQueryEvent newState(properties);
@@ -333,11 +303,7 @@ QIOSInputContext::QIOSInputContext()
, m_keyboardHideGesture([[QIOSKeyboardListener alloc] initWithQIOSInputContext:this])
, m_textResponder(0)
{
- if (isQtApplication()) {
- QIOSScreen *iosScreen = static_cast<QIOSScreen*>(QGuiApplication::primaryScreen()->handle());
- [iosScreen->uiWindow() addGestureRecognizer:m_keyboardHideGesture];
- }
-
+ Q_ASSERT(!qGuiApp->focusWindow());
connect(qGuiApp, &QGuiApplication::focusWindowChanged, this, &QIOSInputContext::focusWindowChanged);
}
@@ -382,7 +348,7 @@ void QIOSInputContext::clearCurrentFocusObject()
void QIOSInputContext::updateKeyboardState(NSNotification *notification)
{
-#ifdef Q_OS_TVOS
+#if defined(Q_OS_TVOS) || defined(Q_OS_VISIONOS)
Q_UNUSED(notification);
#else
static CGRect currentKeyboardRect = CGRectZero;
@@ -402,7 +368,7 @@ void QIOSInputContext::updateKeyboardState(NSNotification *notification)
// The isInputPanelVisible() property is based on whether or not the virtual keyboard
// is visible on screen, and does not follow the logic of the iOS WillShow and WillHide
// notifications which are not emitted for undocked keyboards, and are buggy when dealing
- // with input-accesosory-views. The reason for using frameEnd here (the future state),
+ // with input-accessory-views. The reason for using frameEnd here (the future state),
// instead of the current state reflected in frameBegin, is that QInputMethod::isVisible()
// is documented to reflect the future state in the case of animated transitions.
m_keyboardState.keyboardVisible = CGRectIntersectsRect(frameEnd, [UIScreen mainScreen].bounds);
@@ -472,6 +438,7 @@ UIView *QIOSInputContext::scrollableRootView()
void QIOSInputContext::scrollToCursor()
{
+#if !defined(Q_OS_VISIONOS)
if (!isQtApplication())
return;
@@ -499,8 +466,9 @@ void QIOSInputContext::scrollToCursor()
return;
}
- QWindow *focusWindow = qApp->focusWindow();
- QRect cursorRect = qApp->inputMethod()->cursorRectangle().translated(focusWindow->geometry().topLeft()).toRect();
+ QPlatformWindow *focusWindow = qApp->focusWindow()->handle();
+ QRect windowCurosorRect = QPlatformInputContext::cursorRectangle().toRect();
+ QRect cursorRect = QRect(focusWindow->mapToGlobal(windowCurosorRect.topLeft()), windowCurosorRect.size());
// We explicitly ask for the geometry of the screen instead of the availableGeometry,
// as we hide the status bar when scrolling the screen, so the available geometry will
@@ -527,6 +495,7 @@ void QIOSInputContext::scrollToCursor()
} else {
scroll(0);
}
+#endif
}
void QIOSInputContext::scroll(int y)
@@ -638,12 +607,15 @@ void QIOSInputContext::setFocusObject(QObject *focusObject)
void QIOSInputContext::focusWindowChanged(QWindow *focusWindow)
{
- Q_UNUSED(focusWindow);
-
qImDebug() << "new focus window =" << focusWindow;
reset();
+ if (isQtApplication()) {
+ [m_keyboardHideGesture.view removeGestureRecognizer:m_keyboardHideGesture];
+ [focusView().window addGestureRecognizer:m_keyboardHideGesture];
+ }
+
// The keyboard rectangle depend on the focus window, so
// we need to re-evaluate the keyboard state.
updateKeyboardState();
@@ -667,22 +639,30 @@ void QIOSInputContext::update(Qt::InputMethodQueries updatedProperties)
// focus object. We try to detect code paths that fail this assertion and smooth
// over the situation by doing a manual update of the focus object.
if (qApp->focusObject() != m_imeState.focusObject && updatedProperties != Qt::ImQueryAll) {
- qWarning() << "stale focus object" << m_imeState.focusObject << ", doing manual update";
+ qWarning() << "stale focus object" << static_cast<void *>(m_imeState.focusObject)
+ << ", doing manual update";
setFocusObject(qApp->focusObject());
return;
}
// Mask for properties that we are interested in and see if any of them changed
- updatedProperties &= (Qt::ImEnabled | Qt::ImHints | Qt::ImQueryInput | Qt::ImEnterKeyType | Qt::ImPlatformData);
+ updatedProperties &= (Qt::ImEnabled | Qt::ImHints | Qt::ImQueryInput | Qt::ImEnterKeyType | Qt::ImPlatformData | Qt::ImReadOnly);
// Perform update first, so we can trust the value of inputMethodAccepted()
Qt::InputMethodQueries changedProperties = m_imeState.update(updatedProperties);
- if (inputMethodAccepted()) {
+ const bool inputIsReadOnly = m_imeState.currentState.value(Qt::ImReadOnly).toBool();
+
+ if (inputMethodAccepted() || inputIsReadOnly) {
if (!m_textResponder || [m_textResponder needsKeyboardReconfigure:changedProperties]) {
- qImDebug("creating new text responder");
[m_textResponder autorelease];
- m_textResponder = [[QIOSTextInputResponder alloc] initWithInputContext:this];
+ if (inputIsReadOnly) {
+ qImDebug("creating new read-only text responder");
+ m_textResponder = [[QIOSTextResponder alloc] initWithInputContext:this];
+ } else {
+ qImDebug("creating new read/write text responder");
+ m_textResponder = [[QIOSTextInputResponder alloc] initWithInputContext:this];
+ }
} else {
qImDebug("no need to reconfigure keyboard, just notifying input delegate");
[m_textResponder notifyInputDelegate:changedProperties];
@@ -726,12 +706,33 @@ bool QIOSInputContext::inputMethodAccepted() const
*/
void QIOSInputContext::reset()
{
- qImDebug("updating Qt::ImQueryAll and unmarking text");
+ qImDebug("releasing text responder");
+
+ // UIKit will sometimes, for unknown reasons, unset the input delegate on the
+ // current text responder. This seems to happen as a result of us calling
+ // [self.inputDelegate textDidChange:self] from [m_textResponder reset].
+ // But it won't be set to nil directly, only after a character is typed on
+ // the input panel after the reset. This strange behavior seems to be related
+ // to us overriding [QUIView setInteraction] to ignore UITextInteraction. If we
+ // didn't do that, the delegate would be kept. But not overriding that function
+ // has its own share of issues, so it seems better to keep that way for now.
+ // Instead, we choose to recreate the text responder as a brute-force solution
+ // until we have better knowledge of what is going on (or implement the new
+ // UITextInteraction protocol).
+ const auto oldResponder = m_textResponder;
+ [m_textResponder reset];
+ [m_textResponder autorelease];
+ m_textResponder = nullptr;
update(Qt::ImQueryAll);
- [m_textResponder setMarkedText:@"" selectedRange:NSMakeRange(0, 0)];
- [m_textResponder notifyInputDelegate:Qt::ImQueryInput];
+ // If update() didn't end up creating a new text responder, oldResponder will still be
+ // the first responder. In that case we need to resign it, so that the input panel hides.
+ // (the input panel will apparently not hide if the first responder is only released).
+ if ([oldResponder isFirstResponder]) {
+ qImDebug("IM not enabled, resigning autoreleased text responder as first responder");
+ [oldResponder resignFirstResponder];
+ }
}
/*!
@@ -745,9 +746,7 @@ void QIOSInputContext::reset()
void QIOSInputContext::commit()
{
qImDebug("unmarking text");
-
- [m_textResponder unmarkText];
- [m_textResponder notifyInputDelegate:Qt::ImSurroundingText];
+ [m_textResponder commit];
}
QLocale QIOSInputContext::locale() const
diff --git a/src/plugins/platforms/ios/qiosintegration.h b/src/plugins/platforms/ios/qiosintegration.h
index eeb44b54d3..2c7d33cc94 100644
--- a/src/plugins/platforms/ios/qiosintegration.h
+++ b/src/plugins/platforms/ios/qiosintegration.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QPLATFORMINTEGRATION_UIKIT_H
#define QPLATFORMINTEGRATION_UIKIT_H
@@ -47,7 +11,8 @@
#include <QtCore/private/qfactoryloader_p.h>
#include "qiosapplicationstate.h"
-#ifndef Q_OS_TVOS
+
+#if !defined(Q_OS_TVOS) && !defined(Q_OS_VISIONOS)
#include "qiostextinputoverlay.h"
#endif
@@ -67,15 +32,21 @@ public:
bool hasCapability(Capability cap) const override;
QPlatformWindow *createPlatformWindow(QWindow *window) const override;
+ QPlatformWindow *createForeignWindow(QWindow *window, WId nativeHandle) const override;
QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const override;
+#if QT_CONFIG(opengl)
QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const override;
+#endif
+
QPlatformOffscreenSurface *createPlatformOffscreenSurface(QOffscreenSurface *surface) const override;
QPlatformFontDatabase *fontDatabase() const override;
-#ifndef QT_NO_CLIPBOARD
+
+#if QT_CONFIG(clipboard)
QPlatformClipboard *clipboard() const override;
#endif
+
QPlatformInputContext *inputContext() const override;
QPlatformServices *services() const override;
@@ -87,13 +58,15 @@ public:
QAbstractEventDispatcher *createEventDispatcher() const override;
QPlatformNativeInterface *nativeInterface() const override;
- QTouchDevice *touchDevice();
-#ifndef QT_NO_ACCESSIBILITY
+ QPointingDevice *touchDevice();
+#if QT_CONFIG(accessibility)
QPlatformAccessibility *accessibility() const override;
#endif
void beep() const override;
+ void setApplicationBadge(qint64 number) override;
+
static QIOSIntegration *instance();
// -- QPlatformNativeInterface --
@@ -106,15 +79,15 @@ public:
private:
QPlatformFontDatabase *m_fontDatabase;
-#ifndef Q_OS_TVOS
+#if QT_CONFIG(clipboard)
QPlatformClipboard *m_clipboard;
#endif
QPlatformInputContext *m_inputContext;
- QTouchDevice *m_touchDevice;
+ QPointingDevice *m_touchDevice;
QIOSServices *m_platformServices;
mutable QPlatformAccessibility *m_accessibility;
QFactoryLoader *m_optionalPlugins;
-#ifndef Q_OS_TVOS
+#if !defined(Q_OS_TVOS) && !defined(Q_OS_VISIONOS)
QIOSTextInputOverlay m_textInputOverlay;
#endif
};
diff --git a/src/plugins/platforms/ios/qiosintegration.mm b/src/plugins/platforms/ios/qiosintegration.mm
index d724e65717..7cd21f83f6 100644
--- a/src/plugins/platforms/ios/qiosintegration.mm
+++ b/src/plugins/platforms/ios/qiosintegration.mm
@@ -1,51 +1,15 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#undef QT_NO_FOREACH // this file contains unported legacy Q_FOREACH uses
#include "qiosintegration.h"
#include "qioseventdispatcher.h"
#include "qiosglobal.h"
#include "qioswindow.h"
-#include "qiosbackingstore.h"
#include "qiosscreen.h"
#include "qiosplatformaccessibility.h"
-#include "qioscontext.h"
-#ifndef Q_OS_TVOS
+#if QT_CONFIG(clipboard)
#include "qiosclipboard.h"
#endif
#include "qiosinputcontext.h"
@@ -53,26 +17,31 @@
#include "qiosservices.h"
#include "qiosoptionalplugininterface.h"
+#include <QtGui/qpointingdevice.h>
#include <QtGui/private/qguiapplication_p.h>
+#include <QtGui/private/qrhibackingstore_p.h>
#include <qoffscreensurface.h>
#include <qpa/qplatformoffscreensurface.h>
-#include <QtFontDatabaseSupport/private/qcoretextfontdatabase_p.h>
-#include <QtClipboardSupport/private/qmacmime_p.h>
+#include <QtGui/private/qcoretextfontdatabase_p.h>
+#include <QtGui/private/qmacmimeregistry_p.h>
+#include <QtGui/qutimimeconverter.h>
#include <QDir>
#include <QOperatingSystemVersion>
-#import <AudioToolbox/AudioServices.h>
-
#if QT_CONFIG(opengl)
-#include <QtPlatformCompositorSupport/qpa/qplatformbackingstoreopenglsupport.h>
+#include "qioscontext.h"
#endif
+#import <AudioToolbox/AudioServices.h>
+
#include <QtDebug>
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
class QCoreTextFontEngine;
QIOSIntegration *QIOSIntegration::instance()
@@ -82,13 +51,13 @@ QIOSIntegration *QIOSIntegration::instance()
QIOSIntegration::QIOSIntegration()
: m_fontDatabase(new QCoreTextFontDatabaseEngineFactory<QCoreTextFontEngine>)
-#if !defined(Q_OS_TVOS) && !defined(QT_NO_CLIPBOARD)
+#if QT_CONFIG(clipboard)
, m_clipboard(new QIOSClipboard)
#endif
, m_inputContext(0)
, m_platformServices(new QIOSServices)
, m_accessibility(0)
- , m_optionalPlugins(new QFactoryLoader(QIosOptionalPluginInterface_iid, QLatin1String("/platforms/darwin")))
+ , m_optionalPlugins(new QFactoryLoader(QIosOptionalPluginInterface_iid, "/platforms/darwin"_L1))
{
if (Q_UNLIKELY(!qt_apple_isApplicationExtension() && !qt_apple_sharedApplication())) {
qFatal("Error: You are creating QApplication before calling UIApplicationMain.\n" \
@@ -103,6 +72,10 @@ QIOSIntegration::QIOSIntegration()
void QIOSIntegration::initialize()
{
+#if defined(Q_OS_VISIONOS)
+ // Qt requires a screen, so let's give it a dummy one
+ QWindowSystemInterface::handleScreenAdded(new QIOSScreen);
+#else
UIScreen *mainScreen = [UIScreen mainScreen];
NSMutableArray<UIScreen *> *screens = [[[UIScreen screens] mutableCopy] autorelease];
if (![screens containsObject:mainScreen]) {
@@ -112,23 +85,27 @@ void QIOSIntegration::initialize()
for (UIScreen *screen in screens)
QWindowSystemInterface::handleScreenAdded(new QIOSScreen(screen));
+#endif
// Depends on a primary screen being present
m_inputContext = new QIOSInputContext;
- m_touchDevice = new QTouchDevice;
- m_touchDevice->setType(QTouchDevice::TouchScreen);
- QTouchDevice::Capabilities touchCapabilities = QTouchDevice::Position | QTouchDevice::NormalizedPosition;
+ m_touchDevice = new QPointingDevice;
+ m_touchDevice->setType(QInputDevice::DeviceType::TouchScreen);
+ QPointingDevice::Capabilities touchCapabilities = QPointingDevice::Capability::Position | QPointingDevice::Capability::NormalizedPosition;
+#if !defined(Q_OS_VISIONOS)
if (mainScreen.traitCollection.forceTouchCapability == UIForceTouchCapabilityAvailable)
- touchCapabilities |= QTouchDevice::Pressure;
+ touchCapabilities |= QPointingDevice::Capability::Pressure;
+#endif
m_touchDevice->setCapabilities(touchCapabilities);
- QWindowSystemInterface::registerTouchDevice(m_touchDevice);
+ QWindowSystemInterface::registerInputDevice(m_touchDevice);
#if QT_CONFIG(tabletevent)
QWindowSystemInterfacePrivate::TabletEvent::setPlatformSynthesizesMouse(false);
#endif
- QMacInternalPasteboardMime::initializeMimeTypes();
+ QMacMimeRegistry::initializeMimeTypes();
- for (int i = 0; i < m_optionalPlugins->metaData().size(); ++i)
+ qsizetype size = QList<QPluginParsedMetaData>(m_optionalPlugins->metaData()).size();
+ for (qsizetype i = 0; i < size; ++i)
qobject_cast<QIosOptionalPluginInterface *>(m_optionalPlugins->instance(i))->initPlugin();
}
@@ -137,11 +114,12 @@ QIOSIntegration::~QIOSIntegration()
delete m_fontDatabase;
m_fontDatabase = 0;
-#if !defined(Q_OS_TVOS) && !defined(QT_NO_CLIPBOARD)
+#if QT_CONFIG(clipboard)
delete m_clipboard;
m_clipboard = 0;
#endif
- QMacInternalPasteboardMime::destroyMimeTypes();
+
+ QMacMimeRegistry::destroyMimeTypes();
delete m_inputContext;
m_inputContext = 0;
@@ -162,11 +140,15 @@ QIOSIntegration::~QIOSIntegration()
bool QIOSIntegration::hasCapability(Capability cap) const
{
switch (cap) {
+#if QT_CONFIG(opengl)
case BufferQueueingOpenGL:
return true;
case OpenGL:
case ThreadedOpenGL:
return true;
+ case RasterGLSurface:
+ return true;
+#endif
case ThreadedPixmaps:
return true;
case MultipleWindows:
@@ -175,7 +157,7 @@ bool QIOSIntegration::hasCapability(Capability cap) const
return false;
case ApplicationState:
return true;
- case RasterGLSurface:
+ case ForeignWindows:
return true;
default:
return QPlatformIntegration::hasCapability(cap);
@@ -187,21 +169,23 @@ QPlatformWindow *QIOSIntegration::createPlatformWindow(QWindow *window) const
return new QIOSWindow(window);
}
-// Used when the QWindow's surface type is set by the client to QSurface::RasterSurface
+QPlatformWindow *QIOSIntegration::createForeignWindow(QWindow *window, WId nativeHandle) const
+{
+ return new QIOSWindow(window, nativeHandle);
+}
+
QPlatformBackingStore *QIOSIntegration::createPlatformBackingStore(QWindow *window) const
{
- auto *backingStore = new QIOSBackingStore(window);
-#if QT_CONFIG(opengl)
- backingStore->setOpenGLSupport(new QPlatformBackingStoreOpenGLSupport(backingStore));
-#endif
- return backingStore;
+ return new QRhiBackingStore(window);
}
+#if QT_CONFIG(opengl)
// Used when the QWindow's surface type is set by the client to QSurface::OpenGLSurface
QPlatformOpenGLContext *QIOSIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const
{
return new QIOSContext(context);
}
+#endif
class QIOSOffscreenSurface : public QPlatformOffscreenSurface
{
@@ -231,14 +215,10 @@ QPlatformFontDatabase * QIOSIntegration::fontDatabase() const
return m_fontDatabase;
}
-#ifndef QT_NO_CLIPBOARD
+#if QT_CONFIG(clipboard)
QPlatformClipboard *QIOSIntegration::clipboard() const
{
-#ifndef Q_OS_TVOS
return m_clipboard;
-#else
- return QPlatformIntegration::clipboard();
-#endif
}
#endif
@@ -272,23 +252,23 @@ QVariant QIOSIntegration::styleHint(StyleHint hint) const
QStringList QIOSIntegration::themeNames() const
{
- return QStringList(QLatin1String(QIOSTheme::name));
+ return QStringList(QLatin1StringView(QIOSTheme::name));
}
QPlatformTheme *QIOSIntegration::createPlatformTheme(const QString &name) const
{
- if (name == QLatin1String(QIOSTheme::name))
+ if (name == QLatin1StringView(QIOSTheme::name))
return new QIOSTheme;
return QPlatformIntegration::createPlatformTheme(name);
}
-QTouchDevice *QIOSIntegration::touchDevice()
+QPointingDevice *QIOSIntegration::touchDevice()
{
return m_touchDevice;
}
-#ifndef QT_NO_ACCESSIBILITY
+#if QT_CONFIG(accessibility)
QPlatformAccessibility *QIOSIntegration::accessibility() const
{
if (!m_accessibility)
@@ -309,6 +289,11 @@ void QIOSIntegration::beep() const
#endif
}
+void QIOSIntegration::setApplicationBadge(qint64 number)
+{
+ UIApplication.sharedApplication.applicationIconBadgeNumber = number;
+}
+
// ---------------------------------------------------------
void *QIOSIntegration::nativeResourceForWindow(const QByteArray &resource, QWindow *window)
@@ -328,6 +313,6 @@ void *QIOSIntegration::nativeResourceForWindow(const QByteArray &resource, QWind
// ---------------------------------------------------------
-#include "moc_qiosintegration.cpp"
-
QT_END_NAMESPACE
+
+#include "moc_qiosintegration.cpp"
diff --git a/src/plugins/platforms/ios/qiosmenu.h b/src/plugins/platforms/ios/qiosmenu.h
index 32022a3bb8..b0c8e7e10c 100644
--- a/src/plugins/platforms/ios/qiosmenu.h
+++ b/src/plugins/platforms/ios/qiosmenu.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QIOSMENU_H
#define QIOSMENU_H
@@ -47,6 +11,8 @@
#import "quiview.h"
+#include <QtCore/qpointer.h>
+
class QIOSMenu;
@class QUIMenuController;
@class QUIPickerView;
diff --git a/src/plugins/platforms/ios/qiosmenu.mm b/src/plugins/platforms/ios/qiosmenu.mm
index 74a77de757..227ad2c7f5 100644
--- a/src/plugins/platforms/ios/qiosmenu.mm
+++ b/src/plugins/platforms/ios/qiosmenu.mm
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <qglobal.h>
#include <qguiapplication.h>
@@ -54,7 +18,7 @@
// m_currentMenu points to the currently visible menu.
// Only one menu will be visible at a time, and if a second menu
// is shown on top of a first, the first one will be told to hide.
-QIOSMenu *QIOSMenu::m_currentMenu = 0;
+QIOSMenu *QIOSMenu::m_currentMenu = nullptr;
// -------------------------------------------------------------------------
@@ -441,7 +405,7 @@ void QIOSMenu::dismiss()
break;
}
- m_currentMenu = 0;
+ m_currentMenu = nullptr;
m_visible = false;
}
@@ -458,13 +422,13 @@ void QIOSMenu::toggleShowUsingUIMenuController(bool show)
Q_ASSERT(m_menuController);
[[UIMenuController sharedMenuController] setMenuVisible:NO animated:YES];
[m_menuController release];
- m_menuController = 0;
+ m_menuController = nullptr;
}
}
void QIOSMenu::toggleShowUsingUIPickerView(bool show)
{
- static QObject *focusObjectWithPickerView = 0;
+ static QObject *focusObjectWithPickerView = nullptr;
if (show) {
Q_ASSERT(!m_pickerView);
@@ -477,12 +441,12 @@ void QIOSMenu::toggleShowUsingUIPickerView(bool show)
} else {
Q_ASSERT(focusObjectWithPickerView);
focusObjectWithPickerView->removeEventFilter(this);
- focusObjectWithPickerView = 0;
+ focusObjectWithPickerView = nullptr;
Q_ASSERT(m_pickerView);
[m_pickerView listenForKeyboardWillHideNotification:NO];
[m_pickerView release];
- m_pickerView = 0;
+ m_pickerView = nullptr;
qApp->inputMethod()->update(Qt::ImEnabled | Qt::ImPlatformData);
}
@@ -527,7 +491,7 @@ QIOSMenuItemList QIOSMenu::filterFirstResponderActions(const QIOSMenuItemList &m
// In case of QIOSTextResponder, edit actions will be converted to key events that ends up
// triggering the shortcuts of the filtered menu items.
QIOSMenuItemList filteredMenuItems;
- UIResponder *responder = [UIResponder currentFirstResponder];
+ UIResponder *responder = [UIResponder qt_currentFirstResponder];
for (int i = 0; i < menuItems.count(); ++i) {
QIOSMenuItem *menuItem = menuItems.at(i);
@@ -538,8 +502,8 @@ QIOSMenuItemList QIOSMenu::filterFirstResponderActions(const QIOSMenuItemList &m
|| (shortcut == QKeySequence::Paste && [responder canPerformAction:@selector(paste:) withSender:nil])
|| (shortcut == QKeySequence::Delete && [responder canPerformAction:@selector(delete:) withSender:nil])
|| (shortcut == QKeySequence::SelectAll && [responder canPerformAction:@selector(selectAll:) withSender:nil])
- || (shortcut == QKeySequence::Undo && [responder canPerformAction:@selector(undo:) withSender:nil])
- || (shortcut == QKeySequence::Redo && [responder canPerformAction:@selector(redo:) withSender:nil])
+ || (shortcut == QKeySequence::Undo && [responder canPerformAction:@selector(undo) withSender:nil])
+ || (shortcut == QKeySequence::Redo && [responder canPerformAction:@selector(redo) withSender:nil])
|| (shortcut == QKeySequence::Bold && [responder canPerformAction:@selector(toggleBoldface:) withSender:nil])
|| (shortcut == QKeySequence::Italic && [responder canPerformAction:@selector(toggleItalics:) withSender:nil])
|| (shortcut == QKeySequence::Underline && [responder canPerformAction:@selector(toggleUnderline:) withSender:nil])) {
diff --git a/src/plugins/platforms/ios/qiosmessagedialog.h b/src/plugins/platforms/ios/qiosmessagedialog.h
index 913fe0c2e9..7987956d45 100644
--- a/src/plugins/platforms/ios/qiosmessagedialog.h
+++ b/src/plugins/platforms/ios/qiosmessagedialog.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QIOSMESSAGEDIALOG_H
#define QIOSMESSAGEDIALOG_H
diff --git a/src/plugins/platforms/ios/qiosmessagedialog.mm b/src/plugins/platforms/ios/qiosmessagedialog.mm
index 254922701a..7fbd5d8729 100644
--- a/src/plugins/platforms/ios/qiosmessagedialog.mm
+++ b/src/plugins/platforms/ios/qiosmessagedialog.mm
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#import <UIKit/UIKit.h>
@@ -47,8 +11,11 @@
#include "qiosglobal.h"
#include "quiview.h"
+#include "qiosscreen.h"
#include "qiosmessagedialog.h"
+using namespace Qt::StringLiterals;
+
QIOSMessageDialog::QIOSMessageDialog()
: m_alertController(nullptr)
{
@@ -63,7 +30,7 @@ inline QString QIOSMessageDialog::messageTextPlain()
{
// Concatenate text fragments, and remove HTML tags
const QSharedPointer<QMessageDialogOptions> &opt = options();
- const QString &lineShift = QStringLiteral("\n\n");
+ constexpr auto lineShift = "\n\n"_L1;
const QString &informativeText = opt->informativeText();
const QString &detailedText = opt->detailedText();
@@ -73,7 +40,7 @@ inline QString QIOSMessageDialog::messageTextPlain()
if (!detailedText.isEmpty())
text += lineShift + detailedText;
- text.replace(QLatin1String("<p>"), QStringLiteral("\n"), Qt::CaseInsensitive);
+ text.replace("<p>"_L1, "\n"_L1, Qt::CaseInsensitive);
text.remove(QRegularExpression(QStringLiteral("<[^>]*>")));
return text;
@@ -125,6 +92,9 @@ bool QIOSMessageDialog::show(Qt::WindowFlags windowFlags, Qt::WindowModality win
|| windowModality == Qt::NonModal) // We can only do modal dialogs
return false;
+ if (!options()->checkBoxLabel().isNull())
+ return false; // Can't support
+
m_alertController = [[UIAlertController
alertControllerWithTitle:options()->windowTitle().toNSString()
message:messageTextPlain().toNSString()
@@ -146,7 +116,18 @@ bool QIOSMessageDialog::show(Qt::WindowFlags windowFlags, Qt::WindowModality win
[m_alertController addAction:createAction(NoButton)];
}
- UIWindow *window = parent ? reinterpret_cast<UIView *>(parent->winId()).window : qt_apple_sharedApplication().keyWindow;
+ UIWindow *window = presentationWindow(parent);
+ if (!window)
+ return false;
+
+ if (window.hidden) {
+ // With a window hidden, an attempt to present view controller
+ // below fails with a warning, that a view "is not a part of
+ // any view hierarchy". The UIWindow is initially hidden,
+ // as unhiding it is what hides the splash screen.
+ window.hidden = NO;
+ }
+
[window.rootViewController presentViewController:m_alertController animated:YES completion:nil];
return true;
}
diff --git a/src/plugins/platforms/ios/qiosoptionalplugininterface.h b/src/plugins/platforms/ios/qiosoptionalplugininterface.h
index bae9e5a0d8..c9d96409b9 100644
--- a/src/plugins/platforms/ios/qiosoptionalplugininterface.h
+++ b/src/plugins/platforms/ios/qiosoptionalplugininterface.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QIOPLUGININTERFACE_H
#define QIOPLUGININTERFACE_H
@@ -54,8 +18,8 @@ class QIosOptionalPluginInterface
{
public:
virtual ~QIosOptionalPluginInterface() {}
- virtual void initPlugin() const {};
- virtual UIViewController* createImagePickerController(QIOSFileDialog *) const { return nullptr; };
+ virtual void initPlugin() const {}
+ virtual UIViewController* createImagePickerController(QIOSFileDialog *) const { return nullptr; }
};
Q_DECLARE_INTERFACE(QIosOptionalPluginInterface, QIosOptionalPluginInterface_iid)
diff --git a/src/plugins/platforms/ios/qiosplatformaccessibility.h b/src/plugins/platforms/ios/qiosplatformaccessibility.h
index 989eaa4fb8..96efc663ba 100644
--- a/src/plugins/platforms/ios/qiosplatformaccessibility.h
+++ b/src/plugins/platforms/ios/qiosplatformaccessibility.h
@@ -1,48 +1,12 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QIOSPLATFORMACCESSIBILITY_H
#define QIOSPLATFORMACCESSIBILITY_H
#include <qpa/qplatformaccessibility.h>
-#ifndef QT_NO_ACCESSIBILITY
+#if QT_CONFIG(accessibility)
QT_BEGIN_NAMESPACE
diff --git a/src/plugins/platforms/ios/qiosplatformaccessibility.mm b/src/plugins/platforms/ios/qiosplatformaccessibility.mm
index aef4216e03..eb18ee637e 100644
--- a/src/plugins/platforms/ios/qiosplatformaccessibility.mm
+++ b/src/plugins/platforms/ios/qiosplatformaccessibility.mm
@@ -1,48 +1,15 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#undef QT_NO_FOREACH // this file contains unported legacy Q_FOREACH uses
#include "qiosplatformaccessibility.h"
-#ifndef QT_NO_ACCESSIBILITY
+#if QT_CONFIG(accessibility)
#include <QtGui/QtGui>
#include "qioswindow.h"
+#include "quiaccessibilityelement.h"
QIOSPlatformAccessibility::QIOSPlatformAccessibility()
{}
@@ -61,8 +28,6 @@ void invalidateCache(QAccessibleInterface *iface)
// This will invalidate everything regardless of what window the
// interface belonged to. We might want to revisit this strategy later.
// (Therefore this function still takes the interface as argument)
- // It is also responsible for the bug that focus gets temporary lost
- // when items get added or removed from the screen
foreach (QWindow *win, QGuiApplication::topLevelWindows()) {
if (win && win->handle()) {
QT_PREPEND_NAMESPACE(QIOSWindow) *window = static_cast<QT_PREPEND_NAMESPACE(QIOSWindow) *>(win->handle());
@@ -74,14 +39,35 @@ void invalidateCache(QAccessibleInterface *iface)
void QIOSPlatformAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event)
{
- if (!isActive() || !event->accessibleInterface())
+ auto *accessibleInterface = event->accessibleInterface();
+ if (!isActive() || !accessibleInterface)
return;
switch (event->type()) {
+ case QAccessible::Focus: {
+ auto *element = [QMacAccessibilityElement elementWithId:event->uniqueId()];
+ Q_ASSERT(element);
+ // There's no NSAccessibilityFocusedUIElementChangedNotification, like we have on
+ // macOS. Instead, the documentation for UIAccessibilityLayoutChangedNotification
+ // specifies that the optional argument to UIAccessibilityPostNotification is the
+ // accessibility element for VoiceOver to move to after processing the notification.
+ UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, element);
+ break;
+ }
case QAccessible::ObjectCreated:
case QAccessible::ObjectShow:
case QAccessible::ObjectHide:
case QAccessible::ObjectDestroyed:
- invalidateCache(event->accessibleInterface());
+ invalidateCache(accessibleInterface);
+ switch (accessibleInterface->role()) {
+ case QAccessible::Window:
+ case QAccessible::Dialog:
+ // Bigger changes to the UI require a full reset of VoiceOver
+ UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, nil);
+ break;
+ default:
+ // While smaller changes can be handled by re-reading the layout
+ UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, nil);
+ }
break;
default:
break;
diff --git a/src/plugins/platforms/ios/qiosscreen.h b/src/plugins/platforms/ios/qiosscreen.h
index d5a253461d..f05a5456b3 100644
--- a/src/plugins/platforms/ios/qiosscreen.h
+++ b/src/plugins/platforms/ios/qiosscreen.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QIOSSCREEN_H
#define QIOSSCREEN_H
@@ -46,10 +10,6 @@
@class QIOSOrientationListener;
-@interface QUIWindow : UIWindow
-@property (nonatomic, readonly) BOOL sendingEvent;
-@end
-
QT_BEGIN_NAMESPACE
class QIOSScreen : public QObject, public QPlatformScreen
@@ -57,7 +17,11 @@ class QIOSScreen : public QObject, public QPlatformScreen
Q_OBJECT
public:
+#if !defined(Q_OS_VISIONOS)
QIOSScreen(UIScreen *screen);
+#else
+ QIOSScreen();
+#endif
~QIOSScreen();
QString name() const override;
@@ -67,17 +31,18 @@ public:
int depth() const override;
QImage::Format format() const override;
QSizeF physicalSize() const override;
- QDpi logicalDpi() const override;
+ QDpi logicalBaseDpi() const override;
qreal devicePixelRatio() const override;
qreal refreshRate() const override;
Qt::ScreenOrientation nativeOrientation() const override;
Qt::ScreenOrientation orientation() const override;
- void setOrientationUpdateMask(Qt::ScreenOrientations mask) override;
QPixmap grabWindow(WId window, int x, int y, int width, int height) const override;
+#if !defined(Q_OS_VISIONOS)
UIScreen *uiScreen() const;
+#endif
UIWindow *uiWindow() const;
void setUpdatesPaused(bool);
@@ -87,15 +52,19 @@ public:
private:
void deliverUpdateRequests() const;
- UIScreen *m_uiScreen;
- UIWindow *m_uiWindow;
+#if !defined(Q_OS_VISIONOS)
+ UIScreen *m_uiScreen = nullptr;
+#endif
+ UIWindow *m_uiWindow = nullptr;
QRect m_geometry;
QRect m_availableGeometry;
int m_depth;
+#if !defined(Q_OS_VISIONOS)
uint m_physicalDpi;
+#endif
QSizeF m_physicalSize;
- QIOSOrientationListener *m_orientationListener;
- CADisplayLink *m_displayLink;
+ QIOSOrientationListener *m_orientationListener = nullptr;
+ CADisplayLink *m_displayLink = nullptr;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/ios/qiosscreen.mm b/src/plugins/platforms/ios/qiosscreen.mm
index 9aba658479..e7555c19ab 100644
--- a/src/plugins/platforms/ios/qiosscreen.mm
+++ b/src/plugins/platforms/ios/qiosscreen.mm
@@ -1,41 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#undef QT_NO_FOREACH // this file contains unported legacy Q_FOREACH uses
#include "qiosglobal.h"
#include "qiosintegration.h"
@@ -45,10 +11,14 @@
#include "qiosapplicationdelegate.h"
#include "qiosviewcontroller.h"
#include "quiview.h"
+#include "qiostheme.h"
+#include "quiwindow.h"
#include <QtCore/private/qcore_mac_p.h>
+#include <QtGui/qpointingdevice.h>
#include <QtGui/private/qwindow_p.h>
+#include <QtGui/private/qguiapplication_p.h>
#include <private/qcoregraphics_p.h>
#include <qpa/qwindowsysteminterface.h>
@@ -77,6 +47,7 @@ typedef void (^DisplayLinkBlock)(CADisplayLink *displayLink);
// -------------------------------------------------------------------------
+#if !defined(Q_OS_VISIONOS)
static QIOSScreen* qtPlatformScreenFor(UIScreen *uiScreen)
{
foreach (QScreen *screen, QGuiApplication::screens()) {
@@ -106,14 +77,17 @@ static QIOSScreen* qtPlatformScreenFor(UIScreen *uiScreen)
+ (void)screenConnected:(NSNotification*)notification
{
- Q_ASSERT_X(QIOSIntegration::instance(), Q_FUNC_INFO,
- "Screen connected before QIOSIntegration creation");
+ if (!QIOSIntegration::instance())
+ return; // Will be added when QIOSIntegration is created
QWindowSystemInterface::handleScreenAdded(new QIOSScreen([notification object]));
}
+ (void)screenDisconnected:(NSNotification*)notification
{
+ if (!QIOSIntegration::instance())
+ return;
+
QIOSScreen *screen = qtPlatformScreenFor([notification object]);
Q_ASSERT_X(screen, Q_FUNC_INFO, "Screen disconnected that we didn't know about");
@@ -122,6 +96,9 @@ static QIOSScreen* qtPlatformScreenFor(UIScreen *uiScreen)
+ (void)screenModeChanged:(NSNotification*)notification
{
+ if (!QIOSIntegration::instance())
+ return;
+
QIOSScreen *screen = qtPlatformScreenFor([notification object]);
Q_ASSERT_X(screen, Q_FUNC_INFO, "Screen changed that we didn't know about");
@@ -174,45 +151,15 @@ static QIOSScreen* qtPlatformScreenFor(UIScreen *uiScreen)
@end
-@interface UIScreen (Compatibility)
-@property (nonatomic, readonly) CGRect qt_applicationFrame;
-@end
-
-@implementation UIScreen (Compatibility)
-- (CGRect)qt_applicationFrame
-{
-#ifdef Q_OS_IOS
- return self.applicationFrame;
-#else
- return self.bounds;
-#endif
-}
-@end
-
-// -------------------------------------------------------------------------
-
-@implementation QUIWindow
-
-- (instancetype)initWithFrame:(CGRect)frame
-{
- if ((self = [super initWithFrame:frame]))
- self->_sendingEvent = NO;
-
- return self;
-}
-
-- (void)sendEvent:(UIEvent *)event
-{
- QScopedValueRollback<BOOL> sendingEvent(self->_sendingEvent, YES);
- [super sendEvent:event];
-}
-
-@end
+#endif // !defined(Q_OS_VISIONOS)
// -------------------------------------------------------------------------
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
+#if !defined(Q_OS_VISIONOS)
/*!
Returns the model identifier of the device.
*/
@@ -229,15 +176,17 @@ static QString deviceModelIdentifier()
char value[size];
sysctlbyname(key, &value, &size, NULL, 0);
- return QString::fromLatin1(value);
+ return QString::fromLatin1(QByteArrayView(value, qsizetype(size)));
#endif
}
+#endif // !defined(Q_OS_VISIONOS)
+#if defined(Q_OS_VISIONOS)
+QIOSScreen::QIOSScreen()
+{
+#else
QIOSScreen::QIOSScreen(UIScreen *screen)
- : QPlatformScreen()
- , m_uiScreen(screen)
- , m_uiWindow(0)
- , m_orientationListener(0)
+ : m_uiScreen(screen)
{
QString deviceIdentifier = deviceModelIdentifier();
@@ -274,7 +223,7 @@ QIOSScreen::QIOSScreen(UIScreen *screen)
if (!qt_apple_isApplicationExtension()) {
for (UIWindow *existingWindow in qt_apple_sharedApplication().windows) {
if (existingWindow.screen == m_uiScreen) {
- m_uiWindow = [m_uiWindow retain];
+ m_uiWindow = [existingWindow retain];
break;
}
}
@@ -286,11 +235,15 @@ QIOSScreen::QIOSScreen(UIScreen *screen)
}
}
- updateProperties();
+ m_orientationListener = [[QIOSOrientationListener alloc] initWithQIOSScreen:this];
m_displayLink = [m_uiScreen displayLinkWithBlock:^(CADisplayLink *) { deliverUpdateRequests(); }];
m_displayLink.paused = YES; // Enabled when clients call QWindow::requestUpdate()
[m_displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
+
+#endif // !defined(Q_OS_VISIONOS))
+
+ updateProperties();
}
QIOSScreen::~QIOSScreen()
@@ -303,12 +256,14 @@ QIOSScreen::~QIOSScreen()
QString QIOSScreen::name() const
{
- if (m_uiScreen == [UIScreen mainScreen]) {
- return QString::fromNSString([UIDevice currentDevice].model)
- + QLatin1String(" built-in display");
- } else {
- return QLatin1String("External display");
- }
+#if defined(Q_OS_VISIONOS)
+ return {};
+#else
+ if (m_uiScreen == [UIScreen mainScreen])
+ return QString::fromNSString([UIDevice currentDevice].model) + " built-in display"_L1;
+ else
+ return "External display"_L1;
+#endif
}
void QIOSScreen::updateProperties()
@@ -316,17 +271,13 @@ void QIOSScreen::updateProperties()
QRect previousGeometry = m_geometry;
QRect previousAvailableGeometry = m_availableGeometry;
+#if defined(Q_OS_VISIONOS)
+ // Based on what iPad app reports
+ m_geometry = QRect(0, 0, 1194, 834);
+ m_depth = 24;
+#else
m_geometry = QRectF::fromCGRect(m_uiScreen.bounds).toRect();
- // The application frame doesn't take safe area insets into account, and
- // the safe area insets are not available before the UIWindow is shown,
- // and do not take split-view constraints into account, so we have to
- // combine the two to get the correct available geometry.
- QRect applicationFrame = QRectF::fromCGRect(m_uiScreen.qt_applicationFrame).toRect();
- UIEdgeInsets safeAreaInsets = m_uiWindow.qt_safeAreaInsets;
- m_availableGeometry = m_geometry.adjusted(safeAreaInsets.left, safeAreaInsets.top,
- -safeAreaInsets.right, -safeAreaInsets.bottom).intersected(applicationFrame);
-
#ifndef Q_OS_TVOS
if (m_uiScreen == [UIScreen mainScreen]) {
QIOSViewController *qtViewController = [m_uiWindow.rootViewController isKindOfClass:[QIOSViewController class]] ?
@@ -367,6 +318,14 @@ void QIOSScreen::updateProperties()
m_physicalSize = physicalGeometry.size() / m_physicalDpi * millimetersPerInch;
}
+#endif // defined(Q_OS_VISIONOS)
+
+ // UIScreen does not provide a consistent accessor for the safe area margins
+ // of the screen, and on visionOS we won't even have a UIScreen, so we report
+ // the available geometry of the screen to be the same as the full geometry.
+ // Safe area margins and maximized state is handled in QIOSWindow::setWindowState.
+ m_availableGeometry = m_geometry;
+
// At construction time, we don't yet have an associated QScreen, but we still want
// to compute the properties above so they are ready for when the QScreen attaches.
// Also, at destruction time the QScreen has already been torn down, so notifying
@@ -444,23 +403,35 @@ QSizeF QIOSScreen::physicalSize() const
return m_physicalSize;
}
-QDpi QIOSScreen::logicalDpi() const
+QDpi QIOSScreen::logicalBaseDpi() const
{
return QDpi(72, 72);
}
qreal QIOSScreen::devicePixelRatio() const
{
+#if defined(Q_OS_VISIONOS)
+ return 2.0; // Based on what iPad app reports
+#else
return [m_uiScreen scale];
+#endif
}
qreal QIOSScreen::refreshRate() const
{
+#if defined(Q_OS_VISIONOS)
+ return 120.0; // Based on what iPad app reports
+#else
return m_uiScreen.maximumFramesPerSecond;
+#endif
}
Qt::ScreenOrientation QIOSScreen::nativeOrientation() const
{
+#if defined(Q_OS_VISIONOS)
+ // Based on iPad app reporting native bounds 1668x2388
+ return Qt::PortraitOrientation;
+#else
CGRect nativeBounds =
#if defined(Q_OS_IOS)
m_uiScreen.nativeBounds;
@@ -472,11 +443,12 @@ Qt::ScreenOrientation QIOSScreen::nativeOrientation() const
// be on the safe side we compare the width and height of the bounds.
return nativeBounds.size.width >= nativeBounds.size.height ?
Qt::LandscapeOrientation : Qt::PortraitOrientation;
+#endif
}
Qt::ScreenOrientation QIOSScreen::orientation() const
{
-#ifdef Q_OS_TVOS
+#if defined(Q_OS_TVOS) || defined(Q_OS_VISIONOS)
return Qt::PrimaryOrientation;
#else
// Auxiliary screens are always the same orientation as their primary orientation
@@ -506,42 +478,31 @@ Qt::ScreenOrientation QIOSScreen::orientation() const
#endif
}
-void QIOSScreen::setOrientationUpdateMask(Qt::ScreenOrientations mask)
-{
- if (m_orientationListener && mask == Qt::PrimaryOrientation) {
- [m_orientationListener release];
- m_orientationListener = 0;
- } else if (!m_orientationListener) {
- m_orientationListener = [[QIOSOrientationListener alloc] initWithQIOSScreen:this];
- updateProperties();
- }
-}
-
QPixmap QIOSScreen::grabWindow(WId window, int x, int y, int width, int height) const
{
if (window && ![reinterpret_cast<id>(window) isKindOfClass:[UIView class]])
return QPixmap();
- UIView *view = window ? reinterpret_cast<UIView *>(window) : m_uiWindow;
+ UIView *view = window ? reinterpret_cast<UIView *>(window) : m_uiWindow.rootViewController.view;
if (width < 0)
width = qMax(view.bounds.size.width - x, CGFloat(0));
if (height < 0)
height = qMax(view.bounds.size.height - y, CGFloat(0));
- CGRect captureRect = [m_uiWindow convertRect:CGRectMake(x, y, width, height) fromView:view];
- captureRect = CGRectIntersection(captureRect, m_uiWindow.bounds);
+ CGRect captureRect = [view.window convertRect:CGRectMake(x, y, width, height) fromView:view];
+ captureRect = CGRectIntersection(captureRect, view.window.bounds);
UIGraphicsBeginImageContextWithOptions(captureRect.size, NO, 0.0);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(context, -captureRect.origin.x, -captureRect.origin.y);
- // Draws the complete view hierarchy of m_uiWindow into the given rect, which
- // needs to be the same aspect ratio as the m_uiWindow's size. Since we've
+ // Draws the complete view hierarchy of view.window into the given rect, which
+ // needs to be the same aspect ratio as the view.window's size. Since we've
// translated the graphics context, and are potentially drawing into a smaller
// context than the full window, the resulting image will be a subsection of the
// full screen.
- [m_uiWindow drawViewHierarchyInRect:m_uiWindow.bounds afterScreenUpdates:NO];
+ [view.window drawViewHierarchyInRect:view.window.bounds afterScreenUpdates:NO];
UIImage *screenshot = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
@@ -549,16 +510,18 @@ QPixmap QIOSScreen::grabWindow(WId window, int x, int y, int width, int height)
return QPixmap::fromImage(qt_mac_toQImage(screenshot.CGImage));
}
+#if !defined(Q_OS_VISIONOS)
UIScreen *QIOSScreen::uiScreen() const
{
return m_uiScreen;
}
+#endif
UIWindow *QIOSScreen::uiWindow() const
{
return m_uiWindow;
}
-#include "moc_qiosscreen.cpp"
-
QT_END_NAMESPACE
+
+#include "moc_qiosscreen.cpp"
diff --git a/src/plugins/platforms/ios/qiosservices.h b/src/plugins/platforms/ios/qiosservices.h
index a8575a9151..1f4a828e24 100644
--- a/src/plugins/platforms/ios/qiosservices.h
+++ b/src/plugins/platforms/ios/qiosservices.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QIOSSERVICES_H
#define QIOSSERVICES_H
diff --git a/src/plugins/platforms/ios/qiosservices.mm b/src/plugins/platforms/ios/qiosservices.mm
index 7222bf6793..3e898cfffa 100644
--- a/src/plugins/platforms/ios/qiosservices.mm
+++ b/src/plugins/platforms/ios/qiosservices.mm
@@ -1,47 +1,12 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qiosservices.h"
#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 +21,7 @@ bool QIOSServices::openUrl(const QUrl &url)
return false;
}
+ // avoid recursing back into self
if (url == m_handlingUrl)
return false;
@@ -94,16 +60,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/qiostextinputoverlay.h b/src/plugins/platforms/ios/qiostextinputoverlay.h
index 9ed3a9b271..e502340912 100644
--- a/src/plugins/platforms/ios/qiostextinputoverlay.h
+++ b/src/plugins/platforms/ios/qiostextinputoverlay.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QIOSTEXTEDITOVERLAY_H
#define QIOSTEXTEDITOVERLAY_H
diff --git a/src/plugins/platforms/ios/qiostextinputoverlay.mm b/src/plugins/platforms/ios/qiostextinputoverlay.mm
index 3da4ba5480..01046334a1 100644
--- a/src/plugins/platforms/ios/qiostextinputoverlay.mm
+++ b/src/plugins/platforms/ios/qiostextinputoverlay.mm
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#import <UIKit/UIGestureRecognizerSubclass.h>
#import <UIKit/UITextView.h>
@@ -67,7 +31,7 @@ static SelectionPair querySelection()
QGuiApplication::sendEvent(QGuiApplication::focusObject(), &query);
int anchorPos = query.value(Qt::ImAnchorPosition).toInt();
int cursorPos = query.value(Qt::ImCursorPosition).toInt();
- return qMakePair<int, int>(anchorPos, cursorPos);
+ return qMakePair(anchorPos, cursorPos);
}
static bool hasSelection()
@@ -87,11 +51,12 @@ static void executeBlockWithoutAnimation(Block block)
// -------------------------------------------------------------------------
/**
QIOSEditMenu is just a wrapper class around UIMenuController to
- ease showing and hiding it correcly.
+ ease showing and hiding it correctly.
*/
@interface QIOSEditMenu : NSObject
@property (nonatomic, assign) BOOL visible;
@property (nonatomic, readonly) BOOL isHiding;
+@property (nonatomic, readonly) BOOL shownByUs;
@property (nonatomic, assign) BOOL reshowAfterHidden;
@end
@@ -110,6 +75,7 @@ static void executeBlockWithoutAnimation(Block block)
[center addObserverForName:UIMenuControllerDidHideMenuNotification
object:nil queue:nil usingBlock:^(NSNotification *) {
_isHiding = NO;
+ _shownByUs = NO;
if (self.reshowAfterHidden) {
// To not abort an ongoing hide transition when showing the menu, you can set
// reshowAfterHidden to wait until the transition finishes before reshowing it.
@@ -144,10 +110,15 @@ static void executeBlockWithoutAnimation(Block block)
return;
if (visible) {
+ // UIMenuController is a singleton that can be shown (and hidden) from anywhere.
+ // Try to keep track of whether or not is was shown by us (the gesture recognizers
+ // in this file) to avoid closing it if it was opened from elsewhere.
+ _shownByUs = YES;
// Note that the contents of the edit menu is decided by
// first responder, which is normally QIOSTextResponder.
- QRectF cr = qApp->inputMethod()->cursorRectangle();
- QRectF ar = qApp->inputMethod()->anchorRectangle();
+ QRectF cr = QPlatformInputContext::cursorRectangle();
+ QRectF ar = QPlatformInputContext::anchorRectangle();
+
CGRect targetRect = cr.united(ar).toCGRect();
UIView *focusView = reinterpret_cast<UIView *>(qApp->focusWindow()->winId());
[[UIMenuController sharedMenuController] setTargetRect:targetRect inView:focusView];
@@ -492,6 +463,7 @@ static void executeBlockWithoutAnimation(Block block)
[self createLoupe];
[self updateFocalPoint:QPointF::fromCGPoint(_lastTouchPoint)];
_loupeLayer.visible = YES;
+ QIOSTextInputOverlay::s_editMenu.visible = NO;
break;
case UIGestureRecognizerStateChanged:
// Tell the sub class to move the loupe to the correct position
@@ -588,7 +560,7 @@ static void executeBlockWithoutAnimation(Block block)
- (BOOL)acceptTouchesBegan:(QPointF)touchPoint
{
- Q_UNUSED(touchPoint)
+ Q_UNUSED(touchPoint);
Q_UNREACHABLE();
return NO;
}
@@ -601,7 +573,7 @@ static void executeBlockWithoutAnimation(Block block)
- (void)updateFocalPoint:(QPointF)touchPoint
{
- Q_UNUSED(touchPoint)
+ Q_UNUSED(touchPoint);
Q_UNREACHABLE();
}
@@ -626,14 +598,18 @@ static void executeBlockWithoutAnimation(Block block)
- (BOOL)acceptTouchesBegan:(QPointF)touchPoint
{
- QRectF inputRect = QGuiApplication::inputMethod()->inputItemClipRectangle();
+ QRectF inputRect = QPlatformInputContext::inputItemRectangle();
return !hasSelection() && inputRect.contains(touchPoint);
}
- (void)updateFocalPoint:(QPointF)touchPoint
{
- platformInputContext()->setSelectionOnFocusObject(touchPoint, touchPoint);
self.focalPoint = touchPoint;
+
+ const int currentCursorPos = QInputMethod::queryFocusObject(Qt::ImCursorPosition, QVariant()).toInt();
+ const int newCursorPos = QPlatformInputContext::queryFocusObject(Qt::ImCursorPosition, touchPoint).toInt();
+ if (newCursorPos != currentCursorPos)
+ QPlatformInputContext::setSelectionOnFocusObject(touchPoint, touchPoint);
}
@end
@@ -654,6 +630,7 @@ static void executeBlockWithoutAnimation(Block block)
QIOSHandleLayer *_anchorLayer;
QPointF _touchOffset;
bool _dragOnCursor;
+ bool _dragOnAnchor;
bool _multiLine;
QTimer _updateSelectionTimer;
QMetaObject::Connection _cursorConnection;
@@ -738,6 +715,9 @@ static void executeBlockWithoutAnimation(Block block)
QObject::disconnect(_cursorConnection);
QObject::disconnect(_anchorConnection);
QObject::disconnect(_clipRectConnection);
+
+ if (QIOSTextInputOverlay::s_editMenu.shownByUs)
+ QIOSTextInputOverlay::s_editMenu.visible = NO;
}
}
@@ -781,8 +761,8 @@ static void executeBlockWithoutAnimation(Block block)
// Accept the touch if it "overlaps" with any of the handles
const int handleRadius = 50;
- QPointF cursorCenter = qApp->inputMethod()->cursorRectangle().center();
- QPointF anchorCenter = qApp->inputMethod()->anchorRectangle().center();
+ QPointF cursorCenter = QPlatformInputContext::cursorRectangle().center();
+ QPointF anchorCenter = QPlatformInputContext::anchorRectangle().center();
QPointF cursorOffset = QPointF(cursorCenter.x() - touchPoint.x(), cursorCenter.y() - touchPoint.y());
QPointF anchorOffset = QPointF(anchorCenter.x() - touchPoint.x(), anchorCenter.y() - touchPoint.y());
double cursorDist = hypot(cursorOffset.x(), cursorOffset.y());
@@ -794,9 +774,11 @@ static void executeBlockWithoutAnimation(Block block)
if (cursorDist < anchorDist) {
_touchOffset = cursorOffset;
_dragOnCursor = YES;
+ _dragOnAnchor = NO;
} else {
_touchOffset = anchorOffset;
_dragOnCursor = NO;
+ _dragOnAnchor = YES;
}
return YES;
@@ -808,10 +790,9 @@ static void executeBlockWithoutAnimation(Block block)
// Get the text position under the touch
SelectionPair selection = querySelection();
- const QTransform mapToLocal = QGuiApplication::inputMethod()->inputItemTransform().inverted();
- int touchTextPos = QInputMethod::queryFocusObject(Qt::ImCursorPosition, touchPoint * mapToLocal).toInt();
+ int touchTextPos = QPlatformInputContext::queryFocusObject(Qt::ImCursorPosition, touchPoint).toInt();
- // Ensure that the handels cannot be dragged past each other
+ // Ensure that the handles cannot be dragged past each other
if (_dragOnCursor)
selection.second = (touchTextPos > selection.first) ? touchTextPos : selection.first + 1;
else
@@ -826,8 +807,8 @@ static void executeBlockWithoutAnimation(Block block)
// Move loupe to new position
QRectF handleRect = _dragOnCursor ?
- qApp->inputMethod()->cursorRectangle() :
- qApp->inputMethod()->anchorRectangle();
+ QPlatformInputContext::cursorRectangle() :
+ QPlatformInputContext::anchorRectangle();
self.focalPoint = QPointF(touchPoint.x(), handleRect.center().y());
}
@@ -837,11 +818,9 @@ static void executeBlockWithoutAnimation(Block block)
if (_cursorLayer.visible) {
_cursorLayer.visible = NO;
_anchorLayer.visible = NO;
- // Only hide the edit menu if we had a selection from before, since
- // the edit menu can also be used for other purposes by others (in
- // which case we try our best not to interfere).
- QIOSTextInputOverlay::s_editMenu.visible = NO;
}
+ if (QIOSTextInputOverlay::s_editMenu.shownByUs)
+ QIOSTextInputOverlay::s_editMenu.visible = NO;
return;
}
@@ -854,9 +833,9 @@ static void executeBlockWithoutAnimation(Block block)
}
// Adjust handles and input rect to match the new selection
- QRectF inputRect = QGuiApplication::inputMethod()->inputItemClipRectangle();
- CGRect cursorRect = QGuiApplication::inputMethod()->cursorRectangle().toCGRect();
- CGRect anchorRect = QGuiApplication::inputMethod()->anchorRectangle().toCGRect();
+ QRectF inputRect = QPlatformInputContext::inputItemClipRectangle();
+ CGRect cursorRect = QPlatformInputContext::cursorRectangle().toCGRect();
+ CGRect anchorRect = QPlatformInputContext::anchorRectangle().toCGRect();
if (!_multiLine) {
// Resize the layer a bit bigger to ensure that the handles are
@@ -877,16 +856,16 @@ static void executeBlockWithoutAnimation(Block block)
// -------------------------------------------------------------------------
/**
- This recognizer will trigger if the user taps inside the edit rectangle.
- If there's no selection, and the tap doesn't change the cursor position, the
- visibility of the edit menu will be toggled. Otherwise, if there's a selection, a
- first tap will close the edit menu (if any), and a second tap will remove the selection.
+ This recognizer will show the edit menu if the user taps inside the input
+ item without changing the cursor position, or hide it if it's already visible
+ and the user taps anywhere on the screen.
*/
@interface QIOSTapRecognizer : UITapGestureRecognizer
@end
@implementation QIOSTapRecognizer {
int _cursorPosOnPress;
+ bool _menuShouldBeVisible;
UIView *_focusView;
}
@@ -920,39 +899,71 @@ static void executeBlockWithoutAnimation(Block block)
{
[super touchesBegan:touches withEvent:event];
- if (hasSelection() && !QIOSTextInputOverlay::s_editMenu.isHiding) {
- // If there's a selection and the menu is visible, UIKit will hide the menu on the
- // first tap. But if we get a second tap while the menu is hidden, we choose to diverge
- // a bit from native behavior and instead fail the tap and forward the touch
- // to Qt. This will effectively move the cursor (and remove the selection).
- // This is needed to ensure that the user can remove the selection at any time, but
- // at the same time, also be able to tap on other items in the UI while keeping the
- // selection (e.g make the selection bold by tapping on a bold button in the UI).
+ QRectF inputRect = QPlatformInputContext::inputItemClipRectangle();
+ QPointF touchPos = QPointF::fromCGPoint([static_cast<UITouch *>([touches anyObject]) locationInView:_focusView]);
+ const bool touchInsideInputArea = inputRect.contains(touchPos);
+
+ if (touchInsideInputArea && hasSelection()) {
+ // When we have a selection and the user taps inside the input area, we stop
+ // tracking, and let Qt handle the event like normal. Unless the selection
+ // recogniser is triggered instead (if the touch is on top of the selection
+ // handles) this will typically result in Qt clearing the selection, which in
+ // turn will make the selection recogniser hide the menu.
self.state = UIGestureRecognizerStateFailed;
return;
}
- QRectF inputRect = QGuiApplication::inputMethod()->inputItemClipRectangle();
- QPointF touchPos = QPointF::fromCGPoint([static_cast<UITouch *>([touches anyObject]) locationInView:_focusView]);
- if (!inputRect.contains(touchPos))
+ if (QIOSTextInputOverlay::s_editMenu.visible) {
+ // When the menu is visible and there is no selection, we should always
+ // hide it, regardless of where the user tapped on the screen. We achieve
+ // this by continue tracking so that we receive a touchesEnded call.
+ // But note, we only want to hide the menu, and not clear the selection.
+ // Only when the user taps inside the input area do we want to clear the
+ // selection as well. This is different from native behavior, but done so
+ // deliberately for cross-platform consistency. This will let the user click on
+ // e.g "Bold" and "Italic" buttons elsewhere in the UI to modify the selected text.
+ return;
+ }
+
+ if (!touchInsideInputArea) {
+ // If the menu is not showing, and the touch is outside the input
+ // area, there is nothing left for this recogniser to do.
self.state = UIGestureRecognizerStateFailed;
+ return;
+ }
+ // When no menu is showing, and the touch is inside the input
+ // area, we check if we should show it. We want to do so if
+ // the tap doesn't result in the cursor changing position.
_cursorPosOnPress = QInputMethod::queryFocusObject(Qt::ImCursorPosition, QVariant()).toInt();
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
- QPointF touchPos = QPointF::fromCGPoint([static_cast<UITouch *>([touches anyObject]) locationInView:_focusView]);
- const QTransform mapToLocal = QGuiApplication::inputMethod()->inputItemTransform().inverted();
- int cursorPosOnRelease = QInputMethod::queryFocusObject(Qt::ImCursorPosition, touchPos * mapToLocal).toInt();
-
- if (!QIOSTextInputOverlay::s_editMenu.isHiding && cursorPosOnRelease != _cursorPosOnPress) {
- // We also want to track if the user taps on the screen to close the edit menu. And
- // the way we detect that is to check if the edit menu is hiding when we receive this
- // call. If that's the case, we leave the state as-is to allow a tap to be recognized.
- // Otherwise, if we also see that the cursor will change position, we fail, so that
- // touch events for Qt are not cancelled.
- self.state = UIGestureRecognizerStateFailed;
+ if (QIOSTextInputOverlay::s_editMenu.visible) {
+ _menuShouldBeVisible = false;
+ } else {
+ QPointF touchPos = QPointF::fromCGPoint([static_cast<UITouch *>([touches anyObject]) locationInView:_focusView]);
+ int cursorPosOnRelease = QPlatformInputContext::queryFocusObject(Qt::ImCursorPosition, touchPos).toInt();
+
+ if (cursorPosOnRelease == _cursorPosOnPress) {
+ // We've recognized a gesture to open the menu, but we don't know
+ // whether the user tapped a control that was overlaid our input
+ // area, since we don't do any granular hit-testing in touchesBegan.
+ // To ensure that the gesture doesn't eat touch events that should
+ // have reached another UI control we report the gesture as failed
+ // here, and then manually show the menu at the next runloop pass.
+ _menuShouldBeVisible = true;
+ self.state = UIGestureRecognizerStateFailed;
+ dispatch_async(dispatch_get_main_queue(), ^{
+ QIOSTextInputOverlay::s_editMenu.visible = _menuShouldBeVisible;
+ });
+ } else {
+ // The menu is hidden, and the cursor will change position once
+ // Qt receive the touch release. We therefore fail so that we
+ // don't block the touch event from further processing.
+ self.state = UIGestureRecognizerStateFailed;
+ }
}
[super touchesEnded:touches withEvent:event];
@@ -963,12 +974,7 @@ static void executeBlockWithoutAnimation(Block block)
if (self.state != UIGestureRecognizerStateEnded)
return;
- if (QIOSTextInputOverlay::s_editMenu.isHiding) {
- // Closing the menu is what we want for the first tap, so just return
- return;
- }
-
- QIOSTextInputOverlay::s_editMenu.visible = !QIOSTextInputOverlay::s_editMenu.visible;
+ QIOSTextInputOverlay::s_editMenu.visible = _menuShouldBeVisible;
}
@end
@@ -1000,31 +1006,62 @@ QIOSTextInputOverlay::~QIOSTextInputOverlay()
void QIOSTextInputOverlay::updateFocusObject()
{
+ // Destroy old recognizers since they were created with
+ // dependencies to the old focus object (focus view).
if (m_cursorRecognizer) {
- // Destroy old recognizers since they were created with
- // dependencies to the old focus object (focus view).
m_cursorRecognizer.enabled = NO;
- m_selectionRecognizer.enabled = NO;
- m_openMenuOnTapRecognizer.enabled = NO;
[m_cursorRecognizer release];
- [m_selectionRecognizer release];
- [m_openMenuOnTapRecognizer release];
- [s_editMenu release];
m_cursorRecognizer = nullptr;
+ }
+ if (m_selectionRecognizer) {
+ m_selectionRecognizer.enabled = NO;
+ [m_selectionRecognizer release];
m_selectionRecognizer = nullptr;
+ }
+ if (m_openMenuOnTapRecognizer) {
+ m_openMenuOnTapRecognizer.enabled = NO;
+ [m_openMenuOnTapRecognizer release];
m_openMenuOnTapRecognizer = nullptr;
+ }
+
+ if (s_editMenu) {
+ [s_editMenu release];
s_editMenu = nullptr;
}
- if (platformInputContext()->inputMethodAccepted()) {
- s_editMenu = [QIOSEditMenu new];
- m_cursorRecognizer = [QIOSCursorRecognizer new];
+ const QVariant hintsVariant = QGuiApplication::inputMethod()->queryFocusObject(Qt::ImHints, QVariant());
+ const Qt::InputMethodHints hints = Qt::InputMethodHints(hintsVariant.toUInt());
+ if (hints & Qt::ImhNoTextHandles)
+ return;
+
+ // The focus object can emit selection updates (e.g from mouse drag), and
+ // accept modifying it through IM when dragging on the handles, even if it
+ // doesn't accept text input and IM in general (and hence return false from
+ // inputMethodAccepted()). This is the case for read-only text fields.
+ // Therefore, listen for selection changes also when the focus object
+ // reports that it's ImReadOnly (which we take as a hint that it's actually
+ // a text field, and that selections therefore might happen). But since
+ // we have no guarantee that the focus object can actually accept new selections
+ // through IM (and since we also need to respect if the input accepts selections
+ // in the first place), we only support selections started by the text field (e.g from
+ // mouse drag), even if we in theory could also start selections from a loupe.
+
+ const bool inputAccepted = platformInputContext()->inputMethodAccepted();
+ const bool readOnly = QGuiApplication::inputMethod()->queryFocusObject(Qt::ImReadOnly, QVariant()).toBool();
+
+ if (inputAccepted || readOnly) {
+ if (!(hints & Qt::ImhNoEditMenu))
+ s_editMenu = [QIOSEditMenu new];
m_selectionRecognizer = [QIOSSelectionRecognizer new];
m_openMenuOnTapRecognizer = [QIOSTapRecognizer new];
- m_cursorRecognizer.enabled = YES;
m_selectionRecognizer.enabled = YES;
m_openMenuOnTapRecognizer.enabled = YES;
}
+
+ if (inputAccepted) {
+ m_cursorRecognizer = [QIOSCursorRecognizer new];
+ m_cursorRecognizer.enabled = YES;
+ }
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/ios/qiostextresponder.h b/src/plugins/platforms/ios/qiostextresponder.h
index 074598c1c3..491dc0b632 100644
--- a/src/plugins/platforms/ios/qiostextresponder.h
+++ b/src/plugins/platforms/ios/qiostextresponder.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#import <UIKit/UIKit.h>
@@ -48,10 +12,23 @@ class QIOSInputContext;
QT_END_NAMESPACE
-@interface QIOSTextInputResponder : UIResponder <UITextInputTraits, UIKeyInput, UITextInput>
+@interface QIOSTextResponder : UIResponder
+
+- (instancetype)initWithInputContext:(QT_PREPEND_NAMESPACE(QIOSInputContext) *)context;
+
+- (void)notifyInputDelegate:(Qt::InputMethodQueries)updatedProperties;
+- (BOOL)needsKeyboardReconfigure:(Qt::InputMethodQueries)updatedProperties;
+- (void)reset;
+- (void)commit;
+
+@end
+
+@interface QIOSTextInputResponder : QIOSTextResponder <UITextInputTraits, UIKeyInput, UITextInput>
- (instancetype)initWithInputContext:(QT_PREPEND_NAMESPACE(QIOSInputContext) *)context;
- (BOOL)needsKeyboardReconfigure:(Qt::InputMethodQueries)updatedProperties;
+- (void)reset;
+- (void)commit;
- (void)notifyInputDelegate:(Qt::InputMethodQueries)updatedProperties;
diff --git a/src/plugins/platforms/ios/qiostextresponder.mm b/src/plugins/platforms/ios/qiostextresponder.mm
index a3350bda87..5231a3adde 100644
--- a/src/plugins/platforms/ios/qiostextresponder.mm
+++ b/src/plugins/platforms/ios/qiostextresponder.mm
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qiostextresponder.h"
@@ -147,7 +111,7 @@
// By keeping the responder (QIOSTextInputResponder in this case)
// retained, we ensure that all messages sent to the view during
-// its lifetime in a window hierarcy will be able to traverse the
+// its lifetime in a window hierarchy will be able to traverse the
// responder chain.
- (void)willMoveToWindow:(UIWindow *)window
{
@@ -161,12 +125,11 @@
// -------------------------------------------------------------------------
-@implementation QIOSTextInputResponder {
+@implementation QIOSTextResponder {
+ @public
QT_PREPEND_NAMESPACE(QIOSInputContext) *m_inputContext;
QT_PREPEND_NAMESPACE(QInputMethodQueryEvent) *m_configuredImeState;
- QString m_markedText;
BOOL m_inSendEventToFocusObject;
- BOOL m_inSelectionChange;
}
- (instancetype)initWithInputContext:(QT_PREPEND_NAMESPACE(QIOSInputContext) *)inputContext
@@ -174,14 +137,211 @@
if (!(self = [self init]))
return self;
+ m_inputContext = inputContext;
+ m_configuredImeState = static_cast<QInputMethodQueryEvent*>(m_inputContext->imeState().currentState.clone());
m_inSendEventToFocusObject = NO;
+
+ return self;
+}
+
+- (void)dealloc
+{
+ delete m_configuredImeState;
+ [super dealloc];
+}
+
+- (QVariant)currentImeState:(Qt::InputMethodQuery)query
+{
+ return m_inputContext->imeState().currentState.value(query);
+}
+
+- (BOOL)canBecomeFirstResponder
+{
+ return YES;
+}
+
+- (BOOL)becomeFirstResponder
+{
+ FirstResponderCandidate firstResponderCandidate(self);
+
+ qImDebug() << "self:" << self << "first:" << [UIResponder qt_currentFirstResponder];
+
+ if (![super becomeFirstResponder]) {
+ qImDebug() << self << "was not allowed to become first responder";
+ return NO;
+ }
+
+ qImDebug() << self << "became first responder";
+
+ return YES;
+}
+
+- (BOOL)resignFirstResponder
+{
+ qImDebug() << "self:" << self << "first:" << [UIResponder qt_currentFirstResponder];
+
+ // Don't allow activation events of the window that we're doing text on behalf on
+ // to steal responder.
+ if (FirstResponderCandidate::currentCandidate() == [self nextResponder]) {
+ qImDebug("not allowing parent window to steal responder");
+ return NO;
+ }
+
+ if (![super resignFirstResponder])
+ return NO;
+
+ qImDebug() << self << "resigned first responder";
+
+ // Dismissing the keyboard will trigger resignFirstResponder, but so will
+ // a regular responder transfer to another window. In the former case, iOS
+ // will set the new first-responder to our next-responder, and in the latter
+ // case we'll have an active responder candidate.
+ if (![UIResponder qt_currentFirstResponder] && !FirstResponderCandidate::currentCandidate()) {
+ // No first responder set anymore, sync this with Qt by clearing the
+ // focus object.
+ m_inputContext->clearCurrentFocusObject();
+ } else if ([UIResponder qt_currentFirstResponder] == [self nextResponder]) {
+ // We have resigned the keyboard, and transferred first responder back to the parent view
+ Q_ASSERT(!FirstResponderCandidate::currentCandidate());
+ if ([self currentImeState:Qt::ImEnabled].toBool()) {
+ // The current focus object expects text input, but there
+ // is no keyboard to get input from. So we clear focus.
+ qImDebug("no keyboard available, clearing focus object");
+ m_inputContext->clearCurrentFocusObject();
+ }
+ } else {
+ // We've lost responder status because another Qt window was made active,
+ // another QIOSTextResponder was made first-responder, another UIView was
+ // made first-responder, or the first-responder was cleared globally. In
+ // either of these cases we don't have to do anything.
+ qImDebug("lost first responder, but not clearing focus object");
+ }
+
+ return YES;
+}
+
+- (UIResponder*)nextResponder
+{
+ // Make sure we have a handle/platform window before getting the winId().
+ // In the dtor of QIOSWindow the platform window is set to null before calling
+ // removeFromSuperview which will end up calling nextResponder. That means it's
+ // possible that we can get here while the window is being torn down.
+ return (qApp->focusWindow() && qApp->focusWindow()->handle()) ?
+ reinterpret_cast<QUIView *>(qApp->focusWindow()->handle()->winId()) : 0;
+}
+
+// -------------------------------------------------------------------------
+
+- (void)notifyInputDelegate:(Qt::InputMethodQueries)updatedProperties
+{
+ Q_UNUSED(updatedProperties);
+}
+
+- (BOOL)needsKeyboardReconfigure:(Qt::InputMethodQueries)updatedProperties
+{
+ if (updatedProperties & Qt::ImEnabled) {
+ qImDebug() << "Qt::ImEnabled has changed since text responder was configured, need reconfigure";
+ return YES;
+ }
+
+ if (updatedProperties & Qt::ImReadOnly) {
+ qImDebug() << "Qt::ImReadOnly has changed since text responder was configured, need reconfigure";
+ return YES;
+ }
+
+ return NO;
+}
+
+- (void)reset
+{
+ // Nothing to reset for read-only text fields
+}
+
+- (void)commit
+{
+ // Nothing to commit for read-only text fields
+}
+
+// -------------------------------------------------------------------------
+
+#ifndef QT_NO_SHORTCUT
+
+- (void)sendKeyPressRelease:(Qt::Key)key modifiers:(Qt::KeyboardModifiers)modifiers
+{
+ QScopedValueRollback<BOOL> rollback(m_inSendEventToFocusObject, true);
+ QWindowSystemInterface::handleKeyEvent(qApp->focusWindow(), QEvent::KeyPress, key, modifiers);
+ QWindowSystemInterface::handleKeyEvent(qApp->focusWindow(), QEvent::KeyRelease, key, modifiers);
+}
+
+- (void)sendShortcut:(QKeySequence::StandardKey)standardKey
+{
+ const QKeyCombination combination = QKeySequence(standardKey)[0];
+ [self sendKeyPressRelease:combination.key() modifiers:combination.keyboardModifiers()];
+}
+
+- (BOOL)hasSelection
+{
+ QInputMethodQueryEvent query(Qt::ImAnchorPosition | Qt::ImCursorPosition);
+ QGuiApplication::sendEvent(QGuiApplication::focusObject(), &query);
+ int anchorPos = query.value(Qt::ImAnchorPosition).toInt();
+ int cursorPos = query.value(Qt::ImCursorPosition).toInt();
+ return anchorPos != cursorPos;
+}
+
+- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
+{
+ const bool isSelectAction =
+ action == @selector(select:) ||
+ action == @selector(selectAll:);
+
+ const bool isReadAction = action == @selector(copy:);
+
+ if (!isSelectAction && !isReadAction)
+ return [super canPerformAction:action withSender:sender];
+
+ const bool hasSelection = [self hasSelection];
+ return (!hasSelection && isSelectAction) || (hasSelection && isReadAction);
+}
+
+- (void)copy:(id)sender
+{
+ Q_UNUSED(sender);
+ [self sendShortcut:QKeySequence::Copy];
+}
+
+- (void)select:(id)sender
+{
+ Q_UNUSED(sender);
+ [self sendShortcut:QKeySequence::MoveToPreviousWord];
+ [self sendShortcut:QKeySequence::SelectNextWord];
+}
+
+- (void)selectAll:(id)sender
+{
+ Q_UNUSED(sender);
+ [self sendShortcut:QKeySequence::SelectAll];
+}
+
+#endif // QT_NO_SHORTCUT
+
+@end
+
+// -------------------------------------------------------------------------
+
+@implementation QIOSTextInputResponder {
+ QString m_markedText;
+ BOOL m_inSelectionChange;
+}
+
+- (instancetype)initWithInputContext:(QT_PREPEND_NAMESPACE(QIOSInputContext) *)inputContext
+{
+ if (!(self = [super initWithInputContext:inputContext]))
+ return self;
+
m_inSelectionChange = NO;
- m_inputContext = inputContext;
- m_configuredImeState = new QInputMethodQueryEvent(m_inputContext->imeState().currentState);
QVariantMap platformData = m_configuredImeState->value(Qt::ImPlatformData).toMap();
Qt::InputMethodHints hints = Qt::InputMethodHints(m_configuredImeState->value(Qt::ImHints).toUInt());
-
Qt::EnterKeyType enterKeyType = Qt::EnterKeyType(m_configuredImeState->value(Qt::ImEnterKeyType).toUInt());
switch (enterKeyType) {
@@ -227,13 +387,11 @@
self.keyboardType = UIKeyboardTypeEmailAddress;
else if (hints & Qt::ImhDigitsOnly)
self.keyboardType = UIKeyboardTypeNumberPad;
- else if (hints & Qt::ImhFormattedNumbersOnly)
- self.keyboardType = UIKeyboardTypeDecimalPad;
else if (hints & Qt::ImhDialableCharactersOnly)
self.keyboardType = UIKeyboardTypePhonePad;
else if (hints & Qt::ImhLatinOnly)
self.keyboardType = UIKeyboardTypeASCIICapable;
- else if (hints & Qt::ImhPreferNumbers)
+ else if (hints & (Qt::ImhPreferNumbers | Qt::ImhFormattedNumbersOnly))
self.keyboardType = UIKeyboardTypeNumbersAndPunctuation;
else
self.keyboardType = UIKeyboardTypeDefault;
@@ -243,7 +401,7 @@
if (UIView *accessoryView = static_cast<UIView *>(platformData.value(kImePlatformDataInputAccessoryView).value<void *>()))
self.inputAccessoryView = [[[WrapperView alloc] initWithView:accessoryView] autorelease];
-#ifndef Q_OS_TVOS
+#if !defined(Q_OS_TVOS) && !defined(Q_OS_VISIONOS)
if (platformData.value(kImePlatformDataHideShortcutsBar).toBool()) {
// According to the docs, leadingBarButtonGroups/trailingBarButtonGroups should be set to nil to hide the shortcuts bar.
// However, starting with iOS 10, the API has been surrounded with NS_ASSUME_NONNULL, which contradicts this and causes
@@ -266,29 +424,27 @@
{
self.inputView = 0;
self.inputAccessoryView = 0;
- delete m_configuredImeState;
[super dealloc];
}
- (BOOL)needsKeyboardReconfigure:(Qt::InputMethodQueries)updatedProperties
{
- if ((updatedProperties & Qt::ImEnabled)) {
- Q_ASSERT([self currentImeState:Qt::ImEnabled].toBool());
-
+ Qt::InputMethodQueries relevantProperties = updatedProperties;
+ if ((relevantProperties & Qt::ImEnabled)) {
// When switching on input-methods we need to consider hints and platform data
// as well, as the IM state that we were based on may have been invalidated when
// IM was switched off.
qImDebug("IM was turned on, we need to check hints and platform data as well");
- updatedProperties |= (Qt::ImHints | Qt::ImPlatformData);
+ relevantProperties |= (Qt::ImHints | Qt::ImPlatformData);
}
// Based on what we set up in initWithInputContext above
- updatedProperties &= (Qt::ImHints | Qt::ImEnterKeyType | Qt::ImPlatformData);
+ relevantProperties &= (Qt::ImHints | Qt::ImEnterKeyType | Qt::ImPlatformData);
- if (!updatedProperties)
- return NO;
+ if (!relevantProperties)
+ return [super needsKeyboardReconfigure:updatedProperties];
for (uint i = 0; i < (sizeof(Qt::ImQueryAll) * CHAR_BIT); ++i) {
if (Qt::InputMethodQuery property = Qt::InputMethodQuery(int(updatedProperties & (1 << i)))) {
@@ -299,100 +455,25 @@
}
}
- return NO;
+ return [super needsKeyboardReconfigure:updatedProperties];
}
-- (BOOL)canBecomeFirstResponder
+- (void)reset
{
- return YES;
+ [self setMarkedText:@"" selectedRange:NSMakeRange(0, 0)];
+ [self notifyInputDelegate:Qt::ImSurroundingText];
}
-- (BOOL)becomeFirstResponder
+- (void)commit
{
- FirstResponderCandidate firstResponderCandidate(self);
-
- qImDebug() << "self:" << self << "first:" << [UIResponder currentFirstResponder];
-
- if (![super becomeFirstResponder]) {
- qImDebug() << self << "was not allowed to become first responder";
- return NO;
- }
-
- qImDebug() << self << "became first responder";
-
- return YES;
-}
-
-- (BOOL)resignFirstResponder
-{
- qImDebug() << "self:" << self << "first:" << [UIResponder currentFirstResponder];
-
- // Don't allow activation events of the window that we're doing text on behalf on
- // to steal responder.
- if (FirstResponderCandidate::currentCandidate() == [self nextResponder]) {
- qImDebug("not allowing parent window to steal responder");
- return NO;
- }
-
- if (![super resignFirstResponder])
- return NO;
-
- qImDebug() << self << "resigned first responder";
-
- // Dismissing the keyboard will trigger resignFirstResponder, but so will
- // a regular responder transfer to another window. In the former case, iOS
- // will set the new first-responder to our next-responder, and in the latter
- // case we'll have an active responder candidate.
- if (![UIResponder currentFirstResponder] && !FirstResponderCandidate::currentCandidate()) {
- // No first responder set anymore, sync this with Qt by clearing the
- // focus object.
- m_inputContext->clearCurrentFocusObject();
- } else if ([UIResponder currentFirstResponder] == [self nextResponder]) {
- // We have resigned the keyboard, and transferred first responder back to the parent view
- Q_ASSERT(!FirstResponderCandidate::currentCandidate());
- if ([self currentImeState:Qt::ImEnabled].toBool()) {
- // The current focus object expects text input, but there
- // is no keyboard to get input from. So we clear focus.
- qImDebug("no keyboard available, clearing focus object");
- m_inputContext->clearCurrentFocusObject();
- }
- } else {
- // We've lost responder status because another Qt window was made active,
- // another QIOSTextResponder was made first-responder, another UIView was
- // made first-responder, or the first-responder was cleared globally. In
- // either of these cases we don't have to do anything.
- qImDebug("lost first responder, but not clearing focus object");
- }
-
- return YES;
-}
-
-
-- (UIResponder*)nextResponder
-{
- return qApp->focusWindow() ?
- reinterpret_cast<QUIView *>(qApp->focusWindow()->handle()->winId()) : 0;
+ [self unmarkText];
+ [self notifyInputDelegate:Qt::ImSurroundingText];
}
// -------------------------------------------------------------------------
-- (void)sendKeyPressRelease:(Qt::Key)key modifiers:(Qt::KeyboardModifiers)modifiers
-{
- QScopedValueRollback<BOOL> rollback(m_inSendEventToFocusObject, true);
- QWindowSystemInterface::handleKeyEvent(qApp->focusWindow(), QEvent::KeyPress, key, modifiers);
- QWindowSystemInterface::handleKeyEvent(qApp->focusWindow(), QEvent::KeyRelease, key, modifiers);
-}
-
#ifndef QT_NO_SHORTCUT
-- (void)sendShortcut:(QKeySequence::StandardKey)standardKey
-{
- const int keys = QKeySequence(standardKey)[0];
- Qt::Key key = Qt::Key(keys & 0x0000FFFF);
- Qt::KeyboardModifiers modifiers = Qt::KeyboardModifiers(keys & 0xFFFF0000);
- [self sendKeyPressRelease:key modifiers:modifiers];
-}
-
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
bool isEditAction = (action == @selector(cut:)
@@ -412,10 +493,21 @@
|| action == @selector(redo));
const bool unknownAction = !isEditAction && !isSelectAction;
- const bool hasSelection = ![self selectedTextRange].empty;
+ const bool hasSelection = [self hasSelection];
if (unknownAction)
return [super canPerformAction:action withSender:sender];
+
+ QObject *focusObject = QGuiApplication::focusObject();
+ if (focusObject && focusObject->property("qt_im_readonly").toBool()) {
+ // exceptional menu items for read-only views: do include Copy, do not include Paste etc.
+ if (action == @selector(cut:)
+ || action == @selector(paste:)
+ || action == @selector(delete:))
+ return NO;
+ if (action == @selector(copy:))
+ return YES;
+ }
return (hasSelection && isEditAction) || (!hasSelection && isSelectAction);
}
@@ -425,31 +517,12 @@
[self sendShortcut:QKeySequence::Cut];
}
-- (void)copy:(id)sender
-{
- Q_UNUSED(sender);
- [self sendShortcut:QKeySequence::Copy];
-}
-
- (void)paste:(id)sender
{
Q_UNUSED(sender);
[self sendShortcut:QKeySequence::Paste];
}
-- (void)select:(id)sender
-{
- Q_UNUSED(sender);
- [self sendShortcut:QKeySequence::MoveToPreviousWord];
- [self sendShortcut:QKeySequence::SelectNextWord];
-}
-
-- (void)selectAll:(id)sender
-{
- Q_UNUSED(sender);
- [self sendShortcut:QKeySequence::SelectAll];
-}
-
- (void)delete:(id)sender
{
Q_UNUSED(sender);
@@ -505,15 +578,23 @@
// from within a undo callback.
NSUndoManager *undoMgr = self.undoManager;
[undoMgr removeAllActions];
+
+ [undoMgr beginUndoGrouping];
+ [undoMgr registerUndoWithTarget:self selector:@selector(undo) object:nil];
+ [undoMgr endUndoGrouping];
[undoMgr beginUndoGrouping];
[undoMgr registerUndoWithTarget:self selector:@selector(undo) object:nil];
[undoMgr endUndoGrouping];
- // Schedule an operation that we immediately pop off to be able to schedule a redo
+ // Schedule operations that we immediately pop off to be able to schedule redos
+ [undoMgr beginUndoGrouping];
+ [undoMgr registerUndoWithTarget:self selector:@selector(registerRedo) object:nil];
+ [undoMgr endUndoGrouping];
[undoMgr beginUndoGrouping];
[undoMgr registerUndoWithTarget:self selector:@selector(registerRedo) object:nil];
[undoMgr endUndoGrouping];
[undoMgr undo];
+ [undoMgr undo];
// Note that, perhaps because of a bug in UIKit, the buttons on the shortcuts bar ends up
// disabled if a undo/redo callback doesn't lead to a [UITextInputDelegate textDidChange].
@@ -521,6 +602,11 @@
// become disabled when there is nothing more to undo (Qt didn't change anything upon receiving
// an undo request). This seems to be OK behavior, so we let it stay like that unless it shows
// to cause problems.
+
+ // QTBUG-63393: Having two operations on the rebuilt undo stack keeps the undo/redo widgets
+ // always enabled on the shortcut bar. This workaround was found by experimenting with
+ // removing the removeAllActions call, and is related to the unknown internal implementation
+ // details of how the shortcut bar updates the dimming of its buttons.
});
}
@@ -625,11 +711,6 @@
QCoreApplication::sendEvent(focusObject, &e);
}
-- (QVariant)currentImeState:(Qt::InputMethodQuery)query
-{
- return m_inputContext->imeState().currentState.value(query);
-}
-
- (id<UITextInputTokenizer>)tokenizer
{
return [[[UITextInputStringTokenizer alloc] initWithTextInput:self] autorelease];
@@ -817,20 +898,24 @@
NSRange r = static_cast<QUITextRange*>(range).range;
QList<QInputMethodEvent::Attribute> attrs;
attrs << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, r.location, 0, 0);
- QInputMethodEvent e(m_markedText, attrs);
- [self sendEventToFocusObject:e];
- QRectF startRect = qApp->inputMethod()->cursorRectangle();
+ {
+ QInputMethodEvent e(m_markedText, attrs);
+ [self sendEventToFocusObject:e];
+ }
+ QRectF startRect = QPlatformInputContext::cursorRectangle();
attrs = QList<QInputMethodEvent::Attribute>();
attrs << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, r.location + r.length, 0, 0);
- e = QInputMethodEvent(m_markedText, attrs);
- [self sendEventToFocusObject:e];
- QRectF endRect = qApp->inputMethod()->cursorRectangle();
+ {
+ QInputMethodEvent e(m_markedText, attrs);
+ [self sendEventToFocusObject:e];
+ }
+ QRectF endRect = QPlatformInputContext::cursorRectangle();
if (cursorPos != int(r.location + r.length) || cursorPos != anchorPos) {
attrs = QList<QInputMethodEvent::Attribute>();
attrs << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, qMin(cursorPos, anchorPos), qAbs(cursorPos - anchorPos), 0);
- e = QInputMethodEvent(m_markedText, attrs);
+ QInputMethodEvent e(m_markedText, attrs);
[self sendEventToFocusObject:e];
}
@@ -851,8 +936,7 @@
Q_UNUSED(position);
// Assume for now that position is always the same as
// cursor index until a better API is in place:
- QRectF cursorRect = qApp->inputMethod()->cursorRectangle();
- return cursorRect.toCGRect();
+ return QPlatformInputContext::cursorRectangle().toCGRect();
}
- (void)replaceRange:(UITextRange *)range withText:(NSString *)text
@@ -864,20 +948,20 @@
[self sendEventToFocusObject:e];
}
-- (void)setBaseWritingDirection:(UITextWritingDirection)writingDirection forRange:(UITextRange *)range
+- (void)setBaseWritingDirection:(NSWritingDirection)writingDirection forRange:(UITextRange *)range
{
Q_UNUSED(writingDirection);
Q_UNUSED(range);
// Writing direction is handled by QLocale
}
-- (UITextWritingDirection)baseWritingDirectionForPosition:(UITextPosition *)position inDirection:(UITextStorageDirection)direction
+- (NSWritingDirection)baseWritingDirectionForPosition:(UITextPosition *)position inDirection:(UITextStorageDirection)direction
{
Q_UNUSED(position);
Q_UNUSED(direction);
if (QLocale::system().textDirection() == Qt::RightToLeft)
- return UITextWritingDirectionRightToLeft;
- return UITextWritingDirectionLeftToRight;
+ return NSWritingDirectionRightToLeft;
+ return NSWritingDirectionLeftToRight;
}
- (UITextRange *)characterRangeByExtendingPosition:(UITextPosition *)position inDirection:(UITextLayoutDirection)direction
@@ -891,9 +975,7 @@
- (UITextPosition *)closestPositionToPoint:(CGPoint)point
{
- QPointF p = QPointF::fromCGPoint(point);
- const QTransform mapToLocal = QGuiApplication::inputMethod()->inputItemTransform().inverted();
- int textPos = QInputMethod::queryFocusObject(Qt::ImCursorPosition, p * mapToLocal).toInt();
+ int textPos = QPlatformInputContext::queryFocusObject(Qt::ImCursorPosition, QPointF::fromCGPoint(point)).toInt();
return [QUITextPosition positionWithIndex:textPos];
}
diff --git a/src/plugins/platforms/ios/qiostheme.h b/src/plugins/platforms/ios/qiostheme.h
index c917679a91..f0a404a61a 100644
--- a/src/plugins/platforms/ios/qiostheme.h
+++ b/src/plugins/platforms/ios/qiostheme.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QIOSTHEME_H
#define QIOSTHEME_H
@@ -44,6 +8,8 @@
#include <QtGui/QPalette>
#include <qpa/qplatformtheme.h>
+#include <QtCore/private/qcore_mac_p.h>
+
QT_BEGIN_NAMESPACE
class QIOSTheme : public QPlatformTheme
@@ -55,19 +21,26 @@ public:
const QPalette *palette(Palette type = SystemPalette) const override;
QVariant themeHint(ThemeHint hint) const override;
+ Qt::ColorScheme colorScheme() const override;
+
+#if !defined(Q_OS_TVOS) && !defined(Q_OS_VISIONOS)
QPlatformMenuItem* createPlatformMenuItem() const override;
QPlatformMenu* createPlatformMenu() const override;
+#endif
bool usePlatformNativeDialog(DialogType type) const override;
QPlatformDialogHelper *createPlatformDialogHelper(DialogType type) const override;
const QFont *font(Font type = SystemFont) const override;
+ QIconEngine *createIconEngine(const QString &iconName) const override;
static const char *name;
+ static void initializeSystemPalette();
+
private:
- mutable QHash<QPlatformTheme::Font, QFont *> m_fonts;
- QPalette m_systemPalette;
+ static QPalette s_systemPalette;
+ QMacNotificationObserver m_contentSizeCategoryObserver;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/ios/qiostheme.mm b/src/plugins/platforms/ios/qiostheme.mm
index 5534264a60..3853de9cf1 100644
--- a/src/plugins/platforms/ios/qiostheme.mm
+++ b/src/plugins/platforms/ios/qiostheme.mm
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qiostheme.h"
@@ -44,18 +8,27 @@
#include <QtCore/private/qcore_mac_p.h>
#include <QtGui/QFont>
+#include <QtGui/private/qcoregraphics_p.h>
-#include <QtFontDatabaseSupport/private/qcoretextfontdatabase_p.h>
+#include <QtGui/private/qcoretextfontdatabase_p.h>
+#include <QtGui/private/qappleiconengine_p.h>
#include <QtGui/private/qguiapplication_p.h>
#include <qpa/qplatformintegration.h>
#include <UIKit/UIFont.h>
#include <UIKit/UIInterface.h>
-#ifndef Q_OS_TVOS
+#if !defined(Q_OS_TVOS) && !defined(Q_OS_VISIONOS)
#include "qiosmenu.h"
+#endif
+
+#if !defined(Q_OS_TVOS)
#include "qiosfiledialog.h"
+#include "qioscolordialog.h"
+#include "qiosfontdialog.h"
#include "qiosmessagedialog.h"
+#include "qiosscreen.h"
+#include "quiwindow.h"
#endif
QT_BEGIN_NAMESPACE
@@ -63,47 +36,75 @@ QT_BEGIN_NAMESPACE
const char *QIOSTheme::name = "ios";
QIOSTheme::QIOSTheme()
- : m_systemPalette(*QPlatformTheme::palette(QPlatformTheme::SystemPalette))
{
- m_systemPalette.setBrush(QPalette::Highlight, QColor(204, 221, 237));
- m_systemPalette.setBrush(QPalette::HighlightedText, Qt::black);
+ initializeSystemPalette();
+
+ m_contentSizeCategoryObserver = QMacNotificationObserver(nil,
+ UIContentSizeCategoryDidChangeNotification, [] {
+ qCDebug(lcQpaFonts) << "Contents size category changed to" << UIApplication.sharedApplication.preferredContentSizeCategory;
+ QPlatformFontDatabase::repopulateFontDatabase();
+ });
}
QIOSTheme::~QIOSTheme()
{
- qDeleteAll(m_fonts);
+}
+
+QPalette QIOSTheme::s_systemPalette;
+
+void QIOSTheme::initializeSystemPalette()
+{
+ Q_DECL_IMPORT QPalette qt_fusionPalette(void);
+ s_systemPalette = qt_fusionPalette();
+
+ s_systemPalette.setBrush(QPalette::Window, qt_mac_toQBrush(UIColor.systemGroupedBackgroundColor.CGColor));
+ s_systemPalette.setBrush(QPalette::Active, QPalette::WindowText, qt_mac_toQBrush(UIColor.labelColor.CGColor));
+
+ s_systemPalette.setBrush(QPalette::Base, qt_mac_toQBrush(UIColor.secondarySystemGroupedBackgroundColor.CGColor));
+ s_systemPalette.setBrush(QPalette::Active, QPalette::Text, qt_mac_toQBrush(UIColor.labelColor.CGColor));
+
+ s_systemPalette.setBrush(QPalette::Button, qt_mac_toQBrush(UIColor.secondarySystemBackgroundColor.CGColor));
+ s_systemPalette.setBrush(QPalette::Active, QPalette::ButtonText, qt_mac_toQBrush(UIColor.labelColor.CGColor));
+
+ s_systemPalette.setBrush(QPalette::Active, QPalette::BrightText, qt_mac_toQBrush(UIColor.lightTextColor.CGColor));
+ s_systemPalette.setBrush(QPalette::Active, QPalette::PlaceholderText, qt_mac_toQBrush(UIColor.placeholderTextColor.CGColor));
+
+ s_systemPalette.setBrush(QPalette::Active, QPalette::Link, qt_mac_toQBrush(UIColor.linkColor.CGColor));
+ s_systemPalette.setBrush(QPalette::Active, QPalette::LinkVisited, qt_mac_toQBrush(UIColor.linkColor.CGColor));
+
+ s_systemPalette.setBrush(QPalette::Highlight, QColor(11, 70, 150, 60));
+ s_systemPalette.setBrush(QPalette::HighlightedText, qt_mac_toQBrush(UIColor.labelColor.CGColor));
+
+ if (@available(ios 15.0, *))
+ s_systemPalette.setBrush(QPalette::Accent, qt_mac_toQBrush(UIColor.tintColor.CGColor));
}
const QPalette *QIOSTheme::palette(QPlatformTheme::Palette type) const
{
if (type == QPlatformTheme::SystemPalette)
- return &m_systemPalette;
+ return &s_systemPalette;
return 0;
}
+#if !defined(Q_OS_TVOS) && !defined(Q_OS_VISIONOS)
QPlatformMenuItem* QIOSTheme::createPlatformMenuItem() const
{
-#ifdef Q_OS_TVOS
- return 0;
-#else
- return new QIOSMenuItem();
-#endif
+ return new QIOSMenuItem;
}
QPlatformMenu* QIOSTheme::createPlatformMenu() const
{
-#ifdef Q_OS_TVOS
- return 0;
-#else
- return new QIOSMenu();
-#endif
+ return new QIOSMenu;
}
+#endif
bool QIOSTheme::usePlatformNativeDialog(QPlatformTheme::DialogType type) const
{
switch (type) {
case FileDialog:
case MessageDialog:
+ case ColorDialog:
+ case FontDialog:
return !qt_apple_isApplicationExtension();
default:
return false;
@@ -120,6 +121,12 @@ QPlatformDialogHelper *QIOSTheme::createPlatformDialogHelper(QPlatformTheme::Dia
case MessageDialog:
return new QIOSMessageDialog();
break;
+ case ColorDialog:
+ return new QIOSColorDialog();
+ break;
+ case FontDialog:
+ return new QIOSFontDialog();
+ break;
#endif
default:
return 0;
@@ -130,7 +137,7 @@ QVariant QIOSTheme::themeHint(ThemeHint hint) const
{
switch (hint) {
case QPlatformTheme::StyleNames:
- return QStringList(QStringLiteral("fusion"));
+ return QStringList(QStringLiteral("Fusion"));
case KeyboardScheme:
return QVariant(int(MacKeyboardScheme));
default:
@@ -138,14 +145,42 @@ QVariant QIOSTheme::themeHint(ThemeHint hint) const
}
}
-const QFont *QIOSTheme::font(Font type) const
+Qt::ColorScheme QIOSTheme::colorScheme() const
{
- if (m_fonts.isEmpty()) {
- QCoreTextFontDatabase *ctfd = static_cast<QCoreTextFontDatabase *>(QGuiApplicationPrivate::platformIntegration()->fontDatabase());
- m_fonts = ctfd->themeFonts();
+#if defined(Q_OS_VISIONOS)
+ // On visionOS the concept of light or dark mode does not
+ // apply, as the UI is constantly changing based on what
+ // the lighting conditions are outside the headset, but
+ // the OS reports itself as always being in dark mode.
+ return Qt::ColorScheme::Dark;
+#else
+ // Set the appearance based on the QUIWindow
+ // Fallback to the UIScreen if no window is created yet
+ UIUserInterfaceStyle appearance = UIScreen.mainScreen.traitCollection.userInterfaceStyle;
+ NSArray<UIWindow *> *windows = qt_apple_sharedApplication().windows;
+ for (UIWindow *window in windows) {
+ if ([window isKindOfClass:[QUIWindow class]]) {
+ appearance = static_cast<QUIWindow*>(window).traitCollection.userInterfaceStyle;
+ break;
+ }
}
- return m_fonts.value(type, 0);
+ return appearance == UIUserInterfaceStyleDark
+ ? Qt::ColorScheme::Dark
+ : Qt::ColorScheme::Light;
+#endif
+}
+
+const QFont *QIOSTheme::font(Font type) const
+{
+ const auto *platformIntegration = QGuiApplicationPrivate::platformIntegration();
+ const auto *coreTextFontDatabase = static_cast<QCoreTextFontDatabase *>(platformIntegration->fontDatabase());
+ return coreTextFontDatabase->themeFont(type);
+}
+
+QIconEngine *QIOSTheme::createIconEngine(const QString &iconName) const
+{
+ return new QAppleIconEngine(iconName);
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/ios/qiosviewcontroller.h b/src/plugins/platforms/ios/qiosviewcontroller.h
index 7af4c83b48..237cd57edf 100644
--- a/src/plugins/platforms/ios/qiosviewcontroller.h
+++ b/src/plugins/platforms/ios/qiosviewcontroller.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#import <UIKit/UIKit.h>
#include <QtCore/QtGlobal>
@@ -50,6 +14,8 @@ QT_END_NAMESPACE
- (instancetype)initWithQIOSScreen:(QT_PREPEND_NAMESPACE(QIOSScreen) *)screen;
- (void)updateProperties;
+- (NSArray*)keyCommands;
+- (void)handleShortcut:(UIKeyCommand*)keyCommand;
#ifndef Q_OS_TVOS
@property (nonatomic, assign) UIInterfaceOrientation lockedOrientation;
diff --git a/src/plugins/platforms/ios/qiosviewcontroller.mm b/src/plugins/platforms/ios/qiosviewcontroller.mm
index cd4af46ef7..fa3fef26b6 100644
--- a/src/plugins/platforms/ios/qiosviewcontroller.mm
+++ b/src/plugins/platforms/ios/qiosviewcontroller.mm
@@ -1,53 +1,19 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qiosglobal.h"
#import "qiosviewcontroller.h"
#include <QtCore/qscopedvaluerollback.h>
#include <QtCore/private/qcore_mac_p.h>
+#include <QtGui/private/qapplekeymapper_p.h>
#include <QtGui/QGuiApplication>
#include <QtGui/QWindow>
#include <QtGui/QScreen>
#include <QtGui/private/qwindow_p.h>
+#include <QtGui/private/qguiapplication_p.h>
#include "qiosintegration.h"
#include "qiosscreen.h"
@@ -55,6 +21,8 @@
#include "qioswindow.h"
#include "quiview.h"
+#include <QtCore/qpointer.h>
+
// -------------------------------------------------------------------------
@interface QIOSViewController ()
@@ -120,6 +88,7 @@
- (void)didAddSubview:(UIView *)subview
{
+#if !defined(Q_OS_VISIONOS)
Q_UNUSED(subview);
QT_PREPEND_NAMESPACE(QIOSScreen) *screen = self.qtViewController.platformScreen;
@@ -135,20 +104,30 @@
uiWindow.screen = screen->uiScreen();
uiWindow.hidden = NO;
}
+#endif
}
- (void)willRemoveSubview:(UIView *)subview
{
+#if !defined(Q_OS_VISIONOS)
Q_UNUSED(subview);
- Q_ASSERT(self.window);
UIWindow *uiWindow = self.window;
+ // uiWindow can be null when closing from the ios "app manager" and the app is
+ // showing a native window like UIDocumentBrowserViewController
+ if (!uiWindow)
+ return;
if (uiWindow.screen != [UIScreen mainScreen] && self.subviews.count == 1) {
- // Removing the last view of an external screen, go back to mirror mode
- uiWindow.screen = [UIScreen mainScreen];
- uiWindow.hidden = YES;
+ // We're about to remove the last view of an external screen, so go back
+ // to mirror mode, but defer it until after the view has been removed,
+ // to ensure that we don't try to layout the view that's being removed.
+ dispatch_async(dispatch_get_main_queue(), ^{
+ uiWindow.hidden = YES;
+ uiWindow.screen = [UIScreen mainScreen];
+ });
}
+#endif
}
- (void)layoutSubviews
@@ -235,7 +214,7 @@
{
// The initial frame computed during startup may happen before the view has
// a window, meaning our calculations above will be wrong. We ensure that the
- // frame is set correctly once we have a window to base our calulations on.
+ // frame is set correctly once we have a window to base our calculations on.
[self setFrame:self.window.bounds];
}
@@ -246,6 +225,7 @@
@implementation QIOSViewController {
BOOL m_updatingProperties;
QMetaObject::Connection m_focusWindowChangeConnection;
+ QMetaObject::Connection m_appStateChangedConnection;
}
#ifndef Q_OS_TVOS
@@ -274,7 +254,7 @@
});
QIOSApplicationState *applicationState = &QIOSIntegration::instance()->applicationState;
- QObject::connect(applicationState, &QIOSApplicationState::applicationStateDidChange,
+ m_appStateChangedConnection = QObject::connect(applicationState, &QIOSApplicationState::applicationStateDidChange,
[self](Qt::ApplicationState oldState, Qt::ApplicationState newState) {
if (oldState == Qt::ApplicationSuspended && newState != Qt::ApplicationSuspended) {
// We may have ignored an earlier layout because the application was suspended,
@@ -294,6 +274,7 @@
- (void)dealloc
{
QObject::disconnect(m_focusWindowChangeConnection);
+ QObject::disconnect(m_appStateChangedConnection);
[super dealloc];
}
@@ -308,7 +289,7 @@
Q_ASSERT(!qt_apple_isApplicationExtension());
-#ifndef Q_OS_TVOS
+#if !defined(Q_OS_TVOS) && !defined(Q_OS_VISIONOS)
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
[center addObserver:self selector:@selector(willChangeStatusBarFrame:)
name:UIApplicationWillChangeStatusBarFrameNotification
@@ -330,7 +311,7 @@
- (BOOL)shouldAutorotate
{
-#ifndef Q_OS_TVOS
+#if !defined(Q_OS_TVOS) && !defined(Q_OS_VISIONOS)
return self.platformScreen && self.platformScreen->uiScreen() == [UIScreen mainScreen] && !self.lockedOrientation;
#else
return NO;
@@ -362,6 +343,7 @@
[super didRotateFromInterfaceOrientation:orientation];
}
+#if !defined(Q_OS_VISIONOS)
- (void)willChangeStatusBarFrame:(NSNotification*)notification
{
Q_UNUSED(notification);
@@ -405,6 +387,7 @@
[self.view setNeedsLayout];
}
+#endif
- (void)viewWillLayoutSubviews
{
@@ -425,15 +408,17 @@
if (!self.platformScreen || !self.platformScreen->screen())
return;
+#if !defined(Q_OS_VISIONOS)
// For now we only care about the main screen, as both the statusbar
// visibility and orientation is only appropriate for the main screen.
if (self.platformScreen->uiScreen() != [UIScreen mainScreen])
return;
+#endif
// Prevent recursion caused by updating the status bar appearance (position
// or visibility), which in turn may cause a layout of our subviews, and
// a reset of window-states, which themselves affect the view controller
- // properties such as the statusbar visibilty.
+ // properties such as the statusbar visibility.
if (m_updatingProperties)
return;
@@ -455,7 +440,7 @@
// All decisions are based on the top level window
focusWindow = qt_window_private(focusWindow)->topLevelWindow();
-#ifndef Q_OS_TVOS
+#if !defined(Q_OS_TVOS) && !defined(Q_OS_VISIONOS)
// -------------- Status bar style and visbility ---------------
@@ -523,5 +508,36 @@
#endif
}
+- (NSArray*)keyCommands
+{
+ // FIXME: If we are on iOS 13.4 or later we can use UIKey instead of doing this
+ // So it should be safe to remove this entire function and handleShortcut() as
+ // a result
+ NSMutableArray<UIKeyCommand *> *keyCommands = nil;
+ QShortcutMap &shortcutMap = QGuiApplicationPrivate::instance()->shortcutMap;
+ keyCommands = [[NSMutableArray<UIKeyCommand *> alloc] init];
+ const QList<QKeySequence> keys = shortcutMap.keySequences();
+ for (const QKeySequence &seq : keys) {
+ const QString keyString = seq.toString();
+ [keyCommands addObject:[UIKeyCommand
+ keyCommandWithInput:QString(keyString[keyString.length() - 1]).toNSString()
+ modifierFlags:QAppleKeyMapper::toUIKitModifiers(seq[0].keyboardModifiers())
+ action:@selector(handleShortcut:)]];
+ }
+ return keyCommands;
+}
+
+- (void)handleShortcut:(UIKeyCommand *)keyCommand
+{
+ const QString str = QString::fromNSString([keyCommand input]);
+ Qt::KeyboardModifiers qtMods = QAppleKeyMapper::fromUIKitModifiers(keyCommand.modifierFlags);
+ QChar ch = str.isEmpty() ? QChar() : str.at(0);
+ QShortcutMap &shortcutMap = QGuiApplicationPrivate::instance()->shortcutMap;
+ QKeyEvent keyEvent(QEvent::ShortcutOverride, Qt::Key(ch.toUpper().unicode()), qtMods, str);
+ shortcutMap.tryShortcut(&keyEvent);
+}
+
+
+
@end
diff --git a/src/plugins/platforms/ios/qioswindow.h b/src/plugins/platforms/ios/qioswindow.h
index 2028fc2a42..02b2161202 100644
--- a/src/plugins/platforms/ios/qioswindow.h
+++ b/src/plugins/platforms/ios/qioswindow.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QIOSWINDOW_H
#define QIOSWINDOW_H
@@ -57,7 +21,7 @@ class QIOSWindow : public QObject, public QPlatformWindow
Q_OBJECT
public:
- explicit QIOSWindow(QWindow *window);
+ explicit QIOSWindow(QWindow *window, WId nativeHandle = 0);
~QIOSWindow();
void setGeometry(const QRect &rect) override;
@@ -92,13 +56,20 @@ public:
void requestUpdate() override;
+ void setMask(const QRegion &region) override;
+
+#if QT_CONFIG(opengl)
CAEAGLLayer *eaglLayer() const;
+#endif
+
+ bool isForeignWindow() const override;
+ UIView *view() const;
private:
void applicationStateChanged(Qt::ApplicationState state);
void applyGeometry(const QRect &rect);
- QUIView *m_view;
+ UIView *m_view;
QRect m_normalGeometry;
int m_windowLevel;
@@ -114,6 +85,8 @@ private:
QDebug operator<<(QDebug debug, const QIOSWindow *window);
#endif
+QT_MANGLE_NAMESPACE(QUIView) *quiview_cast(UIView *view);
+
QT_END_NAMESPACE
#endif // QIOSWINDOW_H
diff --git a/src/plugins/platforms/ios/qioswindow.mm b/src/plugins/platforms/ios/qioswindow.mm
index 1b6a802ca2..0f4a6803b3 100644
--- a/src/plugins/platforms/ios/qioswindow.mm
+++ b/src/plugins/platforms/ios/qioswindow.mm
@@ -1,57 +1,27 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qioswindow.h"
#include "qiosapplicationdelegate.h"
-#include "qioscontext.h"
#include "qiosglobal.h"
#include "qiosintegration.h"
#include "qiosscreen.h"
#include "qiosviewcontroller.h"
#include "quiview.h"
+#include "qiosinputcontext.h"
+
+#include <QtCore/private/qcore_mac_p.h>
#include <QtGui/private/qwindow_p.h>
+#include <QtGui/private/qhighdpiscaling_p.h>
#include <qpa/qplatformintegration.h>
+#if QT_CONFIG(opengl)
#import <QuartzCore/CAEAGLLayer.h>
-#ifdef Q_OS_IOS
+#endif
+
+#if QT_CONFIG(metal)
#import <QuartzCore/CAMetalLayer.h>
#endif
@@ -59,31 +29,47 @@
QT_BEGIN_NAMESPACE
-QIOSWindow::QIOSWindow(QWindow *window)
+enum {
+ defaultWindowWidth = 160,
+ defaultWindowHeight = 160
+};
+
+QIOSWindow::QIOSWindow(QWindow *window, WId nativeHandle)
: QPlatformWindow(window)
, m_windowLevel(0)
{
-#ifdef Q_OS_IOS
- if (window->surfaceType() == QSurface::MetalSurface)
- m_view = [[QUIMetalView alloc] initWithQIOSWindow:this];
- else
+ if (nativeHandle) {
+ m_view = reinterpret_cast<UIView *>(nativeHandle);
+ [m_view retain];
+ } else {
+#if QT_CONFIG(metal)
+ if (window->surfaceType() == QSurface::RasterSurface)
+ window->setSurfaceType(QSurface::MetalSurface);
+
+ if (window->surfaceType() == QSurface::MetalSurface)
+ m_view = [[QUIMetalView alloc] initWithQIOSWindow:this];
+ else
#endif
- m_view = [[QUIView alloc] initWithQIOSWindow:this];
+ m_view = [[QUIView alloc] initWithQIOSWindow:this];
+ }
connect(qGuiApp, &QGuiApplication::applicationStateChanged, this, &QIOSWindow::applicationStateChanged);
setParent(QPlatformWindow::parent());
- // Resolve default window geometry in case it was not set before creating the
- // platform window. This picks up eg. minimum-size if set, and defaults to
- // the "maxmized" geometry (even though we're not in that window state).
- // FIXME: Detect if we apply a maximized geometry and send a window state
- // change event in that case.
- m_normalGeometry = initialGeometry(window, QPlatformWindow::geometry(),
- screen()->availableGeometry().width(), screen()->availableGeometry().height());
+ if (!isForeignWindow()) {
+ // Resolve default window geometry in case it was not set before creating the
+ // platform window. This picks up eg. minimum-size if set.
+ m_normalGeometry = initialGeometry(window, QPlatformWindow::geometry(),
+ defaultWindowWidth, defaultWindowHeight);
- setWindowState(window->windowStates());
- setOpacity(window->opacity());
+ setWindowState(window->windowStates());
+ setOpacity(window->opacity());
+ setMask(QHighDpi::toNativeLocalRegion(window->mask(), window));
+ } else {
+ // Pick up essential foreign window state
+ QPlatformWindow::setGeometry(QRectF::fromCGRect(m_view.frame).toRect());
+ }
Qt::ScreenOrientation initialOrientation = window->contentOrientation();
if (initialOrientation != Qt::PrimaryOrientation) {
@@ -100,13 +86,20 @@ QIOSWindow::~QIOSWindow()
// According to the UIResponder documentation, Cocoa Touch should react to system interruptions
// that "might cause the view to be removed from the window" by sending touchesCancelled, but in
// practice this doesn't seem to happen when removing the view from its superview. To ensure that
- // Qt's internal state for touch and mouse handling is kept consistent, we therefor have to force
+ // Qt's internal state for touch and mouse handling is kept consistent, we therefore have to force
// cancellation of all touch events.
[m_view touchesCancelled:[NSSet set] withEvent:0];
clearAccessibleCache();
- m_view.platformWindow = 0;
- [m_view removeFromSuperview];
+
+ quiview_cast(m_view).platformWindow = nullptr;
+
+ // Remove from superview, unless we're a foreign window without a
+ // Qt window parent, in which case the foreign window is used as
+ // a window container for a Qt UI hierarchy inside a native UI.
+ if (!(isForeignWindow() && !QPlatformWindow::parent()))
+ [m_view removeFromSuperview];
+
[m_view release];
}
@@ -145,7 +138,7 @@ void QIOSWindow::setVisible(bool visible)
if (visible && shouldAutoActivateWindow()) {
if (!window()->property("_q_showWithoutActivating").toBool())
requestActivateWindow();
- } else if (!visible && [m_view isActiveWindow]) {
+ } else if (!visible && [quiview_cast(m_view) isActiveWindow]) {
// Our window was active/focus window but now hidden, so relinquish
// focus to the next possible window in the stack.
NSArray<UIView *> *subviews = m_view.viewController.view.subviews;
@@ -234,7 +227,7 @@ void QIOSWindow::applyGeometry(const QRect &rect)
QMargins QIOSWindow::safeAreaMargins() const
{
- UIEdgeInsets safeAreaInsets = m_view.qt_safeAreaInsets;
+ UIEdgeInsets safeAreaInsets = m_view.safeAreaInsets;
return QMargins(safeAreaInsets.left, safeAreaInsets.top,
safeAreaInsets.right, safeAreaInsets.bottom);
}
@@ -258,22 +251,45 @@ void QIOSWindow::setWindowState(Qt::WindowStates state)
if (state & Qt::WindowMinimized) {
applyGeometry(QRect());
} else if (state & (Qt::WindowFullScreen | Qt::WindowMaximized)) {
- // When an application is in split-view mode, the UIScreen still has the
- // same geometry, but the UIWindow is resized to the area reserved for the
- // application. We use this to constrain the geometry used when applying the
- // fullscreen or maximized window states. Note that we do not do this
- // in applyGeometry(), as we don't want to artificially limit window
- // placement "outside" of the screen bounds if that's what the user wants.
-
QRect uiWindowBounds = QRectF::fromCGRect(m_view.window.bounds).toRect();
- QRect fullscreenGeometry = screen()->geometry().intersected(uiWindowBounds);
- QRect maximizedGeometry = window()->flags() & Qt::MaximizeUsingFullscreenGeometryHint ?
- fullscreenGeometry : screen()->availableGeometry().intersected(uiWindowBounds);
+ if (NSProcessInfo.processInfo.iOSAppOnMac) {
+ // iOS apps running as "Designed for iPad" on macOS do not match
+ // our current window management implementation where a single
+ // UIWindow is tied to a single screen. And even if we're on the
+ // right screen, the UIScreen does not account for the 77% scale
+ // of the UIUserInterfaceIdiomPad environment, so we can't use
+ // it to clamp the window geometry. Instead just use the UIWindow
+ // directly, which represents our "screen".
+ applyGeometry(uiWindowBounds);
+ } else if (isRunningOnVisionOS()) {
+ // On visionOS there is no concept of a screen, and hence no concept of
+ // screen-relative system UI that we should keep top level windows away
+ // from, so don't apply the UIWindow safe area insets to the screen.
+ applyGeometry(uiWindowBounds);
+ } else {
+ QRect fullscreenGeometry = screen()->geometry();
+ QRect maximizedGeometry = fullscreenGeometry;
+
+#if !defined(Q_OS_VISIONOS)
+ if (!(window()->flags() & Qt::MaximizeUsingFullscreenGeometryHint)) {
+ // If the safe area margins reflect the screen's outer edges,
+ // then reduce the maximized geometry accordingly. Otherwise
+ // leave it as is, and assume the client will take the safe
+ // are margins into account explicitly.
+ UIScreen *uiScreen = m_view.window.windowScene.screen;
+ UIEdgeInsets safeAreaInsets = m_view.window.safeAreaInsets;
+ if (m_view.window.bounds.size.width == uiScreen.bounds.size.width)
+ maximizedGeometry.adjust(safeAreaInsets.left, 0, -safeAreaInsets.right, 0);
+ if (m_view.window.bounds.size.height == uiScreen.bounds.size.height)
+ maximizedGeometry.adjust(0, safeAreaInsets.top, 0, -safeAreaInsets.bottom);
+ }
+#endif
- if (state & Qt::WindowFullScreen)
- applyGeometry(fullscreenGeometry);
- else
- applyGeometry(maximizedGeometry);
+ if (state & Qt::WindowFullScreen)
+ applyGeometry(fullscreenGeometry.intersected(uiWindowBounds));
+ else
+ applyGeometry(maximizedGeometry.intersected(uiWindowBounds));
+ }
} else {
applyGeometry(m_normalGeometry);
}
@@ -281,21 +297,26 @@ void QIOSWindow::setWindowState(Qt::WindowStates state)
void QIOSWindow::setParent(const QPlatformWindow *parentWindow)
{
- UIView *parentView = parentWindow ? reinterpret_cast<UIView *>(parentWindow->winId())
- : isQtApplication() ? static_cast<QIOSScreen *>(screen())->uiWindow().rootViewController.view : 0;
-
- [parentView addSubview:m_view];
+ UIView *parentView = parentWindow ?
+ reinterpret_cast<UIView *>(parentWindow->winId())
+ : isQtApplication() && !isForeignWindow() ?
+ static_cast<QIOSScreen *>(screen())->uiWindow().rootViewController.view
+ : nullptr;
+
+ if (parentView)
+ [parentView addSubview:m_view];
+ else if (quiview_cast(m_view.superview))
+ [m_view removeFromSuperview];
}
void QIOSWindow::requestActivateWindow()
{
// Note that several windows can be active at the same time if they exist in the same
// hierarchy (transient children). But only one window can be QGuiApplication::focusWindow().
- // Dispite the name, 'requestActivateWindow' means raise and transfer focus to the window:
+ // Despite the name, 'requestActivateWindow' means raise and transfer focus to the window:
if (blockedByModal())
return;
- Q_ASSERT(m_view.window);
[m_view.window makeKeyWindow];
[m_view becomeFirstResponder];
@@ -305,8 +326,6 @@ void QIOSWindow::requestActivateWindow()
void QIOSWindow::raiseOrLower(bool raise)
{
- // Re-insert m_view at the correct index among its sibling views
- // (QWindows) according to their current m_windowLevel:
if (!isQtApplication())
return;
@@ -314,17 +333,27 @@ void QIOSWindow::raiseOrLower(bool raise)
if (subviews.count == 1)
return;
- for (int i = int(subviews.count) - 1; i >= 0; --i) {
- UIView *view = static_cast<UIView *>([subviews objectAtIndex:i]);
- if (view.hidden || view == m_view || !view.qwindow)
- continue;
- int level = static_cast<QIOSWindow *>(view.qwindow->handle())->m_windowLevel;
- if (m_windowLevel > level || (raise && m_windowLevel == level)) {
- [m_view.superview insertSubview:m_view aboveSubview:view];
- return;
+ if (m_view.superview == m_view.qtViewController.view) {
+ // We're a top level window, so we need to take window
+ // levels into account.
+ for (int i = int(subviews.count) - 1; i >= 0; --i) {
+ UIView *view = static_cast<UIView *>([subviews objectAtIndex:i]);
+ if (view.hidden || view == m_view || !view.qwindow)
+ continue;
+ int level = static_cast<QIOSWindow *>(view.qwindow->handle())->m_windowLevel;
+ if (m_windowLevel > level || (raise && m_windowLevel == level)) {
+ [m_view.superview insertSubview:m_view aboveSubview:view];
+ return;
+ }
}
+ [m_view.superview insertSubview:m_view atIndex:0];
+ } else {
+ // Child window, or embedded into a non-Qt view controller
+ if (raise)
+ [m_view.superview bringSubviewToFront:m_view];
+ else
+ [m_view.superview sendSubviewToBack:m_view];
}
- [m_view.superview insertSubview:m_view atIndex:0];
}
void QIOSWindow::updateWindowLevel()
@@ -365,8 +394,11 @@ void QIOSWindow::handleContentOrientationChange(Qt::ScreenOrientation orientatio
void QIOSWindow::applicationStateChanged(Qt::ApplicationState)
{
+ if (isForeignWindow())
+ return;
+
if (window()->isExposed() != isExposed())
- [m_view sendUpdatedExposeEvent];
+ [quiview_cast(m_view) sendUpdatedExposeEvent];
}
qreal QIOSWindow::devicePixelRatio() const
@@ -376,7 +408,10 @@ qreal QIOSWindow::devicePixelRatio() const
void QIOSWindow::clearAccessibleCache()
{
- [m_view clearAccessibleCache];
+ if (isForeignWindow())
+ return;
+
+ [quiview_cast(m_view) clearAccessibleCache];
}
void QIOSWindow::requestUpdate()
@@ -384,11 +419,27 @@ void QIOSWindow::requestUpdate()
static_cast<QIOSScreen *>(screen())->setUpdatesPaused(false);
}
+void QIOSWindow::setMask(const QRegion &region)
+{
+ if (!region.isEmpty()) {
+ QCFType<CGMutablePathRef> maskPath = CGPathCreateMutable();
+ for (const QRect &r : region)
+ CGPathAddRect(maskPath, nullptr, r.toCGRect());
+ CAShapeLayer *maskLayer = [CAShapeLayer layer];
+ maskLayer.path = maskPath;
+ m_view.layer.mask = maskLayer;
+ } else {
+ m_view.layer.mask = nil;
+ }
+}
+
+#if QT_CONFIG(opengl)
CAEAGLLayer *QIOSWindow::eaglLayer() const
{
Q_ASSERT([m_view.layer isKindOfClass:[CAEAGLLayer class]]);
return static_cast<CAEAGLLayer *>(m_view.layer);
}
+#endif
#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug debug, const QIOSWindow *window)
@@ -403,6 +454,37 @@ QDebug operator<<(QDebug debug, const QIOSWindow *window)
}
#endif // !QT_NO_DEBUG_STREAM
-#include "moc_qioswindow.cpp"
+/*!
+ Returns the view cast to a QUIview if possible.
+
+ If the view is not a QUIview, nil is returned, which is safe to
+ send messages to, effectively making [quiview_cast(view) message]
+ a no-op.
+
+ For extra verbosity and clearer code, please consider checking
+ that the platform window is not a foreign window before using
+ this cast, via QPlatformWindow::isForeignWindow().
+
+ Do not use this method solely to check for foreign windows, as
+ that will make the code harder to read for people not working
+ primarily on iOS, who do not know the difference between the
+ UIView and QUIView cases.
+*/
+QUIView *quiview_cast(UIView *view)
+{
+ return qt_objc_cast<QUIView *>(view);
+}
+
+bool QIOSWindow::isForeignWindow() const
+{
+ return ![m_view isKindOfClass:QUIView.class];
+}
+
+UIView *QIOSWindow::view() const
+{
+ return m_view;
+}
QT_END_NAMESPACE
+
+#include "moc_qioswindow.cpp"
diff --git a/src/plugins/platforms/ios/quiaccessibilityelement.h b/src/plugins/platforms/ios/quiaccessibilityelement.h
index 6b8efdcede..8580325436 100644
--- a/src/plugins/platforms/ios/quiaccessibilityelement.h
+++ b/src/plugins/platforms/ios/quiaccessibilityelement.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QUIACCESSIBILITYELEMENT_H
#define QUIACCESSIBILITYELEMENT_H
@@ -43,14 +7,14 @@
#import <UIKit/UIKit.h>
#import <QtGui/QtGui>
-#ifndef QT_NO_ACCESSIBILITY
+#if QT_CONFIG(accessibility)
@interface QT_MANGLE_NAMESPACE(QMacAccessibilityElement) : UIAccessibilityElement
@property (readonly) QAccessible::Id axid;
- (instancetype)initWithId:(QAccessible::Id)anId withAccessibilityContainer:(id)view;
-+ (instancetype)elementWithId:(QAccessible::Id)anId withAccessibilityContainer:(id)view;
++ (instancetype)elementWithId:(QAccessible::Id)anId;
@end
diff --git a/src/plugins/platforms/ios/quiaccessibilityelement.mm b/src/plugins/platforms/ios/quiaccessibilityelement.mm
index 3154536aad..39b2cb8a50 100644
--- a/src/plugins/platforms/ios/quiaccessibilityelement.mm
+++ b/src/plugins/platforms/ios/quiaccessibilityelement.mm
@@ -1,48 +1,14 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "quiaccessibilityelement.h"
-#ifndef QT_NO_ACCESSIBILITY
+#if QT_CONFIG(accessibility)
#include "private/qaccessiblecache_p.h"
#include "private/qcore_mac_p.h"
+#include "uistrings_p.h"
+#include "qioswindow.h"
QT_NAMESPACE_ALIAS_OBJC_CLASS(QMacAccessibilityElement);
@@ -58,7 +24,7 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QMacAccessibilityElement);
return self;
}
-+ (instancetype)elementWithId:(QAccessible::Id)anId withAccessibilityContainer:(id)view
++ (instancetype)elementWithId:(QAccessible::Id)anId
{
Q_ASSERT(anId);
if (!anId)
@@ -68,9 +34,17 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QMacAccessibilityElement);
QMacAccessibilityElement *element = cache->elementForId(anId);
if (!element) {
- Q_ASSERT(QAccessible::accessibleInterface(anId));
- element = [[self alloc] initWithId:anId withAccessibilityContainer:view];
- cache->insertElement(anId, element);
+ auto *a11yInterface = QAccessible::accessibleInterface(anId);
+ Q_ASSERT(a11yInterface);
+ auto *window = a11yInterface->window();
+ if (window && window->handle()) {
+ auto *platformWindow = static_cast<QIOSWindow*>(window->handle());
+ element = [[self alloc] initWithId:anId withAccessibilityContainer:platformWindow->view()];
+ cache->insertElement(anId, element);
+ } else {
+ qWarning() << "Could not create a11y element for" << window
+ << "with platform window" << (window ? window->handle() : nullptr);
+ }
}
return element;
}
@@ -117,14 +91,15 @@ 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) {
return val->currentValue().toString().toNSString();
} else if (QAccessibleTextInterface *text = iface->textInterface()) {
- // FIXME doesn't work?
- return text->text(0, text->characterCount() - 1).toNSString();
+ return text->text(0, text->characterCount()).toNSString();
}
return [super accessibilityHint];
@@ -158,8 +133,27 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QMacAccessibilityElement);
if (state.searchEdit)
traits |= UIAccessibilityTraitSearchField;
- if (iface->role() == QAccessible::Button)
+ if (state.selected)
+ traits |= UIAccessibilityTraitSelected;
+
+ const auto accessibleRole = iface->role();
+ if (accessibleRole == QAccessible::Button) {
traits |= UIAccessibilityTraitButton;
+ } else if (accessibleRole == QAccessible::EditableText) {
+ static auto defaultTextFieldTraits = []{
+ auto *textField = [[[UITextField alloc] initWithFrame:CGRectZero] autorelease];
+ return textField.accessibilityTraits;
+ }();
+ traits |= defaultTextFieldTraits;
+ } else if (accessibleRole == QAccessible::Graphic) {
+ traits |= UIAccessibilityTraitImage;
+ } else if (accessibleRole == QAccessible::Heading) {
+ traits |= UIAccessibilityTraitHeader;
+ } else if (accessibleRole == QAccessible::Link) {
+ traits |= UIAccessibilityTraitLink;
+ } else if (accessibleRole == QAccessible::StaticText) {
+ traits |= UIAccessibilityTraitStaticText;
+ }
if (iface->valueInterface())
traits |= UIAccessibilityTraitAdjustable;
diff --git a/src/plugins/platforms/ios/quiview.h b/src/plugins/platforms/ios/quiview.h
index 1ab9481dd6..7899ec6e0e 100644
--- a/src/plugins/platforms/ios/quiview.h
+++ b/src/plugins/platforms/ios/quiview.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#import <UIKit/UIKit.h>
@@ -56,6 +20,7 @@ QT_END_NAMESPACE
- (instancetype)initWithQIOSWindow:(QT_PREPEND_NAMESPACE(QIOSWindow) *)window;
- (void)sendUpdatedExposeEvent;
- (BOOL)isActiveWindow;
+- (bool)handlePresses:(NSSet<UIPress *> *)presses eventType:(QEvent::Type)type;
@property (nonatomic, assign) QT_PREPEND_NAMESPACE(QIOSWindow) *platformWindow;
@end
@@ -67,10 +32,9 @@ QT_END_NAMESPACE
- (QWindow *)qwindow;
- (UIViewController *)viewController;
- (QIOSViewController*)qtViewController;
-@property (nonatomic, readonly) UIEdgeInsets qt_safeAreaInsets;
@end
-#ifdef Q_OS_IOS
+#if QT_CONFIG(metal)
@interface QUIMetalView : QUIView
@end
#endif
diff --git a/src/plugins/platforms/ios/quiview.mm b/src/plugins/platforms/ios/quiview.mm
index 59eae07388..d5808db305 100644
--- a/src/plugins/platforms/ios/quiview.mm
+++ b/src/plugins/platforms/ios/quiview.mm
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "quiview.h"
@@ -45,26 +9,60 @@
#include "qiostextresponder.h"
#include "qiosscreen.h"
#include "qioswindow.h"
+#include "qiosinputcontext.h"
+#include "quiwindow.h"
#ifndef Q_OS_TVOS
#include "qiosmenu.h"
#endif
+#include <QtCore/qmath.h>
+#include <QtGui/qpointingdevice.h>
#include <QtGui/private/qguiapplication_p.h>
#include <QtGui/private/qwindow_p.h>
+#include <QtGui/private/qapplekeymapper_p.h>
#include <qpa/qwindowsysteminterface_p.h>
Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
+Q_LOGGING_CATEGORY(lcQpaInputEvents, "qt.qpa.input.events")
+
+namespace {
+inline ulong getTimeStamp(UIEvent *event)
+{
+#if TARGET_OS_SIMULATOR == 1
+ // We currently build Qt for simulator using X86_64, even on ARM based macs.
+ // This results in the simulator running on ARM, while the app is running
+ // inside it using Rosetta. And with this combination, the event.timestamp, which is
+ // documented to be in seconds, looks to be something else, and is not progressing
+ // in sync with a normal clock.
+ // Sending out mouse events with a timestamp that doesn't follow normal clock time
+ // will cause problems for mouse-, and pointer handlers that uses them to e.g calculate
+ // the time between a press and release, and to decide if the user is performing a tap
+ // or a drag.
+ // For that reason, we choose to ignore UIEvent.timestamp under the mentioned condition, and
+ // instead rely on NSProcessInfo. Note that if we force the whole simulator to use Rosetta
+ // (and not only the Qt app), the timestamps will progress normally.
+#if defined(Q_PROCESSOR_ARM)
+ #warning The timestamp work-around for x86_64 can (probably) be removed when building for ARM
+#endif
+ return ulong(NSProcessInfo.processInfo.systemUptime * 1000);
+#endif
+
+ return ulong(event.timestamp * 1000);
+}
+}
@implementation QUIView {
- QHash<UITouch *, QWindowSystemInterface::TouchPoint> m_activeTouches;
+ QHash<NSUInteger, QWindowSystemInterface::TouchPoint> m_activeTouches;
UITouch *m_activePencilTouch;
- int m_nextTouchId;
NSMutableArray<UIAccessibilityElement *> *m_accessibleElements;
+ UIPanGestureRecognizer *m_scrollGestureRecognizer;
+ CGPoint m_lastScrollCursorPos;
+ CGPoint m_lastScrollDelta;
}
+ (void)load
{
-#ifndef Q_OS_TVOS
+#if !defined(Q_OS_TVOS) && !defined(Q_OS_VISIONOS)
if (QOperatingSystemVersion::current() < QOperatingSystemVersion(QOperatingSystemVersion::IOS, 11)) {
// iOS 11 handles this though [UIView safeAreaInsetsDidChange], but there's no signal for
// the corresponding top and bottom layout guides that we use on earlier versions. Note
@@ -84,7 +82,10 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
+ (Class)layerClass
{
+#if QT_CONFIG(opengl)
return [CAEAGLLayer class];
+#endif
+ return [super layerClass];
}
- (instancetype)initWithQIOSWindow:(QT_PREPEND_NAMESPACE(QIOSWindow) *)window
@@ -92,6 +93,32 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
if (self = [self initWithFrame:window->geometry().toCGRect()]) {
self.platformWindow = window;
m_accessibleElements = [[NSMutableArray<UIAccessibilityElement *> alloc] init];
+ m_scrollGestureRecognizer = [[UIPanGestureRecognizer alloc]
+ initWithTarget:self
+ action:@selector(handleScroll:)];
+ // The gesture recognizer should only care about scroll gestures (for now)
+ // Set allowedTouchTypes to empty array here to not interfere with touch events
+ // handled by the UIView. Scroll gestures, even those coming from touch devices,
+ // such as trackpads will still be received as they are not touch events
+ m_scrollGestureRecognizer.allowedTouchTypes = [NSArray array];
+ if (@available(ios 13.4, *)) {
+ m_scrollGestureRecognizer.allowedScrollTypesMask = UIScrollTypeMaskAll;
+ }
+ m_scrollGestureRecognizer.maximumNumberOfTouches = 0;
+ m_lastScrollDelta = CGPointZero;
+ m_lastScrollCursorPos = CGPointZero;
+ [self addGestureRecognizer:m_scrollGestureRecognizer];
+
+ if ([self.layer isKindOfClass:CAMetalLayer.class]) {
+ QWindow *window = self.platformWindow->window();
+ if (QColorSpace colorSpace = window->format().colorSpace(); colorSpace.isValid()) {
+ QCFType<CFDataRef> iccData = colorSpace.iccProfile().toCFData();
+ QCFType<CGColorSpaceRef> cgColorSpace = CGColorSpaceCreateWithICCData(iccData);
+ CAMetalLayer *metalLayer = static_cast<CAMetalLayer *>(self.layer);
+ metalLayer.colorspace = cgColorSpace;
+ qCDebug(lcQpaWindow) << "Set" << self << "color space to" << metalLayer.colorspace;
+ }
+ }
}
return self;
@@ -100,6 +127,7 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
- (instancetype)initWithFrame:(CGRect)frame
{
if ((self = [super initWithFrame:frame])) {
+#if QT_CONFIG(opengl)
if ([self.layer isKindOfClass:[CAEAGLLayer class]]) {
// Set up EAGL layer
CAEAGLLayer *eaglLayer = static_cast<CAEAGLLayer *>(self.layer);
@@ -109,6 +137,7 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
kEAGLDrawablePropertyColorFormat: kEAGLColorFormatRGBA8
};
}
+#endif
if (isQtApplication())
self.hidden = YES;
@@ -149,6 +178,7 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
- (void)dealloc
{
[m_accessibleElements release];
+ [m_scrollGestureRecognizer release];
[super dealloc];
}
@@ -168,6 +198,7 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
return description;
}
+#if !defined(Q_OS_VISIONOS)
- (void)willMoveToWindow:(UIWindow *)newWindow
{
// UIKIt will normally set the scale factor of a view to match the corresponding
@@ -177,6 +208,7 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
// FIXME: Allow the scale factor to be customized through QSurfaceFormat.
}
+#endif
- (void)didAddSubview:(UIView *)subview
{
@@ -234,6 +266,9 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
Q_UNUSED(layer);
Q_ASSERT(layer == self.layer);
+ if (!self.platformWindow)
+ return;
+
[self sendUpdatedExposeEvent];
}
@@ -263,7 +298,8 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
- (BOOL)canBecomeFirstResponder
{
- return !(self.platformWindow->window()->flags() & Qt::WindowDoesNotAcceptFocus);
+ return !(self.platformWindow->window()->flags() & (Qt::WindowDoesNotAcceptFocus
+ | Qt::WindowTransparentForInput));
}
- (BOOL)becomeFirstResponder
@@ -274,7 +310,7 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
// blocked by this guard.
FirstResponderCandidate firstResponderCandidate(self);
- qImDebug() << "self:" << self << "first:" << [UIResponder currentFirstResponder];
+ qImDebug() << "self:" << self << "first:" << [UIResponder qt_currentFirstResponder];
if (![super becomeFirstResponder]) {
qImDebug() << self << "was not allowed to become first responder";
@@ -285,7 +321,7 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
}
if (qGuiApp->focusWindow() != self.platformWindow->window())
- QWindowSystemInterface::handleWindowActivated(self.platformWindow->window());
+ QWindowSystemInterface::handleFocusWindowChanged(self.platformWindow->window(), Qt::ActiveWindowFocusReason);
else
qImDebug() << self.platformWindow->window() << "already active, not sending window activation";
@@ -301,7 +337,7 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
// Nor do we want to deactivate the Qt window if the new responder
// is temporarily handling text input on behalf of a Qt window.
- if ([responder isKindOfClass:[QIOSTextInputResponder class]]) {
+ if ([responder isKindOfClass:[QIOSTextResponder class]]) {
while ((responder = [responder nextResponder])) {
if ([responder isKindOfClass:[QUIView class]])
return NO;
@@ -313,7 +349,7 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
- (BOOL)resignFirstResponder
{
- qImDebug() << "self:" << self << "first:" << [UIResponder currentFirstResponder];
+ qImDebug() << "self:" << self << "first:" << [UIResponder qt_currentFirstResponder];
if (![super resignFirstResponder])
return NO;
@@ -322,7 +358,7 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
UIResponder *newResponder = FirstResponderCandidate::currentCandidate();
if ([self responderShouldTriggerWindowDeactivation:newResponder])
- QWindowSystemInterface::handleWindowActivated(0);
+ QWindowSystemInterface::handleFocusWindowChanged(nullptr, Qt::ActiveWindowFocusReason);
return YES;
}
@@ -336,7 +372,7 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
if ([self isFirstResponder])
return YES;
- UIResponder *firstResponder = [UIResponder currentFirstResponder];
+ UIResponder *firstResponder = [UIResponder qt_currentFirstResponder];
if ([firstResponder isKindOfClass:[QIOSTextInputResponder class]]
&& [firstResponder nextResponder] == self)
return YES;
@@ -350,13 +386,11 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
{
[super traitCollectionDidChange: previousTraitCollection];
- QTouchDevice *touchDevice = QIOSIntegration::instance()->touchDevice();
- QTouchDevice::Capabilities touchCapabilities = touchDevice->capabilities();
+ QPointingDevice *touchDevice = QIOSIntegration::instance()->touchDevice();
+ QPointingDevice::Capabilities touchCapabilities = touchDevice->capabilities();
- if (self.traitCollection.forceTouchCapability == UIForceTouchCapabilityAvailable)
- touchCapabilities |= QTouchDevice::Pressure;
- else
- touchCapabilities &= ~QTouchDevice::Pressure;
+ touchCapabilities.setFlag(QPointingDevice::Capability::Pressure,
+ (self.traitCollection.forceTouchCapability == UIForceTouchCapabilityAvailable));
touchDevice->setCapabilities(touchCapabilities);
}
@@ -368,10 +402,10 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
return [super pointInside:point withEvent:event];
}
-- (void)handleTouches:(NSSet *)touches withEvent:(UIEvent *)event withState:(Qt::TouchPointState)state withTimestamp:(ulong)timeStamp
+- (void)handleTouches:(NSSet *)touches withEvent:(UIEvent *)event withState:(QEventPoint::State)state withTimestamp:(ulong)timeStamp
{
QIOSIntegration *iosIntegration = QIOSIntegration::instance();
- bool supportsPressure = QIOSIntegration::instance()->touchDevice()->capabilities() & QTouchDevice::Pressure;
+ bool supportsPressure = QIOSIntegration::instance()->touchDevice()->capabilities() & QPointingDevice::Capability::Pressure;
#if QT_CONFIG(tabletevent)
if (m_activePencilTouch && [touches containsObject:m_activePencilTouch]) {
@@ -386,16 +420,16 @@ 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);
QWindowSystemInterface::handleTabletEvent(self.platformWindow->window(), timeStamp, localViewPosition, globalScreenPosition,
// device, pointerType, buttons
- QTabletEvent::RotationStylus, QTabletEvent::Pen, state == Qt::TouchPointReleased ? Qt::NoButton : Qt::LeftButton,
+ int(QInputDevice::DeviceType::Stylus), int(QPointingDevice::PointerType::Pen), state == QEventPoint::State::Released ? Qt::NoButton : Qt::LeftButton,
// pressure, xTilt, yTilt
pressure, qBound(-60.0, altitudeAngle * azimuth.dx, 60.0), qBound(-60.0, altitudeAngle * azimuth.dy, 60.0),
// tangentialPressure, rotation, z, uid, modifiers
@@ -405,10 +439,20 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
}
#endif
- for (UITouch *uiTouch : m_activeTouches.keys()) {
- QWindowSystemInterface::TouchPoint &touchPoint = m_activeTouches[uiTouch];
- if (![touches containsObject:uiTouch]) {
- touchPoint.state = Qt::TouchPointStationary;
+ if (m_activeTouches.isEmpty())
+ return;
+ for (auto it = m_activeTouches.begin(); it != m_activeTouches.end(); ++it) {
+ auto hash = it.key();
+ QWindowSystemInterface::TouchPoint &touchPoint = it.value();
+ UITouch *uiTouch = nil;
+ for (UITouch *touch in touches) {
+ if (touch.hash == hash) {
+ uiTouch = touch;
+ break;
+ }
+ }
+ if (!uiTouch) {
+ touchPoint.state = QEventPoint::State::Stationary;
} else {
touchPoint.state = state;
@@ -421,7 +465,7 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
touchPoint.area = QRectF(globalScreenPosition, QSize(0, 0));
- // FIXME: Do we really need to support QTouchDevice::NormalizedPosition?
+ // FIXME: Do we really need to support QPointingDevice::Capability::NormalizedPosition?
QSize screenSize = self.platformWindow->screen()->geometry().size();
touchPoint.normalPosition = QPointF(globalScreenPosition.x() / screenSize.width(),
globalScreenPosition.y() / screenSize.height());
@@ -433,14 +477,12 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
// sending a touch press event to Qt, just to have a valid pressure.
touchPoint.pressure = uiTouch.force / uiTouch.maximumPossibleForce;
} else {
- // We don't claim that our touch device supports QTouchDevice::Pressure,
+ // We don't claim that our touch device supports QPointingDevice::Capability::Pressure,
// but fill in a meaningful value in case clients use it anyway.
- touchPoint.pressure = (state == Qt::TouchPointReleased) ? 0.0 : 1.0;
+ touchPoint.pressure = (state == QEventPoint::State::Released) ? 0.0 : 1.0;
}
}
}
- if (m_activeTouches.isEmpty())
- return;
if ([self.window isKindOfClass:[QUIWindow class]] &&
!static_cast<QUIWindow *>(self.window).sendingEvent) {
@@ -455,7 +497,10 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
QWindowSystemInterface::handleTouchEvent<QWindowSystemInterface::AsynchronousDelivery>(
self.platformWindow->window(), timeStamp, iosIntegration->touchDevice(), m_activeTouches.values());
} else {
- QWindowSystemInterface::handleTouchEvent<QWindowSystemInterface::SynchronousDelivery>(
+ // Send the touch event asynchronously, as the application might spin a recursive
+ // event loop in response to the touch event (a dialog e.g.), which will deadlock
+ // the UIKit event delivery system (QTBUG-98651).
+ QWindowSystemInterface::handleTouchEvent<QWindowSystemInterface::AsynchronousDelivery>(
self.platformWindow->window(), timeStamp, iosIntegration->touchDevice(), m_activeTouches.values());
}
}
@@ -476,9 +521,12 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
m_activePencilTouch = touch;
} else
{
- Q_ASSERT(!m_activeTouches.contains(touch));
+ Q_ASSERT(!m_activeTouches.contains(touch.hash));
#endif
- m_activeTouches[touch].id = m_nextTouchId++;
+ // Use window-independent touch identifiers, so that
+ // multi-touch works across windows.
+ static quint16 nextTouchId = 0;
+ m_activeTouches[touch.hash].id = nextTouchId++;
#if QT_CONFIG(tabletevent)
}
#endif
@@ -492,19 +540,20 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
topLevel->requestActivateWindow();
}
- [self handleTouches:touches withEvent:event withState:Qt::TouchPointPressed withTimestamp:ulong(event.timestamp * 1000)];
+ [self handleTouches:touches withEvent:event withState:QEventPoint::State::Pressed withTimestamp:getTimeStamp(event)];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
- [self handleTouches:touches withEvent:event withState:Qt::TouchPointMoved withTimestamp:ulong(event.timestamp * 1000)];
+ [self handleTouches:touches withEvent:event withState:QEventPoint::State::Updated withTimestamp:getTimeStamp(event)];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
- [self handleTouches:touches withEvent:event withState:Qt::TouchPointReleased withTimestamp:ulong(event.timestamp * 1000)];
+ [self handleTouches:touches withEvent:event withState:QEventPoint::State::Released withTimestamp:getTimeStamp(event)];
// Remove ended touch points from the active set:
+#ifndef Q_OS_TVOS
for (UITouch *touch in touches) {
#if QT_CONFIG(tabletevent)
if (touch.type == UITouchTypeStylus) {
@@ -512,11 +561,13 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
} else
#endif
{
- m_activeTouches.remove(touch);
+ m_activeTouches.remove(touch.hash);
}
}
- if (m_activeTouches.isEmpty() && !m_activePencilTouch)
- m_nextTouchId = 0;
+#else
+ // tvOS only supports single touch
+ m_activeTouches.clear();
+#endif
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
@@ -549,16 +600,20 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
qWarning("Subset of active touches cancelled by UIKit");
m_activeTouches.clear();
- m_nextTouchId = 0;
m_activePencilTouch = nil;
- NSTimeInterval timestamp = event ? event.timestamp : [[NSProcessInfo processInfo] systemUptime];
+ ulong timestamp = event ? getTimeStamp(event) : ([[NSProcessInfo processInfo] systemUptime] * 1000);
QIOSIntegration *iosIntegration = static_cast<QIOSIntegration *>(QGuiApplicationPrivate::platformIntegration());
- QWindowSystemInterface::handleTouchCancelEvent(self.platformWindow->window(), ulong(timestamp * 1000), iosIntegration->touchDevice());
+
+ // Send the touch event asynchronously, as the application might spin a recursive
+ // event loop in response to the touch event (a dialog e.g.), which will deadlock
+ // the UIKit event delivery system (QTBUG-98651).
+ QWindowSystemInterface::handleTouchCancelEvent<QWindowSystemInterface::AsynchronousDelivery>(
+ self.platformWindow->window(), timestamp, iosIntegration->touchDevice());
}
-- (int)mapPressTypeToKey:(UIPress*)press
+- (int)mapPressTypeToKey:(UIPress*)press withModifiers:(Qt::KeyboardModifiers)qtModifiers text:(QString &)text
{
switch (press.type) {
case UIPressTypeUpArrow: return Qt::Key_Up;
@@ -569,61 +624,99 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
case UIPressTypeMenu: return Qt::Key_Menu;
case UIPressTypePlayPause: return Qt::Key_MediaTogglePlayPause;
}
+ if (@available(ios 13.4, *)) {
+ NSString *charactersIgnoringModifiers = press.key.charactersIgnoringModifiers;
+ Qt::Key key = QAppleKeyMapper::fromUIKitKey(charactersIgnoringModifiers);
+ if (key != Qt::Key_unknown)
+ return key;
+ return QAppleKeyMapper::fromNSString(qtModifiers, press.key.characters,
+ charactersIgnoringModifiers, text);
+ }
return Qt::Key_unknown;
}
-- (bool)processPresses:(NSSet *)presses withType:(QEvent::Type)type {
+- (bool)isControlKey:(Qt::Key)key
+{
+ switch (key) {
+ case Qt::Key_Up:
+ case Qt::Key_Down:
+ case Qt::Key_Left:
+ case Qt::Key_Right:
+ return true;
+ default:
+ break;
+ }
+
+ return false;
+}
+
+- (bool)handlePresses:(NSSet<UIPress *> *)presses eventType:(QEvent::Type)type
+{
// Presses on Menu button will generate a Menu key event. By default, not handling
// this event will cause the application to return to Headboard (tvOS launcher).
// When handling the event (for example, as a back button), both press and
// release events must be handled accordingly.
+ if (!qApp->focusWindow())
+ return false;
+
+ bool eventHandled = false;
+ const bool imEnabled = QIOSInputContext::instance()->inputMethodAccepted();
- bool handled = false;
for (UIPress* press in presses) {
- int key = [self mapPressTypeToKey:press];
+ Qt::KeyboardModifiers qtModifiers = Qt::NoModifier;
+ if (@available(ios 13.4, *))
+ qtModifiers = QAppleKeyMapper::fromUIKitModifiers(press.key.modifierFlags);
+ QString text;
+ int key = [self mapPressTypeToKey:press withModifiers:qtModifiers text:text];
if (key == Qt::Key_unknown)
continue;
- if (QWindowSystemInterface::handleKeyEvent(self.platformWindow->window(), type, key, Qt::NoModifier))
- handled = true;
+ if (imEnabled && ![self isControlKey:Qt::Key(key)])
+ continue;
+
+ bool keyHandled = QWindowSystemInterface::handleKeyEvent(
+ self.platformWindow->window(), type, key, qtModifiers, text);
+ eventHandled = eventHandled || keyHandled;
}
- return handled;
+ return eventHandled;
}
- (void)pressesBegan:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event
{
- if (![self processPresses:presses withType:QEvent::KeyPress])
+ if (![self handlePresses:presses eventType:QEvent::KeyPress])
[super pressesBegan:presses withEvent:event];
}
- (void)pressesChanged:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event
{
- if (![self processPresses:presses withType:QEvent::KeyPress])
+ if (![self handlePresses:presses eventType:QEvent::KeyPress])
[super pressesChanged:presses withEvent:event];
+ [super pressesChanged:presses withEvent:event];
}
- (void)pressesEnded:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event
{
- if (![self processPresses:presses withType:QEvent::KeyRelease])
+ if (![self handlePresses:presses eventType:QEvent::KeyRelease])
[super pressesEnded:presses withEvent:event];
+ [super pressesEnded:presses withEvent:event];
}
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
-#ifndef Q_OS_TVOS
+#if !defined(Q_OS_TVOS) && !defined(Q_OS_VISIONOS)
// Check first if QIOSMenu should handle the action before continuing up the responder chain
return [QIOSMenu::menuActionTarget() targetForAction:action withSender:sender] != 0;
#else
- Q_UNUSED(action)
- Q_UNUSED(sender)
+ Q_UNUSED(action);
+ Q_UNUSED(sender);
return false;
#endif
}
- (id)forwardingTargetForSelector:(SEL)selector
{
- Q_UNUSED(selector)
-#ifndef Q_OS_TVOS
+ Q_UNUSED(selector);
+#if !defined(Q_OS_TVOS) && !defined(Q_OS_VISIONOS)
return QIOSMenu::menuActionTarget();
#else
return nil;
@@ -638,6 +731,75 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
[super addInteraction:interaction];
}
+- (UIEditingInteractionConfiguration)editingInteractionConfiguration
+{
+ // We only want the three-finger-tap edit menu to be available when there's
+ // actually something to edit. Otherwise the OS will cause a slight delay
+ // before delivering the release of three finger touch input. Note that we
+ // do not do any hit testing here to check that the focus object is the one
+ // being tapped, as the behavior of native iOS apps is to trigger the menu
+ // regardless of where the gesture is being made.
+ return QIOSInputContext::instance()->inputMethodAccepted() ?
+ UIEditingInteractionConfigurationDefault : UIEditingInteractionConfigurationNone;
+}
+
+#if QT_CONFIG(wheelevent)
+- (void)handleScroll:(UIPanGestureRecognizer *)recognizer
+{
+ if (!self.platformWindow->window())
+ return;
+
+ if (!self.canBecomeFirstResponder)
+ return;
+
+ CGPoint translation = [recognizer translationInView:self];
+ CGFloat deltaX = translation.x - m_lastScrollDelta.x;
+ CGFloat deltaY = translation.y - m_lastScrollDelta.y;
+
+ QPoint angleDelta;
+ // From QNSView implementation:
+ // "Since deviceDelta is delivered as pixels rather than degrees, we need to
+ // convert from pixels to degrees in a sensible manner.
+ // It looks like 1/4 degrees per pixel behaves most native.
+ // (NB: Qt expects the unit for delta to be 8 per degree):"
+ const int pixelsToDegrees = 2; // 8 * 1/4
+ angleDelta.setX(deltaX * pixelsToDegrees);
+ angleDelta.setY(deltaY * pixelsToDegrees);
+
+ QPoint pixelDelta;
+ pixelDelta.setX(deltaX);
+ pixelDelta.setY(deltaY);
+
+ NSTimeInterval time_stamp = [[NSProcessInfo processInfo] systemUptime];
+ ulong qt_timestamp = time_stamp * 1000;
+
+ Qt::KeyboardModifiers qt_modifierFlags = Qt::NoModifier;
+ if (@available(ios 13.4, *))
+ qt_modifierFlags = QAppleKeyMapper::fromUIKitModifiers(recognizer.modifierFlags);
+
+ if (recognizer.state == UIGestureRecognizerStateBegan)
+ // locationInView: doesn't return the cursor position at the time of the wheel event,
+ // but rather gives us the position with the deltas applied, so we need to save the
+ // cursor position at the beginning of the gesture
+ m_lastScrollCursorPos = [recognizer locationInView:self];
+
+ if (recognizer.state != UIGestureRecognizerStateEnded) {
+ m_lastScrollDelta.x = translation.x;
+ m_lastScrollDelta.y = translation.y;
+ } else {
+ m_lastScrollDelta = CGPointZero;
+ }
+
+ QPoint qt_local = QPointF::fromCGPoint(m_lastScrollCursorPos).toPoint();
+ QPoint qt_global = self.platformWindow->mapToGlobal(qt_local);
+
+ qCInfo(lcQpaInputEvents).nospace() << "wheel event" << " at " << qt_local
+ << " pixelDelta=" << pixelDelta << " angleDelta=" << angleDelta;
+
+ QWindowSystemInterface::handleWheelEvent(self.platformWindow->window(), qt_timestamp, qt_local, qt_global, pixelDelta, angleDelta, qt_modifierFlags);
+}
+#endif // QT_CONFIG(wheelevent)
+
@end
@implementation UIView (QtHelpers)
@@ -670,33 +832,20 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
return nil;
}
-- (UIEdgeInsets)qt_safeAreaInsets
-{
- return self.safeAreaInsets;
-}
-
@end
-#ifdef Q_OS_IOS
+#if QT_CONFIG(metal)
@implementation QUIMetalView
+ (Class)layerClass
{
-#ifdef TARGET_IPHONE_SIMULATOR
- if (@available(ios 13.0, *))
-#endif
-
return [CAMetalLayer class];
-
-#ifdef TARGET_IPHONE_SIMULATOR
- return nil;
-#endif
}
@end
#endif
-#ifndef QT_NO_ACCESSIBILITY
+#if QT_CONFIG(accessibility)
// Include category as an alternative to using -ObjC (Apple QA1490)
#include "quiview_accessibility.mm"
#endif
diff --git a/src/plugins/platforms/ios/quiview_accessibility.mm b/src/plugins/platforms/ios/quiview_accessibility.mm
index 6612dc131e..04e1f8cfb3 100644
--- a/src/plugins/platforms/ios/quiview_accessibility.mm
+++ b/src/plugins/platforms/ios/quiview_accessibility.mm
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qiosplatformaccessibility.h"
#include "quiaccessibilityelement.h"
@@ -56,16 +20,23 @@
- (void)createAccessibleContainer:(QAccessibleInterface *)iface
{
- if (!iface)
+ if (!iface || iface->state().invisible)
return;
- [self createAccessibleElement: iface];
for (int i = 0; i < iface->childCount(); ++i)
[self createAccessibleContainer: iface->child(i)];
+
+ // The container element must go last, so that it underlays all its children
+ [self createAccessibleElement:iface];
}
- (void)initAccessibility
{
+ // The window may have gone away, but with the view
+ // temporarily caught in the a11y subsystem.
+ if (!self.platformWindow)
+ return;
+
static bool init = false;
if (!init)
QGuiApplicationPrivate::platformIntegration()->accessibility()->setActive(true);
@@ -83,7 +54,6 @@
- (void)clearAccessibleCache
{
[m_accessibleElements removeAllObjects];
- UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, @"");
}
// this is a container, returning yes here means the functions below will never be called
diff --git a/src/plugins/platforms/ios/quiwindow.h b/src/plugins/platforms/ios/quiwindow.h
new file mode 100644
index 0000000000..b5587411e4
--- /dev/null
+++ b/src/plugins/platforms/ios/quiwindow.h
@@ -0,0 +1,13 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QUIWINDOW_H
+#define QUIWINDOW_H
+
+#include <UIKit/UIWindow.h>
+
+@interface QUIWindow : UIWindow
+@property (nonatomic, readonly) BOOL sendingEvent;
+@end
+
+#endif // QUIWINDOW_H
diff --git a/src/plugins/platforms/ios/quiwindow.mm b/src/plugins/platforms/ios/quiwindow.mm
new file mode 100644
index 0000000000..7c910b6d9e
--- /dev/null
+++ b/src/plugins/platforms/ios/quiwindow.mm
@@ -0,0 +1,56 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "quiwindow.h"
+
+#include "qiostheme.h"
+
+#include <QtCore/qscopedvaluerollback.h>
+
+#include <QtGui/private/qguiapplication_p.h>
+#include <QtGui/qpa/qplatformtheme.h>
+
+#include <UIKit/UIKit.h>
+
+@implementation QUIWindow
+
+- (instancetype)initWithFrame:(CGRect)frame
+{
+ if ((self = [super initWithFrame:frame]))
+ self->_sendingEvent = NO;
+
+ return self;
+}
+
+- (void)sendEvent:(UIEvent *)event
+{
+ QScopedValueRollback<BOOL> sendingEvent(self->_sendingEvent, YES);
+ [super sendEvent:event];
+}
+
+#if !defined(Q_OS_VISIONOS)
+- (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection
+{
+ [super traitCollectionDidChange:previousTraitCollection];
+
+ if (!qGuiApp)
+ return;
+
+ Qt::ColorScheme colorScheme = self.traitCollection.userInterfaceStyle
+ == UIUserInterfaceStyleDark
+ ? Qt::ColorScheme::Dark
+ : Qt::ColorScheme::Light;
+
+ if (self.screen == UIScreen.mainScreen) {
+ // Check if the current userInterfaceStyle reports a different appearance than
+ // the platformTheme's appearance. We might have set that one based on the UIScreen
+ if (previousTraitCollection.userInterfaceStyle != self.traitCollection.userInterfaceStyle
+ || QGuiApplicationPrivate::platformTheme()->colorScheme() != colorScheme) {
+ QIOSTheme::initializeSystemPalette();
+ QWindowSystemInterface::handleThemeChange<QWindowSystemInterface::SynchronousDelivery>();
+ }
+ }
+}
+#endif
+
+@end
diff --git a/src/plugins/platforms/ios/uistrings.cpp b/src/plugins/platforms/ios/uistrings.cpp
new file mode 100644
index 0000000000..b17438ba93
--- /dev/null
+++ b/src/plugins/platforms/ios/uistrings.cpp
@@ -0,0 +1,15 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#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..cbe139afac
--- /dev/null
+++ b/src/plugins/platforms/ios/uistrings_p.h
@@ -0,0 +1,30 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#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/.prev_CMakeLists.txt b/src/plugins/platforms/linuxfb/.prev_CMakeLists.txt
deleted file mode 100644
index bcec98e1de..0000000000
--- a/src/plugins/platforms/linuxfb/.prev_CMakeLists.txt
+++ /dev/null
@@ -1,46 +0,0 @@
-# Generated from linuxfb.pro.
-
-#####################################################################
-## QLinuxFbIntegrationPlugin Plugin:
-#####################################################################
-
-qt_add_plugin(QLinuxFbIntegrationPlugin
- OUTPUT_NAME qlinuxfb
- TYPE platforms
- SOURCES
- main.cpp
- qlinuxfbintegration.cpp qlinuxfbintegration.h
- qlinuxfbscreen.cpp qlinuxfbscreen.h
- DEFINES
- QT_NO_FOREACH
- PUBLIC_LIBRARIES
- Qt::Core
- Qt::CorePrivate
- Qt::EventDispatcherSupportPrivate
- Qt::FbSupportPrivate
- Qt::FontDatabaseSupportPrivate
- Qt::Gui
- Qt::GuiPrivate
- Qt::ServiceSupportPrivate
-)
-
-#### Keys ignored in scope 1:.:.:linuxfb.pro:<TRUE>:
-# OTHER_FILES = "linuxfb.json"
-
-## Scopes:
-#####################################################################
-
-qt_extend_target(QLinuxFbIntegrationPlugin CONDITION TARGET Qt::InputSupportPrivate
- PUBLIC_LIBRARIES
- Qt::InputSupportPrivate
-)
-
-qt_extend_target(QLinuxFbIntegrationPlugin CONDITION TARGET Qt::KmsSupportPrivate
- SOURCES
- qlinuxfbdrmscreen.cpp qlinuxfbdrmscreen.h
- PUBLIC_LIBRARIES
- Qt::KmsSupportPrivate
-)
-
-#### Keys ignored in scope 4:.:.:linuxfb.pro:NOT TARGET___equals____ss_QT_DEFAULT_QPA_PLUGIN:
-# PLUGIN_EXTENDS = "-"
diff --git a/src/plugins/platforms/linuxfb/CMakeLists.txt b/src/plugins/platforms/linuxfb/CMakeLists.txt
index 8747894100..9f75f53828 100644
--- a/src/plugins/platforms/linuxfb/CMakeLists.txt
+++ b/src/plugins/platforms/linuxfb/CMakeLists.txt
@@ -1,47 +1,39 @@
-# Generated from linuxfb.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## QLinuxFbIntegrationPlugin Plugin:
#####################################################################
-qt_add_plugin(QLinuxFbIntegrationPlugin
+qt_internal_add_plugin(QLinuxFbIntegrationPlugin
OUTPUT_NAME qlinuxfb
- TYPE platforms
- DEFAULT_IF ${QT_QPA_DEFAULT_PLATFORM} MATCHES linuxfb # special case
+ PLUGIN_TYPE platforms
+ DEFAULT_IF ${QT_QPA_DEFAULT_PLATFORM} MATCHES linuxfb
SOURCES
main.cpp
qlinuxfbintegration.cpp qlinuxfbintegration.h
qlinuxfbscreen.cpp qlinuxfbscreen.h
DEFINES
QT_NO_FOREACH
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Core
Qt::CorePrivate
- Qt::EventDispatcherSupportPrivate
Qt::FbSupportPrivate
- Qt::FontDatabaseSupportPrivate
Qt::Gui
Qt::GuiPrivate
- Qt::ServiceSupportPrivate
)
-#### Keys ignored in scope 1:.:.:linuxfb.pro:<TRUE>:
-# OTHER_FILES = "linuxfb.json"
-
## Scopes:
#####################################################################
-qt_extend_target(QLinuxFbIntegrationPlugin CONDITION TARGET Qt::InputSupportPrivate
- PUBLIC_LIBRARIES
+qt_internal_extend_target(QLinuxFbIntegrationPlugin CONDITION TARGET Qt::InputSupportPrivate
+ LIBRARIES
Qt::InputSupportPrivate
)
-qt_extend_target(QLinuxFbIntegrationPlugin CONDITION TARGET Qt::KmsSupportPrivate
+qt_internal_extend_target(QLinuxFbIntegrationPlugin CONDITION TARGET Qt::KmsSupportPrivate
SOURCES
qlinuxfbdrmscreen.cpp qlinuxfbdrmscreen.h
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::KmsSupportPrivate
)
-
-#### Keys ignored in scope 4:.:.:linuxfb.pro:NOT TARGET___equals____ss_QT_DEFAULT_QPA_PLUGIN:
-# PLUGIN_EXTENDS = "-"
diff --git a/src/plugins/platforms/linuxfb/linuxfb.pro b/src/plugins/platforms/linuxfb/linuxfb.pro
deleted file mode 100644
index d3a4476f80..0000000000
--- a/src/plugins/platforms/linuxfb/linuxfb.pro
+++ /dev/null
@@ -1,31 +0,0 @@
-TARGET = qlinuxfb
-
-DEFINES += QT_NO_FOREACH
-
-QT += \
- core-private gui-private \
- service_support-private eventdispatcher_support-private \
- fontdatabase_support-private fb_support-private
-
-qtHaveModule(input_support-private): \
- QT += input_support-private
-
-SOURCES = main.cpp \
- qlinuxfbintegration.cpp \
- qlinuxfbscreen.cpp
-
-HEADERS = qlinuxfbintegration.h \
- qlinuxfbscreen.h
-
-qtHaveModule(kms_support-private) {
- QT += kms_support-private
- SOURCES += qlinuxfbdrmscreen.cpp
- HEADERS += qlinuxfbdrmscreen.h
-}
-
-OTHER_FILES += linuxfb.json
-
-PLUGIN_TYPE = platforms
-PLUGIN_CLASS_NAME = QLinuxFbIntegrationPlugin
-!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = -
-load(qt_plugin)
diff --git a/src/plugins/platforms/linuxfb/main.cpp b/src/plugins/platforms/linuxfb/main.cpp
index 24156b68e8..12aaafc21a 100644
--- a/src/plugins/platforms/linuxfb/main.cpp
+++ b/src/plugins/platforms/linuxfb/main.cpp
@@ -1,47 +1,13 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <qpa/qplatformintegrationplugin.h>
#include "qlinuxfbintegration.h"
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
class QLinuxFbIntegrationPlugin : public QPlatformIntegrationPlugin
{
Q_OBJECT
@@ -53,10 +19,10 @@ public:
QPlatformIntegration* QLinuxFbIntegrationPlugin::create(const QString& system, const QStringList& paramList)
{
Q_UNUSED(paramList);
- if (!system.compare(QLatin1String("linuxfb"), Qt::CaseInsensitive))
+ if (!system.compare("linuxfb"_L1, Qt::CaseInsensitive))
return new QLinuxFbIntegration(paramList);
- return 0;
+ return nullptr;
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/linuxfb/qlinuxfbdrmscreen.cpp b/src/plugins/platforms/linuxfb/qlinuxfbdrmscreen.cpp
index dcc1ef2790..56b28ba48c 100644
--- a/src/plugins/platforms/linuxfb/qlinuxfbdrmscreen.cpp
+++ b/src/plugins/platforms/linuxfb/qlinuxfbdrmscreen.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
// Experimental DRM dumb buffer backend.
//
@@ -98,7 +62,7 @@ public:
void swapBuffers(Output *output);
- int outputCount() const { return m_outputs.count(); }
+ int outputCount() const { return m_outputs.size(); }
Output *output(int idx) { return &m_outputs[idx]; }
private:
@@ -115,7 +79,7 @@ private:
static void pageFlipHandler(int fd, unsigned int sequence,
unsigned int tv_sec, unsigned int tv_usec, void *user_data);
- QVector<Output> m_outputs;
+ QList<Output> m_outputs;
};
QLinuxFbDevice::QLinuxFbDevice(QKmsScreenConfig *screenConfig)
@@ -161,8 +125,7 @@ void QLinuxFbDevice::close()
void *QLinuxFbDevice::nativeDisplay() const
{
- Q_UNREACHABLE();
- return nullptr;
+ Q_UNREACHABLE_RETURN(nullptr);
}
QPlatformScreen *QLinuxFbDevice::createScreen(const QKmsOutput &output)
@@ -279,7 +242,7 @@ bool QLinuxFbDevice::createFramebuffer(QLinuxFbDevice::Output *output, int buffe
qErrnoWarning(errno, "Failed to map dumb buffer");
return false;
}
- fb.p = mmap(0, fb.size, PROT_READ | PROT_WRITE, MAP_SHARED, fd(), mreq.offset);
+ fb.p = mmap(nullptr, fb.size, PROT_READ | PROT_WRITE, MAP_SHARED, fd(), mreq.offset);
if (fb.p == MAP_FAILED) {
qErrnoWarning(errno, "Failed to mmap dumb buffer");
return false;
@@ -399,6 +362,7 @@ QLinuxFbDrmScreen::~QLinuxFbDrmScreen()
bool QLinuxFbDrmScreen::initialize()
{
m_screenConfig = new QKmsScreenConfig;
+ m_screenConfig->loadConfig();
m_device = new QLinuxFbDevice(m_screenConfig);
if (!m_device->open())
return false;
@@ -443,7 +407,7 @@ QRegion QLinuxFbDrmScreen::doRedraw()
// Image has alpha but no need for blending at this stage.
// Do not waste time with the default SourceOver.
pntr.setCompositionMode(QPainter::CompositionMode_Source);
- for (const QRect &rect : qAsConst(output->dirty[output->backFb]))
+ for (const QRect &rect : std::as_const(output->dirty[output->backFb]))
pntr.drawImage(rect, mScreenImage, rect);
pntr.end();
@@ -466,3 +430,5 @@ QPixmap QLinuxFbDrmScreen::grabWindow(WId wid, int x, int y, int width, int heig
}
QT_END_NAMESPACE
+
+#include "moc_qlinuxfbdrmscreen.cpp"
diff --git a/src/plugins/platforms/linuxfb/qlinuxfbdrmscreen.h b/src/plugins/platforms/linuxfb/qlinuxfbdrmscreen.h
index 50a9576798..25e3aa9248 100644
--- a/src/plugins/platforms/linuxfb/qlinuxfbdrmscreen.h
+++ b/src/plugins/platforms/linuxfb/qlinuxfbdrmscreen.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QLINUXFBDRMSCREEN_H
#define QLINUXFBDRMSCREEN_H
diff --git a/src/plugins/platforms/linuxfb/qlinuxfbintegration.cpp b/src/plugins/platforms/linuxfb/qlinuxfbintegration.cpp
index 68843aa4c5..f87766cf1b 100644
--- a/src/plugins/platforms/linuxfb/qlinuxfbintegration.cpp
+++ b/src/plugins/platforms/linuxfb/qlinuxfbintegration.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qlinuxfbintegration.h"
#include "qlinuxfbscreen.h"
@@ -43,9 +7,9 @@
#include "qlinuxfbdrmscreen.h"
#endif
-#include <QtFontDatabaseSupport/private/qgenericunixfontdatabase_p.h>
-#include <QtServiceSupport/private/qgenericunixservices_p.h>
-#include <QtEventDispatcherSupport/private/qgenericunixeventdispatcher_p.h>
+#include <QtGui/private/qgenericunixfontdatabase_p.h>
+#include <QtGui/private/qgenericunixservices_p.h>
+#include <QtGui/private/qgenericunixeventdispatcher_p.h>
#include <QtFbSupport/private/qfbvthandler_p.h>
#include <QtFbSupport/private/qfbbackingstore_p.h>
@@ -70,15 +34,15 @@
#include <QtInputSupport/private/qtslib_p.h>
#endif
-#include <QtPlatformHeaders/qlinuxfbfunctions.h>
-
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
QLinuxFbIntegration::QLinuxFbIntegration(const QStringList &paramList)
: m_primaryScreen(nullptr),
m_fontDb(new QGenericUnixFontDatabase),
m_services(new QGenericUnixServices),
- m_kbdMgr(0)
+ m_kbdMgr(nullptr)
{
#if QT_CONFIG(kms)
if (qEnvironmentVariableIntValue("QT_QPA_FB_DRM") != 0)
@@ -113,6 +77,7 @@ bool QLinuxFbIntegration::hasCapability(QPlatformIntegration::Capability cap) co
switch (cap) {
case ThreadedPixmaps: return true;
case WindowManagement: return false;
+ case RhiBasedRendering: return false;
default: return QPlatformIntegration::hasCapability(cap);
}
}
@@ -153,7 +118,7 @@ void QLinuxFbIntegration::createInputHandlers()
{
#if QT_CONFIG(libinput)
if (!qEnvironmentVariableIntValue("QT_QPA_FB_NO_LIBINPUT")) {
- new QLibInputHandler(QLatin1String("libinput"), QString());
+ new QLibInputHandler("libinput"_L1, QString());
return;
}
#endif
@@ -161,16 +126,16 @@ void QLinuxFbIntegration::createInputHandlers()
#if QT_CONFIG(tslib)
bool useTslib = qEnvironmentVariableIntValue("QT_QPA_FB_TSLIB");
if (useTslib)
- new QTsLibMouseHandler(QLatin1String("TsLib"), QString());
+ new QTsLibMouseHandler("TsLib"_L1, QString());
#endif
#if QT_CONFIG(evdev)
- m_kbdMgr = new QEvdevKeyboardManager(QLatin1String("EvdevKeyboard"), QString(), this);
- new QEvdevMouseManager(QLatin1String("EvdevMouse"), QString(), this);
+ m_kbdMgr = new QEvdevKeyboardManager("EvdevKeyboard"_L1, QString(), this);
+ new QEvdevMouseManager("EvdevMouse"_L1, QString(), this);
#if QT_CONFIG(tslib)
if (!useTslib)
#endif
- new QEvdevTouchManager(QLatin1String("EvdevTouch"), QString() /* spec */, this);
+ new QEvdevTouchManager("EvdevTouch"_L1, QString() /* spec */, this);
#endif
}
@@ -181,40 +146,26 @@ QPlatformNativeInterface *QLinuxFbIntegration::nativeInterface() const
QFunctionPointer QLinuxFbIntegration::platformFunction(const QByteArray &function) const
{
-#if QT_CONFIG(evdev)
- if (function == QLinuxFbFunctions::loadKeymapTypeIdentifier())
- return QFunctionPointer(loadKeymapStatic);
- else if (function == QLinuxFbFunctions::switchLangTypeIdentifier())
- return QFunctionPointer(switchLangStatic);
-#else
- Q_UNUSED(function)
-#endif
-
- return 0;
+ Q_UNUSED(function);
+ return nullptr;
}
-void QLinuxFbIntegration::loadKeymapStatic(const QString &filename)
-{
#if QT_CONFIG(evdev)
- QLinuxFbIntegration *self = static_cast<QLinuxFbIntegration *>(QGuiApplicationPrivate::platformIntegration());
- if (self->m_kbdMgr)
- self->m_kbdMgr->loadKeymap(filename);
+void QLinuxFbIntegration::loadKeymap(const QString &filename)
+{
+ if (m_kbdMgr)
+ m_kbdMgr->loadKeymap(filename);
else
qWarning("QLinuxFbIntegration: Cannot load keymap, no keyboard handler found");
-#else
- Q_UNUSED(filename);
-#endif
}
-void QLinuxFbIntegration::switchLangStatic()
+void QLinuxFbIntegration::switchLang()
{
-#if QT_CONFIG(evdev)
- QLinuxFbIntegration *self = static_cast<QLinuxFbIntegration *>(QGuiApplicationPrivate::platformIntegration());
- if (self->m_kbdMgr)
- self->m_kbdMgr->switchLang();
+ if (m_kbdMgr)
+ m_kbdMgr->switchLang();
else
qWarning("QLinuxFbIntegration: Cannot switch language, no keyboard handler found");
-#endif
}
+#endif
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/linuxfb/qlinuxfbintegration.h b/src/plugins/platforms/linuxfb/qlinuxfbintegration.h
index af6bd1d630..352bddd907 100644
--- a/src/plugins/platforms/linuxfb/qlinuxfbintegration.h
+++ b/src/plugins/platforms/linuxfb/qlinuxfbintegration.h
@@ -1,47 +1,12 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QLINUXFBINTEGRATION_H
#define QLINUXFBINTEGRATION_H
#include <qpa/qplatformintegration.h>
#include <qpa/qplatformnativeinterface.h>
+#include <QtGui/private/qkeymapper_p.h>
QT_BEGIN_NAMESPACE
@@ -51,6 +16,9 @@ class QFbVtHandler;
class QEvdevKeyboardManager;
class QLinuxFbIntegration : public QPlatformIntegration, public QPlatformNativeInterface
+#if QT_CONFIG(evdev)
+ , public QNativeInterface::Private::QEvdevKeyMapper
+#endif
{
public:
QLinuxFbIntegration(const QStringList &paramList);
@@ -74,10 +42,13 @@ public:
QFunctionPointer platformFunction(const QByteArray &function) const override;
+#if QT_CONFIG(evdev)
+ void loadKeymap(const QString &filename) override;
+ void switchLang() override;
+#endif
+
private:
void createInputHandlers();
- static void loadKeymapStatic(const QString &filename);
- static void switchLangStatic();
QFbScreen *m_primaryScreen;
QPlatformInputContext *m_inputContext;
diff --git a/src/plugins/platforms/linuxfb/qlinuxfbscreen.cpp b/src/plugins/platforms/linuxfb/qlinuxfbscreen.cpp
index cb8962d4b8..e2826f3946 100644
--- a/src/plugins/platforms/linuxfb/qlinuxfbscreen.cpp
+++ b/src/plugins/platforms/linuxfb/qlinuxfbscreen.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qlinuxfbscreen.h"
#include <QtFbSupport/private/qfbcursor_p.h>
@@ -65,6 +29,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
static int openFramebufferDevice(const QString &dev)
{
int fd = -1;
@@ -247,7 +213,7 @@ static QImage::Format determineFormat(const fb_var_screeninfo &info, int depth)
static int openTtyDevice(const QString &device)
{
- const char *const devs[] = { "/dev/tty0", "/dev/tty", "/dev/console", 0 };
+ const char *const devs[] = { "/dev/tty0", "/dev/tty", "/dev/console", nullptr };
int fd = -1;
if (device.isEmpty()) {
@@ -287,9 +253,9 @@ static void blankScreen(int fd, bool on)
}
QLinuxFbScreen::QLinuxFbScreen(const QStringList &args)
- : mArgs(args), mFbFd(-1), mTtyFd(-1), mBlitter(0)
+ : mArgs(args), mFbFd(-1), mTtyFd(-1), mBlitter(nullptr)
{
- mMmap.data = 0;
+ mMmap.data = nullptr;
}
QLinuxFbScreen::~QLinuxFbScreen()
@@ -308,11 +274,11 @@ QLinuxFbScreen::~QLinuxFbScreen()
bool QLinuxFbScreen::initialize()
{
- QRegularExpression ttyRx(QLatin1String("tty=(.*)"));
- QRegularExpression fbRx(QLatin1String("fb=(.*)"));
- QRegularExpression mmSizeRx(QLatin1String("mmsize=(\\d+)x(\\d+)"));
- QRegularExpression sizeRx(QLatin1String("size=(\\d+)x(\\d+)"));
- QRegularExpression offsetRx(QLatin1String("offset=(\\d+)x(\\d+)"));
+ QRegularExpression ttyRx("tty=(.*)"_L1);
+ QRegularExpression fbRx("fb=(.*)"_L1);
+ QRegularExpression mmSizeRx("mmsize=(\\d+)x(\\d+)"_L1);
+ QRegularExpression sizeRx("size=(\\d+)x(\\d+)"_L1);
+ QRegularExpression offsetRx("offset=(\\d+)x(\\d+)"_L1);
QString fbDevice, ttyDevice;
QSize userMmSize;
@@ -320,9 +286,9 @@ bool QLinuxFbScreen::initialize()
bool doSwitchToGraphicsMode = true;
// Parse arguments
- for (const QString &arg : qAsConst(mArgs)) {
+ for (const QString &arg : std::as_const(mArgs)) {
QRegularExpressionMatch match;
- if (arg == QLatin1String("nographicsmodeswitch"))
+ if (arg == "nographicsmodeswitch"_L1)
doSwitchToGraphicsMode = false;
else if (arg.contains(mmSizeRx, &match))
userMmSize = QSize(match.captured(1).toInt(), match.captured(2).toInt());
@@ -337,9 +303,9 @@ bool QLinuxFbScreen::initialize()
}
if (fbDevice.isEmpty()) {
- fbDevice = QLatin1String("/dev/fb0");
+ fbDevice = "/dev/fb0"_L1;
if (!QFile::exists(fbDevice))
- fbDevice = QLatin1String("/dev/graphics/fb0");
+ fbDevice = "/dev/graphics/fb0"_L1;
if (!QFile::exists(fbDevice)) {
qWarning("Unable to figure out framebuffer device. Specify it manually.");
return false;
@@ -378,7 +344,7 @@ bool QLinuxFbScreen::initialize()
// mmap the framebuffer
mMmap.size = finfo.smem_len;
- uchar *data = (unsigned char *)mmap(0, mMmap.size, PROT_READ | PROT_WRITE, MAP_SHARED, mFbFd, 0);
+ uchar *data = (unsigned char *)mmap(nullptr, mMmap.size, PROT_READ | PROT_WRITE, MAP_SHARED, mFbFd, 0);
if ((long)data == -1) {
qErrnoWarning(errno, "Failed to mmap framebuffer");
return false;
@@ -448,3 +414,5 @@ QPixmap QLinuxFbScreen::grabWindow(WId wid, int x, int y, int width, int height)
QT_END_NAMESPACE
+#include "moc_qlinuxfbscreen.cpp"
+
diff --git a/src/plugins/platforms/linuxfb/qlinuxfbscreen.h b/src/plugins/platforms/linuxfb/qlinuxfbscreen.h
index c7ce455e6a..55d6d8ff5f 100644
--- a/src/plugins/platforms/linuxfb/qlinuxfbscreen.h
+++ b/src/plugins/platforms/linuxfb/qlinuxfbscreen.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QLINUXFBSCREEN_H
#define QLINUXFBSCREEN_H
diff --git a/src/plugins/platforms/minimal/.prev_CMakeLists.txt b/src/plugins/platforms/minimal/.prev_CMakeLists.txt
deleted file mode 100644
index 764c684932..0000000000
--- a/src/plugins/platforms/minimal/.prev_CMakeLists.txt
+++ /dev/null
@@ -1,37 +0,0 @@
-# Generated from minimal.pro.
-
-#####################################################################
-## QMinimalIntegrationPlugin Plugin:
-#####################################################################
-
-qt_add_plugin(QMinimalIntegrationPlugin
- OUTPUT_NAME qminimal
- TYPE platforms
- SOURCES
- main.cpp
- qminimalbackingstore.cpp qminimalbackingstore.h
- qminimalintegration.cpp qminimalintegration.h
- DEFINES
- QT_NO_FOREACH
- PUBLIC_LIBRARIES
- Qt::Core
- Qt::CorePrivate
- Qt::EventDispatcherSupportPrivate
- Qt::FontDatabaseSupportPrivate
- Qt::Gui
- Qt::GuiPrivate
-)
-
-#### Keys ignored in scope 1:.:.:minimal.pro:<TRUE>:
-# OTHER_FILES = "minimal.json"
-
-## Scopes:
-#####################################################################
-
-qt_extend_target(QMinimalIntegrationPlugin CONDITION QT_FEATURE_freetype
- LIBRARIES
- WrapFreetype::WrapFreetype
-)
-
-#### Keys ignored in scope 3:.:.:minimal.pro:NOT TARGET___equals____ss_QT_DEFAULT_QPA_PLUGIN:
-# PLUGIN_EXTENDS = "-"
diff --git a/src/plugins/platforms/minimal/CMakeLists.txt b/src/plugins/platforms/minimal/CMakeLists.txt
index 4f4638b640..f3683deccf 100644
--- a/src/plugins/platforms/minimal/CMakeLists.txt
+++ b/src/plugins/platforms/minimal/CMakeLists.txt
@@ -1,38 +1,33 @@
-# Generated from minimal.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## QMinimalIntegrationPlugin Plugin:
#####################################################################
-qt_add_plugin(QMinimalIntegrationPlugin
+qt_find_package(WrapFreetype PROVIDED_TARGETS WrapFreetype::WrapFreetype)
+
+qt_internal_add_plugin(QMinimalIntegrationPlugin
OUTPUT_NAME qminimal
- TYPE platforms
- DEFAULT_IF ${QT_QPA_DEFAULT_PLATFORM} MATCHES minimal # special case
+ PLUGIN_TYPE platforms
+ DEFAULT_IF ${QT_QPA_DEFAULT_PLATFORM} MATCHES minimal
SOURCES
main.cpp
qminimalbackingstore.cpp qminimalbackingstore.h
qminimalintegration.cpp qminimalintegration.h
DEFINES
QT_NO_FOREACH
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Core
Qt::CorePrivate
- Qt::EventDispatcherSupportPrivate
- Qt::FontDatabaseSupportPrivate
Qt::Gui
Qt::GuiPrivate
)
-#### Keys ignored in scope 1:.:.:minimal.pro:<TRUE>:
-# OTHER_FILES = "minimal.json"
-
## Scopes:
#####################################################################
-qt_extend_target(QMinimalIntegrationPlugin CONDITION QT_FEATURE_freetype
+qt_internal_extend_target(QMinimalIntegrationPlugin CONDITION QT_FEATURE_freetype
LIBRARIES
WrapFreetype::WrapFreetype
)
-
-#### Keys ignored in scope 3:.:.:minimal.pro:NOT TARGET___equals____ss_QT_DEFAULT_QPA_PLUGIN:
-# PLUGIN_EXTENDS = "-"
diff --git a/src/plugins/platforms/minimal/main.cpp b/src/plugins/platforms/minimal/main.cpp
index f9a0c17509..03cb3ca588 100644
--- a/src/plugins/platforms/minimal/main.cpp
+++ b/src/plugins/platforms/minimal/main.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <qpa/qplatformintegrationplugin.h>
@@ -43,6 +7,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
class QMinimalIntegrationPlugin : public QPlatformIntegrationPlugin
{
Q_OBJECT
@@ -53,10 +19,10 @@ public:
QPlatformIntegration *QMinimalIntegrationPlugin::create(const QString& system, const QStringList& paramList)
{
- if (!system.compare(QLatin1String("minimal"), Qt::CaseInsensitive))
+ if (!system.compare("minimal"_L1, Qt::CaseInsensitive))
return new QMinimalIntegration(paramList);
- return 0;
+ return nullptr;
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/minimal/minimal.pro b/src/plugins/platforms/minimal/minimal.pro
deleted file mode 100644
index a1a2da547b..0000000000
--- a/src/plugins/platforms/minimal/minimal.pro
+++ /dev/null
@@ -1,22 +0,0 @@
-TARGET = qminimal
-
-QT += \
- core-private gui-private \
- eventdispatcher_support-private fontdatabase_support-private
-
-DEFINES += QT_NO_FOREACH
-
-SOURCES = main.cpp \
- qminimalintegration.cpp \
- qminimalbackingstore.cpp
-HEADERS = qminimalintegration.h \
- qminimalbackingstore.h
-
-OTHER_FILES += minimal.json
-
-qtConfig(freetype): QMAKE_USE_PRIVATE += freetype
-
-PLUGIN_TYPE = platforms
-PLUGIN_CLASS_NAME = QMinimalIntegrationPlugin
-!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = -
-load(qt_plugin)
diff --git a/src/plugins/platforms/minimal/qminimalbackingstore.cpp b/src/plugins/platforms/minimal/qminimalbackingstore.cpp
index 402ee7e2dd..cb432d7ddc 100644
--- a/src/plugins/platforms/minimal/qminimalbackingstore.cpp
+++ b/src/plugins/platforms/minimal/qminimalbackingstore.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qminimalbackingstore.h"
@@ -47,6 +11,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
QMinimalBackingStore::QMinimalBackingStore(QWindow *window)
: QPlatformBackingStore(window)
, mDebug(QMinimalIntegration::instance()->options() & QMinimalIntegration::DebugBackingStore)
@@ -75,7 +41,7 @@ void QMinimalBackingStore::flush(QWindow *window, const QRegion &region, const Q
if (mDebug) {
static int c = 0;
- QString filename = QString("output%1.png").arg(c++, 4, 10, QLatin1Char('0'));
+ QString filename = QString("output%1.png").arg(c++, 4, 10, QChar(u'0'));
qDebug() << "QMinimalBackingStore::flush() saving contents to" << filename.toLocal8Bit().constData();
mImage.save(filename);
}
diff --git a/src/plugins/platforms/minimal/qminimalbackingstore.h b/src/plugins/platforms/minimal/qminimalbackingstore.h
index 2119894809..4bd58fd23d 100644
--- a/src/plugins/platforms/minimal/qminimalbackingstore.h
+++ b/src/plugins/platforms/minimal/qminimalbackingstore.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QBACKINGSTORE_MINIMAL_H
#define QBACKINGSTORE_MINIMAL_H
diff --git a/src/plugins/platforms/minimal/qminimalintegration.cpp b/src/plugins/platforms/minimal/qminimalintegration.cpp
index f457f69f11..4679967431 100644
--- a/src/plugins/platforms/minimal/qminimalintegration.cpp
+++ b/src/plugins/platforms/minimal/qminimalintegration.cpp
@@ -1,81 +1,44 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qminimalintegration.h"
#include "qminimalbackingstore.h"
#include <QtGui/private/qpixmap_raster_p.h>
#include <QtGui/private/qguiapplication_p.h>
+#include <qpa/qplatformfontdatabase.h>
+#include <qpa/qplatformnativeinterface.h>
#include <qpa/qplatformwindow.h>
#include <qpa/qwindowsysteminterface.h>
-#include <QtFontDatabaseSupport/private/qfreetypefontdatabase_p.h>
-#if defined(Q_OS_WINRT)
-# include <QtFontDatabaseSupport/private/qwinrtfontdatabase_p.h>
-#elif defined(Q_OS_WIN)
-# include <QtFontDatabaseSupport/private/qwindowsfontdatabase_p.h>
+#if defined(Q_OS_WIN)
+# include <QtGui/private/qwindowsfontdatabase_p.h>
# if QT_CONFIG(freetype)
-# include <QtFontDatabaseSupport/private/qwindowsfontdatabase_ft_p.h>
+# include <QtGui/private/qwindowsfontdatabase_ft_p.h>
# endif
#elif defined(Q_OS_DARWIN)
-# include <QtFontDatabaseSupport/private/qcoretextfontdatabase_p.h>
+# include <QtGui/private/qcoretextfontdatabase_p.h>
#endif
#if QT_CONFIG(fontconfig)
-# include <QtFontDatabaseSupport/private/qgenericunixfontdatabase_p.h>
-# include <qpa/qplatformfontdatabase.h>
+# include <QtGui/private/qgenericunixfontdatabase_p.h>
#endif
#if QT_CONFIG(freetype)
-#include <QtFontDatabaseSupport/private/qfontengine_ft_p.h>
+#include <QtGui/private/qfontengine_ft_p.h>
+#include <QtGui/private/qfreetypefontdatabase_p.h>
#endif
#if !defined(Q_OS_WIN)
-#include <QtEventDispatcherSupport/private/qgenericunixeventdispatcher_p.h>
-#elif defined(Q_OS_WINRT)
-#include <QtCore/private/qeventdispatcher_winrt_p.h>
+#include <QtGui/private/qgenericunixeventdispatcher_p.h>
#else
#include <QtCore/private/qeventdispatcher_win_p.h>
#endif
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
class QCoreTextFontEngine;
static const char debugBackingStoreEnvironmentVariable[] = "QT_DEBUG_BACKINGSTORE";
@@ -84,18 +47,18 @@ static inline unsigned parseOptions(const QStringList &paramList)
{
unsigned options = 0;
for (const QString &param : paramList) {
- if (param == QLatin1String("enable_fonts"))
+ if (param == "enable_fonts"_L1)
options |= QMinimalIntegration::EnableFonts;
- else if (param == QLatin1String("freetype"))
+ else if (param == "freetype"_L1)
options |= QMinimalIntegration::FreeTypeFontDatabase;
- else if (param == QLatin1String("fontconfig"))
+ else if (param == "fontconfig"_L1)
options |= QMinimalIntegration::FontconfigDatabase;
}
return options;
}
QMinimalIntegration::QMinimalIntegration(const QStringList &parameters)
- : m_fontDatabase(0)
+ : m_fontDatabase(nullptr)
, m_options(parseOptions(parameters))
{
if (qEnvironmentVariableIsSet(debugBackingStoreEnvironmentVariable)
@@ -103,17 +66,18 @@ QMinimalIntegration::QMinimalIntegration(const QStringList &parameters)
m_options |= DebugBackingStore | EnableFonts;
}
- QMinimalScreen *mPrimaryScreen = new QMinimalScreen();
+ m_primaryScreen = new QMinimalScreen();
- mPrimaryScreen->mGeometry = QRect(0, 0, 240, 320);
- mPrimaryScreen->mDepth = 32;
- mPrimaryScreen->mFormat = QImage::Format_ARGB32_Premultiplied;
+ m_primaryScreen->mGeometry = QRect(0, 0, 240, 320);
+ m_primaryScreen->mDepth = 32;
+ m_primaryScreen->mFormat = QImage::Format_ARGB32_Premultiplied;
- QWindowSystemInterface::handleScreenAdded(mPrimaryScreen);
+ QWindowSystemInterface::handleScreenAdded(m_primaryScreen);
}
QMinimalIntegration::~QMinimalIntegration()
{
+ QWindowSystemInterface::handleScreenRemoved(m_primaryScreen);
delete m_fontDatabase;
}
@@ -122,6 +86,7 @@ bool QMinimalIntegration::hasCapability(QPlatformIntegration::Capability cap) co
switch (cap) {
case ThreadedPixmaps: return true;
case MultipleWindows: return true;
+ case RhiBasedRendering: return false;
default: return QPlatformIntegration::hasCapability(cap);
}
}
@@ -138,9 +103,7 @@ public:
QPlatformFontDatabase *QMinimalIntegration::fontDatabase() const
{
if (!m_fontDatabase && (m_options & EnableFonts)) {
-#if defined(Q_OS_WINRT)
- m_fontDatabase = new QWinRTFontDatabase;
-#elif defined(Q_OS_WIN)
+#if defined(Q_OS_WIN)
if (m_options & FreeTypeFontDatabase) {
# if QT_CONFIG(freetype)
m_fontDatabase = new QWindowsFontDatabaseFT;
@@ -189,16 +152,19 @@ QPlatformBackingStore *QMinimalIntegration::createPlatformBackingStore(QWindow *
QAbstractEventDispatcher *QMinimalIntegration::createEventDispatcher() const
{
#ifdef Q_OS_WIN
-#ifndef Q_OS_WINRT
return new QEventDispatcherWin32;
-#else // !Q_OS_WINRT
- return new QEventDispatcherWinRT;
-#endif // Q_OS_WINRT
#else
return createUnixEventDispatcher();
#endif
}
+QPlatformNativeInterface *QMinimalIntegration::nativeInterface() const
+{
+ if (!m_nativeInterface)
+ m_nativeInterface.reset(new QPlatformNativeInterface);
+ return m_nativeInterface.get();
+}
+
QMinimalIntegration *QMinimalIntegration::instance()
{
return static_cast<QMinimalIntegration *>(QGuiApplicationPrivate::platformIntegration());
diff --git a/src/plugins/platforms/minimal/qminimalintegration.h b/src/plugins/platforms/minimal/qminimalintegration.h
index ad1bec2112..6070972b1b 100644
--- a/src/plugins/platforms/minimal/qminimalintegration.h
+++ b/src/plugins/platforms/minimal/qminimalintegration.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QPLATFORMINTEGRATION_MINIMAL_H
#define QPLATFORMINTEGRATION_MINIMAL_H
@@ -43,6 +7,8 @@
#include <qpa/qplatformintegration.h>
#include <qpa/qplatformscreen.h>
+#include <qscopedpointer.h>
+
QT_BEGIN_NAMESPACE
class QMinimalScreen : public QPlatformScreen
@@ -82,12 +48,16 @@ public:
QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const override;
QAbstractEventDispatcher *createEventDispatcher() const override;
+ QPlatformNativeInterface *nativeInterface() const override;
+
unsigned options() const { return m_options; }
static QMinimalIntegration *instance();
private:
mutable QPlatformFontDatabase *m_fontDatabase;
+ mutable QScopedPointer<QPlatformNativeInterface> m_nativeInterface;
+ QMinimalScreen *m_primaryScreen;
unsigned m_options;
};
diff --git a/src/plugins/platforms/minimalegl/.prev_CMakeLists.txt b/src/plugins/platforms/minimalegl/.prev_CMakeLists.txt
deleted file mode 100644
index 7a08af79a9..0000000000
--- a/src/plugins/platforms/minimalegl/.prev_CMakeLists.txt
+++ /dev/null
@@ -1,41 +0,0 @@
-# Generated from minimalegl.pro.
-
-#####################################################################
-## QMinimalEglIntegrationPlugin Plugin:
-#####################################################################
-
-qt_add_plugin(QMinimalEglIntegrationPlugin
- OUTPUT_NAME qminimalegl
- TYPE platforms
- SOURCES
- main.cpp
- qminimaleglintegration.cpp qminimaleglintegration.h
- qminimaleglscreen.cpp qminimaleglscreen.h
- qminimaleglwindow.cpp qminimaleglwindow.h
- DEFINES
- QT_EGL_NO_X11
- PUBLIC_LIBRARIES
- Qt::Core
- Qt::CorePrivate
- Qt::EglSupportPrivate
- Qt::EventDispatcherSupportPrivate
- Qt::FontDatabaseSupportPrivate
- Qt::Gui
- Qt::GuiPrivate
-)
-
-#### Keys ignored in scope 1:.:.:minimalegl.pro:<TRUE>:
-# OTHER_FILES = "minimalegl.json"
-
-## Scopes:
-#####################################################################
-
-qt_extend_target(QMinimalEglIntegrationPlugin CONDITION QT_FEATURE_opengl
- SOURCES
- qminimaleglbackingstore.cpp qminimaleglbackingstore.h
- PUBLIC_LIBRARIES
- Qt::OpenGL
-)
-
-#### Keys ignored in scope 3:.:.:minimalegl.pro:NOT TARGET___equals____ss_QT_DEFAULT_QPA_PLUGIN:
-# PLUGIN_EXTENDS = "-"
diff --git a/src/plugins/platforms/minimalegl/CMakeLists.txt b/src/plugins/platforms/minimalegl/CMakeLists.txt
index 4c8856e35d..a6ec8be781 100644
--- a/src/plugins/platforms/minimalegl/CMakeLists.txt
+++ b/src/plugins/platforms/minimalegl/CMakeLists.txt
@@ -1,13 +1,16 @@
-# Generated from minimalegl.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+qt_find_package(EGL)
#####################################################################
## QMinimalEglIntegrationPlugin Plugin:
#####################################################################
-qt_add_plugin(QMinimalEglIntegrationPlugin
+qt_internal_add_plugin(QMinimalEglIntegrationPlugin
OUTPUT_NAME qminimalegl
- TYPE platforms
- DEFAULT_IF ${QT_QPA_DEFAULT_PLATFORM} MATCHES minimalegl # special case
+ PLUGIN_TYPE platforms
+ DEFAULT_IF ${QT_QPA_DEFAULT_PLATFORM} MATCHES minimalegl
SOURCES
main.cpp
qminimaleglintegration.cpp qminimaleglintegration.h
@@ -15,28 +18,20 @@ qt_add_plugin(QMinimalEglIntegrationPlugin
qminimaleglwindow.cpp qminimaleglwindow.h
DEFINES
QT_EGL_NO_X11
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Core
Qt::CorePrivate
- Qt::EglSupportPrivate
- Qt::EventDispatcherSupportPrivate
- Qt::FontDatabaseSupportPrivate
Qt::Gui
Qt::GuiPrivate
+ EGL::EGL
)
-#### Keys ignored in scope 1:.:.:minimalegl.pro:<TRUE>:
-# OTHER_FILES = "minimalegl.json"
-
## Scopes:
#####################################################################
-qt_extend_target(QMinimalEglIntegrationPlugin CONDITION QT_FEATURE_opengl
+qt_internal_extend_target(QMinimalEglIntegrationPlugin CONDITION QT_FEATURE_opengl
SOURCES
qminimaleglbackingstore.cpp qminimaleglbackingstore.h
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::OpenGL
)
-
-#### Keys ignored in scope 3:.:.:minimalegl.pro:NOT TARGET___equals____ss_QT_DEFAULT_QPA_PLUGIN:
-# PLUGIN_EXTENDS = "-"
diff --git a/src/plugins/platforms/minimalegl/main.cpp b/src/plugins/platforms/minimalegl/main.cpp
index 5aac71e140..3586535277 100644
--- a/src/plugins/platforms/minimalegl/main.cpp
+++ b/src/plugins/platforms/minimalegl/main.cpp
@@ -1,47 +1,13 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <qpa/qplatformintegrationplugin.h>
#include "qminimaleglintegration.h"
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
class QMinimalEglIntegrationPlugin : public QPlatformIntegrationPlugin
{
Q_OBJECT
@@ -53,10 +19,10 @@ public:
QPlatformIntegration* QMinimalEglIntegrationPlugin::create(const QString& system, const QStringList& paramList)
{
Q_UNUSED(paramList);
- if (!system.compare(QLatin1String("minimalegl"), Qt::CaseInsensitive))
+ if (!system.compare("minimalegl"_L1, Qt::CaseInsensitive))
return new QMinimalEglIntegration;
- return 0;
+ return nullptr;
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/minimalegl/minimalegl.pro b/src/plugins/platforms/minimalegl/minimalegl.pro
deleted file mode 100644
index 3f6ae4e248..0000000000
--- a/src/plugins/platforms/minimalegl/minimalegl.pro
+++ /dev/null
@@ -1,37 +0,0 @@
-TARGET = qminimalegl
-
-QT += \
- core-private gui-private \
- eventdispatcher_support-private fontdatabase_support-private egl_support-private
-
-#DEFINES += QEGL_EXTRA_DEBUG
-
-#DEFINES += Q_OPENKODE
-
-# Avoid X11 header collision, use generic EGL native types
-DEFINES += QT_EGL_NO_X11
-
-SOURCES = main.cpp \
- qminimaleglintegration.cpp \
- qminimaleglwindow.cpp \
- qminimaleglscreen.cpp
-
-HEADERS = qminimaleglintegration.h \
- qminimaleglwindow.h \
- qminimaleglscreen.h
-
-qtConfig(opengl) {
- QT += opengl
- SOURCES += qminimaleglbackingstore.cpp
- HEADERS += qminimaleglbackingstore.h
-}
-
-CONFIG += egl
-
-OTHER_FILES += \
- minimalegl.json
-
-PLUGIN_TYPE = platforms
-PLUGIN_CLASS_NAME = QMinimalEglIntegrationPlugin
-!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = -
-load(qt_plugin)
diff --git a/src/plugins/platforms/minimalegl/qminimaleglbackingstore.cpp b/src/plugins/platforms/minimalegl/qminimaleglbackingstore.cpp
index 2319762f31..88131f4f99 100644
--- a/src/plugins/platforms/minimalegl/qminimaleglbackingstore.cpp
+++ b/src/plugins/platforms/minimalegl/qminimaleglbackingstore.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qminimaleglbackingstore.h"
@@ -47,7 +11,7 @@ QT_BEGIN_NAMESPACE
QMinimalEglBackingStore::QMinimalEglBackingStore(QWindow *window)
: QPlatformBackingStore(window)
, m_context(new QOpenGLContext)
- , m_device(0)
+ , m_device(nullptr)
{
m_context->setFormat(window->requestedFormat());
m_context->setScreen(window->screen());
diff --git a/src/plugins/platforms/minimalegl/qminimaleglbackingstore.h b/src/plugins/platforms/minimalegl/qminimaleglbackingstore.h
index 382f2d1404..c9df68796e 100644
--- a/src/plugins/platforms/minimalegl/qminimaleglbackingstore.h
+++ b/src/plugins/platforms/minimalegl/qminimaleglbackingstore.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QMINIMALEGLBACKINGSTORE_H
#define QMINIMALEGLBACKINGSTORE_H
diff --git a/src/plugins/platforms/minimalegl/qminimaleglintegration.cpp b/src/plugins/platforms/minimalegl/qminimaleglintegration.cpp
index a0d35a80cd..e3b610d9be 100644
--- a/src/plugins/platforms/minimalegl/qminimaleglintegration.cpp
+++ b/src/plugins/platforms/minimalegl/qminimaleglintegration.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qminimaleglintegration.h"
@@ -43,15 +7,12 @@
#ifndef QT_NO_OPENGL
# include "qminimaleglbackingstore.h"
#endif
-#include <QtFontDatabaseSupport/private/qgenericunixfontdatabase_p.h>
+#include <QtGui/private/qgenericunixfontdatabase_p.h>
#if defined(Q_OS_UNIX)
-# include <QtEventDispatcherSupport/private/qgenericunixeventdispatcher_p.h>
-#elif defined(Q_OS_WINRT)
-# include <QtCore/private/qeventdispatcher_winrt_p.h>
-# include <QtGui/qpa/qwindowsysteminterface.h>
+# include <QtGui/private/qgenericunixeventdispatcher_p.h>
#elif defined(Q_OS_WIN)
-# include <QtEventDispatcherSupport/private/qwindowsguieventdispatcher_p.h>
+# include <QtGui/private/qwindowsguieventdispatcher_p.h>
#endif
#include <qpa/qplatformwindow.h>
@@ -65,29 +26,6 @@
QT_BEGIN_NAMESPACE
-#ifdef Q_OS_WINRT
-namespace {
-class QWinRTEventDispatcher : public QEventDispatcherWinRT {
-public:
- QWinRTEventDispatcher() {}
-
-protected:
- bool hasPendingEvents() override
- {
- return QEventDispatcherWinRT::hasPendingEvents() || QWindowSystemInterface::windowSystemEventsQueued();
- }
-
- bool sendPostedEvents(QEventLoop::ProcessEventsFlags flags)
- {
- bool didProcess = QEventDispatcherWinRT::sendPostedEvents(flags);
- if (!(flags & QEventLoop::ExcludeUserInputEvents))
- didProcess |= QWindowSystemInterface::sendWindowSystemEvents(flags);
- return didProcess;
- }
-};
-} // anonymous namespace
-#endif // Q_OS_WINRT
-
QMinimalEglIntegration::QMinimalEglIntegration()
: mFontDb(new QGenericUnixFontDatabase()), mScreen(new QMinimalEglScreen(EGL_DEFAULT_DISPLAY))
{
@@ -153,8 +91,6 @@ QAbstractEventDispatcher *QMinimalEglIntegration::createEventDispatcher() const
{
#if defined(Q_OS_UNIX)
return createUnixEventDispatcher();
-#elif defined(Q_OS_WINRT)
- return new QWinRTEventDispatcher;
#elif defined(Q_OS_WIN)
return new QWindowsGuiEventDispatcher;
#else
diff --git a/src/plugins/platforms/minimalegl/qminimaleglintegration.h b/src/plugins/platforms/minimalegl/qminimaleglintegration.h
index 70a51004a6..2bb0f58e63 100644
--- a/src/plugins/platforms/minimalegl/qminimaleglintegration.h
+++ b/src/plugins/platforms/minimalegl/qminimaleglintegration.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QMINIMALEGLINTEGRATION_H
#define QMINIMALEGLINTEGRATION_H
diff --git a/src/plugins/platforms/minimalegl/qminimaleglscreen.cpp b/src/plugins/platforms/minimalegl/qminimaleglscreen.cpp
index 6e122e28ce..716caea067 100644
--- a/src/plugins/platforms/minimalegl/qminimaleglscreen.cpp
+++ b/src/plugins/platforms/minimalegl/qminimaleglscreen.cpp
@@ -1,48 +1,12 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qminimaleglscreen.h"
#include "qminimaleglwindow.h"
-#include <QtEglSupport/private/qeglconvenience_p.h>
+#include <QtGui/private/qeglconvenience_p.h>
#ifndef QT_NO_OPENGL
-# include <QtEglSupport/private/qeglplatformcontext_p.h>
+# include <QtGui/private/qeglplatformcontext_p.h>
#endif
#ifdef Q_OPENKODE
@@ -77,8 +41,8 @@ public:
QMinimalEglScreen::QMinimalEglScreen(EGLNativeDisplayType display)
: m_depth(32)
, m_format(QImage::Format_Invalid)
- , m_platformContext(0)
- , m_surface(0)
+ , m_platformContext(nullptr)
+ , m_surface(nullptr)
{
#ifdef QEGL_EXTRA_DEBUG
qWarning("QEglScreen %p\n", this);
@@ -159,7 +123,7 @@ void QMinimalEglScreen::createAndSetPlatformContext()
q_printEglConfig(m_dpy, config);
#endif
- m_surface = eglCreateWindowSurface(m_dpy, config, eglWindow, NULL);
+ m_surface = eglCreateWindowSurface(m_dpy, config, eglWindow, nullptr);
if (Q_UNLIKELY(m_surface == EGL_NO_SURFACE)) {
qWarning("Could not create the egl surface: error = 0x%x\n", eglGetError());
eglTerminate(m_dpy);
@@ -168,7 +132,7 @@ void QMinimalEglScreen::createAndSetPlatformContext()
// qWarning("Created surface %dx%d\n", w, h);
#ifndef QT_NO_OPENGL
- QEGLPlatformContext *platformContext = new QMinimalEglContext(platformFormat, 0, m_dpy);
+ QEGLPlatformContext *platformContext = new QMinimalEglContext(platformFormat, nullptr, m_dpy);
m_platformContext = platformContext;
#endif
EGLint w,h; // screen size detection
diff --git a/src/plugins/platforms/minimalegl/qminimaleglscreen.h b/src/plugins/platforms/minimalegl/qminimaleglscreen.h
index 926936ae32..7b504d5015 100644
--- a/src/plugins/platforms/minimalegl/qminimaleglscreen.h
+++ b/src/plugins/platforms/minimalegl/qminimaleglscreen.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QMINIMALEGLSCREEN_H
#define QMINIMALEGLSCREEN_H
@@ -44,7 +8,7 @@
#include <QtCore/QTextStream>
-#include <QtEglSupport/private/qt_egl_p.h>
+#include <QtGui/private/qt_egl_p.h>
QT_BEGIN_NAMESPACE
diff --git a/src/plugins/platforms/minimalegl/qminimaleglwindow.cpp b/src/plugins/platforms/minimalegl/qminimaleglwindow.cpp
index 4e3bfbe474..ee8c666c8e 100644
--- a/src/plugins/platforms/minimalegl/qminimaleglwindow.cpp
+++ b/src/plugins/platforms/minimalegl/qminimaleglwindow.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <qpa/qwindowsysteminterface.h>
diff --git a/src/plugins/platforms/minimalegl/qminimaleglwindow.h b/src/plugins/platforms/minimalegl/qminimaleglwindow.h
index 098ec05e6b..dbbe1e6110 100644
--- a/src/plugins/platforms/minimalegl/qminimaleglwindow.h
+++ b/src/plugins/platforms/minimalegl/qminimaleglwindow.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QMINIMALEGLWINDOW_H
#define QMINIMALEGLWINDOW_H
diff --git a/src/plugins/platforms/offscreen/.prev_CMakeLists.txt b/src/plugins/platforms/offscreen/.prev_CMakeLists.txt
deleted file mode 100644
index 62d36ec449..0000000000
--- a/src/plugins/platforms/offscreen/.prev_CMakeLists.txt
+++ /dev/null
@@ -1,40 +0,0 @@
-# Generated from offscreen.pro.
-
-#####################################################################
-## QOffscreenIntegrationPlugin Plugin:
-#####################################################################
-
-qt_add_plugin(QOffscreenIntegrationPlugin
- OUTPUT_NAME qoffscreen
- TYPE platforms
- SOURCES
- main.cpp
- qoffscreencommon.cpp qoffscreencommon.h
- qoffscreenintegration.cpp qoffscreenintegration.h
- qoffscreenwindow.cpp qoffscreenwindow.h
- DEFINES
- QT_NO_FOREACH
- PUBLIC_LIBRARIES
- Qt::Core
- Qt::CorePrivate
- Qt::EventDispatcherSupportPrivate
- Qt::FontDatabaseSupportPrivate
- Qt::Gui
- Qt::GuiPrivate
-)
-
-#### Keys ignored in scope 1:.:.:offscreen.pro:<TRUE>:
-# OTHER_FILES = "offscreen.json"
-
-## Scopes:
-#####################################################################
-
-qt_extend_target(QOffscreenIntegrationPlugin CONDITION QT_FEATURE_opengl AND QT_FEATURE_xlib AND NOT QT_FEATURE_opengles2
- SOURCES
- qoffscreenintegration_x11.cpp qoffscreenintegration_x11.h
- PUBLIC_LIBRARIES
- Qt::GlxSupportPrivate
-)
-
-#### Keys ignored in scope 3:.:.:offscreen.pro:NOT TARGET___equals____ss_QT_DEFAULT_QPA_PLUGIN:
-# PLUGIN_EXTENDS = "-"
diff --git a/src/plugins/platforms/offscreen/CMakeLists.txt b/src/plugins/platforms/offscreen/CMakeLists.txt
index 63474c3760..09ad9a384d 100644
--- a/src/plugins/platforms/offscreen/CMakeLists.txt
+++ b/src/plugins/platforms/offscreen/CMakeLists.txt
@@ -1,13 +1,14 @@
-# Generated from offscreen.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## QOffscreenIntegrationPlugin Plugin:
#####################################################################
-qt_add_plugin(QOffscreenIntegrationPlugin
+qt_internal_add_plugin(QOffscreenIntegrationPlugin
OUTPUT_NAME qoffscreen
- TYPE platforms
- DEFAULT_IF ${QT_QPA_DEFAULT_PLATFORM} MATCHES offscreen # special case
+ PLUGIN_TYPE platforms
+ DEFAULT_IF ${QT_QPA_DEFAULT_PLATFORM} MATCHES offscreen
SOURCES
main.cpp
qoffscreencommon.cpp qoffscreencommon.h
@@ -15,27 +16,19 @@ qt_add_plugin(QOffscreenIntegrationPlugin
qoffscreenwindow.cpp qoffscreenwindow.h
DEFINES
QT_NO_FOREACH
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Core
Qt::CorePrivate
- Qt::EventDispatcherSupportPrivate
- Qt::FontDatabaseSupportPrivate
Qt::Gui
Qt::GuiPrivate
)
-#### Keys ignored in scope 1:.:.:offscreen.pro:<TRUE>:
-# OTHER_FILES = "offscreen.json"
-
## Scopes:
#####################################################################
-qt_extend_target(QOffscreenIntegrationPlugin CONDITION QT_FEATURE_opengl AND QT_FEATURE_xlib AND NOT QT_FEATURE_opengles2
+qt_internal_extend_target(QOffscreenIntegrationPlugin CONDITION QT_FEATURE_opengl AND QT_FEATURE_xlib AND NOT QT_FEATURE_opengles2
SOURCES
qoffscreenintegration_x11.cpp qoffscreenintegration_x11.h
- PUBLIC_LIBRARIES
- Qt::GlxSupportPrivate
+ LIBRARIES
+ X11::X11
)
-
-#### Keys ignored in scope 3:.:.:offscreen.pro:NOT TARGET___equals____ss_QT_DEFAULT_QPA_PLUGIN:
-# PLUGIN_EXTENDS = "-"
diff --git a/src/plugins/platforms/offscreen/main.cpp b/src/plugins/platforms/offscreen/main.cpp
index f364d9f004..4b5527cbde 100644
--- a/src/plugins/platforms/offscreen/main.cpp
+++ b/src/plugins/platforms/offscreen/main.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <qpa/qplatformintegrationplugin.h>
@@ -43,6 +7,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
class QOffscreenIntegrationPlugin : public QPlatformIntegrationPlugin
{
Q_OBJECT
@@ -53,9 +19,8 @@ public:
QPlatformIntegration *QOffscreenIntegrationPlugin::create(const QString& system, const QStringList& paramList)
{
- Q_UNUSED(paramList);
- if (!system.compare(QLatin1String("offscreen"), Qt::CaseInsensitive))
- return QOffscreenIntegration::createOffscreenIntegration();
+ if (!system.compare("offscreen"_L1, Qt::CaseInsensitive))
+ return QOffscreenIntegration::createOffscreenIntegration(paramList);
return nullptr;
}
diff --git a/src/plugins/platforms/offscreen/offscreen.pro b/src/plugins/platforms/offscreen/offscreen.pro
deleted file mode 100644
index f226132592..0000000000
--- a/src/plugins/platforms/offscreen/offscreen.pro
+++ /dev/null
@@ -1,29 +0,0 @@
-TARGET = qoffscreen
-
-QT += \
- core-private gui-private \
- eventdispatcher_support-private fontdatabase_support-private
-
-DEFINES += QT_NO_FOREACH
-
-SOURCES = main.cpp \
- qoffscreenintegration.cpp \
- qoffscreenwindow.cpp \
- qoffscreencommon.cpp
-
-HEADERS = qoffscreenintegration.h \
- qoffscreenwindow.h \
- qoffscreencommon.h
-
-OTHER_FILES += offscreen.json
-
-qtConfig(xlib):qtConfig(opengl):!qtConfig(opengles2) {
- SOURCES += qoffscreenintegration_x11.cpp
- HEADERS += qoffscreenintegration_x11.h
- QT += glx_support-private
-}
-
-PLUGIN_TYPE = platforms
-PLUGIN_CLASS_NAME = QOffscreenIntegrationPlugin
-!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = -
-load(qt_plugin)
diff --git a/src/plugins/platforms/offscreen/qoffscreencommon.cpp b/src/plugins/platforms/offscreen/qoffscreencommon.cpp
index de75a3e012..923fffb29c 100644
--- a/src/plugins/platforms/offscreen/qoffscreencommon.cpp
+++ b/src/plugins/platforms/offscreen/qoffscreencommon.cpp
@@ -1,45 +1,12 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qoffscreencommon.h"
+#include "qoffscreenintegration.h"
#include "qoffscreenwindow.h"
+
+#include <QtGui/QPainter>
#include <QtGui/private/qpixmap_raster_p.h>
#include <QtGui/private/qguiapplication_p.h>
@@ -50,6 +17,16 @@ QT_BEGIN_NAMESPACE
QPlatformWindow *QOffscreenScreen::windowContainingCursor = nullptr;
+
+QList<QPlatformScreen *> QOffscreenScreen::virtualSiblings() const
+{
+ QList<QPlatformScreen *> platformScreens;
+ for (auto screen : m_integration->screens()) {
+ platformScreens.append(screen);
+ }
+ return platformScreens;
+}
+
class QOffscreenCursor : public QPlatformCursor
{
public:
@@ -93,9 +70,10 @@ private:
QPoint m_pos;
};
-QOffscreenScreen::QOffscreenScreen()
+QOffscreenScreen::QOffscreenScreen(const QOffscreenIntegration *integration)
: m_geometry(0, 0, 800, 600)
, m_cursor(new QOffscreenCursor)
+ , m_integration(integration)
{
}
@@ -103,22 +81,25 @@ QPixmap QOffscreenScreen::grabWindow(WId id, int x, int y, int width, int height
{
QRect rect(x, y, width, height);
- QOffscreenWindow *window = QOffscreenWindow::windowForWinId(id);
- if (!window || window->window()->type() == Qt::Desktop) {
+ // id == 0 -> grab the screen, so all windows intersecting rect
+ if (!id) {
+ if (width == -1)
+ rect.setWidth(m_geometry.width());
+ if (height == -1)
+ rect.setHeight(m_geometry.height());
+ QPixmap screenImage(rect.size());
+ QPainter painter(&screenImage);
+ painter.translate(-x, -y);
const QWindowList wl = QGuiApplication::topLevelWindows();
- QWindow *containing = nullptr;
for (QWindow *w : wl) {
- if (w->type() != Qt::Desktop && w->isExposed() && w->geometry().contains(rect)) {
- containing = w;
- break;
+ if (w->isExposed() && w->geometry().intersects(rect)) {
+ QOffscreenBackingStore *store = QOffscreenBackingStore::backingStoreForWinId(w->winId());
+ const QImage windowImage = store ? store->toImage() : QImage();
+ if (!windowImage.isNull())
+ painter.drawImage(w->position(), windowImage);
}
}
-
- if (!containing)
- return QPixmap();
-
- id = containing->winId();
- rect = rect.translated(-containing->geometry().topLeft());
+ return screenImage;
}
QOffscreenBackingStore *store = QOffscreenBackingStore::backingStoreForWinId(id);
@@ -180,8 +161,8 @@ bool QOffscreenBackingStore::scroll(const QRegion &area, int dx, int dy)
if (m_image.isNull())
return false;
- for (const QRect &rect : area)
- qt_scrollRectInImage(m_image, rect, QPoint(dx, dy));
+ const QRect rect = area.boundingRect();
+ qt_scrollRectInImage(m_image, rect, QPoint(dx, dy));
return true;
}
@@ -208,13 +189,13 @@ QPixmap QOffscreenBackingStore::grabWindow(WId window, const QRect &rect) const
QOffscreenBackingStore *QOffscreenBackingStore::backingStoreForWinId(WId id)
{
- return m_backingStoreForWinIdHash.value(id, 0);
+ return m_backingStoreForWinIdHash.value(id, nullptr);
}
void QOffscreenBackingStore::clearHash()
{
for (auto it = m_windowAreaHash.cbegin(), end = m_windowAreaHash.cend(); it != end; ++it) {
- const auto it2 = qAsConst(m_backingStoreForWinIdHash).find(it.key());
+ const auto it2 = std::as_const(m_backingStoreForWinIdHash).find(it.key());
if (it2.value() == this)
m_backingStoreForWinIdHash.erase(it2);
}
@@ -223,4 +204,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 f4f0142911..a3d6227168 100644
--- a/src/plugins/platforms/offscreen/qoffscreencommon.h
+++ b/src/plugins/platforms/offscreen/qoffscreencommon.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QOFFSCREENCOMMON_H
#define QOFFSCREENCOMMON_H
@@ -45,32 +9,45 @@
#include <qpa/qplatformdrag.h>
#endif
#include <qpa/qplatformintegration.h>
+#include <qpa/qplatformnativeinterface.h>
#include <qpa/qplatformscreen.h>
#include <qpa/qplatformwindow.h>
#include <qscopedpointer.h>
#include <qimage.h>
+#include <qjsonobject.h>
#include <qhash.h>
QT_BEGIN_NAMESPACE
+class QOffscreenIntegration;
class QOffscreenScreen : public QPlatformScreen
{
public:
- QOffscreenScreen();
+ QOffscreenScreen(const QOffscreenIntegration *integration);
QRect geometry() const override { return m_geometry; }
int depth() const override { return 32; }
QImage::Format format() const override { return QImage::Format_RGB32; }
+ QDpi logicalDpi() const override { return QDpi(m_logicalDpi, m_logicalDpi); }
+ QDpi logicalBaseDpi() const override { return QDpi(m_logicalBaseDpi, m_logicalBaseDpi); }
+ qreal devicePixelRatio() const override { return m_dpr; }
+ QString name() const override { return m_name; }
QPlatformCursor *cursor() const override { return m_cursor.data(); }
+ QList<QPlatformScreen *> virtualSiblings() const override;
QPixmap grabWindow(WId window, int x, int y, int width, int height) const override;
static QPlatformWindow *windowContainingCursor;
public:
+ QString m_name;
QRect m_geometry;
+ int m_logicalDpi = 96;
+ int m_logicalBaseDpi= 96;
+ qreal m_dpr = 1;
QScopedPointer<QPlatformCursor> m_cursor;
+ const QOffscreenIntegration *m_integration;
};
#if QT_CONFIG(draganddrop)
@@ -93,6 +70,7 @@ public:
bool scroll(const QRegion &area, int dx, int dy) override;
QPixmap grabWindow(WId window, const QRect &rect) const;
+ QImage toImage() const override { return m_image; }
static QOffscreenBackingStore *backingStoreForWinId(WId id);
@@ -105,6 +83,20 @@ private:
static QHash<WId, QOffscreenBackingStore *> m_backingStoreForWinIdHash;
};
+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
#endif
diff --git a/src/plugins/platforms/offscreen/qoffscreenintegration.cpp b/src/plugins/platforms/offscreen/qoffscreenintegration.cpp
index 3a4494fc2e..ea8042928a 100644
--- a/src/plugins/platforms/offscreen/qoffscreenintegration.cpp
+++ b/src/plugins/platforms/offscreen/qoffscreenintegration.cpp
@@ -1,63 +1,28 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qoffscreenintegration.h"
#include "qoffscreenwindow.h"
#include "qoffscreencommon.h"
#if defined(Q_OS_UNIX)
-#include <QtEventDispatcherSupport/private/qgenericunixeventdispatcher_p.h>
+#include <QtGui/private/qgenericunixeventdispatcher_p.h>
#if defined(Q_OS_MAC)
#include <qpa/qplatformfontdatabase.h>
-#include <QtFontDatabaseSupport/private/qcoretextfontdatabase_p.h>
+#include <QtGui/private/qcoretextfontdatabase_p.h>
#else
-#include <QtFontDatabaseSupport/private/qgenericunixfontdatabase_p.h>
+#include <QtGui/private/qgenericunixfontdatabase_p.h>
#endif
#elif defined(Q_OS_WIN)
-#include <QtFontDatabaseSupport/private/qfreetypefontdatabase_p.h>
-#ifndef Q_OS_WINRT
+#include <QtGui/private/qfreetypefontdatabase_p.h>
#include <QtCore/private/qeventdispatcher_win_p.h>
-#else
-#include <QtCore/private/qeventdispatcher_winrt_p.h>
-#endif
#endif
+#include <QtCore/qfile.h>
+#include <QtCore/qjsonarray.h>
+#include <QtCore/qjsondocument.h>
+#include <QtCore/qjsonobject.h>
+#include <QtCore/qjsonvalue.h>
#include <QtGui/private/qpixmap_raster_p.h>
#include <QtGui/private/qguiapplication_p.h>
#include <qpa/qplatforminputcontextfactory_p.h>
@@ -73,6 +38,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
class QCoreTextFontEngine;
template <typename BaseEventDispatcher>
@@ -84,28 +51,15 @@ public:
{
}
- bool processEvents(QEventLoop::ProcessEventsFlags flags)
+ bool processEvents(QEventLoop::ProcessEventsFlags flags) override
{
bool didSendEvents = BaseEventDispatcher::processEvents(flags);
return QWindowSystemInterface::sendWindowSystemEvents(flags) || didSendEvents;
}
-
- bool hasPendingEvents()
- {
- return BaseEventDispatcher::hasPendingEvents()
- || QWindowSystemInterface::windowSystemEventsQueued();
- }
-
- void flush()
- {
- if (qApp)
- qApp->sendPostedEvents();
- BaseEventDispatcher::flush();
- }
};
-QOffscreenIntegration::QOffscreenIntegration()
+QOffscreenIntegration::QOffscreenIntegration(const QStringList& paramList)
{
#if defined(Q_OS_UNIX)
#if defined(Q_OS_MAC)
@@ -122,11 +76,235 @@ QOffscreenIntegration::QOffscreenIntegration()
#endif
m_services.reset(new QPlatformServices);
- QWindowSystemInterface::handleScreenAdded(new QOffscreenScreen);
+ QJsonObject config = resolveConfigFileConfiguration(paramList).value_or(defaultConfiguration());
+ setConfiguration(config);
}
QOffscreenIntegration::~QOffscreenIntegration()
{
+ while (!m_screens.isEmpty())
+ QWindowSystemInterface::handleScreenRemoved(m_screens.takeLast());
+}
+
+/*
+ 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
+
+ The supported top-level config keys are:
+ {
+ "synchronousWindowSystemEvents": <bool>
+ "windowFrameMargins": <bool>,
+ "screens": [<screens>],
+ }
+
+ "screens" is an array of:
+ {
+ "name": string,
+ "x": int,
+ "y": int,
+ "width": int,
+ "height": int,
+ "logicalDpi": int,
+ "logicalBaseDpi": int,
+ "dpr": double,
+ }
+*/
+
+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
+{
+ bool hasConfigFile = false;
+ QString configFilePath;
+ for (const QString &param : paramList) {
+ // Look for "configfile=/path/to/file/"
+ QString configPrefix("configfile="_L1);
+ if (param.startsWith(configPrefix)) {
+ hasConfigFile = true;
+ configFilePath = param.mid(configPrefix.size());
+ }
+ }
+ if (!hasConfigFile)
+ return std::nullopt;
+
+ // Read config file
+ if (configFilePath.isEmpty())
+ qFatal("Missing file path for -configfile platform option");
+ QFile configFile(configFilePath);
+ if (!configFile.exists())
+ qFatal("Could not find platform config file %s", qPrintable(configFilePath));
+ if (!configFile.open(QIODevice::ReadOnly))
+ qFatal("Could not open platform config file for reading %s, %s", qPrintable(configFilePath), qPrintable(configFile.errorString()));
+
+ QByteArray json = configFile.readAll();
+ QJsonParseError error;
+ QJsonDocument config = QJsonDocument::fromJson(json, &error);
+ if (config.isNull())
+ qFatal("Platform config file parse error: %s", qPrintable(error.errorString()));
+
+ 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 = 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 = 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()
@@ -144,6 +322,7 @@ bool QOffscreenIntegration::hasCapability(QPlatformIntegration::Capability cap)
switch (cap) {
case ThreadedPixmaps: return true;
case MultipleWindows: return true;
+ case RhiBasedRendering: return false;
default: return QPlatformIntegration::hasCapability(cap);
}
}
@@ -151,7 +330,7 @@ bool QOffscreenIntegration::hasCapability(QPlatformIntegration::Capability cap)
QPlatformWindow *QOffscreenIntegration::createPlatformWindow(QWindow *window) const
{
Q_UNUSED(window);
- QPlatformWindow *w = new QOffscreenWindow(window);
+ QPlatformWindow *w = new QOffscreenWindow(window, m_windowFrameMarginsEnabled);
w->requestActivateWindow();
return w;
}
@@ -166,16 +345,19 @@ QAbstractEventDispatcher *QOffscreenIntegration::createEventDispatcher() const
#if defined(Q_OS_UNIX)
return createUnixEventDispatcher();
#elif defined(Q_OS_WIN)
-#ifndef Q_OS_WINRT
return new QOffscreenEventDispatcher<QEventDispatcherWin32>();
-#else // !Q_OS_WINRT
- return new QOffscreenEventDispatcher<QEventDispatcherWinRT>();
-#endif // Q_OS_WINRT
#else
return 0;
#endif
}
+QPlatformNativeInterface *QOffscreenIntegration::nativeInterface() const
+{
+ if (!m_nativeInterface)
+ m_nativeInterface.reset(new QOffscreenPlatformNativeInterface(const_cast<QOffscreenIntegration*>(this)));
+ return m_nativeInterface.get();
+}
+
static QString themeName() { return QStringLiteral("offscreen"); }
QStringList QOffscreenIntegration::themeNames() const
@@ -194,12 +376,26 @@ public:
{
switch (h) {
case StyleNames:
- return QVariant(QStringList(QStringLiteral("fusion")));
+ return QVariant(QStringList(QStringLiteral("Fusion")));
default:
break;
}
return QPlatformTheme::themeHint(h);
}
+
+ virtual const QFont *font(Font type = SystemFont) const override
+ {
+ static QFont systemFont("Sans Serif"_L1, 9);
+ static QFont fixedFont("monospace"_L1, 9);
+ switch (type) {
+ case QPlatformTheme::SystemFont:
+ return &systemFont;
+ case QPlatformTheme::FixedFont:
+ return &fixedFont;
+ default:
+ return nullptr;
+ }
+ }
};
QPlatformTheme *QOffscreenIntegration::createPlatformTheme(const QString &name) const
@@ -224,14 +420,24 @@ QPlatformServices *QOffscreenIntegration::services() const
return m_services.data();
}
-QOffscreenIntegration *QOffscreenIntegration::createOffscreenIntegration()
+QOffscreenIntegration *QOffscreenIntegration::createOffscreenIntegration(const QStringList& paramList)
{
+ QOffscreenIntegration *offscreenIntegration = nullptr;
+
#if QT_CONFIG(xlib) && QT_CONFIG(opengl) && !QT_CONFIG(opengles2)
QByteArray glx = qgetenv("QT_QPA_OFFSCREEN_NO_GLX");
if (glx.isEmpty())
- return new QOffscreenX11Integration;
+ offscreenIntegration = new QOffscreenX11Integration(paramList);
#endif
- return new QOffscreenIntegration;
+
+ if (!offscreenIntegration)
+ offscreenIntegration = new QOffscreenIntegration(paramList);
+ return offscreenIntegration;
+}
+
+QList<QOffscreenScreen *> QOffscreenIntegration::screens() const
+{
+ return m_screens;
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/offscreen/qoffscreenintegration.h b/src/plugins/platforms/offscreen/qoffscreenintegration.h
index 098e726550..aab8d305b4 100644
--- a/src/plugins/platforms/offscreen/qoffscreenintegration.h
+++ b/src/plugins/platforms/offscreen/qoffscreenintegration.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QOFFSCREENINTEGRATION_H
#define QOFFSCREENINTEGRATION_H
@@ -44,17 +8,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();
+ 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;
@@ -70,18 +41,25 @@ public:
QPlatformFontDatabase *fontDatabase() const override;
QAbstractEventDispatcher *createEventDispatcher() const override;
+ QPlatformNativeInterface *nativeInterface() const override;
+
QStringList themeNames() const override;
QPlatformTheme *createPlatformTheme(const QString &name) const override;
- static QOffscreenIntegration *createOffscreenIntegration();
+ static QOffscreenIntegration *createOffscreenIntegration(const QStringList& paramList);
-private:
+ QList<QOffscreenScreen *> screens() const;
+protected:
QScopedPointer<QPlatformFontDatabase> m_fontDatabase;
#if QT_CONFIG(draganddrop)
QScopedPointer<QPlatformDrag> m_drag;
#endif
QScopedPointer<QPlatformInputContext> m_inputContext;
QScopedPointer<QPlatformServices> m_services;
+ mutable QScopedPointer<QPlatformNativeInterface> m_nativeInterface;
+ 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 84991d751f..fbee6667ea 100644
--- a/src/plugins/platforms/offscreen/qoffscreenintegration_x11.cpp
+++ b/src/plugins/platforms/offscreen/qoffscreenintegration_x11.cpp
@@ -1,52 +1,15 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qoffscreenintegration_x11.h"
#include <QByteArray>
#include <QOpenGLContext>
-#include <QtPlatformHeaders/QGLXNativeContext>
#include <X11/Xlib.h>
#include <GL/glx.h>
-#include <QtGlxSupport/private/qglxconvenience_p.h>
+#include <QtGui/private/qglxconvenience_p.h>
#include <qpa/qplatformsurface.h>
#include <qsurface.h>
@@ -77,6 +40,14 @@ private:
QOffscreenX11Connection *m_connection;
};
+QOffscreenX11Integration::QOffscreenX11Integration(const QStringList& paramList)
+: QOffscreenIntegration(paramList)
+{
+
+}
+
+QOffscreenX11Integration::~QOffscreenX11Integration() = default;
+
bool QOffscreenX11Integration::hasCapability(QPlatformIntegration::Capability cap) const
{
switch (cap) {
@@ -87,25 +58,39 @@ bool QOffscreenX11Integration::hasCapability(QPlatformIntegration::Capability ca
}
}
+#if !defined(QT_NO_OPENGL) && QT_CONFIG(xcb_glx_plugin)
QPlatformOpenGLContext *QOffscreenX11Integration::createPlatformOpenGLContext(QOpenGLContext *context) const
{
- if (!m_connection)
- m_connection.reset(new QOffscreenX11Connection);
+ auto &connection = nativeInterface()->m_connection;
- if (!m_connection->display())
+ if (!connection)
+ connection.reset(new QOffscreenX11Connection);
+
+ if (!connection->display())
return nullptr;
- return new QOffscreenX11GLXContext(m_connection->x11Info(), context);
+ return new QOffscreenX11GLXContext(connection->x11Info(), context);
}
+#endif // !defined(QT_NO_OPENGL) && QT_CONFIG(xcb_glx_plugin)
-QPlatformNativeInterface *QOffscreenX11Integration::nativeInterface() const
+QOffscreenX11PlatformNativeInterface *QOffscreenX11Integration::nativeInterface() const
{
- return const_cast<QOffscreenX11Integration *>(this);
+ if (!m_nativeInterface)
+ m_nativeInterface.reset(new QOffscreenX11PlatformNativeInterface(const_cast<QOffscreenX11Integration *>(this)));
+ return static_cast<QOffscreenX11PlatformNativeInterface *>(m_nativeInterface.data());
}
-void *QOffscreenX11Integration::nativeResourceForScreen(const QByteArray &resource, QScreen *screen)
+QOffscreenX11PlatformNativeInterface::QOffscreenX11PlatformNativeInterface(QOffscreenIntegration *integration)
+:QOffscreenPlatformNativeInterface(integration)
{
- Q_UNUSED(screen)
+
+}
+
+QOffscreenX11PlatformNativeInterface::~QOffscreenX11PlatformNativeInterface() = default;
+
+void *QOffscreenX11PlatformNativeInterface::nativeResourceForScreen(const QByteArray &resource, QScreen *screen)
+{
+ Q_UNUSED(screen);
if (resource.toLower() == QByteArrayLiteral("display") ) {
if (!m_connection)
m_connection.reset(new QOffscreenX11Connection);
@@ -114,24 +99,33 @@ void *QOffscreenX11Integration::nativeResourceForScreen(const QByteArray &resour
return nullptr;
}
-#ifndef QT_NO_OPENGL
-void *QOffscreenX11Integration::nativeResourceForContext(const QByteArray &resource, QOpenGLContext *context) {
+#if !defined(QT_NO_OPENGL) && QT_CONFIG(xcb_glx_plugin)
+void *QOffscreenX11PlatformNativeInterface::nativeResourceForContext(const QByteArray &resource, QOpenGLContext *context) {
if (resource.toLower() == QByteArrayLiteral("glxconfig") ) {
if (context) {
QOffscreenX11GLXContext *glxPlatformContext = static_cast<QOffscreenX11GLXContext *>(context->handle());
- return glxPlatformContext->glxConfig();
+ if (glxPlatformContext)
+ return glxPlatformContext->glxConfig();
}
}
if (resource.toLower() == QByteArrayLiteral("glxcontext") ) {
if (context) {
QOffscreenX11GLXContext *glxPlatformContext = static_cast<QOffscreenX11GLXContext *>(context->handle());
- return glxPlatformContext->glxContext();
+ if (glxPlatformContext)
+ return glxPlatformContext->glxContext();
}
}
return nullptr;
}
#endif
+#if QT_CONFIG(xcb)
+Display *QOffscreenX11PlatformNativeInterface::display() const
+{
+ return m_connection ? reinterpret_cast<Display *>(m_connection->display()) : nullptr;
+}
+#endif
+
QOffscreenX11Connection::QOffscreenX11Connection()
{
XInitThreads();
@@ -155,6 +149,7 @@ QOffscreenX11Info *QOffscreenX11Connection::x11Info()
return m_x11Info.data();
}
+#if QT_CONFIG(xcb_glx_plugin)
class QOffscreenX11GLXContextData
{
public:
@@ -241,9 +236,6 @@ QOffscreenX11GLXContext::QOffscreenX11GLXContext(QOffscreenX11Info *x11, QOpenGL
d->window = createDummyWindow(x11, visualInfo);
XFree(visualInfo);
}
- if (d->context)
- context->setNativeHandle(QVariant::fromValue<QGLXNativeContext>(QGLXNativeContext(d->context)));
-
}
QOffscreenX11GLXContext::~QOffscreenX11GLXContext()
@@ -296,7 +288,7 @@ bool QOffscreenX11GLXContext::isValid() const
return d->context && d->window;
}
-void *QOffscreenX11GLXContext::glxContext() const
+GLXContext QOffscreenX11GLXContext::glxContext() const
{
return d->context;
}
@@ -305,5 +297,5 @@ void *QOffscreenX11GLXContext::glxConfig() const
{
return d->config;
}
-
+#endif // QT_CONFIG(xcb_glx_plugin)
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/offscreen/qoffscreenintegration_x11.h b/src/plugins/platforms/offscreen/qoffscreenintegration_x11.h
index 5ef51a15a8..d7b5120332 100644
--- a/src/plugins/platforms/offscreen/qoffscreenintegration_x11.h
+++ b/src/plugins/platforms/offscreen/qoffscreenintegration_x11.h
@@ -1,73 +1,54 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QOFFSCREENINTEGRATION_X11_H
#define QOFFSCREENINTEGRATION_X11_H
#include "qoffscreenintegration.h"
+#include "qoffscreencommon.h"
#include <qglobal.h>
#include <qscopedpointer.h>
#include <qpa/qplatformopenglcontext.h>
+#include <QtGui/qguiapplication.h>
QT_BEGIN_NAMESPACE
class QOffscreenX11Connection;
class QOffscreenX11Info;
-class QOffscreenX11Integration : public QOffscreenIntegration, public QPlatformNativeInterface
+class QOffscreenX11PlatformNativeInterface : public QOffscreenPlatformNativeInterface
+#if QT_CONFIG(xcb)
+ , public QNativeInterface::QX11Application
+#endif
{
public:
- bool hasCapability(QPlatformIntegration::Capability cap) const override;
-
- QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const override;
- QPlatformNativeInterface *nativeInterface()const override;
+ QOffscreenX11PlatformNativeInterface(QOffscreenIntegration *integration);
+ ~QOffscreenX11PlatformNativeInterface();
- // QPlatformNativeInterface
void *nativeResourceForScreen(const QByteArray &resource, QScreen *screen) override;
-#ifndef QT_NO_OPENGL
+#if !defined(QT_NO_OPENGL) && QT_CONFIG(xcb_glx_plugin)
void *nativeResourceForContext(const QByteArray &resource, QOpenGLContext *context) override;
#endif
+#if QT_CONFIG(xcb)
+ Display *display() const override;
+ xcb_connection_t *connection() const override { return nullptr; };
+#endif
+ QScopedPointer<QOffscreenX11Connection> m_connection;
+};
-private:
- mutable QScopedPointer<QOffscreenX11Connection> m_connection;
+class QOffscreenX11Integration : public QOffscreenIntegration
+{
+public:
+ QOffscreenX11Integration(const QStringList& paramList);
+ ~QOffscreenX11Integration();
+ bool hasCapability(QPlatformIntegration::Capability cap) const override;
+
+#if !defined(QT_NO_OPENGL) && QT_CONFIG(xcb_glx_plugin)
+ QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const override;
+#endif
+ QOffscreenX11PlatformNativeInterface *nativeInterface() const override;
};
class QOffscreenX11Connection {
@@ -87,9 +68,11 @@ private:
QScopedPointer<QOffscreenX11Info> m_x11Info;
};
+#if QT_CONFIG(xcb_glx_plugin)
class QOffscreenX11GLXContextData;
class QOffscreenX11GLXContext : public QPlatformOpenGLContext
+ , public QNativeInterface::QGLXContext
{
public:
QOffscreenX11GLXContext(QOffscreenX11Info *x11, QOpenGLContext *context);
@@ -104,12 +87,15 @@ public:
bool isSharing() const override;
bool isValid() const override;
+ GLXContext nativeContext() const override { return glxContext(); }
+
void *glxConfig() const;
- void *glxContext() const;
+ GLXContext glxContext() const;
private:
QScopedPointer<QOffscreenX11GLXContextData> d;
};
+#endif // QT_CONFIG(xcb_glx_plugin)
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/offscreen/qoffscreenwindow.cpp b/src/plugins/platforms/offscreen/qoffscreenwindow.cpp
index 53880c877e..1a1471c687 100644
--- a/src/plugins/platforms/offscreen/qoffscreenwindow.cpp
+++ b/src/plugins/platforms/offscreen/qoffscreenwindow.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qoffscreenwindow.h"
#include "qoffscreencommon.h"
@@ -44,21 +8,22 @@
#include <qpa/qwindowsysteminterface.h>
#include <private/qwindow_p.h>
+#include <private/qguiapplication_p.h>
QT_BEGIN_NAMESPACE
-QOffscreenWindow::QOffscreenWindow(QWindow *window)
+QOffscreenWindow::QOffscreenWindow(QWindow *window, bool frameMarginsEnabled)
: QPlatformWindow(window)
, m_positionIncludesFrame(false)
, m_visible(false)
, m_pendingGeometryChangeOnShow(true)
+ , m_frameMarginsRequested(frameMarginsEnabled)
{
- if (window->windowState() == Qt::WindowNoState)
- setGeometry(window->geometry());
- else
+ if (window->windowState() == Qt::WindowNoState) {
+ setGeometry(windowGeometry());
+ } else {
setWindowState(window->windowStates());
-
- QWindowSystemInterface::flushWindowSystemEvents();
+ }
static WId counter = 0;
m_winId = ++counter;
@@ -80,7 +45,7 @@ void QOffscreenWindow::setGeometry(const QRect &rect)
m_positionIncludesFrame = qt_window_private(window())->positionPolicy == QWindowPrivate::WindowFrameInclusive;
- setFrameMarginsEnabled(true);
+ setFrameMarginsEnabled(m_frameMarginsRequested);
setGeometryImpl(rect);
m_normalGeometry = geometry();
@@ -121,7 +86,7 @@ void QOffscreenWindow::setVisible(bool visible)
if (visible) {
if (window()->type() != Qt::ToolTip)
- QWindowSystemInterface::handleWindowActivated(window());
+ QWindowSystemInterface::handleFocusWindowChanged(window(), Qt::ActiveWindowFocusReason);
if (m_pendingGeometryChangeOnShow) {
m_pendingGeometryChangeOnShow = false;
@@ -129,11 +94,26 @@ void QOffscreenWindow::setVisible(bool visible)
}
}
+ const QPoint cursorPos = QCursor::pos();
if (visible) {
QRect rect(QPoint(), geometry().size());
QWindowSystemInterface::handleExposeEvent(window(), rect);
+ if (QWindowPrivate::get(window())->isPopup() && QGuiApplicationPrivate::currentMouseWindow) {
+ QWindowSystemInterface::handleLeaveEvent<QWindowSystemInterface::SynchronousDelivery>
+ (QGuiApplicationPrivate::currentMouseWindow);
+ }
+ if (geometry().contains(cursorPos))
+ QWindowSystemInterface::handleEnterEvent(window(),
+ window()->mapFromGlobal(cursorPos), cursorPos);
} else {
QWindowSystemInterface::handleExposeEvent(window(), QRegion());
+ if (window()->type() & Qt::Window) {
+ if (QWindow *windowUnderMouse = QGuiApplication::topLevelAt(cursorPos)) {
+ QWindowSystemInterface::handleEnterEvent(windowUnderMouse,
+ windowUnderMouse->mapFromGlobal(cursorPos),
+ cursorPos);
+ }
+ }
}
m_visible = visible;
@@ -142,7 +122,7 @@ void QOffscreenWindow::setVisible(bool visible)
void QOffscreenWindow::requestActivateWindow()
{
if (m_visible)
- QWindowSystemInterface::handleWindowActivated(window());
+ QWindowSystemInterface::handleFocusWindowChanged(window(), Qt::ActiveWindowFocusReason);
}
WId QOffscreenWindow::winId() const
@@ -168,7 +148,7 @@ void QOffscreenWindow::setFrameMarginsEnabled(bool enabled)
void QOffscreenWindow::setWindowState(Qt::WindowStates state)
{
- setFrameMarginsEnabled(!(state & Qt::WindowFullScreen));
+ setFrameMarginsEnabled(m_frameMarginsRequested && !(state & Qt::WindowFullScreen));
m_positionIncludesFrame = false;
if (state & Qt::WindowMinimized)
@@ -185,9 +165,9 @@ void QOffscreenWindow::setWindowState(Qt::WindowStates state)
QOffscreenWindow *QOffscreenWindow::windowForWinId(WId id)
{
- return m_windowForWinIdHash.value(id, 0);
+ return m_windowForWinIdHash.value(id, nullptr);
}
-QHash<WId, QOffscreenWindow *> QOffscreenWindow::m_windowForWinIdHash;
+Q_CONSTINIT QHash<WId, QOffscreenWindow *> QOffscreenWindow::m_windowForWinIdHash;
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/offscreen/qoffscreenwindow.h b/src/plugins/platforms/offscreen/qoffscreenwindow.h
index e1f37bb034..d525f2c657 100644
--- a/src/plugins/platforms/offscreen/qoffscreenwindow.h
+++ b/src/plugins/platforms/offscreen/qoffscreenwindow.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QOFFSCREENWINDOW_H
#define QOFFSCREENWINDOW_H
@@ -50,7 +14,7 @@ QT_BEGIN_NAMESPACE
class QOffscreenWindow : public QPlatformWindow
{
public:
- QOffscreenWindow(QWindow *window);
+ QOffscreenWindow(QWindow *window, bool frameMarginsEnabled);
~QOffscreenWindow();
void setGeometry(const QRect &rect) override;
@@ -74,9 +38,10 @@ private:
bool m_positionIncludesFrame;
bool m_visible;
bool m_pendingGeometryChangeOnShow;
+ bool m_frameMarginsRequested;
WId m_winId;
- static QHash<WId, QOffscreenWindow *> m_windowForWinIdHash;
+ Q_CONSTINIT static QHash<WId, QOffscreenWindow *> m_windowForWinIdHash;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/openwfd/main.cpp b/src/plugins/platforms/openwfd/main.cpp
deleted file mode 100644
index 0609f92139..0000000000
--- a/src/plugins/platforms/openwfd/main.cpp
+++ /dev/null
@@ -1,61 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 <qpa/qplatformintegrationplugin.h>
-#include "qopenwfdintegration.h"
-
-QT_BEGIN_NAMESPACE
-
-class QOpenWFDIntegrationPlugin : public QPlatformIntegrationPlugin
-{
- Q_PLUGIN_METADATA(IID QPlatformIntegrationFactoryInterface_iid)
-public:
- QPlatformIntegration *create(const QString&, const QStringList&);
-};
-
-QPlatformIntegration* QOpenWFDIntegrationPlugin::create(const QString& system, const QStringList& paramList)
-{
- Q_UNUSED(paramList);
- if (!system.compare(QLatin1String("openwfd"), Qt::CaseInsensitive))
- return new QOpenWFDIntegration;
-
- return 0;
-}
-
-QT_END_NAMESPACE
diff --git a/src/plugins/platforms/openwfd/openwf.pro b/src/plugins/platforms/openwfd/openwf.pro
deleted file mode 100644
index 6012731b65..0000000000
--- a/src/plugins/platforms/openwfd/openwf.pro
+++ /dev/null
@@ -1,40 +0,0 @@
-TARGET = qopenwf
-
-QT += \
- core-private gui-private \
- eventdispatcher_support-private fontdatabase_support-private
-
-HEADERS += \
- qopenwfddevice.h \
- qopenwfdintegration.h \
- qopenwfdnativeinterface.h \
- qopenwfdscreen.h \
- qopenwfdbackingstore.h \
- qopenwfdevent.h \
- qopenwfdglcontext.h \
- qopenwfdoutputbuffer.h \
- qopenwfdport.h \
- qopenwfdwindow.h \
- qopenwfdportmode.h
-
-SOURCES += \
- main.cpp \
- qopenwfddevice.cpp \
- qopenwfdintegration.cpp \
- qopenwfdnativeinterface.cpp \
- qopenwfdscreen.cpp \
- qopenwfdbackingstore.cpp \
- qopenwfdevent.cpp \
- qopenwfdglcontext.cpp \
- qopenwfdoutputbuffer.cpp \
- qopenwfdport.cpp \
- qopenwfdportmode.cpp \
- qopenwfdwindow.cpp
-
-LIBS += -lWFD
-QMAKE_USE += gbm opengl_es2 egl
-
-PLUGIN_TYPE = platforms
-PLUGIN_CLASS_NAME = QOpenWFDIntegrationPlugin
-!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = -
-load(qt_plugin)
diff --git a/src/plugins/platforms/openwfd/qopenwfdbackingstore.cpp b/src/plugins/platforms/openwfd/qopenwfdbackingstore.cpp
deleted file mode 100644
index 1ee2e05cb1..0000000000
--- a/src/plugins/platforms/openwfd/qopenwfdbackingstore.cpp
+++ /dev/null
@@ -1,64 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 "qopenwfdbackingstore.h"
-
-QOpenWFDBackingStore::QOpenWFDBackingStore(QWindow *window)
- : QPlatformBackingStore(window)
-{
-}
-
-QPaintDevice * QOpenWFDBackingStore::paintDevice()
-{
- return &mImage;
-}
-
-//we don't support flush yet :)
-void QOpenWFDBackingStore::flush(QWindow *window, const QRegion &region, const QPoint &offset)
-{
- Q_UNUSED(window);
- Q_UNUSED(region);
- Q_UNUSED(offset);
-}
-
-void QOpenWFDBackingStore::resize(const QSize &size, const QRegion &staticContents)
-{
- Q_UNUSED(staticContents);
- mImage = QImage(size,QImage::Format_RGB32);
-}
diff --git a/src/plugins/platforms/openwfd/qopenwfdbackingstore.h b/src/plugins/platforms/openwfd/qopenwfdbackingstore.h
deleted file mode 100644
index 99bad8f471..0000000000
--- a/src/plugins/platforms/openwfd/qopenwfdbackingstore.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 QOPENWFDBACKINGSTORE_H
-#define QOPENWFDBACKINGSTORE_H
-
-#include <qpa/qplatformbackingstore.h>
-#include <QtGui/QImage>
-
-class QOpenWFDBackingStore : public QPlatformBackingStore
-{
-public:
- QOpenWFDBackingStore(QWindow *window);
-
- QPaintDevice *paintDevice();
-
- // 'window' can be a child window, in which case 'region' is in child window coordinates and
- // offset is the (child) window's offset in relation to the window surface.
- void flush(QWindow *window, const QRegion &region, const QPoint &offset);
-
- void resize(const QSize &size, const QRegion &staticContents);
-
-private:
- QImage mImage;
-};
-
-#endif // QOPENWFDBACKINGSTORE_H
diff --git a/src/plugins/platforms/openwfd/qopenwfddevice.cpp b/src/plugins/platforms/openwfd/qopenwfddevice.cpp
deleted file mode 100644
index 7a9d22e74d..0000000000
--- a/src/plugins/platforms/openwfd/qopenwfddevice.cpp
+++ /dev/null
@@ -1,315 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 "qopenwfddevice.h"
-
-#include "qopenwfdport.h"
-#include "qopenwfdscreen.h"
-
-#include <QtCore/QDebug>
-
-#include <WF/wfdext.h>
-#include <gbm.h>
-
-QOpenWFDDevice::QOpenWFDDevice(QOpenWFDIntegration *integration, WFDint device_enumeration)
- : mIntegration(integration)
- , mDeviceEnum(device_enumeration)
- , mCommitedDevice(false)
- , mWaitingForBindSourceEvent(false)
-{
- mDevice = wfdCreateDevice(WFD_DEFAULT_DEVICE_ID,WFD_NONE);
- if (mDevice == WFD_INVALID_HANDLE)
- qDebug("failed to create device");
-
- mEvent = wfdCreateEvent(mDevice,0);
- if (mEvent == WFD_INVALID_HANDLE)
- qDebug("failed to create event handle");
-
- //initialize pipelines for device.
- wfdEnumeratePipelines(mDevice,WFD_NONE,0,WFD_NONE);
-
- initializeGbmAndEgl();
-
- WFDint numberOfPorts = wfdEnumeratePorts(mDevice,0,0,0);
- WFDint port_enumerations[numberOfPorts];
- WFDint actualNumberOfPorts = wfdEnumeratePorts(mDevice,port_enumerations,numberOfPorts,WFD_NONE);
- Q_ASSERT(actualNumberOfPorts == numberOfPorts);
-
- for (int i = 0; i < actualNumberOfPorts; i++)
- {
- QOpenWFDPort *port = new QOpenWFDPort(this,port_enumerations[i]);
- if (port->attached()) {
- mPorts.append(port);
- } else {
- delete port;
- }
- }
-
- int fd = wfdDeviceEventGetFD(mDevice,mEvent);
- mEventSocketNotifier = new QSocketNotifier(fd,QSocketNotifier::Read,this);
- connect(mEventSocketNotifier,SIGNAL(activated(int)),SLOT(readEvents()));
-
- mCommitedDevice = true;
- commit(WFD_COMMIT_ENTIRE_DEVICE, handle());
-}
-
-QOpenWFDDevice::~QOpenWFDDevice()
-{
- delete mEventSocketNotifier;
- wfdDestroyEvent(mDevice,mEvent);
-
- for (int i = 0; i < mPorts.size(); i++) {
- //probably don't need to remove them from the list
- QList <WFDint> keys = mUsedPipelines.keys(mPorts.at(i));
- for (int keyIndex = 0; keyIndex < keys.size(); keyIndex++) {
- mUsedPipelines.remove(keys.at(keyIndex));
- }
- //but we have to delete them :)
- delete mPorts[i];
- }
-
- eglDestroyContext(mEglDisplay,mEglContext);
- eglTerminate(mEglDisplay);
-
- gbm_device_destroy(mGbmDevice);
-
- wfdDestroyDevice(mDevice);
-}
-
-WFDDevice QOpenWFDDevice::handle() const
-{
- return mDevice;
-}
-
-QOpenWFDIntegration * QOpenWFDDevice::integration() const
-{
- return mIntegration;
-}
-
-bool QOpenWFDDevice::isPipelineUsed(WFDint pipelineId)
-{
- return mUsedPipelines.contains(pipelineId);
-}
-
-void QOpenWFDDevice::addToUsedPipelineSet(WFDint pipelineId,QOpenWFDPort *port)
-{
- mUsedPipelines.insert(pipelineId,port);
-}
-
-void QOpenWFDDevice::removeFromUsedPipelineSet(WFDint pipelineId)
-{
- mUsedPipelines.remove(pipelineId);
-}
-
-gbm_device * QOpenWFDDevice::gbmDevice() const
-
-{
- return mGbmDevice;
-}
-
-EGLDisplay QOpenWFDDevice::eglDisplay() const
-{
- return mEglDisplay;
-}
-
-EGLContext QOpenWFDDevice::eglContext() const
-{
- return mEglContext;
-}
-
-void QOpenWFDDevice::commit(WFDCommitType type, WFDHandle handle)
-{
- if (mCommitedDevice) {
- wfdDeviceCommit(mDevice,type,handle);
- }
-}
-
-void QOpenWFDDevice::waitForPipelineBindSourceCompleteEvent()
-{
- mWaitingForBindSourceEvent = true;
-
- while (mWaitingForBindSourceEvent) {
- readEvents(WFD_FOREVER);
- }
-}
-
-void QOpenWFDDevice::readEvents(WFDtime wait)
-{
- WFDEventType type = wfdDeviceEventWait(mDevice,mEvent,wait);
-
- if (type == WFD_EVENT_NONE || type == WFD_EVENT_DESTROYED) {
- return;
- }
- switch (type) {
- case WFD_EVENT_INVALID:
- case WFD_EVENT_NONE:
- return;
- case WFD_EVENT_DESTROYED:
- qDebug("Event or Device destoryed!");
- return;
- case WFD_EVENT_PORT_ATTACH_DETACH:
- handlePortAttachDetach();
- break;
- case WFD_EVENT_PORT_PROTECTION_FAILURE:
- qDebug("Port protection event handling not implemented");
- break;
- case WFD_EVENT_PIPELINE_BIND_SOURCE_COMPLETE:
- handlePipelineBindSourceComplete();
- break;
- case WFD_EVENT_PIPELINE_BIND_MASK_COMPLETE:
- qDebug("Pipeline bind mask event handling not implemented");
- break;
- default:
- qDebug("Unrecognized event type: %lu", static_cast<long unsigned int>(type));
- break;
- }
-
-
-}
-
-void QOpenWFDDevice::initializeGbmAndEgl()
-{
-
- qDebug("initializing GBM and EGL");
- int fd = wfdGetDeviceAttribi(mDevice,WFD_DEVICE_ID);
- if (fd < 0) {
- qDebug("failed to get WFD_DEVICE_ID");
- }
-
- mGbmDevice = gbm_create_device(fd);
-
- setenv("EGL_PLATFORM", "drm",1);
-
- mEglDisplay = eglGetDisplay(mGbmDevice);
-
- EGLint minor, major;
-
- if (!eglInitialize(mEglDisplay,&major,&minor)) {
- qDebug("failed to initialize egl");
- }
-
- QByteArray eglExtensions = eglQueryString(mEglDisplay, EGL_EXTENSIONS);
- if (!eglExtensions.contains("EGL_KHR_surfaceless_opengl")) {
- qDebug("This egl implementation does not have the required EGL extension EGL_KHR_surfaceless_opengl");
- }
-
- eglBindAPI(EGL_OPENGL_ES_API);
-
- EGLint contextAttribs[] = {
- EGL_CONTEXT_CLIENT_VERSION, 2,
- EGL_NONE
- };
-
- mEglContext = eglCreateContext(mEglDisplay,NULL,EGL_NO_CONTEXT,contextAttribs);
- if (mEglContext == EGL_NO_CONTEXT) {
- qDebug("Failed to create EGL context");
- }
-
- eglCreateImage = (PFNEGLCREATEIMAGEKHRPROC) eglGetProcAddress("eglCreateImageKHR");
- if (!eglCreateImage) {
- qWarning("failed to load extension eglCreateImageKHR");
- }
-
- eglDestroyImage = (PFNEGLDESTROYIMAGEKHRPROC) eglGetProcAddress("eglDestroyImageKHR");
- if (!eglDestroyImage) {
- qWarning("failed to load extension eglDestoryImageKHR");
- }
-
- glEglImageTargetRenderBufferStorage = (PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC) eglGetProcAddress("glEGLImageTargetRenderbufferStorageOES");
- if (!glEglImageTargetRenderBufferStorage) {
- qWarning("failed to load extension glEGLImageTargetRenderbufferStorageOES");
- }
-}
-
-void QOpenWFDDevice::handlePortAttachDetach()
-{
- WFDint id = wfdGetEventAttribi(mDevice,mEvent,WFD_EVENT_PORT_ATTACH_PORT_ID);
- if (id == WFD_INVALID_PORT_ID)
- return;
-
- WFDint attachState = wfdGetEventAttribi(mDevice,mEvent,WFD_EVENT_PORT_ATTACH_STATE);
- if (attachState == WFD_TRUE) {
- int indexToAdd = -1;
- for (int i = 0; i < mPorts.size(); i++) {
- if (mPorts.at(i)->portId() == id) {
- indexToAdd = i;
- qDebug("found index to attach");
- break;
- }
- }
- if (indexToAdd >= 0) {
- mPorts[indexToAdd]->attach();
- } else {
- mPorts.append(new QOpenWFDPort(this,id));
- }
-
- } else {
- int indexToDelete = -1;
- for (int i = 0; i < mPorts.size(); i++) {
- if (mPorts.at(i)->portId() == id) {
- indexToDelete = i;
- break;
- }
- }
- if (indexToDelete >= 0) {
- QOpenWFDPort *portToDelete = mPorts.at(indexToDelete);
- mPorts.removeAt(indexToDelete);
- delete portToDelete;
- }
- }
-}
-
-void QOpenWFDDevice::handlePipelineBindSourceComplete()
-{
- mWaitingForBindSourceEvent = false;
-
- WFDint overflow = wfdGetEventAttribi(mDevice,mEvent, WFD_EVENT_PIPELINE_BIND_QUEUE_OVERFLOW);
- if (overflow == WFD_TRUE) {
- qDebug("PIPELINE_BIND_QUEUE_OVERFLOW event occurred");
- }
-
- WFDint pipelineId = wfdGetEventAttribi(mDevice,mEvent,WFD_EVENT_PIPELINE_BIND_PIPELINE_ID);
- for (int i = 0; i < mPorts.size(); i++) {
- if (pipelineId != WFD_INVALID_PIPELINE_ID && mUsedPipelines.contains(pipelineId)) {
- QOpenWFDPort *port = mUsedPipelines.value(pipelineId);
- port->screen()->pipelineBindSourceComplete();
- break;
- }
- }
-}
diff --git a/src/plugins/platforms/openwfd/qopenwfddevice.h b/src/plugins/platforms/openwfd/qopenwfddevice.h
deleted file mode 100644
index bd89edd313..0000000000
--- a/src/plugins/platforms/openwfd/qopenwfddevice.h
+++ /dev/null
@@ -1,111 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 QOPENWFDDEVICE_H
-#define QOPENWFDDEVICE_H
-
-#include "qopenwfdintegration.h"
-
-#include <QtCore/QList>
-#include <QtCore/QSet>
-#include <QtCore/QSocketNotifier>
-
-#include <WF/wfd.h>
-
-#include <gbm.h>
-#include <EGL/egl.h>
-#include <EGL/eglext.h>
-#include <GLES2/gl2.h>
-#include <GLES2/gl2ext.h>
-
-class QOpenWFDPort;
-
-class QOpenWFDDevice : public QObject
-{
- Q_OBJECT
-public:
- QOpenWFDDevice(QOpenWFDIntegration *integration, WFDint handle);
- ~QOpenWFDDevice();
- WFDDevice handle() const;
- QOpenWFDIntegration *integration() const;
-
-
- bool isPipelineUsed(WFDint pipelineId);
- void addToUsedPipelineSet(WFDint pipelineId, QOpenWFDPort *port);
- void removeFromUsedPipelineSet(WFDint pipelineId);
-
- gbm_device *gbmDevice() const;
- EGLDisplay eglDisplay() const;
- EGLContext eglContext() const;
-
- PFNEGLCREATEIMAGEKHRPROC eglCreateImage;
- PFNEGLDESTROYIMAGEKHRPROC eglDestroyImage;
- PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC glEglImageTargetRenderBufferStorage;
-
- void commit(WFDCommitType type, WFDHandle handle);
- bool isDeviceInitializedAndCommited() const { return mCommitedDevice; }
-
- void waitForPipelineBindSourceCompleteEvent();
-
-public slots:
- void readEvents(WFDtime wait = 0);
-private:
- void initializeGbmAndEgl();
- void handlePortAttachDetach();
- void handlePipelineBindSourceComplete();
- QOpenWFDIntegration *mIntegration;
- WFDint mDeviceEnum;
- WFDDevice mDevice;
-
- WFDEvent mEvent;
- QSocketNotifier *mEventSocketNotifier;
-
- QList<QOpenWFDPort *> mPorts;
-
- QMap<WFDint, QOpenWFDPort *> mUsedPipelines;
-
- struct gbm_device *mGbmDevice;
- EGLDisplay mEglDisplay;
- EGLContext mEglContext;
-
- bool mCommitedDevice;
- bool mWaitingForBindSourceEvent;
-};
-
-#endif // QOPENWFDDEVICE_H
diff --git a/src/plugins/platforms/openwfd/qopenwfdevent.cpp b/src/plugins/platforms/openwfd/qopenwfdevent.cpp
deleted file mode 100644
index 6ffe5bcf45..0000000000
--- a/src/plugins/platforms/openwfd/qopenwfdevent.cpp
+++ /dev/null
@@ -1,44 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 "qopenwfdevent.h"
-
-QOpenWFDEvent::QOpenWFDEvent()
-{
-}
diff --git a/src/plugins/platforms/openwfd/qopenwfdevent.h b/src/plugins/platforms/openwfd/qopenwfdevent.h
deleted file mode 100644
index 122a61bc5d..0000000000
--- a/src/plugins/platforms/openwfd/qopenwfdevent.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 QOPENWFDEVENT_H
-#define QOPENWFDEVENT_H
-
-class QOpenWFDEvent
-{
-public:
- QOpenWFDEvent();
-};
-
-#endif // QOPENWFDEVENT_H
diff --git a/src/plugins/platforms/openwfd/qopenwfdglcontext.cpp b/src/plugins/platforms/openwfd/qopenwfdglcontext.cpp
deleted file mode 100644
index cf267ea203..0000000000
--- a/src/plugins/platforms/openwfd/qopenwfdglcontext.cpp
+++ /dev/null
@@ -1,101 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 "qopenwfdglcontext.h"
-
-#include "qopenwfdwindow.h"
-#include "qopenwfdscreen.h"
-#include <dlfcn.h>
-
-QOpenWFDGLContext::QOpenWFDGLContext(QOpenWFDDevice *device)
- : QPlatformOpenGLContext()
- , mWfdDevice(device)
-{
-}
-
-QSurfaceFormat QOpenWFDGLContext::format() const
-{
- return QSurfaceFormat();
-}
-
-bool QOpenWFDGLContext::makeCurrent(QPlatformSurface *surface)
-{
- Q_ASSERT(surface->surface()->surfaceType() == QSurface::OpenGLSurface);
-
- EGLDisplay display = mWfdDevice->eglDisplay();
- EGLContext context = mWfdDevice->eglContext();
- if (!eglMakeCurrent(display,EGL_NO_SURFACE,EGL_NO_SURFACE,context)) {
- qDebug("GLContext: eglMakeCurrent FAILED!");
- }
-
- QPlatformWindow *window = static_cast<QPlatformWindow *>(surface);
- QOpenWFDScreen *screen = static_cast<QOpenWFDScreen *>(QPlatformScreen::platformScreenForWindow(window->window()));
- screen->bindFramebuffer();
- return true;
-}
-
-void QOpenWFDGLContext::doneCurrent()
-{
- //do nothing :)
-}
-
-void QOpenWFDGLContext::swapBuffers(QPlatformSurface *surface)
-{
- glFlush();
-
- QPlatformWindow *window = static_cast<QPlatformWindow *>(surface);
- QOpenWFDScreen *screen = static_cast<QOpenWFDScreen *>(QPlatformScreen::platformScreenForWindow(window->window()));
-
- screen->swapBuffers();
-}
-
-QFunctionPointer QOpenWFDGLContext::getProcAddress(const char *procName)
-{
- QFunctionPointer proc = (QFunctionPointer) eglGetProcAddress(procName);
- if (!proc)
- proc = (QFunctionPointer) dlsym(RTLD_DEFAULT, procName);
- return proc;
-}
-
-EGLContext QOpenWFDGLContext::eglContext() const
-{
- return mWfdDevice->eglContext();
-}
-
-
diff --git a/src/plugins/platforms/openwfd/qopenwfdglcontext.h b/src/plugins/platforms/openwfd/qopenwfdglcontext.h
deleted file mode 100644
index 1c2541e098..0000000000
--- a/src/plugins/platforms/openwfd/qopenwfdglcontext.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 QOPENWFDGLCONTEXT_H
-#define QOPENWFDGLCONTEXT_H
-
-#include <qpa/qplatformopenglcontext.h>
-
-#include "qopenwfddevice.h"
-
-class QOpenWFDGLContext : public QPlatformOpenGLContext
-{
-public:
- QOpenWFDGLContext(QOpenWFDDevice *device);
-
- QSurfaceFormat format() const;
-
- bool makeCurrent(QPlatformSurface *surface);
- void doneCurrent();
-
- void swapBuffers(QPlatformSurface *surface);
-
- QFunctionPointer getProcAddress(const char *procName);
-
- EGLContext eglContext() const;
-private:
- QOpenWFDDevice *mWfdDevice;
-};
-
-#endif // QOPENWFDGLCONTEXT_H
diff --git a/src/plugins/platforms/openwfd/qopenwfdintegration.cpp b/src/plugins/platforms/openwfd/qopenwfdintegration.cpp
deleted file mode 100644
index c5dc40a206..0000000000
--- a/src/plugins/platforms/openwfd/qopenwfdintegration.cpp
+++ /dev/null
@@ -1,138 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 "qopenwfdintegration.h"
-#include "qopenwfdscreen.h"
-#include "qopenwfdnativeinterface.h"
-#include "qopenwfddevice.h"
-#include "qopenwfdwindow.h"
-#include "qopenwfdglcontext.h"
-#include "qopenwfdbackingstore.h"
-
-#include <QtPlatformSupport/private/qgenericunixprintersupport_p.h>
-
-#include <QtGui/private/qguiapplication_p.h>
-#include <QtGui/QOpenGLContext>
-#include <QtGui/QScreen>
-#include <qpa/qwindowsysteminterface.h>
-
-#include <QtEventDispatcherSupport/private/qgenericunixeventdispatcher_p.h>
-#include <QtFontDatabaseSupport/private/qgenericunixfontdatabase_p.h>
-
-#include <stdio.h>
-
-#include <WF/wfd.h>
-
-QOpenWFDIntegration::QOpenWFDIntegration()
- : QPlatformIntegration()
- , mPrinterSupport(new QGenericUnixPrinterSupport)
-{
- int numberOfDevices = wfdEnumerateDevices(0,0,0);
-
- WFDint devices[numberOfDevices];
- int actualNumberOfDevices = wfdEnumerateDevices(devices,numberOfDevices,0);
- Q_ASSERT(actualNumberOfDevices == numberOfDevices);
-
- mDevices.reserve(actualNumberOfDevices);
- for (int i = 0; i < actualNumberOfDevices; i++) {
- mDevices.append(new QOpenWFDDevice(this,devices[i]));
- }
-
- mFontDatabase = new QGenericUnixFontDatabase();
- mNativeInterface = new QOpenWFDNativeInterface;
-}
-
-QOpenWFDIntegration::~QOpenWFDIntegration()
-{
- //don't delete screens since they are deleted by the devices
- qDebug("deleting platform integration");
- for (int i = 0; i < mDevices.size(); i++) {
- delete mDevices[i];
- }
-
- delete mFontDatabase;
- delete mNativeInterface;
- delete mPrinterSupport;
-}
-
-bool QOpenWFDIntegration::hasCapability(QPlatformIntegration::Capability cap) const
-{
- switch (cap) {
- case ThreadedPixmaps: return true;
- case OpenGL: return true;
- default: return QPlatformIntegration::hasCapability(cap);
- }
-}
-
-QPlatformWindow *QOpenWFDIntegration::createPlatformWindow(QWindow *window) const
-{
- return new QOpenWFDWindow(window);
-}
-
-QPlatformOpenGLContext *QOpenWFDIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const
-{
- QOpenWFDScreen *screen = static_cast<QOpenWFDScreen *>(context->screen()->handle());
-
- return new QOpenWFDGLContext(screen->port()->device());
-}
-
-QPlatformBackingStore *QOpenWFDIntegration::createPlatformBackingStore(QWindow *window) const
-{
- return new QOpenWFDBackingStore(window);
-}
-
-QAbstractEventDispatcher *QOpenWFDIntegration::createEventDispatcher() const
-{
- return createUnixEventDispatcher();
-}
-
-QPlatformFontDatabase *QOpenWFDIntegration::fontDatabase() const
-{
- return mFontDatabase;
-}
-
-QPlatformNativeInterface * QOpenWFDIntegration::nativeInterface() const
-{
- return mNativeInterface;
-}
-
-QPlatformPrinterSupport * QOpenWFDIntegration::printerSupport() const
-{
- return mPrinterSupport;
-}
diff --git a/src/plugins/platforms/openwfd/qopenwfdintegration.h b/src/plugins/platforms/openwfd/qopenwfdintegration.h
deleted file mode 100644
index 444aaccaaf..0000000000
--- a/src/plugins/platforms/openwfd/qopenwfdintegration.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 QOPENWFDINTEGRATION_H
-#define QOPENWFDINTEGRATION_H
-
-#include <qpa/qplatformintegration.h>
-#include <qpa/qplatformscreen.h>
-
-QT_BEGIN_NAMESPACE
-
-class QOpenWFDDevice;
-class QOpenWFDScreen;
-
-class QOpenWFDIntegration : public QPlatformIntegration
-{
-public:
- QOpenWFDIntegration();
- ~QOpenWFDIntegration();
-
- bool hasCapability(Capability cap) const;
- QPlatformWindow *createPlatformWindow(QWindow *window) const;
- QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const;
- QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const;
-
- //This should not be a factory interface, but rather a accessor
- QAbstractEventDispatcher *createEventDispatcher() const;
-
- QPlatformFontDatabase *fontDatabase() const;
-
- QPlatformNativeInterface *nativeInterface()const;
-
- QPlatformPrinterSupport *printerSupport() const;
-
-private:
- QList<QPlatformScreen *> mScreens;
- QList<QOpenWFDDevice *>mDevices;
-
- QPlatformFontDatabase *mFontDatabase;
- QPlatformNativeInterface *mNativeInterface;
- QPlatformPrinterSupport *mPrinterSupport;
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/plugins/platforms/openwfd/qopenwfdnativeinterface.cpp b/src/plugins/platforms/openwfd/qopenwfdnativeinterface.cpp
deleted file mode 100644
index 8d299c2683..0000000000
--- a/src/plugins/platforms/openwfd/qopenwfdnativeinterface.cpp
+++ /dev/null
@@ -1,139 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 "qopenwfdnativeinterface.h"
-
-#include "qopenwfdscreen.h"
-#include "qopenwfdwindow.h"
-#include "qopenwfdglcontext.h"
-
-#include <private/qguiapplication_p.h>
-#include <QtCore/QMap>
-
-#include <QtCore/QDebug>
-
-#include <QtGui/qguiglcontext_qpa.h>
-
-class QOpenWFDResourceMap : public QMap<QByteArray, QOpenWFDNativeInterface::ResourceType>
-{
-public:
- QOpenWFDResourceMap()
- :QMap<QByteArray, QOpenWFDNativeInterface::ResourceType>()
- {
- insert("wfddevice",QOpenWFDNativeInterface::WFDDevice);
- insert("egldisplay",QOpenWFDNativeInterface::EglDisplay);
- insert("eglcontext",QOpenWFDNativeInterface::EglContext);
- insert("wfdport",QOpenWFDNativeInterface::WFDPort);
- insert("wfdpipeline",QOpenWFDNativeInterface::WFDPipeline);
- }
-};
-
-Q_GLOBAL_STATIC(QOpenWFDResourceMap, qOpenWFDResourceMap)
-
-void *QOpenWFDNativeInterface::nativeResourceForContext(const QByteArray &resourceString, QOpenGLContext *context)
-{
- QByteArray lowerCaseResource = resourceString.toLower();
- ResourceType resource = qOpenWFDResourceMap()->value(lowerCaseResource);
- void *result = 0;
- switch (resource) {
- case EglContext:
- result = eglContextForContext(context);
- break;
- default:
- result = 0;
- }
- return result;
-}
-
-void *QOpenWFDNativeInterface::nativeResourceForWindow(const QByteArray &resourceString, QWindow *window)
-{
- QByteArray lowerCaseResource = resourceString.toLower();
- ResourceType resource = qOpenWFDResourceMap()->value(lowerCaseResource);
- void *result = 0;
- switch (resource) {
- //What should we do for int wfd handles? This is clearly not the solution
- case WFDDevice:
- result = (void *)wfdDeviceForWindow(window);
- break;
- case WFDPort:
- result = (void *)wfdPortForWindow(window);
- break;
- case WFDPipeline:
- result = (void *)wfdPipelineForWindow(window);
- break;
- case EglDisplay:
- result = eglDisplayForWindow(window);
- break;
- default:
- result = 0;
- }
- return result;
-}
-
-WFDHandle QOpenWFDNativeInterface::wfdDeviceForWindow(QWindow *window)
-{
- QOpenWFDWindow *openWFDwindow = static_cast<QOpenWFDWindow *>(window->handle());
- return openWFDwindow->port()->device()->handle();
-}
-
-WFDHandle QOpenWFDNativeInterface::wfdPortForWindow(QWindow *window)
-{
- QOpenWFDWindow *openWFDwindow = static_cast<QOpenWFDWindow *>(window->handle());
- return openWFDwindow->port()->handle();
-}
-
-WFDHandle QOpenWFDNativeInterface::wfdPipelineForWindow(QWindow *window)
-
-{
- QOpenWFDWindow *openWFDwindow = static_cast<QOpenWFDWindow *>(window->handle());
- return openWFDwindow->port()->pipeline();
-
-}
-
-void *QOpenWFDNativeInterface::eglDisplayForWindow(QWindow *window)
-{
- QOpenWFDWindow *openWFDwindow = static_cast<QOpenWFDWindow *>(window->handle());
- return openWFDwindow->port()->device()->eglDisplay();
-}
-
-void * QOpenWFDNativeInterface::eglContextForContext(QOpenGLContext *context)
-{
- QOpenWFDGLContext *openWFDContext = static_cast<QOpenWFDGLContext *>(context->handle());
- return openWFDContext->eglContext();
-}
diff --git a/src/plugins/platforms/openwfd/qopenwfdnativeinterface.h b/src/plugins/platforms/openwfd/qopenwfdnativeinterface.h
deleted file mode 100644
index d50e17ee92..0000000000
--- a/src/plugins/platforms/openwfd/qopenwfdnativeinterface.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 QOPENWFDNATIVEINTERFACE_H
-#define QOPENWFDNATIVEINTERFACE_H
-
-#include <qpa/qplatformnativeinterface.h>
-
-#include <WF/wfdplatform.h>
-
-class QOpenWFDScreen;
-
-class QOpenWFDNativeInterface : public QPlatformNativeInterface
-{
-public:
- enum ResourceType {
- WFDDevice,
- EglDisplay,
- EglContext,
- WFDPort,
- WFDPipeline
- };
-
- void *nativeResourceForContext(const QByteArray &resourceString, QOpenGLContext *context);
- void *nativeResourceForWindow(const QByteArray &resourceString, QWindow *window);
-
- WFDHandle wfdDeviceForWindow(QWindow *window);
- void *eglDisplayForWindow(QWindow *window);
- WFDHandle wfdPortForWindow(QWindow *window);
- WFDHandle wfdPipelineForWindow(QWindow *window);
-
- void *eglContextForContext(QOpenGLContext *context);
-
-private:
- static QOpenWFDScreen *qPlatformScreenForWindow(QWindow *window);
-};
-
-#endif // QOPENWFDNATIVEINTERFACE_H
diff --git a/src/plugins/platforms/openwfd/qopenwfdoutputbuffer.cpp b/src/plugins/platforms/openwfd/qopenwfdoutputbuffer.cpp
deleted file mode 100644
index 4d0de7b0d4..0000000000
--- a/src/plugins/platforms/openwfd/qopenwfdoutputbuffer.cpp
+++ /dev/null
@@ -1,88 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 "qopenwfdoutputbuffer.h"
-
-#include "qopenwfdport.h"
-
-QOpenWFDOutputBuffer::QOpenWFDOutputBuffer(const QSize &size, QOpenWFDPort *port)
- : mPort(port)
- , mAvailable(true)
-{
- qDebug() << "creating output buffer for size" << size;
- glGenRenderbuffers(1,&mRbo);
- glBindRenderbuffer(GL_RENDERBUFFER, mRbo);
-
- mGbm_buffer = gbm_bo_create(port->device()->gbmDevice(),
- size.width(),
- size.height(),
- GBM_BO_FORMAT_XRGB8888,
- GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
-
- mEglImage = port->device()->eglCreateImage(port->device()->eglDisplay(),0, EGL_NATIVE_PIXMAP_KHR, mGbm_buffer, 0);
-
- port->device()->glEglImageTargetRenderBufferStorage(GL_RENDERBUFFER,mEglImage);
-
- mWfdSource = wfdCreateSourceFromImage(port->device()->handle(),port->pipeline(),mEglImage,WFD_NONE);
- if (mWfdSource == WFD_INVALID_HANDLE) {
- qWarning("failed to create wfdSource from image");
- }
-}
-
-QOpenWFDOutputBuffer::~QOpenWFDOutputBuffer()
-{
- wfdDestroySource(mPort->device()->handle(),mWfdSource);
- if (!mPort->device()->eglDestroyImage(mPort->device()->eglDisplay(),mEglImage)) {
- qDebug("could not delete eglImage");
- }
- gbm_bo_destroy(mGbm_buffer);
-
- glDeleteRenderbuffers(1, &mRbo);
-}
-
-void QOpenWFDOutputBuffer::bindToCurrentFbo()
-{
- glFramebufferRenderbuffer(GL_FRAMEBUFFER,
- GL_COLOR_ATTACHMENT0,
- GL_RENDERBUFFER,
- mRbo);
- if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
- qDebug("framebuffer not ready!");
- }
-}
diff --git a/src/plugins/platforms/openwfd/qopenwfdoutputbuffer.h b/src/plugins/platforms/openwfd/qopenwfdoutputbuffer.h
deleted file mode 100644
index 3726237a42..0000000000
--- a/src/plugins/platforms/openwfd/qopenwfdoutputbuffer.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 QOPENWFDOUTPUTBUFFER_H
-#define QOPENWFDOUTPUTBUFFER_H
-
-#include "qopenwfdport.h"
-
-#include <EGL/egl.h>
-#include <GLES2/gl2.h>
-
-class QOpenWFDOutputBuffer
-{
-public:
- QOpenWFDOutputBuffer(const QSize &size, QOpenWFDPort *port);
- ~QOpenWFDOutputBuffer();
- void bindToCurrentFbo();
- bool isAvailable() const { return mAvailable; }
- void setAvailable(bool available) { mAvailable = available; }
-
- WFDSource wfdSource() const { return mWfdSource; }
-private:
- QOpenWFDPort *mPort;
- WFDSource mWfdSource;
- GLuint mRbo;
- EGLImageKHR mEglImage;
- struct gbm_bo *mGbm_buffer;
- bool mAvailable;
-};
-
-#endif // QOPENWFDOUTPUTBUFFER_H
diff --git a/src/plugins/platforms/openwfd/qopenwfdport.cpp b/src/plugins/platforms/openwfd/qopenwfdport.cpp
deleted file mode 100644
index 34b4439958..0000000000
--- a/src/plugins/platforms/openwfd/qopenwfdport.cpp
+++ /dev/null
@@ -1,209 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 "qopenwfdport.h"
-
-#include "qopenwfdportmode.h"
-#include "qopenwfdscreen.h"
-
-#include <QtCore/QDebug>
-
-QOpenWFDPort::QOpenWFDPort(QOpenWFDDevice *device, WFDint portEnumeration)
- : mDevice(device)
- , mPortId(portEnumeration)
- , mAttached(false)
- , mPipelineId(WFD_INVALID_PIPELINE_ID)
- , mPipeline(WFD_INVALID_HANDLE)
-{
- mPort = wfdCreatePort(device->handle(),portEnumeration,0);
- WFDint isPortAttached = wfdGetPortAttribi(device->handle(),mPort,WFD_PORT_ATTACHED);
- if (isPortAttached) {
- attach();
- }
-}
-
-QOpenWFDPort::~QOpenWFDPort()
-{
- detach();
-
- wfdDestroyPort(mDevice->handle(),mPort);
-}
-
-void QOpenWFDPort::attach()
-{
- if (mAttached) {
- return;
- }
-
- //just forcing port to be on
- wfdSetPortAttribi(mDevice->handle(), mPort, WFD_PORT_POWER_MODE, WFD_POWER_MODE_ON);
-
- int numberOfPortModes = wfdGetPortModes(mDevice->handle(),mPort,0,0);
- WFDPortMode portModes[numberOfPortModes];
- int actualNumberOfPortModes = wfdGetPortModes(mDevice->handle(),mPort,portModes,numberOfPortModes);
- Q_ASSERT(actualNumberOfPortModes == numberOfPortModes);
-
- if (!actualNumberOfPortModes) {
- qDebug("didn't find any available port modes");
- return;
- }
-
- for (int i = 0; i < actualNumberOfPortModes; i++) {
- if (portModes[i] != WFD_INVALID_HANDLE) {
- mPortModes.append(QOpenWFDPortMode(this,portModes[i]));
- qDebug() << "PortModeAdded:" << mPortModes.at(mPortModes.size()-1);
- }
- }
-
-
- mPixelSize = setNativeResolutionMode();
- if (mPixelSize.isEmpty()) {
- qDebug("Could not set native resolution mode in QOpenWFPort");
- }
-
- WFDfloat physicalWFDSize[2];
- wfdGetPortAttribfv(mDevice->handle(),mPort,WFD_PORT_PHYSICAL_SIZE,2,physicalWFDSize);
- mPhysicalSize = QSizeF(physicalWFDSize[0],physicalWFDSize[1]);
-
- WFDint numAvailablePipelines = wfdGetPortAttribi(mDevice->handle(),mPort,WFD_PORT_PIPELINE_ID_COUNT);
- if (Q_UNLIKELY(!numAvailablePipelines))
- qFatal("Not possible to make screen that is not possible to create WFPort with no pipline");
-
- WFDint pipeIds[numAvailablePipelines];
- wfdGetPortAttribiv(mDevice->handle(),mPort,WFD_PORT_BINDABLE_PIPELINE_IDS,numAvailablePipelines,pipeIds);
-
- for (int i = 0; i < numAvailablePipelines; i++) {
- if (pipeIds[i] != WFD_INVALID_PIPELINE_ID && !mDevice->isPipelineUsed(pipeIds[i])) {
- mPipelineId = pipeIds[i];
- mDevice-> addToUsedPipelineSet(mPipelineId,this);
-
- mPipeline = wfdCreatePipeline(mDevice->handle(),mPipelineId,WFD_NONE);
- if (Q_UNLIKELY(mPipeline == WFD_INVALID_HANDLE))
- qFatal("Failed to create pipeline for port %p", this);
-
- break;
- }
- }
-
- if (mPipeline == WFD_INVALID_HANDLE) {
- qWarning("Failed to create pipeline and can't bind it to port");
- }
-
- WFDint geomerty[] = { 0, 0, mPixelSize.width(), mPixelSize.height() };
-
- wfdSetPipelineAttribiv(mDevice->handle(),mPipeline, WFD_PIPELINE_SOURCE_RECTANGLE, 4, geomerty);
- wfdSetPipelineAttribiv(mDevice->handle(),mPipeline, WFD_PIPELINE_DESTINATION_RECTANGLE, 4, geomerty);
-
- wfdBindPipelineToPort(mDevice->handle(),mPort,mPipeline);
-
- mScreen = new QOpenWFDScreen(this);
- QWindowSystemInterface::handleScreenAdded(mScreen);
- mAttached = true;
-}
-
-void QOpenWFDPort::detach()
-{
- if (!mAttached)
- return;
-
- mAttached = false;
- mOn = false;
-
- QWindowSystemInterface::handleScreenRemoved(mScreen);
-
- wfdDestroyPipeline(mDevice->handle(),mPipeline);
- mPipelineId = WFD_INVALID_PIPELINE_ID;
- mPipeline = WFD_INVALID_HANDLE;
-}
-
-bool QOpenWFDPort::attached() const
-{
- return mAttached;
-}
-
-QSize QOpenWFDPort::setNativeResolutionMode()
-{
- WFDint nativePixelSize[2];
- wfdGetPortAttribiv(device()->handle(),mPort,WFD_PORT_NATIVE_RESOLUTION,2,nativePixelSize);
- QSize nativeSize(nativePixelSize[0],nativePixelSize[1]);
-
- for (int i = 0; i < mPortModes.size(); i++) {
- const QOpenWFDPortMode &mode = mPortModes.at(i);
- if (nativeSize == mode.size()) {
- wfdSetPortMode(device()->handle(),mPort,mode.handle());
- return nativeSize;
- }
- }
- return QSize();
-}
-
-QSize QOpenWFDPort::pixelSize() const
-{
- return mPixelSize;
-}
-
-QSizeF QOpenWFDPort::physicalSize() const
-{
- return mPhysicalSize;
-}
-
-QOpenWFDDevice * QOpenWFDPort::device() const
-{
- return mDevice;
-}
-
-WFDPort QOpenWFDPort::handle() const
-{
- return mPort;
-}
-
-WFDint QOpenWFDPort::portId() const
-{
- return mPortId;
-}
-
-WFDPipeline QOpenWFDPort::pipeline() const
-{
- return mPipeline;
-}
-
-QOpenWFDScreen * QOpenWFDPort::screen() const
-{
- return mScreen;
-}
diff --git a/src/plugins/platforms/openwfd/qopenwfdport.h b/src/plugins/platforms/openwfd/qopenwfdport.h
deleted file mode 100644
index dc8357961f..0000000000
--- a/src/plugins/platforms/openwfd/qopenwfdport.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 QOPENWFDPORT_H
-#define QOPENWFDPORT_H
-
-#include "qopenwfddevice.h"
-#include "qopenwfdportmode.h"
-
-#include <WF/wfd.h>
-
-class QOpenWFDPort
-{
-public:
- QOpenWFDPort(QOpenWFDDevice *device, WFDint portEnumeration);
- ~QOpenWFDPort();
- void attach();
- void detach();
- bool attached() const;
-
- QSize setNativeResolutionMode();
-
- QSize pixelSize() const;
- QSizeF physicalSize() const;
-
- QOpenWFDDevice *device() const;
- WFDPort handle() const;
- WFDint portId() const;
- WFDPipeline pipeline() const;
- QOpenWFDScreen *screen() const;
-
-private:
- QOpenWFDDevice *mDevice;
- WFDPort mPort;
- WFDint mPortId;
-
- QList<QOpenWFDPortMode> mPortModes;
-
- bool mAttached;
- bool mOn;
- QSize mPixelSize;
- QSizeF mPhysicalSize;
-
- QOpenWFDScreen *mScreen;
-
- WFDint mPipelineId;
- WFDPipeline mPipeline;
-
-};
-
-#endif // QOPENWFDPORT_H
diff --git a/src/plugins/platforms/openwfd/qopenwfdportmode.cpp b/src/plugins/platforms/openwfd/qopenwfdportmode.cpp
deleted file mode 100644
index 26da69ea95..0000000000
--- a/src/plugins/platforms/openwfd/qopenwfdportmode.cpp
+++ /dev/null
@@ -1,61 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 "qopenwfdportmode.h"
-
-#include "qopenwfdport.h"
-
-QOpenWFDPortMode::QOpenWFDPortMode(QOpenWFDPort *port, WFDPortMode portMode)
- : mPortMode(portMode)
-{
- int width = wfdGetPortModeAttribi(port->device()->handle(),port->handle(),portMode,WFD_PORT_MODE_WIDTH);
- int height = wfdGetPortModeAttribi(port->device()->handle(),port->handle(),portMode,WFD_PORT_MODE_HEIGHT);
- mSize = QSize(width,height);
-
- mRefresh = wfdGetPortModeAttribf(port->device()->handle(),port->handle(),portMode,WFD_PORT_MODE_REFRESH_RATE);
- mFlipMirror = wfdGetPortModeAttribi(port->device()->handle(),port->handle(),portMode,WFD_PORT_MODE_FLIP_MIRROR_SUPPORT);
- mInterlaced = wfdGetPortModeAttribi(port->device()->handle(), port->handle(),portMode,WFD_PORT_MODE_INTERLACED);
-}
-
-QDebug operator<<(QDebug s, const QOpenWFDPortMode &portMode)
-{
- s.nospace() << "QOpenWFPortMode( " << portMode.size() << " Refreash: " << portMode.refreshRate()
- << " FlipMirror: " << portMode.flipMirror() << " Interlaced: " << portMode.interlaced();
- return s;
-}
diff --git a/src/plugins/platforms/openwfd/qopenwfdportmode.h b/src/plugins/platforms/openwfd/qopenwfdportmode.h
deleted file mode 100644
index acce9e0b2e..0000000000
--- a/src/plugins/platforms/openwfd/qopenwfdportmode.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 QOPENWFDPORTMODE_H
-#define QOPENWFDPORTMODE_H
-
-#include <WF/wfd.h>
-
-#include <QtCore/QSize>
-
-#include <QtCore/QDebug>
-
-class QOpenWFDPort;
-
-class QOpenWFDPortMode
-{
-public:
- QOpenWFDPortMode(QOpenWFDPort *port, WFDPortMode portMode);
-
- QSize size() const {return mSize;}
- qreal refreshRate() const { return mRefresh; }
- bool flipMirror() const { return mFlipMirror; }
- bool interlaced() const { return mInterlaced; }
-
- WFDPortMode handle() const { return mPortMode; }
-private:
- WFDPortMode mPortMode;
-
- QSize mSize;
- qreal mRefresh;
- bool mFlipMirror;
- bool mInterlaced;
-};
-
-QDebug operator<<(QDebug, const QOpenWFDPortMode &);
-#endif // QOPENWFPORTMODE_H
diff --git a/src/plugins/platforms/openwfd/qopenwfdscreen.cpp b/src/plugins/platforms/openwfd/qopenwfdscreen.cpp
deleted file mode 100644
index ab394fa594..0000000000
--- a/src/plugins/platforms/openwfd/qopenwfdscreen.cpp
+++ /dev/null
@@ -1,190 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 "qopenwfdscreen.h"
-
-#include "qopenwfdport.h"
-#include "qopenwfdoutputbuffer.h"
-
-#include <QtGui/QGuiApplication>
-
-QOpenWFDScreen::QOpenWFDScreen(QOpenWFDPort *port)
- : mPort(port)
- , mFbo(0)
- , mOutputBuffers(BUFFER_NUM)
- , mCurrentRenderBufferIndex(0)
- , mStagedBackBufferIndex(-1)
- , mCommitedBackBufferIndex(-1)
- , mBackBufferIndex(-1)
-{
- printf ("\n");
- printf ("Information of screen %p:\n", this);
- printf (" width..........: %d\n", port->pixelSize().width());
- printf (" height.........: %d\n", port->pixelSize().height());
- printf (" physical width.: %f\n", port->physicalSize().width());
- printf (" physical height: %f\n", port->physicalSize().height());
- printf ("\n");
-
- EGLDisplay display = mPort->device()->eglDisplay();
- EGLContext context = mPort->device()->eglContext();
-
- if (!eglMakeCurrent(display,EGL_NO_SURFACE,EGL_NO_SURFACE,context)) {
- qDebug("screen: eglMakeCurrent FAILED");
- }
-
- glGenFramebuffers(1,&mFbo);
- glBindFramebuffer(GL_FRAMEBUFFER,mFbo);
-
- for (int i = 0; i < mOutputBuffers.size(); i++) {
- mOutputBuffers[i] = new QOpenWFDOutputBuffer(mPort->pixelSize(),mPort);
- }
-
- mStagedBackBufferIndex = mOutputBuffers.size()-1;
- mOutputBuffers[mStagedBackBufferIndex]->setAvailable(false);;
- commitStagedOutputBuffer();
-
- mOutputBuffers.at(mCurrentRenderBufferIndex)->bindToCurrentFbo();
-
- if (mPort->device()->isDeviceInitializedAndCommited()) {
- mPort->device()->commit(WFD_COMMIT_ENTIRE_PORT,mPort->handle());
- }
-
-}
-
-QOpenWFDScreen::~QOpenWFDScreen()
-{
- for (int i = 0; i < mOutputBuffers.size(); i++) {
- delete mOutputBuffers[i];
- }
- glDeleteFramebuffers(1, &mFbo);
-}
-
-QRect QOpenWFDScreen::geometry() const
-{
- return QRect(QPoint(),mPort->pixelSize());
-}
-
-int QOpenWFDScreen::depth() const
-{
- return 32;
-}
-
-QImage::Format QOpenWFDScreen::format() const
-{
- return QImage::Format_RGB32;
-}
-
-QSizeF QOpenWFDScreen::physicalSize() const
-{
- return mPort->physicalSize();
-}
-
-QOpenWFDPort * QOpenWFDScreen::port() const
-{
- return mPort;
-}
-
-void QOpenWFDScreen::swapBuffers()
-{
- glFlush();
-
- setStagedBackBuffer(mCurrentRenderBufferIndex);
- mCurrentRenderBufferIndex = nextAvailableRenderBuffer();
-
- bindFramebuffer();
- mOutputBuffers.at(mCurrentRenderBufferIndex)->bindToCurrentFbo();
-}
-
-void QOpenWFDScreen::bindFramebuffer()
-{
- glBindFramebuffer(GL_FRAMEBUFFER,mFbo);
-}
-
-void QOpenWFDScreen::setStagedBackBuffer(int bufferIndex)
-{
- if (mStagedBackBufferIndex >= 0) {
- mOutputBuffers[mStagedBackBufferIndex]->setAvailable(true);
- }
-
- mOutputBuffers[bufferIndex]->setAvailable(false);;
- mStagedBackBufferIndex = bufferIndex;
-
- if (mCommitedBackBufferIndex < 0) {
- commitStagedOutputBuffer();
- }
-}
-
-void QOpenWFDScreen::commitStagedOutputBuffer()
-{
- Q_ASSERT(mStagedBackBufferIndex >= 0);
- wfdBindSourceToPipeline(mPort->device()->handle(),
- mPort->pipeline(),
- mOutputBuffers.at(mStagedBackBufferIndex)->wfdSource(),
- WFD_TRANSITION_AT_VSYNC,
- 0);
- mPort->device()->commit(WFD_COMMIT_PIPELINE,mPort->pipeline());
- mCommitedBackBufferIndex = mStagedBackBufferIndex;
- mStagedBackBufferIndex = -1;
-}
-
-int QOpenWFDScreen::nextAvailableRenderBuffer() const
-{
- while (true) {
- for (int i = 0; i < mOutputBuffers.size(); i++) {
- if (mOutputBuffers.at(i)->isAvailable()) {
- return i;
- }
- }
- mPort->device()->waitForPipelineBindSourceCompleteEvent();
- }
-}
-
-void QOpenWFDScreen::pipelineBindSourceComplete()
-{
- if (mBackBufferIndex >= 0) {
- mOutputBuffers[mBackBufferIndex]->setAvailable(true);
- }
-
- mBackBufferIndex = mCommitedBackBufferIndex;
- mCommitedBackBufferIndex = -1;
-
- if (mStagedBackBufferIndex >= 0) {
- commitStagedOutputBuffer();
- }
-}
diff --git a/src/plugins/platforms/openwfd/qopenwfdscreen.h b/src/plugins/platforms/openwfd/qopenwfdscreen.h
deleted file mode 100644
index dec51d306b..0000000000
--- a/src/plugins/platforms/openwfd/qopenwfdscreen.h
+++ /dev/null
@@ -1,88 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 QOPENWFDSCREEN_H
-#define QOPENWFDSCREEN_H
-
-#include <qpa/qplatformscreen.h>
-
-
-#include "qopenwfdoutputbuffer.h"
-
-#include <WF/wfd.h>
-
-#include <QtCore/QVarLengthArray>
-
-#define BUFFER_NUM 4
-
-class QOpenWFDPort;
-class QOpenWFDScreen : public QPlatformScreen
-{
-public:
- QOpenWFDScreen(QOpenWFDPort *port);
- ~QOpenWFDScreen();
-
- QRect geometry() const;
- int depth() const;
- QImage::Format format() const;
- QSizeF physicalSize() const;
-
- QOpenWFDPort *port() const;
-
- void swapBuffers();
- void bindFramebuffer();
- void pipelineBindSourceComplete();
-
-private:
- void setStagedBackBuffer(int bufferIndex);
- void commitStagedOutputBuffer();
- int nextAvailableRenderBuffer() const;
-
- QOpenWFDPort *mPort;
-
- GLuint mFbo;
-
- QVarLengthArray<QOpenWFDOutputBuffer *, BUFFER_NUM> mOutputBuffers;
- int mCurrentRenderBufferIndex;
- int mStagedBackBufferIndex;
- int mCommitedBackBufferIndex;
- int mBackBufferIndex;
-};
-
-#endif
diff --git a/src/plugins/platforms/openwfd/qopenwfdwindow.cpp b/src/plugins/platforms/openwfd/qopenwfdwindow.cpp
deleted file mode 100644
index 9320c19bbe..0000000000
--- a/src/plugins/platforms/openwfd/qopenwfdwindow.cpp
+++ /dev/null
@@ -1,59 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 "qopenwfdwindow.h"
-
-#include "qopenwfdscreen.h"
-#include <qpa/qwindowsysteminterface.h>
-
-QOpenWFDWindow::QOpenWFDWindow(QWindow *window)
- : QPlatformWindow(window)
-{
-
- QPlatformScreen *platformScreen = QPlatformScreen::platformScreenForWindow(window);
- mPort = static_cast<QOpenWFDScreen *>(platformScreen)->port();
-
- QWindowSystemInterface::handleGeometryChange(window,QRect(QPoint(0,0),mPort->screen()->geometry().size()));
-}
-
-QOpenWFDPort *QOpenWFDWindow::port() const
-{
- return mPort;
-}
-
diff --git a/src/plugins/platforms/openwfd/qopenwfdwindow.h b/src/plugins/platforms/openwfd/qopenwfdwindow.h
deleted file mode 100644
index 2cb131b65b..0000000000
--- a/src/plugins/platforms/openwfd/qopenwfdwindow.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 QOPENWFDWINDOW_H
-#define QOPENWFDWINDOW_H
-
-#include <qpa/qplatformwindow.h>
-#include <QtCore/QVarLengthArray>
-
-#include "qopenwfdport.h"
-
-class QOpenWFDWindow : public QPlatformWindow
-{
-public:
- QOpenWFDWindow(QWindow *window);
-
- QOpenWFDPort *port() const;
-
-private:
- QOpenWFDPort *mPort;
-};
-
-#endif // QOPENWFWINDOW_H
diff --git a/src/plugins/platforms/platforms.pro b/src/plugins/platforms/platforms.pro
deleted file mode 100644
index c4f2b30965..0000000000
--- a/src/plugins/platforms/platforms.pro
+++ /dev/null
@@ -1,51 +0,0 @@
-TEMPLATE = subdirs
-QT_FOR_CONFIG += gui-private
-
-android:!android-embedded: SUBDIRS += android
-
-!android: SUBDIRS += minimal
-
-!android:qtConfig(freetype): SUBDIRS += offscreen
-
-qtConfig(xcb) {
- SUBDIRS += xcb
-}
-
-uikit:!watchos: SUBDIRS += ios
-osx: SUBDIRS += cocoa
-
-win32:!winrt:qtConfig(direct3d9): SUBDIRS += windows
-winrt:qtConfig(direct3d11): SUBDIRS += winrt
-
-qtConfig(direct3d11_1):qtConfig(direct2d1_1):qtConfig(directwrite1) {
- SUBDIRS += direct2d
-}
-
-qnx {
- SUBDIRS += qnx
-}
-
-qtConfig(eglfs) {
- SUBDIRS += eglfs
- SUBDIRS += minimalegl
-}
-
-qtConfig(directfb) {
- SUBDIRS += directfb
-}
-
-qtConfig(linuxfb): SUBDIRS += linuxfb
-
-qtHaveModule(network):qtConfig(vnc): SUBDIRS += vnc
-
-freebsd {
- SUBDIRS += bsdfb
-}
-
-haiku {
- SUBDIRS += haiku
-}
-
-wasm: SUBDIRS += wasm
-
-qtConfig(integrityfb): SUBDIRS += integrity
diff --git a/src/plugins/platforms/qnx/CMakeLists.txt b/src/plugins/platforms/qnx/CMakeLists.txt
new file mode 100644
index 0000000000..9fb412d8a4
--- /dev/null
+++ b/src/plugins/platforms/qnx/CMakeLists.txt
@@ -0,0 +1,93 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## QQnxIntegrationPlugin Plugin:
+#####################################################################
+
+qt_internal_add_plugin(QQnxIntegrationPlugin
+ OUTPUT_NAME qqnx
+ PLUGIN_TYPE platforms
+ DEFAULT_IF ${QT_QPA_DEFAULT_PLATFORM} MATCHES qnx
+ SOURCES
+ main.cpp main.h
+ qqnxabstractcover.h
+ qqnxabstractnavigator.cpp qqnxabstractnavigator.h
+ qqnxabstractvirtualkeyboard.cpp qqnxabstractvirtualkeyboard.h
+ qqnxbuffer.cpp qqnxbuffer.h
+ qqnxcursor.cpp qqnxcursor.h
+ qqnxforeignwindow.cpp qqnxforeignwindow.h
+ qqnxglobal.cpp qqnxglobal.h
+ qqnxintegration.cpp qqnxintegration.h
+ qqnxkeytranslator.h
+ qqnxlgmon.h
+ qqnxnativeinterface.cpp qqnxnativeinterface.h
+ qqnxnavigatoreventhandler.cpp qqnxnavigatoreventhandler.h
+ qqnxrasterbackingstore.cpp qqnxrasterbackingstore.h
+ qqnxrasterwindow.cpp qqnxrasterwindow.h
+ qqnxscreen.cpp qqnxscreen.h
+ qqnxscreeneventfilter.h
+ qqnxscreeneventhandler.cpp qqnxscreeneventhandler.h
+ qqnxscreeneventthread.cpp qqnxscreeneventthread.h
+ qqnxservices.cpp qqnxservices.h
+ qqnxwindow.cpp qqnxwindow.h
+ NO_PCH_SOURCES
+ qqnxclipboard.cpp # undef QT_NO_FOREACH
+ qqnxintegration.cpp # undef QT_NO_FOREACH
+ qqnxscreen.cpp # undef QT_NO_FOREACH
+ qqnxscreeneventhandler.cpp # undef QT_NO_FOREACH
+ qqnxwindow.cpp # undef QT_NO_FOREACH
+ LIBRARIES
+ Qt::Core
+ Qt::CorePrivate
+ Qt::Gui
+ Qt::GuiPrivate
+ screen
+)
+
+## Scopes:
+#####################################################################
+
+qt_internal_extend_target(QQnxIntegrationPlugin CONDITION QT_FEATURE_egl
+ SOURCES
+ qqnxeglwindow.cpp qqnxeglwindow.h
+ qqnxglcontext.cpp qqnxglcontext.h
+ LIBRARIES
+ EGL::EGL
+)
+
+qt_internal_extend_target(QQnxIntegrationPlugin CONDITION QT_FEATURE_qqnx_pps
+ SOURCES
+ qqnxbuttoneventnotifier.cpp qqnxbuttoneventnotifier.h
+ qqnxnavigatoreventnotifier.cpp qqnxnavigatoreventnotifier.h
+ qqnxnavigatorpps.cpp qqnxnavigatorpps.h
+ qqnxvirtualkeyboardpps.cpp qqnxvirtualkeyboardpps.h
+ LIBRARIES
+ PPS::PPS
+)
+
+qt_internal_extend_target(QQnxIntegrationPlugin CONDITION QT_FEATURE_clipboard AND QT_FEATURE_qqnx_pps
+ SOURCES
+ qqnxclipboard.cpp qqnxclipboard.h
+ LIBRARIES
+ clipboard
+)
+
+qt_internal_extend_target(QQnxIntegrationPlugin CONDITION QT_FEATURE_qqnx_imf AND QT_FEATURE_qqnx_pps
+ SOURCES
+ qqnxinputcontext_imf.cpp qqnxinputcontext_imf.h
+)
+
+qt_internal_extend_target(QQnxIntegrationPlugin CONDITION QT_FEATURE_qqnx_pps AND NOT QT_FEATURE_qqnx_imf
+ SOURCES
+ qqnxinputcontext_noimf.cpp qqnxinputcontext_noimf.h
+)
+
+qt_internal_extend_target(QQnxIntegrationPlugin CONDITION lgmon
+ SOURCES
+ qqnxlgmon.cpp
+ DEFINES
+ QQNX_LGMON
+ LIBRARIES
+ lgmon
+)
diff --git a/src/plugins/platforms/qnx/main.cpp b/src/plugins/platforms/qnx/main.cpp
index b5869fa603..e5656d7cb9 100644
--- a/src/plugins/platforms/qnx/main.cpp
+++ b/src/plugins/platforms/qnx/main.cpp
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2011 - 2014 BlackBerry Limited. All rights reserved.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2011 - 2014 BlackBerry Limited. All rights reserved.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "main.h"
#include "qqnxintegration.h"
@@ -43,9 +7,11 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
QPlatformIntegration *QQnxIntegrationPlugin::create(const QString& system, const QStringList& paramList)
{
- if (!system.compare(QLatin1String("qnx"), Qt::CaseInsensitive)) {
+ if (!system.compare("qnx"_L1, Qt::CaseInsensitive)) {
qqnxLgmonInit();
return new QQnxIntegration(paramList);
}
diff --git a/src/plugins/platforms/qnx/main.h b/src/plugins/platforms/qnx/main.h
index 5d5bf95686..155e0ec9a6 100644
--- a/src/plugins/platforms/qnx/main.h
+++ b/src/plugins/platforms/qnx/main.h
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2011 - 2012 Research In Motion
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2011 - 2012 Research In Motion
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <qpa/qplatformintegrationplugin.h>
diff --git a/src/plugins/platforms/qnx/qnx.pro b/src/plugins/platforms/qnx/qnx.pro
deleted file mode 100644
index bfd56e8d13..0000000000
--- a/src/plugins/platforms/qnx/qnx.pro
+++ /dev/null
@@ -1,125 +0,0 @@
-TARGET = qqnx
-
-QT += \
- core-private gui-private \
- fontdatabase_support-private eventdispatcher_support-private egl_support-private
-
-# Uncomment this to build with support for IMF once it becomes available in the BBNDK
-#CONFIG += qqnx_imf
-
-# Uncomment these to enable debugging output for various aspects of the plugin
-#DEFINES += QQNXBUFFER_DEBUG
-#DEFINES += QQNXBUTTON_DEBUG
-#DEFINES += QQNXCLIPBOARD_DEBUG
-#DEFINES += QQNXFILEDIALOGHELPER_DEBUG
-#DEFINES += QQNXGLBACKINGSTORE_DEBUG
-#DEFINES += QQNXGLCONTEXT_DEBUG
-#DEFINES += QQNXINPUTCONTEXT_DEBUG
-#DEFINES += QQNXINPUTCONTEXT_IMF_EVENT_DEBUG
-#DEFINES += QQNXINTEGRATION_DEBUG
-#DEFINES += QQNXNAVIGATOREVENTHANDLER_DEBUG
-#DEFINES += QQNXNAVIGATOREVENTNOTIFIER_DEBUG
-#DEFINES += QQNXNAVIGATOR_DEBUG
-#DEFINES += QQNXRASTERBACKINGSTORE_DEBUG
-#DEFINES += QQNXSCREENEVENTTHREAD_DEBUG
-#DEFINES += QQNXSCREENEVENT_DEBUG
-#DEFINES += QQNXSCREEN_DEBUG
-#DEFINES += QQNXVIRTUALKEYBOARD_DEBUG
-#DEFINES += QQNXWINDOW_DEBUG
-#DEFINES += QQNXCURSOR_DEBUG
-#DEFINES += QQNXFILEPICKER_DEBUG
-#DEFINES += QQNXEGLWINDOW_DEBUG
-#DEFINES += QQNXRASTERWINDOW_DEBUG
-
-SOURCES = main.cpp \
- qqnxbuffer.cpp \
- qqnxforeignwindow.cpp \
- qqnxintegration.cpp \
- qqnxscreen.cpp \
- qqnxwindow.cpp \
- qqnxrasterbackingstore.cpp \
- qqnxscreeneventhandler.cpp \
- qqnxnativeinterface.cpp \
- qqnxnavigatoreventhandler.cpp \
- qqnxabstractnavigator.cpp \
- qqnxabstractvirtualkeyboard.cpp \
- qqnxservices.cpp \
- qqnxcursor.cpp \
- qqnxrasterwindow.cpp \
- qqnxglobal.cpp \
- qqnxscreeneventthread.cpp
-
-HEADERS = main.h \
- qqnxbuffer.h \
- qqnxforeignwindow.h \
- qqnxkeytranslator.h \
- qqnxintegration.h \
- qqnxscreen.h \
- qqnxwindow.h \
- qqnxrasterbackingstore.h \
- qqnxscreeneventhandler.h \
- qqnxnativeinterface.h \
- qqnxnavigatoreventhandler.h \
- qqnxabstractnavigator.h \
- qqnxabstractvirtualkeyboard.h \
- qqnxabstractcover.h \
- qqnxservices.h \
- qqnxcursor.h \
- qqnxrasterwindow.h \
- qqnxscreeneventfilter.h \
- qqnxglobal.h \
- qqnxlgmon.h \
- qqnxscreeneventthread.h
-
-LIBS += -lscreen
-
-qtConfig(egl) {
- SOURCES += qqnxglcontext.cpp \
- qqnxeglwindow.cpp
-
- HEADERS += qqnxglcontext.h \
- qqnxeglwindow.h
-
- QMAKE_USE += egl
-}
-
-qtConfig(qqnx_pps) {
- SOURCES += qqnxbuttoneventnotifier.cpp \
- qqnxnavigatorpps.cpp \
- qqnxnavigatoreventnotifier.cpp \
- qqnxvirtualkeyboardpps.cpp
-
- HEADERS += qqnxbuttoneventnotifier.h \
- qqnxnavigatorpps.h \
- qqnxnavigatoreventnotifier.h \
- qqnxvirtualkeyboardpps.h
-
- QMAKE_USE += pps
-
- qtConfig(clipboard) {
- SOURCES += qqnxclipboard.cpp
- HEADERS += qqnxclipboard.h
- LIBS += -lclipboard
- }
-
- qtConfig(qqnx_imf) {
- HEADERS += qqnxinputcontext_imf.h
- SOURCES += qqnxinputcontext_imf.cpp
- } else {
- HEADERS += qqnxinputcontext_noimf.h
- SOURCES += qqnxinputcontext_noimf.cpp
- }
-}
-
-lgmon {
- DEFINES += QQNX_LGMON
- SOURCES += qqnxlgmon.cpp
- QMAKE_USE += lgmon
-}
-
-OTHER_FILES += qnx.json
-
-PLUGIN_TYPE = platforms
-PLUGIN_CLASS_NAME = QQnxIntegrationPlugin
-!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = -
-load(qt_plugin)
diff --git a/src/plugins/platforms/qnx/qqnxabstractcover.h b/src/plugins/platforms/qnx/qqnxabstractcover.h
index f2838c8477..bb3be00364 100644
--- a/src/plugins/platforms/qnx/qqnxabstractcover.h
+++ b/src/plugins/platforms/qnx/qqnxabstractcover.h
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2013 BlackBerry Limited. All rights reserved.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2013 BlackBerry Limited. All rights reserved.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQNXABSTRACTCOVER_H
#define QQNXABSTRACTCOVER_H
diff --git a/src/plugins/platforms/qnx/qqnxabstractnavigator.cpp b/src/plugins/platforms/qnx/qqnxabstractnavigator.cpp
index a395599832..05389d3ea6 100644
--- a/src/plugins/platforms/qnx/qqnxabstractnavigator.cpp
+++ b/src/plugins/platforms/qnx/qqnxabstractnavigator.cpp
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2012 Research In Motion
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2012 Research In Motion
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqnxabstractnavigator.h"
diff --git a/src/plugins/platforms/qnx/qqnxabstractnavigator.h b/src/plugins/platforms/qnx/qqnxabstractnavigator.h
index 24e28dae96..b4e4dd9bf8 100644
--- a/src/plugins/platforms/qnx/qqnxabstractnavigator.h
+++ b/src/plugins/platforms/qnx/qqnxabstractnavigator.h
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2012 Research In Motion
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2012 Research In Motion
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQNXABSTRACTNAVIGATOR_H
#define QQNXABSTRACTNAVIGATOR_H
@@ -50,7 +14,7 @@ class QQnxAbstractNavigator : public QObject
{
Q_OBJECT
public:
- explicit QQnxAbstractNavigator(QObject *parent = 0);
+ explicit QQnxAbstractNavigator(QObject *parent = nullptr);
~QQnxAbstractNavigator();
bool invokeUrl(const QUrl &url);
diff --git a/src/plugins/platforms/qnx/qqnxabstractvirtualkeyboard.cpp b/src/plugins/platforms/qnx/qqnxabstractvirtualkeyboard.cpp
index 7e639a7ea6..3549bccf40 100644
--- a/src/plugins/platforms/qnx/qqnxabstractvirtualkeyboard.cpp
+++ b/src/plugins/platforms/qnx/qqnxabstractvirtualkeyboard.cpp
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2013 BlackBerry Limited. All rights reserved.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2013 BlackBerry Limited. All rights reserved.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqnxabstractvirtualkeyboard.h"
@@ -149,6 +113,8 @@ QQnxAbstractVirtualKeyboard::EnterKeyType
case Qt::EnterKeyPrevious: // unsupported
return DefaultReturn;
}
+ Q_UNREACHABLE();
+ return DefaultReturn;
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/qnx/qqnxabstractvirtualkeyboard.h b/src/plugins/platforms/qnx/qqnxabstractvirtualkeyboard.h
index 24be03b46c..8c34cabb20 100644
--- a/src/plugins/platforms/qnx/qqnxabstractvirtualkeyboard.h
+++ b/src/plugins/platforms/qnx/qqnxabstractvirtualkeyboard.h
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2013 BlackBerry Limited. All rights reserved.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2013 BlackBerry Limited. All rights reserved.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQNXABSTRACTVIRTUALKEYBOARD_H
#define QQNXABSTRACTVIRTUALKEYBOARD_H
@@ -64,7 +28,7 @@ public:
enum KeyboardMode { Default, Url, Email, Web, NumPunc, Number, Symbol, Phone, Pin, Password, Alphanumeric };
enum EnterKeyType { DefaultReturn, Connect, Done, Go, Join, Next, Search, Send, Submit };
- explicit QQnxAbstractVirtualKeyboard(QObject *parent = 0);
+ explicit QQnxAbstractVirtualKeyboard(QObject *parent = nullptr);
virtual bool showKeyboard() = 0;
virtual bool hideKeyboard() = 0;
diff --git a/src/plugins/platforms/qnx/qqnxbuffer.cpp b/src/plugins/platforms/qnx/qqnxbuffer.cpp
index cd05a679b1..1ea9a8b0d3 100644
--- a/src/plugins/platforms/qnx/qqnxbuffer.cpp
+++ b/src/plugins/platforms/qnx/qqnxbuffer.cpp
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2011 - 2012 Research In Motion
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2011 - 2012 Research In Motion
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqnxglobal.h"
@@ -77,7 +41,7 @@ QQnxBuffer::QQnxBuffer(screen_buffer_t buffer)
// Get access to buffer's data
errno = 0;
- uchar *dataPtr = 0;
+ uchar *dataPtr = nullptr;
Q_SCREEN_CRITICALERROR(
screen_get_buffer_property_pv(buffer, SCREEN_PROPERTY_POINTER, (void **)&dataPtr),
"Failed to query buffer pointer");
diff --git a/src/plugins/platforms/qnx/qqnxbuffer.h b/src/plugins/platforms/qnx/qqnxbuffer.h
index 9ee0d5d60c..b8f1443ad1 100644
--- a/src/plugins/platforms/qnx/qqnxbuffer.h
+++ b/src/plugins/platforms/qnx/qqnxbuffer.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2011 - 2012 Research In Motion
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2011 - 2012 Research In Motion
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQNXBUFFER_H
#define QQNXBUFFER_H
@@ -55,8 +19,8 @@ public:
virtual ~QQnxBuffer();
screen_buffer_t nativeBuffer() const { return m_buffer; }
- const QImage *image() const { return (m_buffer != 0) ? &m_image : 0; }
- QImage *image() { return (m_buffer != 0) ? &m_image : 0; }
+ const QImage *image() const { return (m_buffer != nullptr) ? &m_image : nullptr; }
+ QImage *image() { return (m_buffer != nullptr) ? &m_image : nullptr; }
QRect rect() const { return m_image.rect(); }
diff --git a/src/plugins/platforms/qnx/qqnxbuttoneventnotifier.cpp b/src/plugins/platforms/qnx/qqnxbuttoneventnotifier.cpp
index a6236f2376..6497367579 100644
--- a/src/plugins/platforms/qnx/qqnxbuttoneventnotifier.cpp
+++ b/src/plugins/platforms/qnx/qqnxbuttoneventnotifier.cpp
@@ -1,47 +1,13 @@
-/***************************************************************************
-**
-** Copyright (C) 2012 Research In Motion
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2012 Research In Motion
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqnxbuttoneventnotifier.h"
#include <QtGui/QGuiApplication>
#include <qpa/qwindowsysteminterface.h>
+#include <QtCore/qhash.h>
+#include <QtCore/qbytearray.h>
#include <QtCore/QDebug>
#include <QtCore/QMetaEnum>
#include <QtCore/QSocketNotifier>
@@ -55,8 +21,8 @@
QT_BEGIN_NAMESPACE
-static const char *ppsPath = "/pps/system/buttons/status";
-static const int ppsBufferSize = 256;
+const char *QQnxButtonEventNotifier::ppsPath = "/pps/system/buttons/status";
+const size_t QQnxButtonEventNotifier::ppsBufferSize = 256;
QQnxButtonEventNotifier::QQnxButtonEventNotifier(QObject *parent)
: QObject(parent),
@@ -96,7 +62,7 @@ void QQnxButtonEventNotifier::start()
}
m_readNotifier = new QSocketNotifier(m_fd, QSocketNotifier::Read);
- QObject::connect(m_readNotifier, SIGNAL(activated(int)), this, SLOT(updateButtonStates()));
+ QObject::connect(m_readNotifier, SIGNAL(activated(QSocketDescriptor)), this, SLOT(updateButtonStates()));
qButtonDebug("successfully connected to Navigator. fd = %d", m_fd);
}
diff --git a/src/plugins/platforms/qnx/qqnxbuttoneventnotifier.h b/src/plugins/platforms/qnx/qqnxbuttoneventnotifier.h
index aa2c118b3a..81ccf64415 100644
--- a/src/plugins/platforms/qnx/qqnxbuttoneventnotifier.h
+++ b/src/plugins/platforms/qnx/qqnxbuttoneventnotifier.h
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2012 Research In Motion
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2012 Research In Motion
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQNXBUTTONSEVENTNOTIFIER_H
#define QQNXBUTTONSEVENTNOTIFIER_H
@@ -64,7 +28,7 @@ public:
ButtonDown
};
- explicit QQnxButtonEventNotifier(QObject *parent = 0);
+ explicit QQnxButtonEventNotifier(QObject *parent = nullptr);
~QQnxButtonEventNotifier();
public Q_SLOTS:
@@ -81,6 +45,9 @@ private:
QSocketNotifier *m_readNotifier;
ButtonState m_state[ButtonCount];
QList<QByteArray> m_buttonKeys;
+
+ static const char *ppsPath;
+ static const size_t ppsBufferSize;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/qnx/qqnxclipboard.cpp b/src/plugins/platforms/qnx/qqnxclipboard.cpp
index 78174549b1..8e42148c12 100644
--- a/src/plugins/platforms/qnx/qqnxclipboard.cpp
+++ b/src/plugins/platforms/qnx/qqnxclipboard.cpp
@@ -1,41 +1,7 @@
-/***************************************************************************
-**
-** Copyright (C) 2011 - 2012 Research In Motion
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2011 - 2012 Research In Motion
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#undef QT_NO_FOREACH // this file contains unported legacy Q_FOREACH uses
#if !defined(QT_NO_CLIPBOARD)
@@ -141,9 +107,9 @@ public:
}
protected:
- QVariant retrieveData(const QString &mimetype, QVariant::Type preferredType) const override
+ QVariant retrieveData(const QString &mimetype, QMetaType preferredType) const override
{
- qClipboardDebug() << "mimetype=" << mimetype << "preferredType=" << preferredType;
+ qClipboardDebug() << "mimetype=" << mimetype << "preferredType=" << preferredType.name();
if (is_clipboard_format_present(mimetype.toUtf8().constData()) != 0)
return QMimeData::retrieveData(mimetype, preferredType);
diff --git a/src/plugins/platforms/qnx/qqnxclipboard.h b/src/plugins/platforms/qnx/qqnxclipboard.h
index b9466214f8..adc70b158a 100644
--- a/src/plugins/platforms/qnx/qqnxclipboard.h
+++ b/src/plugins/platforms/qnx/qqnxclipboard.h
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2011 - 2012 Research In Motion
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2011 - 2012 Research In Motion
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQNXCLIPBOARD_H
#define QQNXCLIPBOARD_H
diff --git a/src/plugins/platforms/qnx/qqnxcursor.cpp b/src/plugins/platforms/qnx/qqnxcursor.cpp
index 7da965d636..03c4e16401 100644
--- a/src/plugins/platforms/qnx/qqnxcursor.cpp
+++ b/src/plugins/platforms/qnx/qqnxcursor.cpp
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2011 - 2012 Research In Motion
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2011 - 2012 Research In Motion
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqnxcursor.h"
diff --git a/src/plugins/platforms/qnx/qqnxcursor.h b/src/plugins/platforms/qnx/qqnxcursor.h
index 9559bfb4ce..6592e0a5ee 100644
--- a/src/plugins/platforms/qnx/qqnxcursor.h
+++ b/src/plugins/platforms/qnx/qqnxcursor.h
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2011 - 2012 Research In Motion
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2011 - 2012 Research In Motion
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQNXCURSOR_H
#define QQNXCURSOR_H
diff --git a/src/plugins/platforms/qnx/qqnxeglwindow.cpp b/src/plugins/platforms/qnx/qqnxeglwindow.cpp
index 48766fc435..ed53308216 100644
--- a/src/plugins/platforms/qnx/qqnxeglwindow.cpp
+++ b/src/plugins/platforms/qnx/qqnxeglwindow.cpp
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2013 - 2014 BlackBerry Limited. All rights reserved.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2013 - 2014 BlackBerry Limited. All rights reserved.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqnxeglwindow.h"
@@ -79,7 +43,7 @@ bool QQnxEglWindow::isInitialized() const
void QQnxEglWindow::ensureInitialized(QQnxGLContext* context)
{
if (m_newSurfaceRequested.testAndSetOrdered(true, false)) {
- const QMutexLocker locker(&m_mutex); // Set geomety must not reset the requestedBufferSize till
+ const QMutexLocker locker(&m_mutex); // Set geometry must not reset the requestedBufferSize till
// the surface is created
if (m_requestedBufferSize != bufferSize() || m_eglSurface == EGL_NO_SURFACE) {
diff --git a/src/plugins/platforms/qnx/qqnxeglwindow.h b/src/plugins/platforms/qnx/qqnxeglwindow.h
index d8cfd730ac..909a901d3c 100644
--- a/src/plugins/platforms/qnx/qqnxeglwindow.h
+++ b/src/plugins/platforms/qnx/qqnxeglwindow.h
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2013 BlackBerry Limited. All rights reserved.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2013 BlackBerry Limited. All rights reserved.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQNXEGLWINDOW_H
#define QQNXEGLWINDOW_H
diff --git a/src/plugins/platforms/qnx/qqnxforeignwindow.cpp b/src/plugins/platforms/qnx/qqnxforeignwindow.cpp
index 94608215dc..8c83a245d5 100644
--- a/src/plugins/platforms/qnx/qqnxforeignwindow.cpp
+++ b/src/plugins/platforms/qnx/qqnxforeignwindow.cpp
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2018 QNX Software Systems. All rights reserved.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2018 QNX Software Systems. All rights reserved.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqnxforeignwindow.h"
#include "qqnxintegration.h"
diff --git a/src/plugins/platforms/qnx/qqnxforeignwindow.h b/src/plugins/platforms/qnx/qqnxforeignwindow.h
index 22dde643e4..83857c0c5d 100644
--- a/src/plugins/platforms/qnx/qqnxforeignwindow.h
+++ b/src/plugins/platforms/qnx/qqnxforeignwindow.h
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2018 QNX Software Systems. All rights reserved.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2018 QNX Software Systems. All rights reserved.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQNXFOREIGNWINDOW_H
#define QQNXFOREIGNWINDOW_H
diff --git a/src/plugins/platforms/qnx/qqnxglcontext.cpp b/src/plugins/platforms/qnx/qqnxglcontext.cpp
index 69391c4fec..7b5b11b2e4 100644
--- a/src/plugins/platforms/qnx/qqnxglcontext.cpp
+++ b/src/plugins/platforms/qnx/qqnxglcontext.cpp
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2011 - 2013 BlackBerry Limited. All rights reserved.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2011 - 2013 BlackBerry Limited. All rights reserved.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqnxglcontext.h"
#include "qqnxintegration.h"
@@ -60,7 +24,7 @@ QT_BEGIN_NAMESPACE
static QEGLPlatformContext::Flags makeFlags()
{
- QEGLPlatformContext::Flags result = 0;
+ QEGLPlatformContext::Flags result = {};
if (!QQnxIntegration::instance()->options().testFlag(QQnxIntegration::SurfacelessEGLContext))
result |= QEGLPlatformContext::NoSurfaceless;
@@ -69,7 +33,7 @@ static QEGLPlatformContext::Flags makeFlags()
}
QQnxGLContext::QQnxGLContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share)
- : QEGLPlatformContext(format, share, QQnxIntegration::instance()->eglDisplay(), 0, QVariant(),
+ : QEGLPlatformContext(format, share, QQnxIntegration::instance()->eglDisplay(), nullptr,
makeFlags())
{
}
diff --git a/src/plugins/platforms/qnx/qqnxglcontext.h b/src/plugins/platforms/qnx/qqnxglcontext.h
index 5d807ee9e4..96e2865da1 100644
--- a/src/plugins/platforms/qnx/qqnxglcontext.h
+++ b/src/plugins/platforms/qnx/qqnxglcontext.h
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2011 - 2012 Research In Motion
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2011 - 2012 Research In Motion
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQNXGLCONTEXT_H
#define QQNXGLCONTEXT_H
@@ -46,7 +10,7 @@
#include <QtCore/QSize>
#include <EGL/egl.h>
-#include <QtEglSupport/private/qeglplatformcontext_p.h>
+#include <QtGui/private/qeglplatformcontext_p.h>
QT_BEGIN_NAMESPACE
diff --git a/src/plugins/platforms/qnx/qqnxglobal.cpp b/src/plugins/platforms/qnx/qqnxglobal.cpp
index c17f6a7546..85642b44b3 100644
--- a/src/plugins/platforms/qnx/qqnxglobal.cpp
+++ b/src/plugins/platforms/qnx/qqnxglobal.cpp
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2011 - 2014 BlackBerry Limited. All rights reserved.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2011 - 2014 BlackBerry Limited. All rights reserved.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <errno.h>
#include <QDebug>
diff --git a/src/plugins/platforms/qnx/qqnxglobal.h b/src/plugins/platforms/qnx/qqnxglobal.h
index db11ffc228..455edc23dc 100644
--- a/src/plugins/platforms/qnx/qqnxglobal.h
+++ b/src/plugins/platforms/qnx/qqnxglobal.h
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2011 - 2014 BlackBerry Limited. All rights reserved.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2011 - 2014 BlackBerry Limited. All rights reserved.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQNXGLOBAL_H
#define QQNXGLOBAL_H
diff --git a/src/plugins/platforms/qnx/qqnxinputcontext_imf.cpp b/src/plugins/platforms/qnx/qqnxinputcontext_imf.cpp
index ce3a445d7c..a1063444d1 100644
--- a/src/plugins/platforms/qnx/qqnxinputcontext_imf.cpp
+++ b/src/plugins/platforms/qnx/qqnxinputcontext_imf.cpp
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2013 BlackBerry Limited. All rights reserved.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2013 BlackBerry Limited. All rights reserved.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqnxinputcontext_imf.h"
#include "qqnxabstractvirtualkeyboard.h"
@@ -76,8 +40,8 @@
static QQnxInputContext *sInputContextInstance;
static QColor sSelectedColor(0,0xb8,0,85);
-static const input_session_t *sSpellCheckSession = 0;
-static const input_session_t *sInputSession = 0;
+static const input_session_t *sSpellCheckSession = nullptr;
+static const input_session_t *sInputSession = nullptr;
static bool isSessionOkay(input_session_t *ic)
{
return ic !=0 && sInputSession != 0 && ic->component_id == sInputSession->component_id;
@@ -515,13 +479,13 @@ static spannable_string_t *toSpannableString(const QString &text)
}
-static const input_session_t *(*p_ictrl_open_session)(connection_interface_t *) = 0;
-static void (*p_ictrl_close_session)(input_session_t *) = 0;
-static int32_t (*p_ictrl_dispatch_event)(event_t*) = 0;
-static int32_t (*p_imf_client_init)() = 0;
-static void (*p_imf_client_disconnect)() = 0;
-static int32_t (*p_vkb_init_selection_service)() = 0;
-static int32_t (*p_ictrl_get_num_active_sessions)() = 0;
+static const input_session_t *(*p_ictrl_open_session)(connection_interface_t *) = nullptr;
+static void (*p_ictrl_close_session)(input_session_t *) = nullptr;
+static int32_t (*p_ictrl_dispatch_event)(event_t*) = nullptr;
+static int32_t (*p_imf_client_init)() = nullptr;
+static void (*p_imf_client_disconnect)() = nullptr;
+static int32_t (*p_vkb_init_selection_service)() = nullptr;
+static int32_t (*p_ictrl_get_num_active_sessions)() = nullptr;
static bool s_imfInitFailed = false;
static bool imfAvailable()
@@ -602,7 +566,7 @@ QQnxInputContext::~QQnxInputContext()
qInputContextDebug();
Q_ASSERT(sInputContextInstance == this);
- sInputContextInstance = 0;
+ sInputContextInstance = nullptr;
if (!imfAvailable())
return;
@@ -735,7 +699,7 @@ void QQnxInputContext::closeSession()
if (sInputSession) {
p_ictrl_close_session((input_session_t *)sInputSession);
- sInputSession = 0;
+ sInputSession = nullptr;
}
// These are likely already in the right state but this depends on the text control
// having called reset or commit. So, just in case, set them to proper values.
diff --git a/src/plugins/platforms/qnx/qqnxinputcontext_imf.h b/src/plugins/platforms/qnx/qqnxinputcontext_imf.h
index e758ae5bf3..a20ec6727c 100644
--- a/src/plugins/platforms/qnx/qqnxinputcontext_imf.h
+++ b/src/plugins/platforms/qnx/qqnxinputcontext_imf.h
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2013 BlackBerry Limited. All rights reserved.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2013 BlackBerry Limited. All rights reserved.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQNXINPUTCONTEXT_H
#define QQNXINPUTCONTEXT_H
diff --git a/src/plugins/platforms/qnx/qqnxinputcontext_noimf.cpp b/src/plugins/platforms/qnx/qqnxinputcontext_noimf.cpp
index d57d0871a2..2a4e5b509b 100644
--- a/src/plugins/platforms/qnx/qqnxinputcontext_noimf.cpp
+++ b/src/plugins/platforms/qnx/qqnxinputcontext_noimf.cpp
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2013 BlackBerry Limited. All rights reserved.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2013 BlackBerry Limited. All rights reserved.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqnxinputcontext_noimf.h"
#include "qqnxabstractvirtualkeyboard.h"
diff --git a/src/plugins/platforms/qnx/qqnxinputcontext_noimf.h b/src/plugins/platforms/qnx/qqnxinputcontext_noimf.h
index 8d6104af80..7f5e1ded3e 100644
--- a/src/plugins/platforms/qnx/qqnxinputcontext_noimf.h
+++ b/src/plugins/platforms/qnx/qqnxinputcontext_noimf.h
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2011 - 2012 Research In Motion
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2011 - 2012 Research In Motion
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQNXINPUTCONTEXT_H
#define QQNXINPUTCONTEXT_H
diff --git a/src/plugins/platforms/qnx/qqnxintegration.cpp b/src/plugins/platforms/qnx/qqnxintegration.cpp
index 84baa6ec44..310d5d4c8a 100644
--- a/src/plugins/platforms/qnx/qqnxintegration.cpp
+++ b/src/plugins/platforms/qnx/qqnxintegration.cpp
@@ -1,41 +1,7 @@
-/***************************************************************************
-**
-** Copyright (C) 2013 BlackBerry Limited. All rights reserved.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2013 BlackBerry Limited. All rights reserved.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#undef QT_NO_FOREACH // this file contains unported legacy Q_FOREACH uses
#include "qqnxglobal.h"
@@ -106,24 +72,26 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
QQnxIntegration *QQnxIntegration::ms_instance;
static inline QQnxIntegration::Options parseOptions(const QStringList &paramList)
{
QQnxIntegration::Options options = QQnxIntegration::NoOptions;
- if (!paramList.contains(QLatin1String("no-fullscreen"))) {
+ if (!paramList.contains("no-fullscreen"_L1)) {
options |= QQnxIntegration::FullScreenApplication;
}
- if (paramList.contains(QLatin1String("flush-screen-context"))) {
+ if (paramList.contains("flush-screen-context"_L1)) {
options |= QQnxIntegration::AlwaysFlushScreenContext;
}
- if (paramList.contains(QLatin1String("rootwindow"))) {
+ if (paramList.contains("rootwindow"_L1)) {
options |= QQnxIntegration::RootWindow;
}
- if (!paramList.contains(QLatin1String("disable-EGL_KHR_surfaceless_context"))) {
+ if (!paramList.contains("disable-EGL_KHR_surfaceless_context"_L1)) {
options |= QQnxIntegration::SurfacelessEGLContext;
}
@@ -132,11 +100,11 @@ static inline QQnxIntegration::Options parseOptions(const QStringList &paramList
static inline int getContextCapabilities(const QStringList &paramList)
{
- QString contextCapabilitiesPrefix = QStringLiteral("screen-context-capabilities=");
+ constexpr auto contextCapabilitiesPrefix = "screen-context-capabilities="_L1;
int contextCapabilities = SCREEN_APPLICATION_CONTEXT;
for (const QString &param : paramList) {
if (param.startsWith(contextCapabilitiesPrefix)) {
- QStringRef value = param.midRef(contextCapabilitiesPrefix.length());
+ auto value = QStringView{param}.mid(contextCapabilitiesPrefix.length());
bool ok = false;
contextCapabilities = value.toInt(&ok, 0);
if (!ok)
@@ -427,6 +395,7 @@ QPlatformOpenGLContext *QQnxIntegration::createPlatformOpenGLContext(QOpenGLCont
}
#endif
+#if QT_CONFIG(qqnx_pps)
QPlatformInputContext *QQnxIntegration::inputContext() const
{
qIntegrationDebug();
@@ -434,6 +403,7 @@ QPlatformInputContext *QQnxIntegration::inputContext() const
return m_qpaInputContext;
return m_inputContext;
}
+#endif
void QQnxIntegration::moveToScreen(QWindow *window, int screen)
{
@@ -568,7 +538,7 @@ static bool getRequestedDisplays(QJsonArray &requestedDisplays)
// Read the requested display order
const QJsonObject object = doc.object();
- requestedDisplays = object.value(QLatin1String("displayOrder")).toArray();
+ requestedDisplays = object.value("displayOrder"_L1).toArray();
return true;
}
@@ -603,7 +573,7 @@ QList<screen_display_t *> QQnxIntegration::sortDisplays(screen_display_t *availa
// Go through all the requested displays IDs
QList<screen_display_t *> orderedDisplays;
- for (const QJsonValue &value : qAsConst(requestedDisplays)) {
+ for (const QJsonValue &value : std::as_const(requestedDisplays)) {
int requestedValue = value.toInt();
// Move all displays with matching ID from the intermediate list
diff --git a/src/plugins/platforms/qnx/qqnxintegration.h b/src/plugins/platforms/qnx/qqnxintegration.h
index 2596af3c45..f126300aed 100644
--- a/src/plugins/platforms/qnx/qqnxintegration.h
+++ b/src/plugins/platforms/qnx/qqnxintegration.h
@@ -1,47 +1,12 @@
-/***************************************************************************
-**
-** Copyright (C) 2011 - 2013 BlackBerry Limited. All rights reserved.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2011 - 2013 BlackBerry Limited. All rights reserved.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQNXINTEGRATION_H
#define QQNXINTEGRATION_H
#include <qpa/qplatformintegration.h>
#include <private/qtguiglobal_p.h>
+#include <QtCore/qhash.h>
#include <QtCore/qmutex.h>
#include <screen/screen.h>
@@ -75,8 +40,7 @@ class QQnxButtonEventNotifier;
class QQnxClipboard;
#endif
-template<class K, class V> class QHash;
-typedef QHash<screen_window_t, QWindow *> QQnxWindowMapper;
+using QQnxWindowMapper = QHash<screen_window_t, QWindow *>;
class QQnxIntegration : public QPlatformIntegration
{
diff --git a/src/plugins/platforms/qnx/qqnxkeytranslator.h b/src/plugins/platforms/qnx/qqnxkeytranslator.h
index 9400b88dbb..824f7ad523 100644
--- a/src/plugins/platforms/qnx/qqnxkeytranslator.h
+++ b/src/plugins/platforms/qnx/qqnxkeytranslator.h
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2011 - 2012 Research In Motion
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2011 - 2012 Research In Motion
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQNXKEYTRANSLATOR_H
#define QQNXKEYTRANSLATOR_H
diff --git a/src/plugins/platforms/qnx/qqnxlgmon.cpp b/src/plugins/platforms/qnx/qqnxlgmon.cpp
index e751953ec2..2aa7f253ef 100644
--- a/src/plugins/platforms/qnx/qqnxlgmon.cpp
+++ b/src/plugins/platforms/qnx/qqnxlgmon.cpp
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2014 BlackBerry Limited. All rights reserved.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2014 BlackBerry Limited. All rights reserved.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqnxlgmon.h"
diff --git a/src/plugins/platforms/qnx/qqnxlgmon.h b/src/plugins/platforms/qnx/qqnxlgmon.h
index 3502e9e7af..50344b6774 100644
--- a/src/plugins/platforms/qnx/qqnxlgmon.h
+++ b/src/plugins/platforms/qnx/qqnxlgmon.h
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2014 BlackBerry Limited. All rights reserved.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2014 BlackBerry Limited. All rights reserved.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQNXLGMON_H
#define QQNXLGMON_H
diff --git a/src/plugins/platforms/qnx/qqnxnativeinterface.cpp b/src/plugins/platforms/qnx/qqnxnativeinterface.cpp
index 25f7b09a60..2731e0eea4 100644
--- a/src/plugins/platforms/qnx/qqnxnativeinterface.cpp
+++ b/src/plugins/platforms/qnx/qqnxnativeinterface.cpp
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2012 Research In Motion
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2012 Research In Motion
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqnxnativeinterface.h"
@@ -60,6 +24,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
QQnxNativeInterface::QQnxNativeInterface(QQnxIntegration *integration)
: m_integration(integration)
{
@@ -116,9 +82,7 @@ void QQnxNativeInterface::setWindowProperty(QPlatformWindow *window, const QStri
{
QQnxWindow *qnxWindow = static_cast<QQnxWindow*>(window);
- if (name == QLatin1String("mmRendererWindowName")) {
- qnxWindow->setMMRendererWindowName(value.toString());
- } else if (name == QLatin1String("qnxWindowGroup")) {
+ if (name == "qnxWindowGroup"_L1) {
if (value.isNull())
qnxWindow->joinWindowGroup(QByteArray());
else if (value.canConvert<QByteArray>())
@@ -134,7 +98,7 @@ QPlatformNativeInterface::NativeResourceForIntegrationFunction QQnxNativeInterfa
if (resource == "blackberryIMFCheckSpelling")
return reinterpret_cast<NativeResourceForIntegrationFunction>(QQnxInputContext::checkSpelling);
#else
- Q_UNUSED(resource)
+ Q_UNUSED(resource);
#endif
return 0;
}
diff --git a/src/plugins/platforms/qnx/qqnxnativeinterface.h b/src/plugins/platforms/qnx/qqnxnativeinterface.h
index 25f1c29b02..9363e1baee 100644
--- a/src/plugins/platforms/qnx/qqnxnativeinterface.h
+++ b/src/plugins/platforms/qnx/qqnxnativeinterface.h
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2012 Research In Motion
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2012 Research In Motion
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQNXNATIVEINTERFACE_H
#define QQNXNATIVEINTERFACE_H
diff --git a/src/plugins/platforms/qnx/qqnxnavigatoreventhandler.cpp b/src/plugins/platforms/qnx/qqnxnavigatoreventhandler.cpp
index 0e16764b79..cee86a68a0 100644
--- a/src/plugins/platforms/qnx/qqnxnavigatoreventhandler.cpp
+++ b/src/plugins/platforms/qnx/qqnxnavigatoreventhandler.cpp
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2012 Research In Motion
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2012 Research In Motion
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqnxnavigatoreventhandler.h"
diff --git a/src/plugins/platforms/qnx/qqnxnavigatoreventhandler.h b/src/plugins/platforms/qnx/qqnxnavigatoreventhandler.h
index 3e10052459..342b6c3ef6 100644
--- a/src/plugins/platforms/qnx/qqnxnavigatoreventhandler.h
+++ b/src/plugins/platforms/qnx/qqnxnavigatoreventhandler.h
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2012 Research In Motion
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2012 Research In Motion
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQNXNAVIGATOREVENTHANDLER_H
#define QQNXNAVIGATOREVENTHANDLER_H
@@ -48,7 +12,7 @@ class QQnxNavigatorEventHandler : public QObject
{
Q_OBJECT
public:
- explicit QQnxNavigatorEventHandler(QObject *parent = 0);
+ explicit QQnxNavigatorEventHandler(QObject *parent = nullptr);
bool handleOrientationCheck(int angle);
void handleOrientationChange(int angle);
diff --git a/src/plugins/platforms/qnx/qqnxnavigatoreventnotifier.cpp b/src/plugins/platforms/qnx/qqnxnavigatoreventnotifier.cpp
index 1f630863b7..8024214e69 100644
--- a/src/plugins/platforms/qnx/qqnxnavigatoreventnotifier.cpp
+++ b/src/plugins/platforms/qnx/qqnxnavigatoreventnotifier.cpp
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2011 - 2012 Research In Motion
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2011 - 2012 Research In Motion
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqnxnavigatoreventnotifier.h"
@@ -59,11 +23,11 @@
#define qNavigatorEventNotifierDebug QT_NO_QDEBUG_MACRO
#endif
-static const char *navigatorControlPath = "/pps/services/navigator/control";
-static const int ppsBufferSize = 4096;
-
QT_BEGIN_NAMESPACE
+const char *QQnxNavigatorEventNotifier::navigatorControlPath = "/pps/services/navigator/control";
+const size_t QQnxNavigatorEventNotifier::ppsBufferSize = 4096;
+
QQnxNavigatorEventNotifier::QQnxNavigatorEventNotifier(QQnxNavigatorEventHandler *eventHandler, QObject *parent)
: QObject(parent),
m_fd(-1),
@@ -96,7 +60,7 @@ void QQnxNavigatorEventNotifier::start()
}
m_readNotifier = new QSocketNotifier(m_fd, QSocketNotifier::Read);
- connect(m_readNotifier, SIGNAL(activated(int)), this, SLOT(readData()));
+ connect(m_readNotifier, SIGNAL(activated(QSocketDescriptor)), this, SLOT(readData()));
}
void QQnxNavigatorEventNotifier::parsePPS(const QByteArray &ppsData, QByteArray &msg, QByteArray &dat, QByteArray &id)
diff --git a/src/plugins/platforms/qnx/qqnxnavigatoreventnotifier.h b/src/plugins/platforms/qnx/qqnxnavigatoreventnotifier.h
index 17c31c096c..66100ece3f 100644
--- a/src/plugins/platforms/qnx/qqnxnavigatoreventnotifier.h
+++ b/src/plugins/platforms/qnx/qqnxnavigatoreventnotifier.h
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2011 - 2012 Research In Motion
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2011 - 2012 Research In Motion
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQNXNAVIGATOREVENTNOTIFIER_H
#define QQNXNAVIGATOREVENTNOTIFIER_H
@@ -51,7 +15,7 @@ class QQnxNavigatorEventNotifier : public QObject
{
Q_OBJECT
public:
- explicit QQnxNavigatorEventNotifier(QQnxNavigatorEventHandler *eventHandler, QObject *parent = 0);
+ explicit QQnxNavigatorEventNotifier(QQnxNavigatorEventHandler *eventHandler, QObject *parent = nullptr);
~QQnxNavigatorEventNotifier();
public Q_SLOTS:
@@ -68,6 +32,9 @@ private:
int m_fd;
QSocketNotifier *m_readNotifier;
QQnxNavigatorEventHandler *m_eventHandler;
+
+ static const char *navigatorControlPath;
+ static const size_t ppsBufferSize;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/qnx/qqnxnavigatorpps.cpp b/src/plugins/platforms/qnx/qqnxnavigatorpps.cpp
index d5234ca92f..c945f3e98a 100644
--- a/src/plugins/platforms/qnx/qqnxnavigatorpps.cpp
+++ b/src/plugins/platforms/qnx/qqnxnavigatorpps.cpp
@@ -1,45 +1,11 @@
-/***************************************************************************
-**
-** Copyright (C) 2012 Research In Motion
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2012 Research In Motion
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqnxnavigatorpps.h"
#include <QDebug>
+#include <QHash>
+#include <QByteArray>
#include <private/qcore_unix_p.h>
#if defined(QQNXNAVIGATOR_DEBUG)
@@ -48,11 +14,11 @@
#define qNavigatorDebug QT_NO_QDEBUG_MACRO
#endif
-static const char *navigatorControlPath = "/pps/services/navigator/control";
-static const int ppsBufferSize = 4096;
-
QT_BEGIN_NAMESPACE
+const char *QQnxNavigatorPps::navigatorControlPath = "/pps/services/navigator/control";
+const size_t QQnxNavigatorPps::ppsBufferSize = 4096;
+
QQnxNavigatorPps::QQnxNavigatorPps(QObject *parent)
: QQnxAbstractNavigator(parent)
, m_fd(-1)
diff --git a/src/plugins/platforms/qnx/qqnxnavigatorpps.h b/src/plugins/platforms/qnx/qqnxnavigatorpps.h
index 3c818f51a6..cbe0f99621 100644
--- a/src/plugins/platforms/qnx/qqnxnavigatorpps.h
+++ b/src/plugins/platforms/qnx/qqnxnavigatorpps.h
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2012 Research In Motion
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2012 Research In Motion
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQNXNAVIGATORPPS_H
#define QQNXNAVIGATORPPS_H
@@ -50,7 +14,7 @@ class QQnxNavigatorPps : public QQnxAbstractNavigator
{
Q_OBJECT
public:
- explicit QQnxNavigatorPps(QObject *parent = 0);
+ explicit QQnxNavigatorPps(QObject *parent = nullptr);
~QQnxNavigatorPps();
protected:
@@ -62,8 +26,9 @@ private:
bool sendPpsMessage(const QByteArray &message, const QByteArray &data);
void parsePPS(const QByteArray &ppsData, QHash<QByteArray, QByteArray> &messageFields);
-private:
int m_fd;
+ static const char *navigatorControlPath;
+ static const size_t ppsBufferSize;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/qnx/qqnxrasterbackingstore.cpp b/src/plugins/platforms/qnx/qqnxrasterbackingstore.cpp
index dd7f907ee0..cf80e44f84 100644
--- a/src/plugins/platforms/qnx/qqnxrasterbackingstore.cpp
+++ b/src/plugins/platforms/qnx/qqnxrasterbackingstore.cpp
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2011 - 2013 BlackBerry Limited. All rights reserved.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2011 - 2013 BlackBerry Limited. All rights reserved.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqnxrasterbackingstore.h"
#include "qqnxrasterwindow.h"
@@ -79,7 +43,7 @@ QPaintDevice *QQnxRasterBackingStore::paintDevice()
void QQnxRasterBackingStore::flush(QWindow *window, const QRegion &region, const QPoint &offset)
{
- Q_UNUSED(offset)
+ Q_UNUSED(offset);
qRasterBackingStoreDebug() << "w =" << this->window();
@@ -89,17 +53,11 @@ void QQnxRasterBackingStore::flush(QWindow *window, const QRegion &region, const
if (!m_needsPosting)
return;
- QQnxWindow *targetWindow = 0;
- if (window)
- targetWindow = static_cast<QQnxWindow *>(window->handle());
-
- // we only need to flush the platformWindow backing store, since this is
- // the buffer where all drawing operations of all windows, including the
- // child windows, are performed; conceptually ,child windows have no buffers
- // (actually they do have a 1x1 placeholder buffer due to libscreen limitations),
- // since Qt will only draw to the backing store of the top-level window.
- if (!targetWindow || targetWindow == platformWindow())
- platformWindow()->post(region); // update the display with newly rendered content
+ auto *targetWindow = window
+ ? static_cast<QQnxRasterWindow *>(window->handle()) : platformWindow();
+
+ if (targetWindow)
+ targetWindow->post(region); // update the display with newly rendered content
m_needsPosting = false;
m_scrolled = false;
diff --git a/src/plugins/platforms/qnx/qqnxrasterbackingstore.h b/src/plugins/platforms/qnx/qqnxrasterbackingstore.h
index 96ac193dda..13ef42f61e 100644
--- a/src/plugins/platforms/qnx/qqnxrasterbackingstore.h
+++ b/src/plugins/platforms/qnx/qqnxrasterbackingstore.h
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2011 - 2012 Research In Motion
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2011 - 2012 Research In Motion
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQNXRASTERWINDOWSURFACE_H
#define QQNXRASTERWINDOWSURFACE_H
diff --git a/src/plugins/platforms/qnx/qqnxrasterwindow.cpp b/src/plugins/platforms/qnx/qqnxrasterwindow.cpp
index 0014ef8c6e..fb7a1d3fd3 100644
--- a/src/plugins/platforms/qnx/qqnxrasterwindow.cpp
+++ b/src/plugins/platforms/qnx/qqnxrasterwindow.cpp
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2013 - 2014 BlackBerry Limited. All rights reserved.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2013 - 2014 BlackBerry Limited. All rights reserved.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqnxglobal.h"
@@ -177,9 +141,8 @@ void QQnxRasterWindow::setParent(const QPlatformWindow *wnd)
void QQnxRasterWindow::adjustBufferSize()
{
- // When having a raster window we don't need any buffers, since
- // Qt will draw to the parent TLW backing store.
- const QSize windowSize = window()->parent() ? QSize(0,0) : window()->size();
+ const QSize windowSize = window()->size();
+
if (windowSize != bufferSize())
setBufferSize(windowSize);
}
@@ -195,13 +158,6 @@ void QQnxRasterWindow::resetBuffers()
m_currentBufferIndex = -1;
m_previousDirty = QRegion();
m_scrolled = QRegion();
- if (window()->parent() && bufferSize() == QSize(1,1)) {
- // If we have a parent then we're not really rendering. But if we don't render we'll
- // be invisible and any children won't show up. This should be harmless since we're
- // rendering into a 1x1 window that has transparency set to discard.
- renderBuffer();
- post(QRegion(0,0,1,1));
- }
}
void QQnxRasterWindow::blitPreviousToCurrent(const QRegion &region, int dx, int dy, bool flush)
diff --git a/src/plugins/platforms/qnx/qqnxrasterwindow.h b/src/plugins/platforms/qnx/qqnxrasterwindow.h
index 99396efd57..09d772bb69 100644
--- a/src/plugins/platforms/qnx/qqnxrasterwindow.h
+++ b/src/plugins/platforms/qnx/qqnxrasterwindow.h
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2013 BlackBerry Limited. All rights reserved.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2013 BlackBerry Limited. All rights reserved.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQNXRASTERWINDOW_H
#define QQNXRASTERWINDOW_H
diff --git a/src/plugins/platforms/qnx/qqnxscreen.cpp b/src/plugins/platforms/qnx/qqnxscreen.cpp
index 46df500330..9d689da991 100644
--- a/src/plugins/platforms/qnx/qqnxscreen.cpp
+++ b/src/plugins/platforms/qnx/qqnxscreen.cpp
@@ -1,41 +1,7 @@
-/***************************************************************************
-**
-** Copyright (C) 2011 - 2013 BlackBerry Limited. All rights reserved.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2011 - 2013 BlackBerry Limited. All rights reserved.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#undef QT_NO_FOREACH // this file contains unported legacy Q_FOREACH uses
#include "qqnxglobal.h"
@@ -62,13 +28,9 @@
#error Please define QQNX_PHYSICAL_SCREEN_WIDTH and QQNX_PHYSICAL_SCREEN_HEIGHT to values greater than zero
#endif
-// The default z-order of a window (intended to be overlain) created by
-// mmrender.
-static const int MMRENDER_DEFAULT_ZORDER = -1;
-
// The maximum z-order at which a foreign window will be considered
// an underlay.
-static const int MAX_UNDERLAY_ZORDER = MMRENDER_DEFAULT_ZORDER - 1;
+static const int MAX_UNDERLAY_ZORDER = -1;
QT_BEGIN_NAMESPACE
@@ -90,7 +52,7 @@ static QSize determineScreenSize(screen_display_t display, bool primaryScreen) {
const QString envPhySizeStr = qgetenv("QQNX_PHYSICAL_SCREEN_SIZE");
if (!envPhySizeStr.isEmpty()) {
- const auto envPhySizeStrList = envPhySizeStr.splitRef(QLatin1Char(','));
+ const auto envPhySizeStrList = QStringView{envPhySizeStr}.split(u',');
const int envWidth = envPhySizeStrList.size() == 2 ? envPhySizeStrList[0].toInt() : -1;
const int envHeight = envPhySizeStrList.size() == 2 ? envPhySizeStrList[1].toInt() : -1;
@@ -118,38 +80,6 @@ static QSize determineScreenSize(screen_display_t display, bool primaryScreen) {
#endif
}
-static QQnxWindow *findMultimediaWindow(const QList<QQnxWindow*> &windows,
- const QByteArray &mmWindowId)
-{
- Q_FOREACH (QQnxWindow *sibling, windows) {
- if (sibling->mmRendererWindowName() == mmWindowId)
- return sibling;
-
- QQnxWindow *mmWindow = findMultimediaWindow(sibling->children(), mmWindowId);
-
- if (mmWindow)
- return mmWindow;
- }
-
- return 0;
-}
-
-static QQnxWindow *findMultimediaWindow(const QList<QQnxWindow*> &windows,
- screen_window_t mmWindowId)
-{
- Q_FOREACH (QQnxWindow *sibling, windows) {
- if (sibling->mmRendererWindow() == mmWindowId)
- return sibling;
-
- QQnxWindow *mmWindow = findMultimediaWindow(sibling->children(), mmWindowId);
-
- if (mmWindow)
- return mmWindow;
- }
-
- return 0;
-}
-
QQnxScreen::QQnxScreen(screen_context_t screenContext, screen_display_t display, bool primaryScreen)
: m_screenContext(screenContext),
m_display(display),
@@ -714,19 +644,6 @@ void QQnxScreen::addUnderlayWindow(screen_window_t window)
updateHierarchy();
}
-void QQnxScreen::addMultimediaWindow(const QByteArray &id, screen_window_t window)
-{
- // find the QnxWindow this mmrenderer window is related to
- QQnxWindow *mmWindow = findMultimediaWindow(m_childWindows, id);
-
- if (!mmWindow)
- return;
-
- mmWindow->setMMRendererWindow(window);
-
- updateHierarchy();
-}
-
void QQnxScreen::removeOverlayOrUnderlayWindow(screen_window_t window)
{
const int numRemoved = m_overlays.removeAll(window) + m_underlays.removeAll(window);
@@ -762,32 +679,24 @@ void QQnxScreen::newWindowCreated(void *window)
windowName = QByteArray(windowNameBuffer);
- if (display == nativeDisplay()) {
- // A window was created on this screen. If we don't know about this window yet, it means
- // it was not created by Qt, but by some foreign library like the multimedia renderer, which
- // creates an overlay window when playing a video.
- //
- // Treat all foreign windows as overlays, underlays or as windows
- // created by the BlackBerry QtMultimedia plugin.
- //
- // In the case of the BlackBerry QtMultimedia plugin, we need to
- // "attach" the foreign created mmrenderer window to the correct
- // platform window (usually the one belonging to QVideoWidget) to
- // ensure proper z-ordering.
- //
- // Otherwise, assume that if a foreign window already has a Z-Order both negative and
- // less than the default Z-Order installed by mmrender on windows it creates,
- // the windows should be treated as an underlay. Otherwise, we treat it as an overlay.
- if (!windowName.isEmpty() && windowName.startsWith("MmRendererVideoWindowControl")) {
- addMultimediaWindow(windowName, windowHandle);
- } else if (!findWindow(windowHandle)) {
- if (zorder <= MAX_UNDERLAY_ZORDER)
- addUnderlayWindow(windowHandle);
- else
- addOverlayWindow(windowHandle);
- Q_EMIT foreignWindowCreated(windowHandle);
- }
- }
+ if (display != nativeDisplay())
+ return;
+
+ // A window was created on this screen. If we don't know about this window yet, it means
+ // it was not created by Qt, but by some foreign library.
+ //
+ // Treat all foreign windows as overlays or underlays. A window will
+ // be treated as an underlay if its Z-order is less or equal than
+ // MAX_UNDERLAY_ZORDER. Otherwise, it will be treated as an overlay.
+ if (findWindow(windowHandle))
+ return;
+
+ if (zorder <= MAX_UNDERLAY_ZORDER)
+ addUnderlayWindow(windowHandle);
+ else
+ addOverlayWindow(windowHandle);
+
+ Q_EMIT foreignWindowCreated(windowHandle);
}
void QQnxScreen::windowClosed(void *window)
@@ -795,12 +704,7 @@ void QQnxScreen::windowClosed(void *window)
Q_ASSERT(thread() == QThread::currentThread());
const screen_window_t windowHandle = reinterpret_cast<screen_window_t>(window);
- QQnxWindow *mmWindow = findMultimediaWindow(m_childWindows, windowHandle);
-
- if (mmWindow)
- mmWindow->clearMMRendererWindow();
- else
- removeOverlayOrUnderlayWindow(windowHandle);
+ removeOverlayOrUnderlayWindow(windowHandle);
}
void QQnxScreen::windowGroupStateChanged(const QByteArray &id, Qt::WindowState state)
diff --git a/src/plugins/platforms/qnx/qqnxscreen.h b/src/plugins/platforms/qnx/qqnxscreen.h
index a6d5623d04..f988b42ab4 100644
--- a/src/plugins/platforms/qnx/qqnxscreen.h
+++ b/src/plugins/platforms/qnx/qqnxscreen.h
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2011 - 2012 Research In Motion
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2011 - 2012 Research In Motion
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QBBSCREEN_H
#define QBBSCREEN_H
@@ -138,7 +102,6 @@ private:
void resizeWindows(const QRect &previousScreenGeometry);
void addOverlayWindow(screen_window_t window);
void addUnderlayWindow(screen_window_t window);
- void addMultimediaWindow(const QByteArray &id, screen_window_t window);
void removeOverlayOrUnderlayWindow(screen_window_t window);
screen_context_t m_screenContext;
diff --git a/src/plugins/platforms/qnx/qqnxscreeneventfilter.h b/src/plugins/platforms/qnx/qqnxscreeneventfilter.h
index 857865cc34..bc6d2720f4 100644
--- a/src/plugins/platforms/qnx/qqnxscreeneventfilter.h
+++ b/src/plugins/platforms/qnx/qqnxscreeneventfilter.h
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2013 BlackBerry Limited. All rights reserved.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2013 BlackBerry Limited. All rights reserved.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQNXSCREENEVENTFILTER_H
#define QQNXSCREENEVENTFILTER_H
diff --git a/src/plugins/platforms/qnx/qqnxscreeneventhandler.cpp b/src/plugins/platforms/qnx/qqnxscreeneventhandler.cpp
index e3a6aea99f..e93a38f62c 100644
--- a/src/plugins/platforms/qnx/qqnxscreeneventhandler.cpp
+++ b/src/plugins/platforms/qnx/qqnxscreeneventhandler.cpp
@@ -1,41 +1,7 @@
-/***************************************************************************
-**
-** Copyright (C) 2013 BlackBerry Limited. All rights reserved.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2013 BlackBerry Limited. All rights reserved.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#undef QT_NO_FOREACH // this file contains unported legacy Q_FOREACH uses
#include "qqnxglobal.h"
@@ -76,8 +42,7 @@ static QString keyString(int sym, QChar::Category category)
} else if (category == QChar::Other_PrivateUse) {
return keyStringForPrivateUseQnxKey(sym);
} else {
- uint ucs4_sym = sym;
- return QString::fromUcs4(&ucs4_sym, 1);
+ return QStringView{QChar::fromUcs4(sym)}.toString();
}
}
@@ -137,19 +102,31 @@ static void finishCloseEvent(screen_event_t event)
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
QQnxScreenEventHandler::QQnxScreenEventHandler(QQnxIntegration *integration)
: m_qnxIntegration(integration)
, m_lastButtonState(Qt::NoButton)
, m_lastMouseWindow(0)
, m_touchDevice(0)
+ , m_mouseDevice(0)
, m_eventThread(0)
, m_focusLostTimer(-1)
{
// Create a touch device
- m_touchDevice = new QTouchDevice;
- m_touchDevice->setType(QTouchDevice::TouchScreen);
- m_touchDevice->setCapabilities(QTouchDevice::Position | QTouchDevice::Area | QTouchDevice::Pressure | QTouchDevice::NormalizedPosition);
- QWindowSystemInterface::registerTouchDevice(m_touchDevice);
+ m_touchDevice = new QPointingDevice(
+ "touchscreen"_L1, 1, QInputDevice::DeviceType::TouchScreen,
+ QPointingDevice::PointerType::Finger,
+ QPointingDevice::Capability::Position | QPointingDevice::Capability::Area
+ | QPointingDevice::Capability::Pressure
+ | QPointingDevice::Capability::NormalizedPosition,
+ MaximumTouchPoints, 8);
+ QWindowSystemInterface::registerInputDevice(m_touchDevice);
+
+ m_mouseDevice = new QPointingDevice("mouse"_L1, 2, QInputDevice::DeviceType::Mouse,
+ QPointingDevice::PointerType::Generic,
+ QPointingDevice::Capability::Position, 1, 8);
+ QWindowSystemInterface::registerInputDevice(m_mouseDevice);
// initialize array of touch points
for (int i = 0; i < MaximumTouchPoints; i++) {
@@ -161,7 +138,7 @@ QQnxScreenEventHandler::QQnxScreenEventHandler(QQnxIntegration *integration)
m_touchPoints[i].pressure = 1.0;
// nothing touching
- m_touchPoints[i].state = Qt::TouchPointReleased;
+ m_touchPoints[i].state = QEventPoint::State::Released;
}
}
@@ -288,11 +265,7 @@ void QQnxScreenEventHandler::processEvents()
break;
++count;
-#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
qintptr result = 0;
-#else
- long result = 0;
-#endif
QAbstractEventDispatcher* dispatcher = QAbstractEventDispatcher::instance();
bool handled = dispatcher && dispatcher->filterNativeEvent(QByteArrayLiteral("screen_event_t"), event, &result);
if (!handled)
@@ -378,6 +351,10 @@ void QQnxScreenEventHandler::handlePointerEvent(screen_event_t event)
screen_get_event_property_iv(event, SCREEN_PROPERTY_MOUSE_WHEEL, &wheelDelta),
"Failed to query event wheel delta");
+ long long timestamp;
+ Q_SCREEN_CHECKERROR(screen_get_event_property_llv(event, SCREEN_PROPERTY_TIMESTAMP, &timestamp),
+ "Failed to get timestamp");
+
// Map window handle to top-level QWindow
QWindow *w = QQnxIntegration::instance()->window(qnxWindow);
@@ -415,7 +392,7 @@ void QQnxScreenEventHandler::handlePointerEvent(screen_event_t event)
if (buttonState & 0x01)
buttons |= Qt::LeftButton;
if (buttonState & 0x02)
- buttons |= Qt::MidButton;
+ buttons |= Qt::MiddleButton;
if (buttonState & 0x04)
buttons |= Qt::RightButton;
if (buttonState & 0x08)
@@ -431,20 +408,55 @@ void QQnxScreenEventHandler::handlePointerEvent(screen_event_t event)
if (w) {
// Inject mouse event into Qt only if something has changed.
- if (m_lastGlobalMousePoint != globalPoint ||
- m_lastLocalMousePoint != localPoint ||
- m_lastButtonState != buttons) {
- if (m_lastButtonState != 0 && buttons == 0)
+ if (m_lastGlobalMousePoint != globalPoint || m_lastLocalMousePoint != localPoint) {
+ QWindowSystemInterface::handleMouseEvent(w, timestamp, m_mouseDevice, localPoint,
+ globalPoint, buttons, Qt::NoButton,
+ QEvent::MouseMove);
+ qScreenEventDebug() << "Qt mouse move, w=" << w << ", (" << localPoint.x() << ","
+ << localPoint.y() << "), b=" << static_cast<int>(buttons);
+ }
+
+ if (m_lastButtonState != buttons) {
+ static const auto supportedButtons = { Qt::LeftButton, Qt::MiddleButton,
+ Qt::RightButton, Qt::ExtraButton1,
+ Qt::ExtraButton2, Qt::ExtraButton3,
+ Qt::ExtraButton4, Qt::ExtraButton5 };
+
+ int releasedButtons = (m_lastButtonState ^ buttons) & ~buttons;
+ for (auto button : supportedButtons) {
+ if (releasedButtons & button) {
+ QWindowSystemInterface::handleMouseEvent(w, timestamp, m_mouseDevice,
+ localPoint, globalPoint, buttons,
+ button, QEvent::MouseButtonRelease);
+ qScreenEventDebug() << "Qt mouse release, w=" << w << ", (" << localPoint.x()
+ << "," << localPoint.y() << "), b=" << button;
+ }
+ }
+
+ if (m_lastButtonState != 0 && buttons == 0) {
(static_cast<QQnxWindow *>(w->handle()))->handleActivationEvent();
- QWindowSystemInterface::handleMouseEvent(w, localPoint, globalPoint, buttons);
- qScreenEventDebug() << "Qt mouse, w=" << w << ", (" << localPoint.x() << "," << localPoint.y() << "), b=" << static_cast<int>(buttons);
+ }
+
+ int pressedButtons = (m_lastButtonState ^ buttons) & buttons;
+ for (auto button : supportedButtons) {
+ if (pressedButtons & button) {
+ QWindowSystemInterface::handleMouseEvent(w, timestamp, m_mouseDevice,
+ localPoint, globalPoint, buttons,
+ button, QEvent::MouseButtonPress);
+ qScreenEventDebug() << "Qt mouse press, w=" << w << ", (" << localPoint.x()
+ << "," << localPoint.y() << "), b=" << button;
+ }
+ }
}
if (wheelDelta) {
// Screen only supports a single wheel, so we will assume Vertical orientation for
// now since that is pretty much standard.
- QWindowSystemInterface::handleWheelEvent(w, localPoint, globalPoint, wheelDelta, Qt::Vertical);
- qScreenEventDebug() << "Qt wheel, w=" << w << ", (" << localPoint.x() << "," << localPoint.y() << "), d=" << static_cast<int>(wheelDelta);
+ QPoint angleDelta(0, wheelDelta);
+ QWindowSystemInterface::handleWheelEvent(w, timestamp, m_mouseDevice, localPoint,
+ globalPoint, QPoint(), angleDelta);
+ qScreenEventDebug() << "Qt wheel, w=" << w << ", (" << localPoint.x() << ","
+ << localPoint.y() << "), d=" << static_cast<int>(wheelDelta);
}
}
@@ -533,7 +545,7 @@ void QQnxScreenEventHandler::handleTouchEvent(screen_event_t event, int qnxType)
parent = parent->parent();
}
- //Qt expects the pressure between 0 and 1. There is however no definit upper limit for
+ //Qt expects the pressure between 0 and 1. There is however no definite upper limit for
//the integer value of touch event pressure. The 200 was determined by experiment, it
//usually does not get higher than that.
m_touchPoints[touchId].pressure = static_cast<qreal>(touchPressure)/200.0;
@@ -545,15 +557,15 @@ void QQnxScreenEventHandler::handleTouchEvent(screen_event_t event, int qnxType)
QEvent::Type type = QEvent::None;
switch (qnxType) {
case SCREEN_EVENT_MTOUCH_TOUCH:
- m_touchPoints[touchId].state = Qt::TouchPointPressed;
+ m_touchPoints[touchId].state = QEventPoint::State::Pressed;
type = QEvent::TouchBegin;
break;
case SCREEN_EVENT_MTOUCH_MOVE:
- m_touchPoints[touchId].state = Qt::TouchPointMoved;
+ m_touchPoints[touchId].state = QEventPoint::State::Updated;
type = QEvent::TouchUpdate;
break;
case SCREEN_EVENT_MTOUCH_RELEASE:
- m_touchPoints[touchId].state = Qt::TouchPointReleased;
+ m_touchPoints[touchId].state = QEventPoint::State::Released;
type = QEvent::TouchEnd;
break;
}
@@ -564,9 +576,9 @@ void QQnxScreenEventHandler::handleTouchEvent(screen_event_t event, int qnxType)
if (i == touchId) {
// current touch point is always active
pointList.append(m_touchPoints[i]);
- } else if (m_touchPoints[i].state != Qt::TouchPointReleased) {
+ } else if (m_touchPoints[i].state != QEventPoint::State::Released) {
// finger is down but did not move
- m_touchPoints[i].state = Qt::TouchPointStationary;
+ m_touchPoints[i].state = QEventPoint::State::Stationary;
pointList.append(m_touchPoints[i]);
}
}
@@ -698,7 +710,7 @@ void QQnxScreenEventHandler::handleKeyboardFocusPropertyEvent(screen_window_t wi
}
if (focus && focusWindow != QGuiApplication::focusWindow())
- QWindowSystemInterface::handleWindowActivated(focusWindow);
+ QWindowSystemInterface::handleFocusWindowChanged(focusWindow, Qt::ActiveWindowFocusReason);
else if (!focus && focusWindow == QGuiApplication::focusWindow())
m_focusLostTimer = startTimer(50);
}
@@ -736,6 +748,6 @@ void QQnxScreenEventHandler::timerEvent(QTimerEvent *event)
}
}
-#include "moc_qqnxscreeneventhandler.cpp"
-
QT_END_NAMESPACE
+
+#include "moc_qqnxscreeneventhandler.cpp"
diff --git a/src/plugins/platforms/qnx/qqnxscreeneventhandler.h b/src/plugins/platforms/qnx/qqnxscreeneventhandler.h
index b35967610e..d27186af9e 100644
--- a/src/plugins/platforms/qnx/qqnxscreeneventhandler.h
+++ b/src/plugins/platforms/qnx/qqnxscreeneventhandler.h
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2013 BlackBerry Limited. All rights reserved.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2013 BlackBerry Limited. All rights reserved.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQNXSCREENEVENTHANDLER_H
#define QQNXSCREENEVENTHANDLER_H
@@ -97,7 +61,8 @@ private:
QPoint m_lastLocalMousePoint;
Qt::MouseButtons m_lastButtonState;
screen_window_t m_lastMouseWindow;
- QTouchDevice *m_touchDevice;
+ QPointingDevice *m_touchDevice;
+ QPointingDevice *m_mouseDevice;
QWindowSystemInterface::TouchPoint m_touchPoints[MaximumTouchPoints];
QList<QQnxScreenEventFilter*> m_eventFilters;
QQnxScreenEventThread *m_eventThread;
diff --git a/src/plugins/platforms/qnx/qqnxscreeneventthread.cpp b/src/plugins/platforms/qnx/qqnxscreeneventthread.cpp
index 491c314488..69997e4ba0 100644
--- a/src/plugins/platforms/qnx/qqnxscreeneventthread.cpp
+++ b/src/plugins/platforms/qnx/qqnxscreeneventthread.cpp
@@ -1,42 +1,6 @@
-/***************************************************************************
-**
-** Copyright (C) 2017 QNX Software Systems. All rights reserved.
-** Copyright (C) 2011 - 2012 Research In Motion
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 QNX Software Systems. All rights reserved.
+// Copyright (C) 2011 - 2012 Research In Motion
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqnxglobal.h"
diff --git a/src/plugins/platforms/qnx/qqnxscreeneventthread.h b/src/plugins/platforms/qnx/qqnxscreeneventthread.h
index e5b762369c..482cd5c967 100644
--- a/src/plugins/platforms/qnx/qqnxscreeneventthread.h
+++ b/src/plugins/platforms/qnx/qqnxscreeneventthread.h
@@ -1,42 +1,6 @@
-/***************************************************************************
-**
-** Copyright (C) 2017 QNX Software Systems. All rights reserved.
-** Copyright (C) 2011 - 2012 Research In Motion
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 QNX Software Systems. All rights reserved.
+// Copyright (C) 2011 - 2012 Research In Motion
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQNXSCREENEVENTTHREAD_H
#define QQNXSCREENEVENTTHREAD_H
diff --git a/src/plugins/platforms/qnx/qqnxscreentraits.h b/src/plugins/platforms/qnx/qqnxscreentraits.h
index ebd74141f2..983ef53048 100644
--- a/src/plugins/platforms/qnx/qqnxscreentraits.h
+++ b/src/plugins/platforms/qnx/qqnxscreentraits.h
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2018 QNX Software Systems. All rights reserved.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2018 QNX Software Systems. All rights reserved.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQNXSCREENTRAITS_H
#define QQNXSCREENTRAITS_H
diff --git a/src/plugins/platforms/qnx/qqnxservices.cpp b/src/plugins/platforms/qnx/qqnxservices.cpp
index 76c4ac34f9..379bb63507 100644
--- a/src/plugins/platforms/qnx/qqnxservices.cpp
+++ b/src/plugins/platforms/qnx/qqnxservices.cpp
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2011 - 2012 Research In Motion
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2011 - 2012 Research In Motion
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqnxservices.h"
diff --git a/src/plugins/platforms/qnx/qqnxservices.h b/src/plugins/platforms/qnx/qqnxservices.h
index cbf029fdb9..dfe385bf76 100644
--- a/src/plugins/platforms/qnx/qqnxservices.h
+++ b/src/plugins/platforms/qnx/qqnxservices.h
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2011 - 2012 Research In Motion
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2011 - 2012 Research In Motion
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQNXSERVICES_H
#define QQNXSERVICES_H
diff --git a/src/plugins/platforms/qnx/qqnxvirtualkeyboardpps.cpp b/src/plugins/platforms/qnx/qqnxvirtualkeyboardpps.cpp
index 025c03c058..b4650de315 100644
--- a/src/plugins/platforms/qnx/qqnxvirtualkeyboardpps.cpp
+++ b/src/plugins/platforms/qnx/qqnxvirtualkeyboardpps.cpp
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2011 - 2012 Research In Motion
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2011 - 2012 Research In Motion
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqnxvirtualkeyboardpps.h"
#include "qqnxscreen.h"
@@ -134,7 +98,7 @@ bool QQnxVirtualKeyboardPps::connect()
m_buffer = new char[ms_bufferSize];
if (Q_UNLIKELY(!m_buffer)) {
- qCritical("QQnxVirtualKeyboard: Unable to allocate buffer of %d bytes. "
+ qCritical("QQnxVirtualKeyboard: Unable to allocate buffer of %zu bytes. "
"Size is unavailable.", ms_bufferSize);
return false;
}
@@ -143,7 +107,7 @@ bool QQnxVirtualKeyboardPps::connect()
return false;
m_readNotifier = new QSocketNotifier(m_fd, QSocketNotifier::Read);
- QObject::connect(m_readNotifier, SIGNAL(activated(int)), this, SLOT(ppsDataReady()));
+ QObject::connect(m_readNotifier, SIGNAL(activated(QSocketDescriptor)), this, SLOT(ppsDataReady()));
return true;
}
@@ -162,9 +126,9 @@ bool QQnxVirtualKeyboardPps::queryPPSInfo()
void QQnxVirtualKeyboardPps::ppsDataReady()
{
- ssize_t nread = qt_safe_read(m_fd, m_buffer, ms_bufferSize - 1);
+ qint64 nread = qt_safe_read(m_fd, m_buffer, ms_bufferSize - 1);
- qVirtualKeyboardDebug("keyboardMessage size: %zd", nread);
+ qVirtualKeyboardDebug("keyboardMessage size: %lld", nread);
if (nread < 0){
connect(); // reconnect
return;
@@ -177,7 +141,7 @@ void QQnxVirtualKeyboardPps::ppsDataReady()
// nread is the real space necessary, not the amount read.
if (Q_UNLIKELY(static_cast<size_t>(nread) > ms_bufferSize - 1)) {
- qCritical("QQnxVirtualKeyboard: Keyboard buffer size too short; need %u.", nread + 1);
+ qCritical("QQnxVirtualKeyboard: Keyboard buffer size too short; need %lld.", nread + 1);
connect(); // reconnect
return;
}
@@ -240,7 +204,7 @@ bool QQnxVirtualKeyboardPps::showKeyboard()
if (!prepareToSend())
return false;
- // NOTE: This must be done everytime the keyboard is shown even if there is no change because
+ // NOTE: This must be done every time the keyboard is shown even if there is no change because
// hiding the keyboard wipes the setting.
applyKeyboardOptions();
diff --git a/src/plugins/platforms/qnx/qqnxvirtualkeyboardpps.h b/src/plugins/platforms/qnx/qqnxvirtualkeyboardpps.h
index 51d55a2036..88af284db3 100644
--- a/src/plugins/platforms/qnx/qqnxvirtualkeyboardpps.h
+++ b/src/plugins/platforms/qnx/qqnxvirtualkeyboardpps.h
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2011 - 2012 Research In Motion
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2011 - 2012 Research In Motion
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef VIRTUALKEYBOARDPPS_H
#define VIRTUALKEYBOARDPPS_H
diff --git a/src/plugins/platforms/qnx/qqnxwindow.cpp b/src/plugins/platforms/qnx/qqnxwindow.cpp
index 1d3d609017..eed45227f6 100644
--- a/src/plugins/platforms/qnx/qqnxwindow.cpp
+++ b/src/plugins/platforms/qnx/qqnxwindow.cpp
@@ -1,41 +1,7 @@
-/***************************************************************************
-**
-** Copyright (C) 2011 - 2013 BlackBerry Limited. All rights reserved.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2011 - 2013 BlackBerry Limited. All rights reserved.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#undef QT_NO_FOREACH // this file contains unported legacy Q_FOREACH uses
#include "qqnxglobal.h"
@@ -157,7 +123,6 @@ QQnxWindow::QQnxWindow(QWindow *window, screen_context_t context, bool needRootW
m_exposed(true),
m_foreign(false),
m_windowState(Qt::WindowNoState),
- m_mmRendererWindow(0),
m_firstActivateHandled(false)
{
qWindowDebug() << "window =" << window << ", size =" << window->size();
@@ -225,6 +190,21 @@ QQnxWindow::QQnxWindow(QWindow *window, screen_context_t context, bool needRootW
if (windowGroup.isValid() && windowGroup.canConvert<QByteArray>())
joinWindowGroup(windowGroup.toByteArray());
+ QVariant pipelineValue = window->property("_q_platform_qnxPipeline");
+ if (pipelineValue.isValid()) {
+ bool ok = false;
+ int pipeline = pipelineValue.toInt(&ok);
+ if (ok) {
+ qWindowDebug() << "Set pipeline value to" << pipeline;
+
+ Q_SCREEN_CHECKERROR(
+ screen_set_window_property_iv(m_window, SCREEN_PROPERTY_PIPELINE, &pipeline),
+ "Failed to set window pipeline");
+ } else {
+ qWindowDebug() << "Invalid pipeline value:" << pipelineValue;
+ }
+ }
+
int debug = 0;
if (Q_UNLIKELY(debug_fps())) {
debug |= SCREEN_DEBUG_GRAPH_FPS;
@@ -265,7 +245,6 @@ QQnxWindow::QQnxWindow(QWindow *window, screen_context_t context, screen_window_
, m_exposed(true)
, m_foreign(true)
, m_windowState(Qt::WindowNoState)
- , m_mmRendererWindow(0)
, m_parentGroupName(256, 0)
, m_isTopLevel(false)
{
@@ -551,7 +530,7 @@ void QQnxWindow::removeFromParent()
if (Q_UNLIKELY(!m_parentWindow->m_childWindows.removeAll(this)))
qFatal("QQnxWindow: Window Hierarchy broken; window has parent, but parent hasn't got child.");
else
- m_parentWindow = 0;
+ m_parentWindow = nullptr;
} else if (m_screen) {
m_screen->removeWindow(this);
}
@@ -619,7 +598,7 @@ void QQnxWindow::lower()
void QQnxWindow::requestActivateWindow()
{
- QQnxWindow *focusWindow = 0;
+ QQnxWindow *focusWindow = nullptr;
if (QGuiApplication::focusWindow())
focusWindow = static_cast<QQnxWindow*>(QGuiApplication::focusWindow()->handle());
@@ -649,7 +628,7 @@ void QQnxWindow::requestActivateWindow()
platformScreen->rootWindow()->m_windowGroupName == currentWindow->m_parentGroupName) {
currentWindow = platformScreen->rootWindow();
} else {
- currentWindow = 0;
+ currentWindow = nullptr;
}
}
@@ -737,22 +716,6 @@ void QQnxWindow::propagateSizeHints()
qWindowDebug("ignored");
}
-void QQnxWindow::setMMRendererWindowName(const QString &name)
-{
- m_mmRendererWindowName = name;
-}
-
-void QQnxWindow::setMMRendererWindow(screen_window_t handle)
-{
- m_mmRendererWindow = handle;
-}
-
-void QQnxWindow::clearMMRendererWindow()
-{
- m_mmRendererWindowName.clear();
- m_mmRendererWindow = 0;
-}
-
QPlatformScreen *QQnxWindow::screen() const
{
return m_screen;
@@ -897,9 +860,6 @@ void QQnxWindow::updateZorder(int &topZorder)
{
updateZorder(m_window, topZorder);
- if (m_mmRendererWindow)
- updateZorder(m_mmRendererWindow, topZorder);
-
Q_FOREACH (QQnxWindow *childWindow, m_childWindows)
childWindow->updateZorder(topZorder);
}
@@ -931,10 +891,12 @@ void QQnxWindow::applyWindowState()
void QQnxWindow::windowPosted()
{
- if (m_cover)
+ if (m_cover) {
m_cover->updateCover();
-
- qqnxLgmonFramePosted(m_cover); // for performance measurements
+ qqnxLgmonFramePosted(true); // for performance measurements
+ } else {
+ qqnxLgmonFramePosted(false); // for performance measurements
+ }
}
bool QQnxWindow::shouldMakeFullScreen() const
diff --git a/src/plugins/platforms/qnx/qqnxwindow.h b/src/plugins/platforms/qnx/qqnxwindow.h
index 9040619c41..d302f22415 100644
--- a/src/plugins/platforms/qnx/qqnxwindow.h
+++ b/src/plugins/platforms/qnx/qqnxwindow.h
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2011 - 2013 BlackBerry Limited. All rights reserved.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2011 - 2013 BlackBerry Limited. All rights reserved.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQNXWINDOW_H
#define QQNXWINDOW_H
@@ -91,10 +55,6 @@ public:
void propagateSizeHints() override;
- void setMMRendererWindowName(const QString &name);
- void setMMRendererWindow(screen_window_t handle);
- void clearMMRendererWindow();
-
QPlatformScreen *screen() const override;
const QList<QQnxWindow*>& children() const { return m_childWindows; }
@@ -102,10 +62,6 @@ public:
void minimize();
- QString mmRendererWindowName() const { return m_mmRendererWindowName; }
-
- screen_window_t mmRendererWindow() const { return m_mmRendererWindow; }
-
void setRotation(int rotation);
QByteArray groupName() const { return m_windowGroupName; }
@@ -152,8 +108,6 @@ private:
bool m_foreign;
QRect m_unmaximizedGeometry;
Qt::WindowStates m_windowState;
- QString m_mmRendererWindowName;
- screen_window_t m_mmRendererWindow;
// Group name of window group headed by this window
QByteArray m_windowGroupName;
diff --git a/src/plugins/platforms/vkkhrdisplay/CMakeLists.txt b/src/plugins/platforms/vkkhrdisplay/CMakeLists.txt
new file mode 100644
index 0000000000..719e5c45e6
--- /dev/null
+++ b/src/plugins/platforms/vkkhrdisplay/CMakeLists.txt
@@ -0,0 +1,32 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+qt_find_package(WrapFreetype PROVIDED_TARGETS WrapFreetype::WrapFreetype)
+
+qt_internal_add_plugin(QVkKhrDisplayIntegrationPlugin
+ OUTPUT_NAME qvkkhrdisplay
+ PLUGIN_TYPE platforms
+ DEFAULT_IF ${QT_QPA_DEFAULT_PLATFORM} MATCHES vkkhrdisplay
+ SOURCES
+ main.cpp
+ qvkkhrdisplayintegration.cpp qvkkhrdisplayintegration.h
+ qvkkhrdisplayvulkaninstance.cpp qvkkhrdisplayvulkaninstance.h
+ DEFINES
+ QT_NO_FOREACH
+ LIBRARIES
+ Qt::Core
+ Qt::CorePrivate
+ Qt::FbSupportPrivate
+ Qt::Gui
+ Qt::GuiPrivate
+)
+
+qt_internal_extend_target(QVkKhrDisplayIntegrationPlugin CONDITION QT_FEATURE_freetype
+ LIBRARIES
+ WrapFreetype::WrapFreetype
+)
+
+qt_internal_extend_target(QVkKhrDisplayIntegrationPlugin CONDITION TARGET Qt::InputSupportPrivate
+ LIBRARIES
+ Qt::InputSupportPrivate
+)
diff --git a/src/plugins/platforms/vkkhrdisplay/main.cpp b/src/plugins/platforms/vkkhrdisplay/main.cpp
new file mode 100644
index 0000000000..aa2dc3abf5
--- /dev/null
+++ b/src/plugins/platforms/vkkhrdisplay/main.cpp
@@ -0,0 +1,29 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <qpa/qplatformintegrationplugin.h>
+#include "qvkkhrdisplayintegration.h"
+
+QT_BEGIN_NAMESPACE
+
+using namespace Qt::StringLiterals;
+
+class QVkKhrDisplayIntegrationPlugin : public QPlatformIntegrationPlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID QPlatformIntegrationFactoryInterface_iid FILE "vkkhrdisplay.json")
+public:
+ QPlatformIntegration *create(const QString&, const QStringList&) override;
+};
+
+QPlatformIntegration *QVkKhrDisplayIntegrationPlugin::create(const QString &system, const QStringList &paramList)
+{
+ if (!system.compare("vkkhrdisplay"_L1, Qt::CaseInsensitive))
+ return new QVkKhrDisplayIntegration(paramList);
+
+ return nullptr;
+}
+
+QT_END_NAMESPACE
+
+#include "main.moc"
diff --git a/src/plugins/platforms/vkkhrdisplay/qvkkhrdisplayintegration.cpp b/src/plugins/platforms/vkkhrdisplay/qvkkhrdisplayintegration.cpp
new file mode 100644
index 0000000000..502c2518f2
--- /dev/null
+++ b/src/plugins/platforms/vkkhrdisplay/qvkkhrdisplayintegration.cpp
@@ -0,0 +1,315 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qvkkhrdisplayintegration.h"
+#include "qvkkhrdisplayvulkaninstance.h"
+
+#include <qpa/qplatformwindow.h>
+#include <qpa/qplatformbackingstore.h>
+#include <qpa/qplatforminputcontextfactory_p.h>
+#include <qpa/qwindowsysteminterface.h>
+
+#include <QtGui/private/qguiapplication_p.h>
+#include <QtGui/private/qwindow_p.h>
+#include <QtGui/private/qgenericunixeventdispatcher_p.h>
+#include <QtGui/private/qgenericunixfontdatabase_p.h>
+#include <QtGui/private/qgenericunixthemes_p.h>
+#include <QtGui/private/qgenericunixservices_p.h>
+
+#include <QtFbSupport/private/qfbvthandler_p.h>
+
+#if QT_CONFIG(libinput)
+#include <QtInputSupport/private/qlibinputhandler_p.h>
+#endif
+
+#if QT_CONFIG(evdev)
+#include <QtInputSupport/private/qevdevmousemanager_p.h>
+#include <QtInputSupport/private/qevdevkeyboardmanager_p.h>
+#include <QtInputSupport/private/qevdevtouchmanager_p.h>
+#endif
+
+#if QT_CONFIG(tslib)
+#include <QtInputSupport/private/qtslib_p.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+using namespace Qt::StringLiterals;
+
+class QVkKhrDisplayScreen : public QPlatformScreen
+{
+public:
+ QRect geometry() const override { return m_geometry; }
+ int depth() const override { return m_depth; }
+ QImage::Format format() const override { return m_format; }
+ void setVk(QVkKhrDisplayVulkanInstance *inst);
+
+private:
+ QVkKhrDisplayVulkanInstance *m_vk = nullptr;
+ QRect m_geometry;
+ int m_depth = 32;
+ QImage::Format m_format = QImage::Format_ARGB32_Premultiplied;
+ friend class QVkKhrDisplayIntegration;
+};
+
+void QVkKhrDisplayScreen::setVk(QVkKhrDisplayVulkanInstance *inst)
+{
+ m_vk = inst;
+ m_geometry = QRect(QPoint(0, 0), m_vk->displaySize());
+ QWindowSystemInterface::handleScreenGeometryChange(screen(), m_geometry, m_geometry);
+ qDebug() << "Screen will report geometry" << m_geometry;
+
+ // Thanks to this deferred screen setup, a QWindow with a size based on the
+ // dummy screen size may already exist. Try to resize it.
+ QScreen *thisScreen = screen();
+ for (QWindow *window : QGuiApplication::allWindows()) {
+ if (window->isTopLevel() && window->screen() == thisScreen)
+ window->handle()->setGeometry(QRect()); // set fullscreen geometry
+ }
+}
+
+class QVkKhrDisplayWindow : public QPlatformWindow
+{
+public:
+ QVkKhrDisplayWindow(QWindow *window) : QPlatformWindow(window) { }
+ ~QVkKhrDisplayWindow();
+
+ void *vulkanSurfacePtr();
+
+ void setGeometry(const QRect &r) override;
+
+private:
+ VkSurfaceKHR m_surface = VK_NULL_HANDLE;
+};
+
+QVkKhrDisplayWindow::~QVkKhrDisplayWindow()
+{
+ if (m_surface) {
+ QVulkanInstance *inst = window()->vulkanInstance();
+ if (inst)
+ static_cast<QVkKhrDisplayVulkanInstance *>(inst->handle())->destroySurface(m_surface);
+ }
+}
+
+void *QVkKhrDisplayWindow::vulkanSurfacePtr()
+{
+ if (m_surface)
+ return &m_surface;
+
+ QVulkanInstance *inst = window()->vulkanInstance();
+ if (!inst) {
+ qWarning("Attempted to create Vulkan surface without an instance; was QWindow::setVulkanInstance() called?");
+ return nullptr;
+ }
+ QVkKhrDisplayVulkanInstance *vkdinst = static_cast<QVkKhrDisplayVulkanInstance *>(inst->handle());
+ m_surface = vkdinst->createSurface(window());
+
+ return &m_surface;
+}
+
+void QVkKhrDisplayWindow::setGeometry(const QRect &)
+{
+ // We only support full-screen windows
+ QRect rect(screen()->availableGeometry());
+ QWindowSystemInterface::handleGeometryChange(window(), rect);
+ QPlatformWindow::setGeometry(rect);
+
+ const QRect lastReportedGeometry = qt_window_private(window())->geometry;
+ if (rect != lastReportedGeometry)
+ QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(0, 0), rect.size()));
+}
+
+// does not actually support raster content, just paint into a QImage and that's it for now
+class QVkKhrDisplayBackingStore : public QPlatformBackingStore
+{
+public:
+ QVkKhrDisplayBackingStore(QWindow *window) : QPlatformBackingStore(window) { }
+
+ QPaintDevice *paintDevice() override { return &m_image; }
+ void flush(QWindow *window, const QRegion &region, const QPoint &offset) override {
+ Q_UNUSED(window);
+ Q_UNUSED(region);
+ Q_UNUSED(offset);
+ }
+ void resize(const QSize &size, const QRegion &staticContents) override {
+ Q_UNUSED(staticContents);
+ QImage::Format format = QGuiApplication::primaryScreen()->handle()->format();
+ if (m_image.size() != size)
+ m_image = QImage(size, format);
+ }
+
+private:
+ QImage m_image;
+};
+
+QVkKhrDisplayIntegration::QVkKhrDisplayIntegration(const QStringList &parameters)
+{
+ Q_UNUSED(parameters);
+}
+
+QVkKhrDisplayIntegration::~QVkKhrDisplayIntegration()
+{
+ QWindowSystemInterface::handleScreenRemoved(m_primaryScreen);
+ delete m_services;
+ delete m_fontDatabase;
+ delete m_vtHandler;
+}
+
+bool QVkKhrDisplayIntegration::hasCapability(QPlatformIntegration::Capability cap) const
+{
+ switch (cap) {
+ case ThreadedPixmaps: return true;
+ case WindowManagement: return false;
+ default: return QPlatformIntegration::hasCapability(cap);
+ }
+}
+
+void QVkKhrDisplayIntegration::initialize()
+{
+ m_primaryScreen = new QVkKhrDisplayScreen;
+
+ // The real values are only known when the QVulkanInstance initializes, use
+ // dummy values until then.
+ m_primaryScreen->m_geometry = QRect(0, 0, 1920, 1080);
+ m_primaryScreen->m_depth = 32;
+ m_primaryScreen->m_format = QImage::Format_ARGB32_Premultiplied;
+
+ QWindowSystemInterface::handleScreenAdded(m_primaryScreen);
+
+ m_inputContext = QPlatformInputContextFactory::create();
+
+ m_vtHandler = new QFbVtHandler;
+
+ if (!qEnvironmentVariableIntValue("QT_QPA_DISABLE_INPUT"))
+ createInputHandlers();
+}
+
+QPlatformFontDatabase *QVkKhrDisplayIntegration::fontDatabase() const
+{
+ if (!m_fontDatabase)
+ m_fontDatabase = new QGenericUnixFontDatabase;
+
+ return m_fontDatabase;
+}
+
+QPlatformServices *QVkKhrDisplayIntegration::services() const
+{
+ if (!m_services)
+ m_services = new QGenericUnixServices;
+
+ return m_services;
+}
+
+QPlatformInputContext *QVkKhrDisplayIntegration::inputContext() const
+{
+ return m_inputContext;
+}
+
+QPlatformTheme *QVkKhrDisplayIntegration::createPlatformTheme(const QString &name) const
+{
+ return QGenericUnixTheme::createUnixTheme(name);
+}
+
+QPlatformNativeInterface *QVkKhrDisplayIntegration::nativeInterface() const
+{
+ return const_cast<QVkKhrDisplayIntegration *>(this);
+}
+
+QPlatformWindow *QVkKhrDisplayIntegration::createPlatformWindow(QWindow *window) const
+{
+ if (window->surfaceType() != QSurface::VulkanSurface) {
+ qWarning("vkkhrdisplay platform plugin only supports QWindow with surfaceType == VulkanSurface");
+ // Assume VulkanSurface, better than crashing. Consider e.g. an autotest
+ // creating a default QWindow just to have something to be used with
+ // QRhi's Null backend. Continuing to set up a Vulkan window (even
+ // though the request was Raster or something) is better than failing to
+ // create a platform window, and may even be sufficient in some cases.
+ }
+
+ QVkKhrDisplayWindow *w = new QVkKhrDisplayWindow(window);
+ w->setGeometry(QRect()); // set fullscreen geometry
+ w->requestActivateWindow();
+ return w;
+}
+
+QPlatformBackingStore *QVkKhrDisplayIntegration::createPlatformBackingStore(QWindow *window) const
+{
+ return new QVkKhrDisplayBackingStore(window);
+}
+
+QAbstractEventDispatcher *QVkKhrDisplayIntegration::createEventDispatcher() const
+{
+ return createUnixEventDispatcher();
+}
+
+void QVkKhrDisplayIntegration::handleInstanceCreated(QVkKhrDisplayVulkanInstance *inst, void *userData)
+{
+ QVkKhrDisplayIntegration *self = static_cast<QVkKhrDisplayIntegration *>(userData);
+ self->m_primaryScreen->setVk(inst);
+}
+
+QPlatformVulkanInstance *QVkKhrDisplayIntegration::createPlatformVulkanInstance(QVulkanInstance *instance) const
+{
+ QVkKhrDisplayVulkanInstance *inst = new QVkKhrDisplayVulkanInstance(instance);
+ inst->setCreatedCallback(handleInstanceCreated, const_cast<QVkKhrDisplayIntegration *>(this));
+ return inst;
+}
+
+enum ResourceType {
+ VkSurface
+};
+
+static int resourceType(const QByteArray &key)
+{
+ static const QByteArray names[] = { // match ResourceType
+ QByteArrayLiteral("vksurface")
+ };
+ const QByteArray *end = names + sizeof(names) / sizeof(names[0]);
+ const QByteArray *result = std::find(names, end, key);
+ if (result == end)
+ result = std::find(names, end, key.toLower());
+ return int(result - names);
+}
+
+void *QVkKhrDisplayIntegration::nativeResourceForWindow(const QByteArray &resource, QWindow *window)
+{
+ void *result = nullptr;
+
+ switch (resourceType(resource)) {
+ case VkSurface:
+ if (window && window->handle() && window->surfaceType() == QSurface::VulkanSurface)
+ result = static_cast<QVkKhrDisplayWindow *>(window->handle())->vulkanSurfacePtr();
+ break;
+ default:
+ break;
+ }
+
+ return result;
+}
+
+void QVkKhrDisplayIntegration::createInputHandlers()
+{
+#if QT_CONFIG(libinput)
+ if (!qEnvironmentVariableIntValue("QT_QPA_NO_LIBINPUT")) {
+ new QLibInputHandler("libinput"_L1, QString());
+ return;
+ }
+#endif
+
+#if QT_CONFIG(tslib)
+ bool useTslib = qEnvironmentVariableIntValue("QT_QPA_TSLIB");
+ if (useTslib)
+ new QTsLibMouseHandler("TsLib"_L1, QString());
+#endif
+
+#if QT_CONFIG(evdev)
+ new QEvdevKeyboardManager("EvdevKeyboard"_L1, QString(), this);
+ new QEvdevMouseManager("EvdevMouse"_L1, QString(), this);
+#if QT_CONFIG(tslib)
+ if (!useTslib)
+#endif
+ new QEvdevTouchManager("EvdevTouch"_L1, QString() /* spec */, this);
+#endif
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/vkkhrdisplay/qvkkhrdisplayintegration.h b/src/plugins/platforms/vkkhrdisplay/qvkkhrdisplayintegration.h
new file mode 100644
index 0000000000..a80b831226
--- /dev/null
+++ b/src/plugins/platforms/vkkhrdisplay/qvkkhrdisplayintegration.h
@@ -0,0 +1,52 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QPLATFORMINTEGRATION_VKKHRDISPLAY_H
+#define QPLATFORMINTEGRATION_VKKHRDISPLAY_H
+
+#include <qpa/qplatformintegration.h>
+#include <qpa/qplatformnativeinterface.h>
+#include <qpa/qplatformscreen.h>
+
+QT_BEGIN_NAMESPACE
+
+class QVkKhrDisplayScreen;
+class QVkKhrDisplayVulkanInstance;
+class QFbVtHandler;
+
+class QVkKhrDisplayIntegration : public QPlatformIntegration, public QPlatformNativeInterface
+{
+public:
+ explicit QVkKhrDisplayIntegration(const QStringList &parameters);
+ ~QVkKhrDisplayIntegration();
+
+ void initialize() override;
+
+ bool hasCapability(QPlatformIntegration::Capability cap) const override;
+ QPlatformFontDatabase *fontDatabase() const override;
+ QPlatformServices *services() const override;
+ QPlatformInputContext *inputContext() const override;
+ QPlatformTheme *createPlatformTheme(const QString &name) const override;
+ QPlatformNativeInterface *nativeInterface() const override;
+
+ QPlatformWindow *createPlatformWindow(QWindow *window) const override;
+ QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const override;
+ QAbstractEventDispatcher *createEventDispatcher() const override;
+ QPlatformVulkanInstance *createPlatformVulkanInstance(QVulkanInstance *instance) const override;
+
+ void *nativeResourceForWindow(const QByteArray &resource, QWindow *window) override;
+
+private:
+ static void handleInstanceCreated(QVkKhrDisplayVulkanInstance *, void *);
+ void createInputHandlers();
+
+ mutable QPlatformFontDatabase *m_fontDatabase = nullptr;
+ mutable QPlatformServices *m_services = nullptr;
+ QPlatformInputContext *m_inputContext = nullptr;
+ QFbVtHandler *m_vtHandler = nullptr;
+ QVkKhrDisplayScreen *m_primaryScreen = nullptr;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/plugins/platforms/eglfs/api/vulkan/qeglfsvulkaninstance.cpp b/src/plugins/platforms/vkkhrdisplay/qvkkhrdisplayvulkaninstance.cpp
index a75251ca5f..2e8d60209e 100644
--- a/src/plugins/platforms/eglfs/api/vulkan/qeglfsvulkaninstance.cpp
+++ b/src/plugins/platforms/vkkhrdisplay/qvkkhrdisplayvulkaninstance.cpp
@@ -1,65 +1,26 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 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 "qeglfsvulkaninstance_p.h"
-#include "qeglfswindow_p.h"
-#include "qeglfshooks_p.h"
-#include <QLoggingCategory>
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-QT_BEGIN_NAMESPACE
+#include "qvkkhrdisplayvulkaninstance.h"
+#include <QVarLengthArray>
-Q_DECLARE_LOGGING_CATEGORY(qLcEglDevDebug)
+QT_BEGIN_NAMESPACE
-QEglFSVulkanInstance::QEglFSVulkanInstance(QVulkanInstance *instance)
+QVkKhrDisplayVulkanInstance::QVkKhrDisplayVulkanInstance(QVulkanInstance *instance)
: m_instance(instance)
{
- loadVulkanLibrary(QStringLiteral("vulkan"));
+ loadVulkanLibrary(QStringLiteral("vulkan"), 1);
}
-void QEglFSVulkanInstance::createOrAdoptInstance()
+void QVkKhrDisplayVulkanInstance::createOrAdoptInstance()
{
- qCDebug(qLcEglDevDebug, "Creating Vulkan instance for VK_KHR_display");
+ qDebug("Creating Vulkan instance for VK_KHR_display");
const QByteArray extName = QByteArrayLiteral("VK_KHR_display");
initInstance(m_instance, { extName });
if (!m_vkInst)
return;
+
if (!enabledExtensions().contains(extName)) {
qWarning("Failed to enable VK_KHR_display extension");
return;
@@ -85,6 +46,9 @@ void QEglFSVulkanInstance::createOrAdoptInstance()
m_enumeratePhysicalDevices = (PFN_vkEnumeratePhysicalDevices)
m_vkGetInstanceProcAddr(m_vkInst, "vkEnumeratePhysicalDevices");
+ m_getPhysicalDeviceSurfaceSupportKHR = reinterpret_cast<PFN_vkGetPhysicalDeviceSurfaceSupportKHR>(
+ m_vkGetInstanceProcAddr(m_vkInst, "vkGetPhysicalDeviceSurfaceSupportKHR"));
+
// Use for first physical device, unless overridden by QT_VK_PHYSICAL_DEVICE_INDEX.
// This behavior matches what the Vulkan backend of QRhi would do.
@@ -109,55 +73,62 @@ void QEglFSVulkanInstance::createOrAdoptInstance()
if (m_physDev == VK_NULL_HANDLE)
m_physDev = physDevs[0];
+
+ if (chooseDisplay()) {
+ if (m_createdCallback)
+ m_createdCallback(this, m_createdCallbackUserData);
+ }
}
-bool QEglFSVulkanInstance::supportsPresent(VkPhysicalDevice physicalDevice,
- uint32_t queueFamilyIndex,
- QWindow *window)
+bool QVkKhrDisplayVulkanInstance::supportsPresent(VkPhysicalDevice physicalDevice,
+ uint32_t queueFamilyIndex,
+ QWindow *window)
{
- Q_UNUSED(physicalDevice);
- Q_UNUSED(queueFamilyIndex);
- Q_UNUSED(window);
- return true;
+ if (!m_getPhysicalDeviceSurfaceSupportKHR)
+ return true;
+
+ VkSurfaceKHR surface = QVulkanInstance::surfaceForWindow(window);
+ VkBool32 supported = false;
+ m_getPhysicalDeviceSurfaceSupportKHR(physicalDevice, queueFamilyIndex, surface, &supported);
+
+ return supported;
}
-VkSurfaceKHR QEglFSVulkanInstance::createSurface(QEglFSWindow *window)
+bool QVkKhrDisplayVulkanInstance::chooseDisplay()
{
#if VK_KHR_display
- qCDebug(qLcEglDevDebug, "Creating VkSurfaceKHR via VK_KHR_display for window %p", (void *) window);
-
- if (!m_physDev) {
- qWarning("No physical device, cannot create surface");
- return VK_NULL_HANDLE;
- }
-
uint32_t displayCount = 0;
VkResult err = m_getPhysicalDeviceDisplayPropertiesKHR(m_physDev, &displayCount, nullptr);
if (err != VK_SUCCESS) {
qWarning("Failed to get display properties: %d", err);
- return VK_NULL_HANDLE;
+ return false;
}
- qCDebug(qLcEglDevDebug, "Display count: %u", displayCount);
+ qDebug("Display count: %u", displayCount);
QVarLengthArray<VkDisplayPropertiesKHR, 4> displayProps(displayCount);
m_getPhysicalDeviceDisplayPropertiesKHR(m_physDev, &displayCount, displayProps.data());
- VkDisplayKHR display = VK_NULL_HANDLE;
- VkDisplayModeKHR displayMode = VK_NULL_HANDLE;
- uint32_t width = 0;
- uint32_t height = 0;
+ m_display = VK_NULL_HANDLE;
+ m_displayMode = VK_NULL_HANDLE;
+
+ // Pick the first display and the first mode, unless specified via env.vars.
+ uint32_t wantedDisplayIndex = 0;
+ uint32_t wantedModeIndex = 0;
+ if (qEnvironmentVariableIsSet("QT_VK_DISPLAY_INDEX"))
+ wantedDisplayIndex = uint32_t(qEnvironmentVariableIntValue("QT_VK_DISPLAY_INDEX"));
+ if (qEnvironmentVariableIsSet("QT_VK_MODE_INDEX"))
+ wantedModeIndex = uint32_t(qEnvironmentVariableIntValue("QT_VK_MODE_INDEX"));
for (uint32_t i = 0; i < displayCount; ++i) {
const VkDisplayPropertiesKHR &disp(displayProps[i]);
- qCDebug(qLcEglDevDebug, "Display #%u:\n display: %p\n name: %s\n dimensions: %ux%u\n resolution: %ux%u",
+ qDebug("Display #%u:\n display: %p\n name: %s\n dimensions: %ux%u\n resolution: %ux%u",
i, (void *) disp.display, disp.displayName,
disp.physicalDimensions.width, disp.physicalDimensions.height,
disp.physicalResolution.width, disp.physicalResolution.height);
- // Just pick the first display and the first mode.
- if (i == 0)
- display = disp.display;
+ if (i == wantedDisplayIndex)
+ m_display = disp.display;
uint32_t modeCount = 0;
if (m_getDisplayModePropertiesKHR(m_physDev, disp.display, &modeCount, nullptr) != VK_SUCCESS) {
@@ -168,56 +139,59 @@ VkSurfaceKHR QEglFSVulkanInstance::createSurface(QEglFSWindow *window)
m_getDisplayModePropertiesKHR(m_physDev, disp.display, &modeCount, modeProps.data());
for (uint32_t j = 0; j < modeCount; ++j) {
const VkDisplayModePropertiesKHR &mode(modeProps[j]);
- qCDebug(qLcEglDevDebug, " Mode #%u:\n mode: %p\n visibleRegion: %ux%u\n refreshRate: %u",
+ qDebug(" Mode #%u:\n mode: %p\n visibleRegion: %ux%u\n refreshRate: %u",
j, (void *) mode.displayMode,
mode.parameters.visibleRegion.width, mode.parameters.visibleRegion.height,
mode.parameters.refreshRate);
- if (j == 0) {
- displayMode = mode.displayMode;
- width = mode.parameters.visibleRegion.width;
- height = mode.parameters.visibleRegion.height;
+ if (j == wantedModeIndex && i == wantedDisplayIndex) {
+ m_displayMode = mode.displayMode;
+ m_width = mode.parameters.visibleRegion.width;
+ m_height = mode.parameters.visibleRegion.height;
}
}
}
- if (display == VK_NULL_HANDLE || displayMode == VK_NULL_HANDLE) {
+ if (m_display == VK_NULL_HANDLE || m_displayMode == VK_NULL_HANDLE) {
qWarning("Failed to choose display and mode");
- return VK_NULL_HANDLE;
+ return false;
}
+
+ qDebug("Using display #%u with mode #%u", wantedDisplayIndex, wantedModeIndex);
+
uint32_t planeCount = 0;
err = m_getPhysicalDeviceDisplayPlanePropertiesKHR(m_physDev, &planeCount, nullptr);
if (err != VK_SUCCESS) {
qWarning("Failed to get plane properties: %d", err);
- return VK_NULL_HANDLE;
+ return false;
}
- qCDebug(qLcEglDevDebug, "Plane count: %u", planeCount);
+ qDebug("Plane count: %u", planeCount);
QVarLengthArray<VkDisplayPlanePropertiesKHR, 4> planeProps(planeCount);
m_getPhysicalDeviceDisplayPlanePropertiesKHR(m_physDev, &planeCount, planeProps.data());
- uint32_t planeIndex = UINT_MAX;
+ m_planeIndex = UINT_MAX;
for (uint32_t i = 0; i < planeCount; ++i) {
uint32_t supportedDisplayCount = 0;
err = m_getDisplayPlaneSupportedDisplaysKHR(m_physDev, i, &supportedDisplayCount, nullptr);
if (err != VK_SUCCESS) {
qWarning("Failed to query supported displays for plane: %d", err);
- return VK_NULL_HANDLE;
+ return false;
}
QVarLengthArray<VkDisplayKHR, 4> supportedDisplays(supportedDisplayCount);
m_getDisplayPlaneSupportedDisplaysKHR(m_physDev, i, &supportedDisplayCount, supportedDisplays.data());
- qCDebug(qLcEglDevDebug, "Plane #%u supports %u displays, currently bound to display %p",
+ qDebug("Plane #%u supports %u displays, currently bound to display %p",
i, supportedDisplayCount, (void *) planeProps[i].currentDisplay);
VkDisplayPlaneCapabilitiesKHR caps;
- err = m_getDisplayPlaneCapabilitiesKHR(m_physDev, displayMode, i, &caps);
+ err = m_getDisplayPlaneCapabilitiesKHR(m_physDev, m_displayMode, i, &caps);
if (err != VK_SUCCESS) {
qWarning("Failed to query plane capabilities: %d", err);
- return VK_NULL_HANDLE;
+ return false;
}
- qCDebug(qLcEglDevDebug, " supportedAlpha: %d (1=no, 2=global, 4=per pixel, 8=per pixel premul)\n"
+ qDebug(" supportedAlpha: %d (1=no, 2=global, 4=per pixel, 8=per pixel premul)\n"
" minSrc=%d, %d %ux%u\n"
" maxSrc=%d, %d %ux%u\n"
" minDst=%d, %d %ux%u\n"
@@ -229,52 +203,69 @@ VkSurfaceKHR QEglFSVulkanInstance::createSurface(QEglFSWindow *window)
caps.maxDstPosition.x, caps.maxDstPosition.y, caps.maxDstExtent.width, caps.maxDstExtent.height);
// if the plane is not in use and supports our chosen display, use that plane
- if (supportedDisplays.contains(display)
- && (planeProps[i].currentDisplay == VK_NULL_HANDLE || planeProps[i].currentDisplay == display))
+ if (supportedDisplays.contains(m_display)
+ && (planeProps[i].currentDisplay == VK_NULL_HANDLE || planeProps[i].currentDisplay == m_display))
{
- planeIndex = i;
+ m_planeIndex = i;
+ m_planeStackIndex = planeProps[i].currentStackIndex;
}
}
- if (planeIndex == UINT_MAX) {
+ if (m_planeIndex == UINT_MAX) {
qWarning("Failed to find a suitable plane");
- return VK_NULL_HANDLE;
+ return false;
}
- qCDebug(qLcEglDevDebug, "Using plane #%u", planeIndex);
+ qDebug("Using plane #%u", m_planeIndex);
+ return true;
+#else
+ return false;
+#endif
+}
+
+VkSurfaceKHR QVkKhrDisplayVulkanInstance::createSurface(QWindow *window)
+{
+#if VK_KHR_display
+ qDebug("Creating VkSurfaceKHR via VK_KHR_display for window %p", (void *) window);
+
+ if (!m_physDev) {
+ qWarning("No physical device, cannot create surface");
+ return VK_NULL_HANDLE;
+ }
+ if (!m_display || !m_displayMode) {
+ qWarning("No display mode chosen, cannot create surface");
+ return VK_NULL_HANDLE;
+ }
VkDisplaySurfaceCreateInfoKHR surfaceCreateInfo = {};
surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_DISPLAY_SURFACE_CREATE_INFO_KHR;
- surfaceCreateInfo.displayMode = displayMode;
- surfaceCreateInfo.planeIndex = planeIndex;
- surfaceCreateInfo.planeStackIndex = planeProps[planeIndex].currentStackIndex;
+ surfaceCreateInfo.displayMode = m_displayMode;
+ surfaceCreateInfo.planeIndex = m_planeIndex;
+ surfaceCreateInfo.planeStackIndex = m_planeStackIndex;
surfaceCreateInfo.transform = VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR;
surfaceCreateInfo.globalAlpha = 1.0f;
surfaceCreateInfo.alphaMode = VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR;
- surfaceCreateInfo.imageExtent = { width, height };
+ surfaceCreateInfo.imageExtent = { m_width, m_height };
VkSurfaceKHR surface = VK_NULL_HANDLE;
- err = m_createDisplayPlaneSurfaceKHR(m_vkInst, &surfaceCreateInfo, nullptr, &surface);
+ VkResult err = m_createDisplayPlaneSurfaceKHR(m_vkInst, &surfaceCreateInfo, nullptr, &surface);
if (err != VK_SUCCESS || surface == VK_NULL_HANDLE) {
qWarning("Failed to create surface: %d", err);
return VK_NULL_HANDLE;
}
- qCDebug(qLcEglDevDebug, "Created surface %p", (void *) surface);
+ qDebug("Created surface %p", (void *) surface);
return surface;
-
#else
Q_UNUSED(window);
- qWarning("VK_KHR_display support was not compiled in, cannot create surface");
return VK_NULL_HANDLE;
#endif
}
-void QEglFSVulkanInstance::presentAboutToBeQueued(QWindow *window)
+void QVkKhrDisplayVulkanInstance::presentAboutToBeQueued(QWindow *window)
{
- // support QT_QPA_EGLFS_FORCEVSYNC (i.MX8 with eglfs_viv)
- qt_egl_device_integration()->waitForVSync(window->handle());
+ Q_UNUSED(window);
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/vkkhrdisplay/qvkkhrdisplayvulkaninstance.h b/src/plugins/platforms/vkkhrdisplay/qvkkhrdisplayvulkaninstance.h
new file mode 100644
index 0000000000..bf99dc037f
--- /dev/null
+++ b/src/plugins/platforms/vkkhrdisplay/qvkkhrdisplayvulkaninstance.h
@@ -0,0 +1,70 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QVKKHRDISPLAYVULKANINSTANCE_H
+#define QVKKHRDISPLAYVULKANINSTANCE_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 <QtGui/private/qbasicvulkanplatforminstance_p.h>
+#include <QtCore/qsize.h>
+
+QT_BEGIN_NAMESPACE
+
+class QVkKhrDisplayVulkanInstance : public QBasicPlatformVulkanInstance
+{
+public:
+ QVkKhrDisplayVulkanInstance(QVulkanInstance *instance);
+
+ void createOrAdoptInstance() override;
+ bool supportsPresent(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, QWindow *window) override;
+ void presentAboutToBeQueued(QWindow *window) override;
+
+ VkSurfaceKHR createSurface(QWindow *window);
+
+ QSize displaySize() const { return QSize(int(m_width), int(m_height)); }
+
+ using CreatedCallback = void (*)(QVkKhrDisplayVulkanInstance *, void *);
+ void setCreatedCallback(CreatedCallback callback, void *userData) {
+ m_createdCallback = callback;
+ m_createdCallbackUserData = userData;
+ }
+
+private:
+ bool chooseDisplay();
+
+ QVulkanInstance *m_instance;
+ VkPhysicalDevice m_physDev = VK_NULL_HANDLE;
+ PFN_vkEnumeratePhysicalDevices m_enumeratePhysicalDevices = nullptr;
+ PFN_vkGetPhysicalDeviceSurfaceSupportKHR m_getPhysicalDeviceSurfaceSupportKHR = nullptr;
+#if VK_KHR_display
+ PFN_vkGetPhysicalDeviceDisplayPropertiesKHR m_getPhysicalDeviceDisplayPropertiesKHR = nullptr;
+ PFN_vkGetDisplayModePropertiesKHR m_getDisplayModePropertiesKHR = nullptr;
+ PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR m_getPhysicalDeviceDisplayPlanePropertiesKHR = nullptr;
+ PFN_vkGetDisplayPlaneSupportedDisplaysKHR m_getDisplayPlaneSupportedDisplaysKHR = nullptr;
+ PFN_vkGetDisplayPlaneCapabilitiesKHR m_getDisplayPlaneCapabilitiesKHR = nullptr;
+ PFN_vkCreateDisplayPlaneSurfaceKHR m_createDisplayPlaneSurfaceKHR = nullptr;
+#endif
+
+ CreatedCallback m_createdCallback = nullptr;
+ void *m_createdCallbackUserData = nullptr;
+ VkDisplayKHR m_display = VK_NULL_HANDLE;
+ VkDisplayModeKHR m_displayMode = VK_NULL_HANDLE;
+ uint32_t m_width = 0;
+ uint32_t m_height = 0;
+ uint32_t m_planeIndex = UINT_MAX;
+ uint32_t m_planeStackIndex = UINT_MAX;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/plugins/platforms/vkkhrdisplay/vkkhrdisplay.json b/src/plugins/platforms/vkkhrdisplay/vkkhrdisplay.json
new file mode 100644
index 0000000000..dd7a77eb68
--- /dev/null
+++ b/src/plugins/platforms/vkkhrdisplay/vkkhrdisplay.json
@@ -0,0 +1,3 @@
+{
+ "Keys": [ "vkkhrdisplay" ]
+}
diff --git a/src/plugins/platforms/vnc/.prev_CMakeLists.txt b/src/plugins/platforms/vnc/.prev_CMakeLists.txt
deleted file mode 100644
index a26cc0be2b..0000000000
--- a/src/plugins/platforms/vnc/.prev_CMakeLists.txt
+++ /dev/null
@@ -1,43 +0,0 @@
-# Generated from vnc.pro.
-
-#####################################################################
-## QVncIntegrationPlugin Plugin:
-#####################################################################
-
-qt_add_plugin(QVncIntegrationPlugin
- OUTPUT_NAME qvnc
- TYPE platforms
- SOURCES
- main.cpp
- qvnc.cpp qvnc_p.h
- qvncclient.cpp qvncclient.h
- qvncintegration.cpp qvncintegration.h
- qvncscreen.cpp qvncscreen.h
- DEFINES
- QT_NO_FOREACH
- PUBLIC_LIBRARIES
- Qt::Core
- Qt::CorePrivate
- Qt::EventDispatcherSupportPrivate
- Qt::FbSupportPrivate
- Qt::FontDatabaseSupportPrivate
- Qt::Gui
- Qt::GuiPrivate
- Qt::Network
- Qt::ServiceSupportPrivate
- Qt::ThemeSupportPrivate
-)
-
-#### Keys ignored in scope 1:.:.:vnc.pro:<TRUE>:
-# OTHER_FILES = "vnc.json"
-
-## Scopes:
-#####################################################################
-
-qt_extend_target(QVncIntegrationPlugin CONDITION TARGET Qt::InputSupportPrivate
- PUBLIC_LIBRARIES
- Qt::InputSupportPrivate
-)
-
-#### Keys ignored in scope 3:.:.:vnc.pro:NOT TARGET___equals____ss_QT_DEFAULT_QPA_PLUGIN:
-# PLUGIN_EXTENDS = "-"
diff --git a/src/plugins/platforms/vnc/CMakeLists.txt b/src/plugins/platforms/vnc/CMakeLists.txt
index cb84355d81..25cb399bd0 100644
--- a/src/plugins/platforms/vnc/CMakeLists.txt
+++ b/src/plugins/platforms/vnc/CMakeLists.txt
@@ -1,13 +1,14 @@
-# Generated from vnc.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## QVncIntegrationPlugin Plugin:
#####################################################################
-qt_add_plugin(QVncIntegrationPlugin
+qt_internal_add_plugin(QVncIntegrationPlugin
OUTPUT_NAME qvnc
- TYPE platforms
- DEFAULT_IF ${QT_QPA_DEFAULT_PLATFORM} MATCHES vnc # special case
+ PLUGIN_TYPE platforms
+ DEFAULT_IF ${QT_QPA_DEFAULT_PLATFORM} MATCHES vnc
SOURCES
main.cpp
qvnc.cpp qvnc_p.h
@@ -16,29 +17,19 @@ qt_add_plugin(QVncIntegrationPlugin
qvncscreen.cpp qvncscreen.h
DEFINES
QT_NO_FOREACH
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Core
Qt::CorePrivate
- Qt::EventDispatcherSupportPrivate
Qt::FbSupportPrivate
- Qt::FontDatabaseSupportPrivate
Qt::Gui
Qt::GuiPrivate
Qt::Network
- Qt::ServiceSupportPrivate
- Qt::ThemeSupportPrivate
)
-#### Keys ignored in scope 1:.:.:vnc.pro:<TRUE>:
-# OTHER_FILES = "vnc.json"
-
## Scopes:
#####################################################################
-qt_extend_target(QVncIntegrationPlugin CONDITION TARGET Qt::InputSupportPrivate
- PUBLIC_LIBRARIES
+qt_internal_extend_target(QVncIntegrationPlugin CONDITION TARGET Qt::InputSupportPrivate
+ LIBRARIES
Qt::InputSupportPrivate
)
-
-#### Keys ignored in scope 3:.:.:vnc.pro:NOT TARGET___equals____ss_QT_DEFAULT_QPA_PLUGIN:
-# PLUGIN_EXTENDS = "-"
diff --git a/src/plugins/platforms/vnc/main.cpp b/src/plugins/platforms/vnc/main.cpp
index ac7e18e03f..43c59454a3 100644
--- a/src/plugins/platforms/vnc/main.cpp
+++ b/src/plugins/platforms/vnc/main.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <qpa/qplatformintegrationplugin.h>
#include "qvncintegration.h"
@@ -43,6 +7,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
class QVncIntegrationPlugin : public QPlatformIntegrationPlugin
{
Q_OBJECT
@@ -53,7 +19,7 @@ public:
QPlatformIntegration* QVncIntegrationPlugin::create(const QString& system, const QStringList& paramList)
{
- if (!system.compare(QLatin1String("vnc"), Qt::CaseInsensitive))
+ if (!system.compare("vnc"_L1, Qt::CaseInsensitive))
return new QVncIntegration(paramList);
return nullptr;
diff --git a/src/plugins/platforms/vnc/qvnc.cpp b/src/plugins/platforms/vnc/qvnc.cpp
index 8390fa19cd..99e80e5801 100644
--- a/src/plugins/platforms/vnc/qvnc.cpp
+++ b/src/plugins/platforms/vnc/qvnc.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qvnc_p.h"
#include "qvncscreen.h"
#include "qvncclient.h"
@@ -48,7 +12,7 @@
#include <QtGui/QWindow>
#ifdef Q_OS_WIN
-#include <Winsock2.h>
+#include <winsock2.h>
#else
#include <arpa/inet.h>
#endif
@@ -245,7 +209,7 @@ static const struct {
void QRfbRect::read(QTcpSocket *s)
{
quint16 buf[4];
- s->read((char*)buf, 8);
+ s->read(reinterpret_cast<char*>(buf), 8);
x = ntohs(buf[0]);
y = ntohs(buf[1]);
w = ntohs(buf[2]);
@@ -259,7 +223,7 @@ void QRfbRect::write(QTcpSocket *s) const
buf[1] = htons(y);
buf[2] = htons(w);
buf[3] = htons(h);
- s->write((char*)buf, 8);
+ s->write(reinterpret_cast<char*>(buf) , 8);
}
void QRfbPixelFormat::read(QTcpSocket *s)
@@ -271,15 +235,15 @@ void QRfbPixelFormat::read(QTcpSocket *s)
bigEndian = buf[2];
trueColor = buf[3];
- quint16 a = ntohs(*(quint16 *)(buf + 4));
+ quint16 a = ntohs(*reinterpret_cast<quint16 *>(buf + 4));
redBits = 0;
while (a) { a >>= 1; redBits++; }
- a = ntohs(*(quint16 *)(buf + 6));
+ a = ntohs(*reinterpret_cast<quint16 *>(buf + 6));
greenBits = 0;
while (a) { a >>= 1; greenBits++; }
- a = ntohs(*(quint16 *)(buf + 8));
+ a = ntohs(*reinterpret_cast<quint16 *>(buf + 8));
blueBits = 0;
while (a) { a >>= 1; blueBits++; }
@@ -298,15 +262,15 @@ void QRfbPixelFormat::write(QTcpSocket *s)
quint16 a = 0;
for (int i = 0; i < redBits; i++) a = (a << 1) | 1;
- *(quint16 *)(buf + 4) = htons(a);
+ *reinterpret_cast<quint16 *>(buf + 4) = htons(a);
a = 0;
for (int i = 0; i < greenBits; i++) a = (a << 1) | 1;
- *(quint16 *)(buf + 6) = htons(a);
+ *reinterpret_cast<quint16 *>(buf + 6) = htons(a);
a = 0;
for (int i = 0; i < blueBits; i++) a = (a << 1) | 1;
- *(quint16 *)(buf + 8) = htons(a);
+ *reinterpret_cast<quint16 *>(buf + 8) = htons(a);
buf[10] = redShift;
buf[11] = greenShift;
@@ -324,14 +288,14 @@ void QRfbServerInit::setName(const char *n)
void QRfbServerInit::read(QTcpSocket *s)
{
- s->read((char *)&width, 2);
+ s->read(reinterpret_cast<char *>(&width), 2);
width = ntohs(width);
- s->read((char *)&height, 2);
+ s->read(reinterpret_cast<char *>(&height), 2);
height = ntohs(height);
format.read(s);
quint32 len;
- s->read((char *)&len, 4);
+ s->read(reinterpret_cast<char *>(&len), 4);
len = ntohl(len);
name = new char [len + 1];
@@ -342,14 +306,14 @@ void QRfbServerInit::read(QTcpSocket *s)
void QRfbServerInit::write(QTcpSocket *s)
{
quint16 t = htons(width);
- s->write((char *)&t, 2);
+ s->write(reinterpret_cast<char *>(&t), 2);
t = htons(height);
- s->write((char *)&t, 2);
+ s->write(reinterpret_cast<char *>(&t), 2);
format.write(s);
- quint32 len = strlen(name);
+ quint32 len = static_cast<quint32>(strlen(name));
len = htonl(len);
- s->write((char *)&len, 4);
- s->write(name, strlen(name));
+ s->write(reinterpret_cast<char *>(&len), 4);
+ s->write(name, static_cast<qint64>(strlen(name)));
}
bool QRfbSetEncodings::read(QTcpSocket *s)
@@ -359,7 +323,7 @@ bool QRfbSetEncodings::read(QTcpSocket *s)
char tmp;
s->read(&tmp, 1); // padding
- s->read((char *)&count, 2);
+ s->read(reinterpret_cast<char *>(&count), 2);
count = ntohs(count);
return true;
@@ -383,17 +347,17 @@ bool QRfbKeyEvent::read(QTcpSocket *s)
s->read(&down, 1);
quint16 tmp;
- s->read((char *)&tmp, 2); // padding
+ s->read(reinterpret_cast<char *>(&tmp), 2); // padding
quint32 key;
- s->read((char *)&key, 4);
+ s->read(reinterpret_cast<char *>(&key), 4);
key = ntohl(key);
unicode = 0;
keycode = 0;
int i = 0;
while (keyMap[i].keysym && !keycode) {
- if (keyMap[i].keysym == (int)key)
+ if (keyMap[i].keysym == static_cast<int>(key))
keycode = keyMap[i].keycode;
i++;
}
@@ -425,14 +389,14 @@ bool QRfbPointerEvent::read(QTcpSocket *s)
if (buttonMask & 1)
buttons |= Qt::LeftButton;
if (buttonMask & 2)
- buttons |= Qt::MidButton;
+ buttons |= Qt::MiddleButton;
if (buttonMask & 4)
buttons |= Qt::RightButton;
quint16 tmp;
- s->read((char *)&tmp, 2);
+ s->read(reinterpret_cast<char *>(&tmp), 2);
x = ntohs(tmp);
- s->read((char *)&tmp, 2);
+ s->read(reinterpret_cast<char *>(&tmp), 2);
y = ntohs(tmp);
return true;
@@ -445,7 +409,7 @@ bool QRfbClientCutText::read(QTcpSocket *s)
char tmp[3];
s->read(tmp, 3); // padding
- s->read((char *)&length, 4);
+ s->read(reinterpret_cast<char *>(&length), 4);
length = ntohl(length);
return true;
@@ -477,6 +441,9 @@ void QRfbRawEncoder::write()
// server->screen()->geometry().height());
// }
+ const QImage screenImage = client->server()->screenImage();
+ rgn &= screenImage.rect();
+
const auto rectsInRegion = rgn.rectCount();
{
@@ -486,23 +453,21 @@ void QRfbRawEncoder::write()
{
const quint16 count = htons(rectsInRegion);
- socket->write((char *)&count, sizeof(count));
+ socket->write(reinterpret_cast<const char *>(&count), sizeof(count));
}
if (rectsInRegion <= 0)
return;
- const QImage screenImage = client->server()->screenImage();
-
for (const QRect &tileRect: rgn) {
const QRfbRect rect(tileRect.x(), tileRect.y(),
tileRect.width(), tileRect.height());
rect.write(socket);
const quint32 encoding = htonl(0); // raw encoding
- socket->write((char *)&encoding, sizeof(encoding));
+ socket->write(reinterpret_cast<const char *>(&encoding), sizeof(encoding));
- int linestep = screenImage.bytesPerLine();
+ qsizetype linestep = screenImage.bytesPerLine();
const uchar *screendata = screenImage.scanLine(rect.y)
+ rect.x * screenImage.depth() / 8;
@@ -514,15 +479,16 @@ void QRfbRawEncoder::write()
// convert pixels
char *b = buffer.data();
const int bstep = rect.w * bytesPerPixel;
+ const int depth = screenImage.depth();
for (int i = 0; i < rect.h; ++i) {
- client->convertPixels(b, (const char*)screendata, rect.w);
+ client->convertPixels(b, reinterpret_cast<const char*>(screendata), rect.w, depth);
screendata += linestep;
b += bstep;
}
socket->write(buffer.constData(), bufferSize);
} else {
for (int i = 0; i < rect.h; ++i) {
- socket->write((const char*)screendata, rect.w * bytesPerPixel);
+ socket->write(reinterpret_cast<const char*>(screendata), rect.w * bytesPerPixel);
screendata += linestep;
}
}
@@ -552,13 +518,13 @@ void QVncClientCursor::write(QVncClient *client) const
{
const quint16 tmp[6] = { htons(0),
htons(1),
- htons(uint16_t(hotspot.x())), htons(uint16_t(hotspot.y())),
- htons(uint16_t(cursor.width())),
- htons(uint16_t(cursor.height())) };
- socket->write((char*)tmp, sizeof(tmp));
+ htons(static_cast<uint16_t>(hotspot.x())), htons(static_cast<uint16_t>(hotspot.y())),
+ htons(static_cast<uint16_t>(cursor.width())),
+ htons(static_cast<uint16_t>(cursor.height())) };
+ socket->write(reinterpret_cast<const char*>(tmp), sizeof(tmp));
const qint32 encoding = qToBigEndian(-239);
- socket->write((char*)(&encoding), sizeof(encoding));
+ socket->write(reinterpret_cast<const char*>(&encoding), sizeof(encoding));
}
if (cursor.isNull())
@@ -568,9 +534,10 @@ void QVncClientCursor::write(QVncClient *client) const
Q_ASSERT(cursor.hasAlphaChannel());
const QImage img = cursor.convertToFormat(client->server()->screen()->format());
const int n = client->clientBytesPerPixel() * img.width();
+ const int depth = img.depth();
char *buffer = new char[n];
for (int i = 0; i < img.height(); ++i) {
- client->convertPixels(buffer, (const char*)img.scanLine(i), img.width());
+ client->convertPixels(buffer, (const char*)img.scanLine(i), img.width(), depth);
socket->write(buffer, n);
}
delete[] buffer;
@@ -581,7 +548,7 @@ void QVncClientCursor::write(QVncClient *client) const
Q_ASSERT(bitmap.size() == img.size());
const int width = (bitmap.width() + 7) / 8;
for (int i = 0; i < bitmap.height(); ++i)
- socket->write((const char*)bitmap.scanLine(i), width);
+ socket->write(reinterpret_cast<const char*>(bitmap.scanLine(i)), width);
}
void QVncClientCursor::changeCursor(QCursor *widgetCursor, QWindow *window)
@@ -600,20 +567,23 @@ void QVncClientCursor::changeCursor(QCursor *widgetCursor, QWindow *window)
cursor = *platformImage.image();
hotspot = platformImage.hotspot();
}
- for (auto client : qAsConst(clients))
+ for (auto client : std::as_const(clients))
client->setDirtyCursor();
}
void QVncClientCursor::addClient(QVncClient *client)
{
- if (!clients.contains(client))
+ if (!clients.contains(client)) {
clients.append(client);
+ // Force a cursor update when the client connects.
+ client->setDirtyCursor();
+ }
}
uint QVncClientCursor::removeClient(QVncClient *client)
{
clients.removeOne(client);
- return clients.count();
+ return clients.size();
}
#endif // QT_CONFIG(cursor)
@@ -643,7 +613,7 @@ QVncServer::~QVncServer()
void QVncServer::setDirty()
{
- for (auto client : qAsConst(clients))
+ for (auto client : std::as_const(clients))
client->setDirty(qvnc_screen->dirtyRegion);
qvnc_screen->clearDirty();
@@ -665,11 +635,10 @@ void QVncServer::newConnection()
void QVncServer::discardClient(QVncClient *client)
{
clients.removeOne(client);
+ qvnc_screen->disableClientCursor(client);
client->deleteLater();
- if (clients.isEmpty()) {
- qvnc_screen->disableClientCursor(client);
+ if (clients.isEmpty())
qvnc_screen->setPowerState(QPlatformScreen::PowerStateOff);
- }
}
inline QImage QVncServer::screenImage() const
@@ -678,3 +647,5 @@ inline QImage QVncServer::screenImage() const
}
QT_END_NAMESPACE
+
+#include "moc_qvnc_p.cpp"
diff --git a/src/plugins/platforms/vnc/qvnc_p.h b/src/plugins/platforms/vnc/qvnc_p.h
index f7f2f74ddb..642f872c21 100644
--- a/src/plugins/platforms/vnc/qvnc_p.h
+++ b/src/plugins/platforms/vnc/qvnc_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QVNC_P_H
#define QVNC_P_H
@@ -380,7 +344,7 @@ public:
QImage cursor;
QPoint hotspot;
- QVector<QVncClient *> clients;
+ QList<QVncClient *> clients;
};
#endif // QT_CONFIG(cursor)
@@ -408,7 +372,7 @@ private slots:
private:
QTcpServer *serverSocket;
- QVector<QVncClient*> clients;
+ QList<QVncClient*> clients;
QVncScreen *qvnc_screen;
quint16 m_port;
};
diff --git a/src/plugins/platforms/vnc/qvncclient.cpp b/src/plugins/platforms/vnc/qvncclient.cpp
index c5caddc58d..b3aafd0194 100644
--- a/src/plugins/platforms/vnc/qvncclient.cpp
+++ b/src/plugins/platforms/vnc/qvncclient.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qvncclient.h"
#include "qvnc_p.h"
@@ -47,7 +11,7 @@
#include <QtGui/qguiapplication.h>
#ifdef Q_OS_WIN
-#include <Winsock2.h>
+#include <winsock2.h>
#else
#include <arpa/inet.h>
#endif
@@ -97,10 +61,8 @@ void QVncClient::setDirty(const QRegion &region)
}
}
-void QVncClient::convertPixels(char *dst, const char *src, int count) const
+void QVncClient::convertPixels(char *dst, const char *src, int count, int screendepth) const
{
- const int screendepth = m_server->screen()->depth();
-
// cutoffs
#if Q_BYTE_ORDER == Q_BIG_ENDIAN
if (!m_swapBytes)
@@ -617,7 +579,7 @@ void QVncClient::keyEvent()
m_keymod = ev.down ? m_keymod | Qt::AltModifier :
m_keymod & ~Qt::AltModifier;
if (ev.unicode || ev.keycode)
- QWindowSystemInterface::handleKeyEvent(nullptr, ev.down ? QEvent::KeyPress : QEvent::KeyRelease, ev.keycode, m_keymod, QString(ev.unicode));
+ QWindowSystemInterface::handleKeyEvent(nullptr, ev.down ? QEvent::KeyPress : QEvent::KeyRelease, ev.keycode, m_keymod, QString(QChar::fromUcs2(ev.unicode)));
m_handleMsg = false;
}
}
@@ -668,3 +630,5 @@ bool QVncClient::pixelConversionNeeded() const
}
QT_END_NAMESPACE
+
+#include "moc_qvncclient.cpp"
diff --git a/src/plugins/platforms/vnc/qvncclient.h b/src/plugins/platforms/vnc/qvncclient.h
index a7a6b6b361..4c4c8d71e5 100644
--- a/src/plugins/platforms/vnc/qvncclient.h
+++ b/src/plugins/platforms/vnc/qvncclient.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QVNCCLIENT_H
#define QVNCCLIENT_H
@@ -77,7 +41,7 @@ public:
return m_pixelFormat.bitsPerPixel / 8;
}
- void convertPixels(char *dst, const char *src, int count) const;
+ void convertPixels(char *dst, const char *src, int count, int depth) const;
inline bool doPixelConversion() const { return m_needConversion; }
signals:
diff --git a/src/plugins/platforms/vnc/qvncintegration.cpp b/src/plugins/platforms/vnc/qvncintegration.cpp
index c7a796464a..48e6567d89 100644
--- a/src/plugins/platforms/vnc/qvncintegration.cpp
+++ b/src/plugins/platforms/vnc/qvncintegration.cpp
@@ -1,49 +1,13 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qvncintegration.h"
#include "qvncscreen.h"
#include "qvnc_p.h"
-#include <QtFontDatabaseSupport/private/qgenericunixfontdatabase_p.h>
-#include <QtServiceSupport/private/qgenericunixservices_p.h>
-#include <QtEventDispatcherSupport/private/qgenericunixeventdispatcher_p.h>
+#include <QtGui/private/qgenericunixfontdatabase_p.h>
+#include <QtGui/private/qgenericunixservices_p.h>
+#include <QtGui/private/qgenericunixeventdispatcher_p.h>
#include <QtFbSupport/private/qfbbackingstore_p.h>
#include <QtFbSupport/private/qfbwindow_p.h>
@@ -58,11 +22,13 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
QVncIntegration::QVncIntegration(const QStringList &paramList)
: m_fontDb(new QGenericUnixFontDatabase),
m_services(new QGenericUnixServices)
{
- QRegularExpression portRx(QLatin1String("port=(\\d+)"));
+ QRegularExpression portRx("port=(\\d+)"_L1);
quint16 port = 5900;
for (const QString &arg : paramList) {
QRegularExpressionMatch match;
@@ -105,6 +71,7 @@ bool QVncIntegration::hasCapability(QPlatformIntegration::Capability cap) const
switch (cap) {
case ThreadedPixmaps: return true;
case WindowManagement: return false;
+ case RhiBasedRendering: return false;
default: return QPlatformIntegration::hasCapability(cap);
}
}
diff --git a/src/plugins/platforms/vnc/qvncintegration.h b/src/plugins/platforms/vnc/qvncintegration.h
index 34a6a6b941..6c00ba8493 100644
--- a/src/plugins/platforms/vnc/qvncintegration.h
+++ b/src/plugins/platforms/vnc/qvncintegration.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QVNCINTEGRATION_H
#define QVNCINTEGRATION_H
diff --git a/src/plugins/platforms/vnc/qvncscreen.cpp b/src/plugins/platforms/vnc/qvncscreen.cpp
index 5dc3919ff5..c87df20ef6 100644
--- a/src/plugins/platforms/vnc/qvncscreen.cpp
+++ b/src/plugins/platforms/vnc/qvncscreen.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qvncscreen.h"
#include "qvnc_p.h"
@@ -49,6 +13,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
QVncScreen::QVncScreen(const QStringList &args)
: mArgs(args)
@@ -66,16 +32,16 @@ QVncScreen::~QVncScreen()
bool QVncScreen::initialize()
{
- QRegularExpression sizeRx(QLatin1String("size=(\\d+)x(\\d+)"));
- QRegularExpression mmSizeRx(QLatin1String("mmsize=(?<width>(\\d*\\.)?\\d+)x(?<height>(\\d*\\.)?\\d+)"));
- QRegularExpression depthRx(QLatin1String("depth=(\\d+)"));
+ QRegularExpression sizeRx("size=(\\d+)x(\\d+)"_L1);
+ QRegularExpression mmSizeRx("mmsize=(?<width>(\\d*\\.)?\\d+)x(?<height>(\\d*\\.)?\\d+)"_L1);
+ QRegularExpression depthRx("depth=(\\d+)"_L1);
mGeometry = QRect(0, 0, 1024, 768);
mFormat = QImage::Format_ARGB32_Premultiplied;
mDepth = 32;
mPhysicalSize = QSizeF(mGeometry.width()/96.*25.4, mGeometry.height()/96.*25.4);
- for (const QString &arg : qAsConst(mArgs)) {
+ for (const QString &arg : std::as_const(mArgs)) {
QRegularExpressionMatch match;
if (arg.contains(mmSizeRx, &match)) {
mPhysicalSize = QSizeF(match.captured("width").toDouble(), match.captured("height").toDouble());
@@ -86,14 +52,13 @@ bool QVncScreen::initialize()
}
}
- QFbScreen::initializeCompositor();
-
switch (depth()) {
case 32:
dirty = new QVncDirtyMapOptimized<quint32>(this);
break;
case 16:
dirty = new QVncDirtyMapOptimized<quint16>(this);
+ mFormat = QImage::Format_RGB16;
break;
case 8:
dirty = new QVncDirtyMapOptimized<quint8>(this);
@@ -105,6 +70,8 @@ bool QVncScreen::initialize()
return false;
}
+ QFbScreen::initializeCompositor();
+
setPowerState(PowerStateOff);
return true;
@@ -132,22 +99,26 @@ void QVncScreen::enableClientCursor(QVncClient *client)
clientCursor = new QVncClientCursor();
clientCursor->addClient(client);
#else
- Q_UNUSED(client)
+ Q_UNUSED(client);
#endif
}
void QVncScreen::disableClientCursor(QVncClient *client)
{
#if QT_CONFIG(cursor)
+ if (!clientCursor)
+ return;
+
uint clientCount = clientCursor->removeClient(client);
if (clientCount == 0) {
delete clientCursor;
clientCursor = nullptr;
- }
- mCursor = new QFbCursor(this);
+ if (mCursor == nullptr)
+ mCursor = new QFbCursor(this);
+ }
#else
- Q_UNUSED(client)
+ Q_UNUSED(client);
#endif
}
@@ -210,3 +181,5 @@ QFbScreen::Flags QVncScreen::flags() const
QT_END_NAMESPACE
+#include "moc_qvncscreen.cpp"
+
diff --git a/src/plugins/platforms/vnc/qvncscreen.h b/src/plugins/platforms/vnc/qvncscreen.h
index db658d4ecc..a954a670ec 100644
--- a/src/plugins/platforms/vnc/qvncscreen.h
+++ b/src/plugins/platforms/vnc/qvncscreen.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QVncScreen_H
#define QVncScreen_H
diff --git a/src/plugins/platforms/vnc/vnc.pro b/src/plugins/platforms/vnc/vnc.pro
deleted file mode 100644
index 1fa682303f..0000000000
--- a/src/plugins/platforms/vnc/vnc.pro
+++ /dev/null
@@ -1,31 +0,0 @@
-TARGET = qvnc
-
-QT += \
- core-private network gui-private \
- service_support-private theme_support-private fb_support-private \
- eventdispatcher_support-private fontdatabase_support-private
-
-qtHaveModule(input_support-private): \
- QT += input_support-private
-
-DEFINES += QT_NO_FOREACH
-
-SOURCES = \
- main.cpp \
- qvncintegration.cpp \
- qvncscreen.cpp \
- qvnc.cpp \
- qvncclient.cpp
-
-HEADERS = \
- qvncintegration.h \
- qvncscreen.h \
- qvnc_p.h \
- qvncclient.h
-
-OTHER_FILES += vnc.json
-
-PLUGIN_TYPE = platforms
-PLUGIN_CLASS_NAME = QVncIntegrationPlugin
-!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = -
-load(qt_plugin)
diff --git a/src/plugins/platforms/wasm/CMakeLists.txt b/src/plugins/platforms/wasm/CMakeLists.txt
new file mode 100644
index 0000000000..185b921a4f
--- /dev/null
+++ b/src/plugins/platforms/wasm/CMakeLists.txt
@@ -0,0 +1,108 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## QWasmIntegrationPlugin Plugin:
+#####################################################################
+
+qt_internal_add_plugin(QWasmIntegrationPlugin
+ OUTPUT_NAME qwasm
+ DEFAULT_IF ${QT_QPA_DEFAULT_PLATFORM} MATCHES wasm
+ PLUGIN_TYPE platforms
+ STATIC
+ SOURCES
+ main.cpp
+ qwasmaccessibility.cpp qwasmaccessibility.h
+ qwasmbase64iconstore.cpp qwasmbase64iconstore.h
+ qwasmclipboard.cpp qwasmclipboard.h
+ qwasmcompositor.cpp qwasmcompositor.h
+ qwasmcssstyle.cpp qwasmcssstyle.h
+ qwasmcursor.cpp qwasmcursor.h
+ qwasmdom.cpp qwasmdom.h
+ qwasmevent.cpp qwasmevent.h
+ qwasmeventdispatcher.cpp qwasmeventdispatcher.h
+ qwasmfontdatabase.cpp qwasmfontdatabase.h
+ qwasmintegration.cpp qwasmintegration.h
+ qwasmkeytranslator.cpp qwasmkeytranslator.h
+ qwasmoffscreensurface.cpp qwasmoffscreensurface.h
+ qwasmopenglcontext.cpp qwasmopenglcontext.h
+ qwasmplatform.cpp qwasmplatform.h
+ qwasmscreen.cpp qwasmscreen.h
+ qwasmservices.cpp qwasmservices.h
+ qwasmtheme.cpp qwasmtheme.h
+ qwasmwindow.cpp qwasmwindow.h
+ qwasmwindowclientarea.cpp qwasmwindowclientarea.h
+ qwasmwindowtreenode.cpp qwasmwindowtreenode.h
+ qwasmwindownonclientarea.cpp qwasmwindownonclientarea.h
+ qwasminputcontext.cpp qwasminputcontext.h
+ qwasmwindowstack.cpp qwasmwindowstack.h
+ qwasmdrag.cpp qwasmdrag.h
+ DEFINES
+ QT_EGL_NO_X11
+ QT_NO_FOREACH
+ LIBRARIES
+ Qt::Core
+ Qt::CorePrivate
+ Qt::Gui
+ Qt::GuiPrivate
+)
+
+# Resources:
+set(wasmfonts_resource_files
+ "${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
+ LIBRARIES
+ Qt::OpenGL
+ Qt::OpenGLPrivate
+)
+
+# PLUGIN_EXTENDS = "-"
+
+set(wasm_support_files
+ wasm_shell.html
+ qtloader.js
+ resources/qtlogo.svg
+)
+
+set(wasmwindow_resource_files
+ "resources/maximize.svg"
+ "resources/qtlogo.svg"
+ "resources/restore.svg"
+ "resources/x.svg"
+)
+
+qt_internal_add_resource(QWasmIntegrationPlugin "wasmwindow"
+ PREFIX
+ "/wasm-window"
+ BASE
+ "resources"
+ FILES
+ ${wasmwindow_resource_files}
+)
+
+qt_path_join(destination ${QT_INSTALL_DIR} "plugins/platforms")
+qt_copy_or_install(FILES
+ ${wasm_support_files}
+ DESTINATION "${destination}"
+)
+# 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/main.cpp b/src/plugins/platforms/wasm/main.cpp
index a4d23b4e0d..f32ef5aab8 100644
--- a/src/plugins/platforms/wasm/main.cpp
+++ b/src/plugins/platforms/wasm/main.cpp
@@ -1,37 +1,13 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the plugins of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL$
-** 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 General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 or (at your option) 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.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-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <qpa/qplatformintegrationplugin.h>
#include "qwasmintegration.h"
QT_BEGIN_NAMESPACE
+using namespace Qt::Literals::StringLiterals;
+
class QWasmIntegrationPlugin : public QPlatformIntegrationPlugin
{
Q_OBJECT
@@ -43,7 +19,7 @@ public:
QPlatformIntegration *QWasmIntegrationPlugin::create(const QString& system, const QStringList& paramList)
{
Q_UNUSED(paramList);
- if (!system.compare(QStringLiteral("wasm"), Qt::CaseInsensitive))
+ if (!system.compare("wasm"_L1, Qt::CaseInsensitive))
return new QWasmIntegration;
return nullptr;
diff --git a/src/plugins/platforms/wasm/qtloader.js b/src/plugins/platforms/wasm/qtloader.js
index ef4a6ec2b9..bbc0ac68ab 100644
--- a/src/plugins/platforms/wasm/qtloader.js
+++ b/src/plugins/platforms/wasm/qtloader.js
@@ -1,577 +1,295 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the plugins of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL$
-** 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 General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 or (at your option) 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.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-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-// QtLoader provides javascript API for managing Qt application modules.
-//
-// QtLoader provides API on top of Emscripten which supports common lifecycle
-// tasks such as displaying placeholder content while the module downloads,
-// handing application exits, and checking for browser wasm support.
-//
-// There are two usage modes:
-// * Managed: QtLoader owns and manages the HTML display elements like
-// the loader and canvas.
-// * External: The embedding HTML page owns the display elements. QtLoader
-// provides event callbacks which the page reacts to.
-//
-// Managed mode usage:
-//
-// var config = {
-// containerElements : [$("container-id")];
-// }
-// var qtLoader = QtLoader(config);
-// qtLoader.loadEmscriptenModule("applicationName");
-//
-// External mode.usage:
-//
-// var config = {
-// canvasElements : [$("canvas-id")],
-// showLoader: function() {
-// loader.style.display = 'block'
-// canvas.style.display = 'hidden'
-// },
-// showCanvas: function() {
-// loader.style.display = 'hidden'
-// canvas.style.display = 'block'
-// return canvas;
-// }
-// }
-// var qtLoader = QtLoader(config);
-// qtLoader.loadEmscriptenModule("applicationName");
-//
-// Config keys
-//
-// containerElements : [container-element, ...]
-// One or more HTML elements. QtLoader will display loader elements
-// on these while loading the applicaton, and replace the loader with a
-// canvas on load complete.
-// canvasElements : [canvas-element, ...]
-// One or more canvas elements.
-// showLoader : function(status, containerElement)
-// Optional loading element constructor function. Implement to create
-// a custom loading screen. This function may be called multiple times,
-// while preparing the application binary. "status" is a string
-// containing the loading sub-status, and may be either "Downloading",
-// or "Compiling". The browser may be using streaming compilation, in
-// which case the wasm module is compiled during downloading and the
-// there is no separate compile step.
-// showCanvas : function(containerElement)
-// Optional canvas constructor function. Implement to create custom
-// canvas elements.
-// showExit : function(crashed, exitCode, containerElement)
-// Optional exited element constructor function.
-// showError : function(crashed, exitCode, containerElement)
-// Optional error element constructor function.
-//
-// path : <string>
-// Prefix path for wasm file, realative to the loading HMTL file.
-// restartMode : "DoNotRestart", "RestartOnExit", "RestartOnCrash"
-// Controls whether the application should be reloaded on exits. The default is "DoNotRestart"
-// restartType : "RestartModule", "ReloadPage"
-// restartLimit : <int>
-// Restart attempts limit. The default is 10.
-// stdoutEnabled : <bool>
-// stderrEnabled : <bool>
-// environment : <object>
-// key-value environment variable pairs.
-//
-// QtLoader object API
-//
-// webAssemblySupported : bool
-// webGLSupported : bool
-// canLoadQt : bool
-// Reports if WebAssembly and WebGL are supported. These are requirements for
-// running Qt applications.
-// loadEmscriptenModule(applicationName)
-// Loads the application from the given emscripten javascript module file and wasm file
-// status
-// One of "Created", "Loading", "Running", "Exited".
-// crashed
-// Set to true if there was an unclean exit.
-// exitCode
-// main()/emscripten_force_exit() return code. Valid on status change to
-// "Exited", iff crashed is false.
-// exitText
-// Abort/exit message.
-// addCanvasElement
-// Add canvas at run-time. Adds a corresponding QScreen,
-// removeCanvasElement
-// Remove canvas at run-time. Removes the corresponding QScreen.
-// resizeCanvasElement
-// Signals to the application that a canvas has been resized.
-// setFontDpi
-// Sets the logical font dpi for the application.
-
-
-var Module = {}
-
-function QtLoader(config)
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+/**
+ * Loads the instance of a WASM module.
+ *
+ * @param config May contain any key normally accepted by emscripten and the 'qt' extra key, with
+ * the following sub-keys:
+ * - environment: { [name:string] : string }
+ * environment variables set on the instance
+ * - onExit: (exitStatus: { text: string, code?: number, crashed: bool }) => void
+ * called when the application has exited for any reason. There are two cases:
+ * aborted: crashed is true, text contains an error message.
+ * exited: crashed is false, code contians the exit code.
+ *
+ * Note that by default Emscripten does not exit when main() returns. This behavior
+ * is controlled by the EXIT_RUNTIME linker flag; set "-s EXIT_RUNTIME=1" to make
+ * Emscripten tear down the runtime and exit when main() returns.
+ *
+ * - containerElements: HTMLDivElement[]
+ * Array of host elements for Qt screens. Each of these elements is mapped to a QScreen on
+ * launch.
+ * - fontDpi: number
+ * Specifies font DPI for the instance
+ * - onLoaded: () => void
+ * Called when the module has loaded.
+ * - entryFunction: (emscriptenConfig: object) => Promise<EmscriptenModule>
+ * Qt always uses emscripten's MODULARIZE option. This is the MODULARIZE entry function.
+ * - module: Promise<WebAssembly.Module>
+ * The module to create the instance from (optional). Specifying the module allows optimizing
+ * use cases where several instances are created from a single WebAssembly source.
+ * - qtdir: string
+ * Path to Qt installation. This path will be used for loading Qt shared libraries and plugins.
+ * The path is set to 'qt' by default, and is relative to the path of the web page's html file.
+ * This property is not in use when static linking is used, since this build mode includes all
+ * libraries and plugins in the wasm file.
+ * - preload: [string]: Array of file paths to json-encoded files which specifying which files to preload.
+ * The preloaded files will be downloaded at application startup and copied to the in-memory file
+ * system provided by Emscripten.
+ *
+ * Each json file must contain an array of source, destination objects:
+ * [
+ * {
+ * "source": "path/to/source",
+ * "destination": "/path/to/destination"
+ * },
+ * ...
+ * ]
+ * The source path is relative to the html file path. The destination path must be
+ * an absolute path.
+ *
+ * $QTDIR may be used as a placeholder for the "qtdir" configuration property (see @qtdir), for instance:
+ * "source": "$QTDIR/plugins/imageformats/libqjpeg.so"
+ * - localFonts.requestPermission: bool
+ * Whether Qt should request for local fonts access permission on startup (default false).
+ * - localFonts.familiesCollection string
+ * Specifies a collection of local fonts to load. Possible values are:
+ * "NoFontFamilies" : Don't load any font families
+ * "DefaultFontFamilies" : A subset of available font families; currently the "web-safe" fonts (default).
+ * "AllFontFamilies" : All local font families (not reccomended)
+ * - localFonts.extraFamilies: [string]
+ * Adds additional font families to be loaded at startup.
+ *
+ * @return Promise<instance: EmscriptenModule>
+ * The promise is resolved when the module has been instantiated and its main function has been
+ * called.
+ *
+ * @see https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/emscripten for
+ * EmscriptenModule
+ */
+async function qtLoad(config)
{
- function webAssemblySupported() {
- return typeof WebAssembly !== "undefined"
- }
-
- function webGLSupported() {
- // We expect that WebGL is supported if WebAssembly is; however
- // the GPU may be blacklisted.
- try {
- var canvas = document.createElement("canvas");
- return !!(window.WebGLRenderingContext && (canvas.getContext("webgl") || canvas.getContext("experimental-webgl")));
- } catch (e) {
- return false;
+ const throwIfEnvUsedButNotExported = (instance, config) =>
+ {
+ const environment = config.environment;
+ if (!environment || Object.keys(environment).length === 0)
+ return;
+ const isEnvExported = typeof instance.ENV === 'object';
+ if (!isEnvExported)
+ throw new Error('ENV must be exported if environment variables are passed');
+ };
+
+ if (typeof config !== 'object')
+ throw new Error('config is required, expected an object');
+ if (typeof config.qt !== 'object')
+ throw new Error('config.qt is required, expected an object');
+ if (typeof config.qt.entryFunction !== 'function')
+ throw new Error('config.qt.entryFunction is required, expected a function');
+
+ config.qt.qtdir ??= 'qt';
+ config.qt.preload ??= [];
+
+ config.qtContainerElements = config.qt.containerElements;
+ delete config.qt.containerElements;
+ config.qtFontDpi = config.qt.fontDpi;
+ delete config.qt.fontDpi;
+
+ // Make Emscripten not call main(); this gives us more control over
+ // the startup sequence.
+ const originalNoInitialRun = config.noInitialRun;
+ const originalArguments = config.arguments;
+ config.noInitialRun = true;
+
+ // Used for rejecting a failed load's promise where emscripten itself does not allow it,
+ // like in instantiateWasm below. This allows us to throw in case of a load error instead of
+ // hanging on a promise to entry function, which emscripten unfortunately does.
+ let circuitBreakerReject;
+ const circuitBreaker = new Promise((_, reject) => { circuitBreakerReject = reject; });
+
+ // If module async getter is present, use it so that module reuse is possible.
+ if (config.qt.module) {
+ config.instantiateWasm = async (imports, successCallback) =>
+ {
+ try {
+ const module = await config.qt.module;
+ successCallback(
+ await WebAssembly.instantiate(module, imports), module);
+ } catch (e) {
+ circuitBreakerReject(e);
+ }
}
}
-
- function canLoadQt() {
- // The current Qt implementation requires WebAssembly (asm.js is not in use),
- // and also WebGL (there is no raster fallback).
- return webAssemblySupported() && webGLSupported();
- }
-
- function removeChildren(element) {
- while (element.firstChild) element.removeChild(element.firstChild);
- }
-
- function createCanvas() {
- var canvas = document.createElement("canvas");
- canvas.className = "QtCanvas";
- canvas.style.height = "100%";
- canvas.style.width = "100%";
-
- // Set contentEditable in order to enable clipboard events; hide the resulting focus frame.
- canvas.contentEditable = true;
- canvas.style.outline = "0px solid transparent";
- canvas.style.caretColor = "transparent";
- canvas.style.cursor = "default";
-
- return canvas;
- }
-
- // Set default state handler functions and create canvases if needed
- if (config.containerElements !== undefined) {
-
- config.canvasElements = config.containerElements.map(createCanvas);
-
- config.showError = config.showError || function(errorText, container) {
- removeChildren(container);
- var errorTextElement = document.createElement("text");
- errorTextElement.className = "QtError"
- errorTextElement.innerHTML = errorText;
- return errorTextElement;
+ const fetchJsonHelper = async path => (await fetch(path)).json();
+ const filesToPreload = (await Promise.all(config.qt.preload.map(fetchJsonHelper))).flat();
+ const qtPreRun = (instance) => {
+ // Copy qt.environment to instance.ENV
+ throwIfEnvUsedButNotExported(instance, config);
+ for (const [name, value] of Object.entries(config.qt.environment ?? {}))
+ instance.ENV[name] = value;
+
+ // Preload files from qt.preload
+ const makeDirs = (FS, filePath) => {
+ const parts = filePath.split("/");
+ let path = "/";
+ for (let i = 0; i < parts.length - 1; ++i) {
+ const part = parts[i];
+ if (part == "")
+ continue;
+ path += part + "/";
+ try {
+ FS.mkdir(path);
+ } catch (error) {
+ const EEXIST = 20;
+ if (error.errno != EEXIST)
+ throw error;
+ }
+ }
}
- config.showLoader = config.showLoader || function(loadingState, container) {
- removeChildren(container);
- var loadingText = document.createElement("text");
- loadingText.className = "QtLoading"
- loadingText.innerHTML = '<p><center> ${loadingState}...</center><p>';
- return loadingText;
- };
-
- config.showCanvas = config.showCanvas || function(canvas, container) {
- removeChildren(container);
+ const extractFilenameAndDir = (path) => {
+ const parts = path.split('/');
+ const filename = parts.pop();
+ const dir = parts.join('/');
+ return {
+ filename: filename,
+ dir: dir
+ };
}
-
- config.showExit = config.showExit || function(crashed, exitCode, container) {
- if (!crashed)
- return undefined;
-
- removeChildren(container);
- var fontSize = 54;
- var crashSymbols = ["\u{1F615}", "\u{1F614}", "\u{1F644}", "\u{1F928}", "\u{1F62C}",
- "\u{1F915}", "\u{2639}", "\u{1F62E}", "\u{1F61E}", "\u{1F633}"];
- var symbolIndex = Math.floor(Math.random() * crashSymbols.length);
- var errorHtml = `<font size='${fontSize}'> ${crashSymbols[symbolIndex]} </font>`
- var errorElement = document.createElement("text");
- errorElement.className = "QtExit"
- errorElement.innerHTML = errorHtml;
- return errorElement;
+ const preloadFile = (file) => {
+ makeDirs(instance.FS, file.destination);
+ const source = file.source.replace('$QTDIR', config.qt.qtdir);
+ const filenameAndDir = extractFilenameAndDir(file.destination);
+ instance.FS.createPreloadedFile(filenameAndDir.dir, filenameAndDir.filename, source, true, true);
}
+ const isFsExported = typeof instance.FS === 'object';
+ if (!isFsExported)
+ throw new Error('FS must be exported if preload is used');
+ filesToPreload.forEach(preloadFile);
}
- config.restartMode = config.restartMode || "DoNotRestart";
- config.restartLimit = config.restartLimit || 10;
-
- if (config.stdoutEnabled === undefined) config.stdoutEnabled = true;
- if (config.stderrEnabled === undefined) config.stderrEnabled = true;
-
- // Make sure config.path is defined and ends with "/" if needed
- if (config.path === undefined)
- config.path = "";
- if (config.path.length > 0 && !config.path.endsWith("/"))
- config.path = config.path.concat("/");
-
- if (config.environment === undefined)
- config.environment = {};
-
- var publicAPI = {};
- publicAPI.webAssemblySupported = webAssemblySupported();
- publicAPI.webGLSupported = webGLSupported();
- publicAPI.canLoadQt = canLoadQt();
- publicAPI.canLoadApplication = canLoadQt();
- publicAPI.status = undefined;
- publicAPI.loadEmscriptenModule = loadEmscriptenModule;
- publicAPI.addCanvasElement = addCanvasElement;
- publicAPI.removeCanvasElement = removeCanvasElement;
- publicAPI.resizeCanvasElement = resizeCanvasElement;
- publicAPI.setFontDpi = setFontDpi;
- publicAPI.fontDpi = fontDpi;
-
- restartCount = 0;
-
- function fetchResource(filePath) {
- var fullPath = config.path + filePath;
- return fetch(fullPath).then(function(response) {
- if (!response.ok) {
- self.error = response.status + " " + response.statusText + " " + response.url;
- setStatus("Error");
- return Promise.reject(self.error)
- } else {
- return response;
- }
- });
- }
-
- function fetchText(filePath) {
- return fetchResource(filePath).then(function(response) {
- return response.text();
- });
- }
-
- function fetchThenCompileWasm(response) {
- return response.arrayBuffer().then(function(data) {
- self.loaderSubState = "Compiling";
- setStatus("Loading") // trigger loaderSubState udpate
- return WebAssembly.compile(data);
- });
- }
-
- function fetchCompileWasm(filePath) {
- return fetchResource(filePath).then(function(response) {
- if (typeof WebAssembly.compileStreaming !== "undefined") {
- self.loaderSubState = "Downloading/Compiling";
- setStatus("Loading");
- return WebAssembly.compileStreaming(response).catch(function(error) {
- // compileStreaming may/will fail if the server does not set the correct
- // mime type (application/wasm) for the wasm file. Fall back to fetch,
- // then compile in this case.
- return fetchThenCompileWasm(response);
- });
- } else {
- // Fall back to fetch, then compile if compileStreaming is not supported
- return fetchThenCompileWasm(response);
- }
- });
- }
-
- function loadEmscriptenModule(applicationName) {
-
- // Loading in qtloader.js goes through four steps:
- // 1) Check prerequisites
- // 2) Download resources
- // 3) Configure the emscripten Module object
- // 4) Start the emcripten runtime, after which emscripten takes over
-
- // Check for Wasm & WebGL support; set error and return before downloading resources if missing
- if (!webAssemblySupported()) {
- self.error = "Error: WebAssembly is not supported"
- setStatus("Error");
- return;
- }
- if (!webGLSupported()) {
- self.error = "Error: WebGL is not supported"
- setStatus("Error");
- return;
- }
-
- // Continue waiting if loadEmscriptenModule() is called again
- if (publicAPI.status == "Loading")
- return;
- self.loaderSubState = "Downloading";
- setStatus("Loading");
-
- // Fetch emscripten generated javascript runtime
- var emscriptenModuleSource = undefined
- var emscriptenModuleSourcePromise = fetchText(applicationName + ".js").then(function(source) {
- emscriptenModuleSource = source
- });
-
- // Fetch and compile wasm module
- var wasmModule = undefined;
- var wasmModulePromise = fetchCompileWasm(applicationName + ".wasm").then(function (module) {
- wasmModule = module;
- });
-
- // Wait for all resources ready
- Promise.all([emscriptenModuleSourcePromise, wasmModulePromise]).then(function(){
- completeLoadEmscriptenModule(applicationName, emscriptenModuleSource, wasmModule);
- }).catch(function(error) {
- self.error = error;
- setStatus("Error");
- });
+ if (!config.preRun)
+ config.preRun = [];
+ config.preRun.push(qtPreRun);
+
+ const originalLocateFile = config.locateFile;
+ config.locateFile = filename =>
+ {
+ const originalLocatedFilename = originalLocateFile ? originalLocateFile(filename) : filename;
+ if (originalLocatedFilename.startsWith('libQt6'))
+ return `${config.qt.qtdir}/lib/${originalLocatedFilename}`;
+ return originalLocatedFilename;
}
- function completeLoadEmscriptenModule(applicationName, emscriptenModuleSource, wasmModule) {
+ let onExitCalled = false;
+ const originalOnExit = config.onExit;
+ config.onExit = code => {
+ originalOnExit?.();
- // 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) {
- WebAssembly.instantiate(wasmModule, imports).then(function(instance) {
- successCallback(instance, wasmModule);
- }, function(error) {
- self.error = error;
- setStatus("Error");
+ if (!onExitCalled) {
+ onExitCalled = true;
+ config.qt.onExit?.({
+ code,
+ crashed: false
});
- return {};
- };
-
- Module.locateFile = Module.locateFile || function(filename) {
- return config.path + filename;
- };
-
- // Attach status callbacks
- Module.setStatus = Module.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) {
- // console.log("monitorRunDependencies " + left)
- };
-
- // Attach standard out/err callbacks.
- Module.print = Module.print || function(text) {
- if (config.stdoutEnabled)
- console.log(text)
- };
- Module.printErr = Module.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.
- if (text.startsWith !== undefined && text.startsWith("bad name in getProcAddress:"))
- return;
-
- if (config.stderrEnabled)
- console.log(text)
- };
-
- // Error handling: set status to "Exited", update crashed and
- // exitCode according to exit type.
- // 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) {
- publicAPI.crashed = true;
- publicAPI.exitText = text;
- setStatus("Exited");
- };
- Module.quit = Module.quit || function(code, exception) {
- if (exception.name == "ExitStatus") {
- // Clean exit with code
- publicAPI.exitText = undefined
- publicAPI.exitCode = code;
- } else {
- publicAPI.exitText = exception.toString();
- publicAPI.crashed = true;
- }
- setStatus("Exited");
- };
-
- // Set environment variables
- Module.preRun = Module.preRun || []
- Module.preRun.push(function() {
- for (var [key, value] of Object.entries(config.environment)) {
- ENV[key.toUpperCase()] = value;
- }
- });
-
- Module.mainScriptUrlOrBlob = new Blob([emscriptenModuleSource], {type: 'text/javascript'});
-
- Module.qtCanvasElements = config.canvasElements;
-
- config.restart = function() {
-
- // Restart by reloading the page. This will wipe all state which means
- // reload loops can't be prevented.
- if (config.restartType == "ReloadPage") {
- location.reload();
- }
-
- // Restart by readling the emscripten app module.
- ++self.restartCount;
- if (self.restartCount > config.restartLimit) {
- self.error = "Error: This application has crashed too many times and has been disabled. Reload the page to try again."
- setStatus("Error");
- return;
- }
- loadEmscriptenModule(applicationName);
- };
-
- publicAPI.exitCode = undefined;
- 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
- }
-
- function setErrorContent() {
- if (config.containerElements === undefined) {
- if (config.showError !== undefined)
- config.showError(self.error);
- return;
- }
-
- for (container of config.containerElements) {
- var errorElement = config.showError(self.error, container);
- container.appendChild(errorElement);
}
}
- function setLoaderContent() {
- if (config.containerElements === undefined) {
- if (config.showLoader !== undefined)
- config.showLoader(self.loaderSubState);
- return;
- }
-
- for (container of config.containerElements) {
- var loaderElement = config.showLoader(self.loaderSubState, container);
- container.appendChild(loaderElement);
+ const originalOnAbort = config.onAbort;
+ config.onAbort = text =>
+ {
+ originalOnAbort?.();
+
+ if (!onExitCalled) {
+ onExitCalled = true;
+ config.qt.onExit?.({
+ text,
+ crashed: true
+ });
}
- }
-
- function setCanvasContent() {
- if (config.containerElements === undefined) {
- if (config.showCanvas !== undefined)
- config.showCanvas();
+ };
+
+ // Call app/emscripten module entry function. It may either come from the emscripten
+ // runtime script or be customized as needed.
+ let instance;
+ try {
+ instance = await Promise.race(
+ [circuitBreaker, config.qt.entryFunction(config)]);
+
+ // Call main after creating the instance. We've opted into manually
+ // calling main() by setting noInitialRun in the config. Thie Works around
+ // issue where Emscripten suppresses all exceptions thrown during main.
+ if (!originalNoInitialRun)
+ instance.callMain(originalArguments);
+ } catch (e) {
+ // If this is the exception thrown by app.exec() then that is a normal
+ // case and we suppress it.
+ if (e == "unwind") // not much to go on
return;
- }
- for (var i = 0; i < config.containerElements.length; ++i) {
- var container = config.containerElements[i];
- var canvas = config.canvasElements[i];
- config.showCanvas(canvas, container);
- container.appendChild(canvas);
+ if (!onExitCalled) {
+ onExitCalled = true;
+ config.qt.onExit?.({
+ text: e.message,
+ crashed: true
+ });
}
+ throw e;
}
- function setExitContent() {
-
- // publicAPI.crashed = true;
-
- if (publicAPI.status != "Exited")
- return;
-
- if (config.containerElements === undefined) {
- if (config.showExit !== undefined)
- config.showExit(publicAPI.crashed, publicAPI.exitCode);
- return;
- }
-
- if (!publicAPI.crashed)
- return;
+ return instance;
+}
- for (container of config.containerElements) {
- var loaderElement = config.showExit(publicAPI.crashed, publicAPI.exitCode, container);
- if (loaderElement !== undefined)
- container.appendChild(loaderElement);
- }
+// Compatibility API. This API is deprecated,
+// and will be removed in a future version of Qt.
+function QtLoader(qtConfig) {
+
+ const warning = 'Warning: The QtLoader API is deprecated and will be removed in ' +
+ 'a future version of Qt. Please port to the new qtLoad() API.';
+ console.warn(warning);
+
+ let emscriptenConfig = qtConfig.moduleConfig || {}
+ qtConfig.moduleConfig = undefined;
+ const showLoader = qtConfig.showLoader;
+ qtConfig.showLoader = undefined;
+ const showError = qtConfig.showError;
+ qtConfig.showError = undefined;
+ const showExit = qtConfig.showExit;
+ qtConfig.showExit = undefined;
+ const showCanvas = qtConfig.showCanvas;
+ qtConfig.showCanvas = undefined;
+ if (qtConfig.canvasElements) {
+ qtConfig.containerElements = qtConfig.canvasElements
+ qtConfig.canvasElements = undefined;
+ } else {
+ qtConfig.containerElements = qtConfig.containerElements;
+ qtConfig.containerElements = undefined;
}
-
- var committedStatus = undefined;
- function handleStatusChange() {
- if (publicAPI.status != "Loading" && committedStatus == publicAPI.status)
- return;
- committedStatus = publicAPI.status;
-
- if (publicAPI.status == "Error") {
- setErrorContent();
- } else if (publicAPI.status == "Loading") {
- setLoaderContent();
- } else if (publicAPI.status == "Running") {
- setCanvasContent();
- } else if (publicAPI.status == "Exited") {
- if (config.restartMode == "RestartOnExit" ||
- config.restartMode == "RestartOnCrash" && publicAPI.crashed) {
- committedStatus = undefined;
- config.restart();
- } else {
- setExitContent();
+ emscriptenConfig.qt = qtConfig;
+
+ let qtloader = {
+ exitCode: undefined,
+ exitText: "",
+ loadEmscriptenModule: _name => {
+ try {
+ qtLoad(emscriptenConfig);
+ } catch (e) {
+ showError?.(e.message);
}
}
-
- // Send status change notification
- if (config.statusChanged)
- config.statusChanged(publicAPI.status);
}
- function setStatus(status) {
- if (status != "Loading" && publicAPI.status == status)
- return;
- publicAPI.status = status;
-
- window.setTimeout(function() { handleStatusChange(); }, 0);
+ qtConfig.onLoaded = () => {
+ showCanvas?.();
}
- function addCanvasElement(element) {
- if (publicAPI.status == "Running")
- Module.qtAddCanvasElement(element);
- else
- console.log("Error: addCanvasElement can only be called in the Running state");
+ qtConfig.onExit = exit => {
+ qtloader.exitCode = exit.code
+ qtloader.exitText = exit.text;
+ showExit?.();
}
- function removeCanvasElement(element) {
- if (publicAPI.status == "Running")
- 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);
- }
+ showLoader?.("Loading");
- function setFontDpi(dpi) {
- Module.qtFontDpi = dpi;
- if (publicAPI.status == "Running")
- Module.qtSetFontDpi(dpi);
- }
-
- function fontDpi() {
- return Module.qtFontDpi;
- }
-
- setStatus("Created");
-
- return publicAPI;
-}
+ return qtloader;
+};
diff --git a/src/plugins/platforms/wasm/qtlogo.svg b/src/plugins/platforms/wasm/qtlogo.svg
deleted file mode 100644
index ad7c7776bf..0000000000
--- a/src/plugins/platforms/wasm/qtlogo.svg
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<svg
- xmlns:dc="http://purl.org/dc/elements/1.1/"
- xmlns:cc="http://creativecommons.org/ns#"
- xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
- xmlns:svg="http://www.w3.org/2000/svg"
- xmlns="http://www.w3.org/2000/svg"
- width="462pt"
- height="339pt"
- viewBox="0 0 462 339"
- version="1.1">
- <metadata
- id="metadata20">
- <rdf:RDF>
- <cc:Work
- rdf:about="">
- <dc:format>image/svg+xml</dc:format>
- <dc:type
- rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
- <dc:title></dc:title>
- </cc:Work>
- </rdf:RDF>
- </metadata>
- <path
- fill="#41cd52"
- d=" M 63.50 0.00 L 462.00 0.00 L 462.00 274.79 C 440.60 296.26 419.13 317.66 397.61 339.00 L 0.00 339.00 L 0.00 63.39 C 21.08 42.18 42.34 21.13 63.50 0.00 Z"
- id="path6" />
- <path
- d=" M 122.37 71.33 C 137.50 61.32 156.21 58.79 174.00 58.95 C 190.94 59.16 208.72 62.13 222.76 72.24 C 232.96 79.41 239.59 90.48 244.01 101.93 C 251.16 120.73 253.26 141.03 253.50 161.01 C 253.53 181.13 252.62 201.69 245.96 220.86 C 241.50 233.90 233.01 245.48 221.81 253.52 C 229.87 266.58 238.09 279.54 246.15 292.60 C 236.02 297.27 225.92 301.97 215.78 306.62 C 207.15 292.38 198.56 278.11 189.90 263.89 C 178.19 265.81 166.21 265.66 154.44 264.36 C 140.34 262.67 125.97 258.37 115.09 248.88 C 106.73 241.64 101.48 231.51 97.89 221.21 C 92.01 203.79 90.43 185.25 90.16 166.97 C 90.02 147.21 91.28 127.14 97.24 108.18 C 101.85 93.92 109.48 79.69 122.37 71.33 Z"
- id="path8"
- fill="#ffffff" />
- <path
- d=" M 294.13 70.69 C 304.73 70.68 315.33 70.68 325.93 70.69 C 325.96 84.71 325.92 98.72 325.95 112.74 C 339.50 112.76 353.05 112.74 366.60 112.75 C 366.37 121.85 366.12 130.95 365.86 140.05 C 352.32 140.08 338.79 140.04 325.25 140.07 C 325.28 163.05 325.18 186.03 325.30 209.01 C 325.56 215.30 325.42 221.94 328.19 227.75 C 330.21 232.23 335.65 233.38 340.08 233.53 C 348.43 233.50 356.77 233.01 365.12 232.86 C 365.63 241.22 366.12 249.59 366.60 257.95 C 349.99 260.74 332.56 264.08 316.06 258.86 C 309.11 256.80 302.63 252.19 299.81 245.32 C 294.76 233.63 294.35 220.62 294.13 208.07 C 294.11 185.40 294.13 162.74 294.12 140.07 C 286.73 140.05 279.34 140.08 271.95 140.05 C 271.93 130.96 271.93 121.86 271.95 112.76 C 279.34 112.73 286.72 112.77 294.11 112.74 C 294.14 98.72 294.10 84.71 294.13 70.69 Z"
- id="path10"
- fill="#ffffff" />
- <path
- fill="#41cd52"
- d=" M 160.51 87.70 C 170.80 86.36 181.60 86.72 191.34 90.61 C 199.23 93.73 205.93 99.84 209.47 107.58 C 214.90 119.31 216.98 132.26 218.03 145.05 C 219.17 162.07 219.01 179.25 216.66 196.17 C 215.01 206.24 212.66 216.85 205.84 224.79 C 198.92 232.76 188.25 236.18 178.01 236.98 C 167.21 237.77 155.82 236.98 146.07 231.87 C 140.38 228.84 135.55 224.09 132.73 218.27 C 129.31 211.30 127.43 203.69 126.11 196.07 C 122.13 171.91 121.17 146.91 126.61 122.89 C 128.85 113.83 132.11 104.53 138.73 97.70 C 144.49 91.85 152.51 88.83 160.51 87.70 Z"
- id="path12" />
-</svg>
diff --git a/src/plugins/platforms/wasm/qwasmaccessibility.cpp b/src/plugins/platforms/wasm/qwasmaccessibility.cpp
new file mode 100644
index 0000000000..4c3cb46ba3
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmaccessibility.cpp
@@ -0,0 +1,789 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "qwasmaccessibility.h"
+#include "qwasmscreen.h"
+#include "qwasmwindow.h"
+#include "qwasmintegration.h"
+#include <QtGui/qwindow.h>
+
+#if QT_CONFIG(accessibility)
+
+#include <QtGui/private/qaccessiblebridgeutils_p.h>
+
+Q_LOGGING_CATEGORY(lcQpaAccessibility, "qt.qpa.accessibility")
+
+// Qt WebAssembly a11y backend
+//
+// This backend implements accessibility support by creating "shadowing" html
+// elements for each Qt UI element. We access the DOM by using Emscripten's
+// val.h API.
+//
+// Currently, html elements are created in response to notifyAccessibilityUpdate
+// events. In addition or alternatively, we could also walk the accessibility tree
+// from setRootObject().
+
+QWasmAccessibility::QWasmAccessibility()
+{
+
+ s_instance = this;
+}
+
+QWasmAccessibility::~QWasmAccessibility()
+{
+ s_instance = nullptr;
+}
+
+QWasmAccessibility *QWasmAccessibility::s_instance = nullptr;
+
+QWasmAccessibility* QWasmAccessibility::get()
+{
+ return s_instance;
+}
+
+void QWasmAccessibility::addAccessibilityEnableButton(QWindow *window)
+{
+ get()->addAccessibilityEnableButtonImpl(window);
+}
+
+void QWasmAccessibility::removeAccessibilityEnableButton(QWindow *window)
+{
+ get()->removeAccessibilityEnableButtonImpl(window);
+}
+
+void QWasmAccessibility::addAccessibilityEnableButtonImpl(QWindow *window)
+{
+ if (m_accessibilityEnabled)
+ return;
+
+ emscripten::val container = getContainer(window);
+ emscripten::val document = getDocument(container);
+ emscripten::val button = document.call<emscripten::val>("createElement", std::string("button"));
+ button.set("innerText", std::string("Enable Screen Reader"));
+ button["classList"].call<void>("add", emscripten::val("hidden-visually-read-by-screen-reader"));
+ container.call<void>("appendChild", button);
+
+ auto enableContext = std::make_tuple(button, std::make_unique<qstdweb::EventCallback>
+ (button, std::string("click"), [this](emscripten::val) { enableAccessibility(); }));
+ m_enableButtons.insert(std::make_pair(window, std::move(enableContext)));
+}
+
+void QWasmAccessibility::removeAccessibilityEnableButtonImpl(QWindow *window)
+{
+ auto it = m_enableButtons.find(window);
+ if (it == m_enableButtons.end())
+ return;
+
+ // Remove button
+ auto [element, callback] = it->second;
+ Q_UNUSED(callback);
+ element["parentElement"].call<void>("removeChild", element);
+ m_enableButtons.erase(it);
+}
+
+void QWasmAccessibility::enableAccessibility()
+{
+ // Enable accessibility globally for the applicaton. Remove all "enable"
+ // buttons and populate the accessibility tree, starting from the root object.
+
+ Q_ASSERT(!m_accessibilityEnabled);
+ m_accessibilityEnabled = true;
+ for (const auto& [key, value] : m_enableButtons) {
+ const auto &[element, callback] = value;
+ Q_UNUSED(key);
+ Q_UNUSED(callback);
+ element["parentElement"].call<void>("removeChild", element);
+ }
+ m_enableButtons.clear();
+ populateAccessibilityTree(QAccessible::queryAccessibleInterface(m_rootObject));
+}
+
+emscripten::val QWasmAccessibility::getContainer(QWindow *window)
+{
+ return window ? static_cast<QWasmWindow *>(window->handle())->a11yContainer()
+ : emscripten::val::undefined();
+}
+
+emscripten::val QWasmAccessibility::getContainer(QAccessibleInterface *iface)
+{
+ if (!iface)
+ return emscripten::val::undefined();
+ return getContainer(getWindow(iface));
+}
+
+QWindow *QWasmAccessibility::getWindow(QAccessibleInterface *iface)
+{
+ QWindow *window = iface->window();
+ // this is needed to add tabs as the window is not available
+ if (!window && iface->parent())
+ window = iface->parent()->window();
+ return window;
+}
+
+emscripten::val QWasmAccessibility::getDocument(const emscripten::val &container)
+{
+ if (container.isUndefined())
+ return emscripten::val::global("document");
+ return container["ownerDocument"];
+}
+
+emscripten::val QWasmAccessibility::getDocument(QAccessibleInterface *iface)
+{
+ return getDocument(getContainer(iface));
+}
+
+emscripten::val QWasmAccessibility::createHtmlElement(QAccessibleInterface *iface)
+{
+ // Get the html container element for the interface; this depends on which
+ // QScreen it is on. If the interface is not on a screen yet we get an undefined
+ // container, and the code below handles that case as well.
+ emscripten::val container = getContainer(iface);
+
+ // Get the correct html document for the container, or fall back
+ // to the global document. TODO: Does using the correct document actually matter?
+ emscripten::val document = getDocument(container);
+
+ // Translate the Qt a11y elemen role into html element type + ARIA role.
+ // Here we can either create <div> elements with a spesific ARIA role,
+ // or create e.g. <button> elements which should have built-in accessibility.
+ emscripten::val element = [this, iface, document] {
+
+ emscripten::val element = emscripten::val::undefined();
+
+ switch (iface->role()) {
+
+ case QAccessible::Button: {
+ element = document.call<emscripten::val>("createElement", std::string("button"));
+ element.call<void>("addEventListener", emscripten::val("click"),
+ emscripten::val::module_property("qtEventReceived"), true);
+ } break;
+ case QAccessible::CheckBox: {
+ element = document.call<emscripten::val>("createElement", std::string("input"));
+ element.call<void>("setAttribute", std::string("type"), std::string("checkbox"));
+ if (iface->state().checked) {
+ element.call<void>("setAttribute", std::string("checked"), std::string("true"));
+ }
+ element.call<void>("addEventListener", emscripten::val("change"),
+ emscripten::val::module_property("qtEventReceived"), true);
+
+ } break;
+
+ case QAccessible::RadioButton: {
+ element = document.call<emscripten::val>("createElement", std::string("input"));
+ element.call<void>("setAttribute", std::string("type"), std::string("radio"));
+ if (iface->state().checked) {
+ element.call<void>("setAttribute", std::string("checked"), std::string("true"));
+ }
+ element.set(std::string("name"), std::string("buttonGroup"));
+ element.call<void>("addEventListener", emscripten::val("change"),
+ emscripten::val::module_property("qtEventReceived"), true);
+ } break;
+
+ case QAccessible::SpinBox: {
+ element = document.call<emscripten::val>("createElement", std::string("input"));
+ element.call<void>("setAttribute", std::string("type"), std::string("number"));
+ std::string valueString = iface->valueInterface()->currentValue().toString().toStdString();
+ element.call<void>("setAttribute", std::string("value"), valueString);
+ element.call<void>("addEventListener", emscripten::val("change"),
+ emscripten::val::module_property("qtEventReceived"), true);
+ } break;
+
+ case QAccessible::Slider: {
+ element = document.call<emscripten::val>("createElement", std::string("input"));
+ element.call<void>("setAttribute", std::string("type"), std::string("range"));
+ std::string valueString = iface->valueInterface()->currentValue().toString().toStdString();
+ element.call<void>("setAttribute", std::string("value"), valueString);
+ element.call<void>("addEventListener", emscripten::val("change"),
+ emscripten::val::module_property("qtEventReceived"), true);
+ } break;
+
+ case QAccessible::PageTabList:{
+ element = document.call<emscripten::val>("createElement", std::string("div"));
+ element.call<void>("setAttribute", std::string("role"), std::string("tablist"));
+ QString idName = iface->text(QAccessible::Name).replace(" ", "_");
+ idName += "_tabList";
+ element.call<void>("setAttribute", std::string("id"), idName.toStdString());
+
+ for (int i = 0; i < iface->childCount(); ++i) {
+ if (iface->child(i)->role() == QAccessible::PageTab){
+ emscripten::val elementTab = emscripten::val::undefined();
+ elementTab = ensureHtmlElement(iface->child(i));
+ elementTab.call<void>("setAttribute", std::string("aria-owns"), idName.toStdString());
+ setHtmlElementGeometry(iface->child(i));
+ }
+ }
+ } break;
+
+ case QAccessible::PageTab:{
+ element = document.call<emscripten::val>("createElement", std::string("button"));
+ element.call<void>("setAttribute", std::string("role"), std::string("tab"));
+ QString text = iface->text(QAccessible::Name);
+ element.call<void>("setAttribute", std::string("title"), text.toStdString());
+ element.call<void>("addEventListener", emscripten::val("click"),
+ emscripten::val::module_property("qtEventReceived"), true);
+ } break;
+
+ case QAccessible::ScrollBar: {
+ element = document.call<emscripten::val>("createElement", std::string("div"));
+ element.call<void>("setAttribute", std::string("role"), std::string("scrollbar"));
+ std::string valueString = iface->valueInterface()->currentValue().toString().toStdString();
+ element.call<void>("setAttribute", std::string("aria-valuenow"), valueString);
+ element.call<void>("addEventListener", emscripten::val("change"),
+ emscripten::val::module_property("qtEventReceived"), true);
+ } break;
+
+ case QAccessible::StaticText: {
+ element = document.call<emscripten::val>("createElement", std::string("textarea"));
+ element.call<void>("setAttribute", std::string("readonly"), std::string("true"));
+
+ } break;
+ case QAccessible::Dialog: {
+ element = document.call<emscripten::val>("createElement", std::string("dialog"));
+ }break;
+ case QAccessible::ToolBar:{
+ element = document.call<emscripten::val>("createElement", std::string("div"));
+ QString text = iface->text(QAccessible::Name);
+
+ element.call<void>("setAttribute", std::string("role"), std::string("toolbar"));
+ element.call<void>("setAttribute", std::string("title"), text.toStdString());
+ element.call<void>("addEventListener", emscripten::val("click"),
+ emscripten::val::module_property("qtEventReceived"), true);
+ }break;
+ case QAccessible::MenuItem:
+ case QAccessible::ButtonMenu: {
+ element = document.call<emscripten::val>("createElement", std::string("button"));
+ QString text = iface->text(QAccessible::Name);
+
+ element.call<void>("setAttribute", std::string("role"), std::string("menuitem"));
+ element.call<void>("setAttribute", std::string("title"), text.toStdString());
+ element.call<void>("addEventListener", emscripten::val("click"),
+ emscripten::val::module_property("qtEventReceived"), true);
+ }break;
+ case QAccessible::MenuBar:
+ case QAccessible::PopupMenu: {
+ element = document.call<emscripten::val>("createElement",std::string("div"));
+ QString text = iface->text(QAccessible::Name);
+ element.call<void>("setAttribute", std::string("role"), std::string("menubar"));
+ element.call<void>("setAttribute", std::string("title"), text.toStdString());
+ for (int i = 0; i < iface->childCount(); ++i) {
+ emscripten::val childElement = emscripten::val::undefined();
+ childElement= ensureHtmlElement(iface->child(i));
+ childElement.call<void>("setAttribute", std::string("aria-owns"), text.toStdString());
+ setHtmlElementTextName(iface->child(i));
+ setHtmlElementGeometry(iface->child(i));
+ }
+ }break;
+ case QAccessible::EditableText: {
+ element = document.call<emscripten::val>("createElement", std::string("input"));
+ element.call<void>("setAttribute", std::string("type"),std::string("text"));
+ element.call<void>("addEventListener", emscripten::val("input"),
+ emscripten::val::module_property("qtEventReceived"), true);
+ } break;
+ default:
+ qCDebug(lcQpaAccessibility) << "TODO: createHtmlElement() handle" << iface->role();
+ element = document.call<emscripten::val>("createElement", std::string("div"));
+ }
+
+ return element;
+
+ }();
+
+ // Add the html element to the container if we have one. If not there
+ // is a second chance when handling the ObjectShow event.
+ if (!container.isUndefined())
+ container.call<void>("appendChild", element);
+
+ return element;
+}
+
+void QWasmAccessibility::destroyHtmlElement(QAccessibleInterface *iface)
+{
+ Q_UNUSED(iface);
+ qCDebug(lcQpaAccessibility) << "TODO destroyHtmlElement";
+}
+
+emscripten::val QWasmAccessibility::ensureHtmlElement(QAccessibleInterface *iface)
+{
+ auto it = m_elements.find(iface);
+ if (it != m_elements.end())
+ return it.value();
+
+ emscripten::val element = createHtmlElement(iface);
+ m_elements.insert(iface, element);
+
+ return element;
+}
+
+void QWasmAccessibility::setHtmlElementVisibility(QAccessibleInterface *iface, bool visible)
+{
+ emscripten::val element = ensureHtmlElement(iface);
+ emscripten::val container = getContainer(iface);
+
+ if (container.isUndefined()) {
+ qCDebug(lcQpaAccessibility) << "TODO: setHtmlElementVisibility: unable to find html container for element" << iface;
+ return;
+ }
+
+ container.call<void>("appendChild", element);
+
+ element.set("ariaHidden", !visible); // ariaHidden mean completely hidden; maybe some sort of soft-hidden should be used.
+}
+
+void QWasmAccessibility::setHtmlElementGeometry(QAccessibleInterface *iface)
+{
+ emscripten::val element = ensureHtmlElement(iface);
+
+ // QAccessibleInterface gives us the geometry in global (screen) coordinates. Translate that
+ // to window geometry in order to position elements relative to window origin.
+ QWindow *window = getWindow(iface);
+ if (!window)
+ qCWarning(lcQpaAccessibility) << "Unable to find window for" << iface << "setting null geometry";
+ QRect screenGeometry = iface->rect();
+ QPoint windowPos = window ? window->mapFromGlobal(screenGeometry.topLeft()) : QPoint();
+ QRect windowGeometry(windowPos, screenGeometry.size());
+
+ setHtmlElementGeometry(element, windowGeometry);
+}
+
+void QWasmAccessibility::setHtmlElementGeometry(emscripten::val element, QRect geometry)
+{
+ // Position the element using "position: absolute" in order to place
+ // it under the corresponding Qt element in the screen.
+ emscripten::val style = element["style"];
+ style.set("position", std::string("absolute"));
+ style.set("z-index", std::string("-1")); // FIXME: "0" should be sufficient to order beheind the
+ // screen element, but isn't
+ style.set("left", std::to_string(geometry.x()) + "px");
+ style.set("top", std::to_string(geometry.y()) + "px");
+ style.set("width", std::to_string(geometry.width()) + "px");
+ style.set("height", std::to_string(geometry.height()) + "px");
+}
+
+void QWasmAccessibility::setHtmlElementTextName(QAccessibleInterface *iface)
+{
+ emscripten::val element = ensureHtmlElement(iface);
+ QString text = iface->text(QAccessible::Name);
+ element.set("innerHTML", text.toStdString()); // FIXME: use something else than innerHTML
+}
+
+void QWasmAccessibility::setHtmlElementTextNameLE(QAccessibleInterface *iface) {
+ emscripten::val element = ensureHtmlElement(iface);
+ QString text = iface->text(QAccessible::Name);
+ element.call<void>("setAttribute", std::string("name"), text.toStdString());
+ QString value = iface->text(QAccessible::Value);
+ element.set("innerHTML", value.toStdString());
+}
+
+void QWasmAccessibility::setHtmlElementDescription(QAccessibleInterface *iface) {
+ emscripten::val element = ensureHtmlElement(iface);
+ QString desc = iface->text(QAccessible::Description);
+ element.call<void>("setAttribute", std::string("aria-description"), desc.toStdString());
+}
+
+void QWasmAccessibility::handleStaticTextUpdate(QAccessibleEvent *event)
+{
+ switch (event->type()) {
+ case QAccessible::NameChanged: {
+ setHtmlElementTextName(event->accessibleInterface());
+ } break;
+ case QAccessible::DescriptionChanged: {
+ setHtmlElementDescription(event->accessibleInterface());
+ } break;
+ default:
+ qCDebug(lcQpaAccessibility) << "TODO: implement handleStaticTextUpdate for event" << event->type();
+ break;
+ }
+}
+
+void QWasmAccessibility::handleLineEditUpdate(QAccessibleEvent *event) {
+
+ switch (event->type()) {
+ case QAccessible::NameChanged: {
+ setHtmlElementTextName(event->accessibleInterface());
+ } break;
+ case QAccessible::Focus:
+ case QAccessible::TextRemoved:
+ case QAccessible::TextInserted:
+ case QAccessible::TextCaretMoved: {
+ setHtmlElementTextNameLE(event->accessibleInterface());
+ } break;
+ case QAccessible::DescriptionChanged: {
+ setHtmlElementDescription(event->accessibleInterface());
+ } break;
+ default:
+ qCDebug(lcQpaAccessibility) << "TODO: implement handleLineEditUpdate for event" << event->type();
+ break;
+ }
+}
+
+void QWasmAccessibility::handleEventFromHtmlElement(const emscripten::val event)
+{
+
+ QAccessibleInterface *iface = m_elements.key(event["target"]);
+ if (iface == nullptr) {
+ return;
+ } else {
+ QString eventType = QString::fromStdString(event["type"].as<std::string>());
+ const auto& actionNames = QAccessibleBridgeUtils::effectiveActionNames(iface);
+ if (actionNames.contains(QAccessibleActionInterface::pressAction())) {
+
+ iface->actionInterface()->doAction(QAccessibleActionInterface::pressAction());
+
+ } else if (actionNames.contains(QAccessibleActionInterface::toggleAction())) {
+
+ iface->actionInterface()->doAction(QAccessibleActionInterface::toggleAction());
+
+ } else if (actionNames.contains(QAccessibleActionInterface::increaseAction()) ||
+ actionNames.contains(QAccessibleActionInterface::decreaseAction())) {
+
+ QString val = QString::fromStdString(event["target"]["value"].as<std::string>());
+
+ iface->valueInterface()->setCurrentValue(val.toInt());
+
+ } else if (eventType == "input") {
+
+ // as EditableTextInterface is not implemented in qml accessibility
+ // so we need to check the role for text to update in the textbox during accessibility
+
+ if (iface->editableTextInterface() || iface->role() == QAccessible::EditableText) {
+ std::string insertText = event["target"]["value"].as<std::string>();
+ iface->setText(QAccessible::Value, QString::fromStdString(insertText));
+ }
+ }
+ }
+}
+
+void QWasmAccessibility::handleButtonUpdate(QAccessibleEvent *event)
+{
+ qCDebug(lcQpaAccessibility) << "TODO: implement handleButtonUpdate for event" << event->type();
+}
+
+void QWasmAccessibility::handleCheckBoxUpdate(QAccessibleEvent *event)
+{
+ switch (event->type()) {
+ case QAccessible::Focus:
+ case QAccessible::NameChanged: {
+ setHtmlElementTextName(event->accessibleInterface());
+ } break;
+ case QAccessible::StateChanged: {
+ QAccessibleInterface *accessible = event->accessibleInterface();
+ emscripten::val element = ensureHtmlElement(accessible);
+ bool checkedString = accessible->state().checked ? true : false;
+ element.call<void>("setAttribute", std::string("checked"), checkedString);
+ } break;
+ case QAccessible::DescriptionChanged: {
+ setHtmlElementDescription(event->accessibleInterface());
+ } break;
+ default:
+ qCDebug(lcQpaAccessibility) << "TODO: implement handleCheckBoxUpdate for event" << event->type();
+ break;
+ }
+}
+void QWasmAccessibility::handleToolUpdate(QAccessibleEvent *event)
+{
+ QAccessibleInterface *iface = event->accessibleInterface();
+ QString text = iface->text(QAccessible::Name);
+ QString desc = iface->text(QAccessible::Description);
+ switch (event->type()) {
+ case QAccessible::NameChanged:
+ case QAccessible::StateChanged:{
+ emscripten::val element = ensureHtmlElement(iface);
+ element.call<void>("setAttribute", std::string("title"), text.toStdString());
+ } break;
+ case QAccessible::DescriptionChanged: {
+ setHtmlElementDescription(event->accessibleInterface());
+ } break;
+ default:
+ qCDebug(lcQpaAccessibility) << "TODO: implement handleToolUpdate for event" << event->type();
+ break;
+ }
+}
+void QWasmAccessibility::handleMenuUpdate(QAccessibleEvent *event)
+{
+ QAccessibleInterface *iface = event->accessibleInterface();
+ QString text = iface->text(QAccessible::Name);
+ QString desc = iface->text(QAccessible::Description);
+ switch (event->type()) {
+ case QAccessible::Focus:
+ case QAccessible::NameChanged:
+ case QAccessible::MenuStart ://"TODO: To implement later
+ case QAccessible::PopupMenuStart://"TODO: To implement later
+ case QAccessible::StateChanged:{
+ emscripten::val element = ensureHtmlElement(iface);
+ element.call<void>("setAttribute", std::string("title"), text.toStdString());
+ } break;
+ case QAccessible::DescriptionChanged: {
+ setHtmlElementDescription(event->accessibleInterface());
+ } break;
+ default:
+ qCDebug(lcQpaAccessibility) << "TODO: implement handleMenuUpdate for event" << event->type();
+ break;
+ }
+}
+void QWasmAccessibility::handleDialogUpdate(QAccessibleEvent *event) {
+
+ switch (event->type()) {
+ case QAccessible::NameChanged:
+ case QAccessible::Focus:
+ case QAccessible::DialogStart:
+ case QAccessible::StateChanged: {
+ setHtmlElementTextName(event->accessibleInterface());
+ } break;
+ case QAccessible::DescriptionChanged: {
+ setHtmlElementDescription(event->accessibleInterface());
+ } break;
+ default:
+ qCDebug(lcQpaAccessibility) << "TODO: implement handleLineEditUpdate for event" << event->type();
+ break;
+ }
+}
+
+void QWasmAccessibility::populateAccessibilityTree(QAccessibleInterface *iface)
+{
+ if (!iface)
+ return;
+
+ // Create html element for the interface, sync up properties.
+ ensureHtmlElement(iface);
+ const bool visible = !iface->state().invisible;
+ setHtmlElementVisibility(iface, visible);
+ setHtmlElementGeometry(iface);
+ setHtmlElementTextName(iface);
+ setHtmlElementDescription(iface);
+
+ for (int i = 0; i < iface->childCount(); ++i)
+ populateAccessibilityTree(iface->child(i));
+}
+
+void QWasmAccessibility::handleRadioButtonUpdate(QAccessibleEvent *event)
+{
+ switch (event->type()) {
+ case QAccessible::Focus:
+ case QAccessible::NameChanged: {
+ setHtmlElementTextName(event->accessibleInterface());
+ } break;
+ case QAccessible::StateChanged: {
+ QAccessibleInterface *accessible = event->accessibleInterface();
+ emscripten::val element = ensureHtmlElement(accessible);
+ std::string checkedString = accessible->state().checked ? "true" : "false";
+ element.call<void>("setAttribute", std::string("checked"), checkedString);
+ } break;
+ case QAccessible::DescriptionChanged: {
+ setHtmlElementDescription(event->accessibleInterface());
+ } break;
+ default:
+ qDebug() << "TODO: implement handleRadioButtonUpdate for event" << event->type();
+ break;
+ }
+}
+
+void QWasmAccessibility::handleSpinBoxUpdate(QAccessibleEvent *event)
+{
+ switch (event->type()) {
+ case QAccessible::Focus:
+ case QAccessible::NameChanged: {
+ setHtmlElementTextName(event->accessibleInterface());
+ } break;
+ case QAccessible::ValueChanged: {
+ QAccessibleInterface *accessible = event->accessibleInterface();
+ emscripten::val element = ensureHtmlElement(accessible);
+ std::string valueString = accessible->valueInterface()->currentValue().toString().toStdString();
+ element.call<void>("setAttribute", std::string("value"), valueString);
+ } break;
+ case QAccessible::DescriptionChanged: {
+ setHtmlElementDescription(event->accessibleInterface());
+ } break;
+ default:
+ qDebug() << "TODO: implement handleSpinBoxUpdate for event" << event->type();
+ break;
+ }
+}
+
+void QWasmAccessibility::handleSliderUpdate(QAccessibleEvent *event)
+{
+ switch (event->type()) {
+ case QAccessible::Focus:
+ case QAccessible::NameChanged: {
+ setHtmlElementTextName(event->accessibleInterface());
+ } break;
+ case QAccessible::ValueChanged: {
+ QAccessibleInterface *accessible = event->accessibleInterface();
+ emscripten::val element = ensureHtmlElement(accessible);
+ std::string valueString = accessible->valueInterface()->currentValue().toString().toStdString();
+ element.call<void>("setAttribute", std::string("value"), valueString);
+ } break;
+ case QAccessible::DescriptionChanged: {
+ setHtmlElementDescription(event->accessibleInterface());
+ } break;
+ default:
+ qDebug() << "TODO: implement handleSliderUpdate for event" << event->type();
+ break;
+ }
+}
+
+void QWasmAccessibility::handleScrollBarUpdate(QAccessibleEvent *event)
+{
+ switch (event->type()) {
+ case QAccessible::Focus:
+ case QAccessible::NameChanged: {
+ setHtmlElementTextName(event->accessibleInterface());
+ } break;
+ case QAccessible::ValueChanged: {
+ QAccessibleInterface *accessible = event->accessibleInterface();
+ emscripten::val element = ensureHtmlElement(accessible);
+ std::string valueString = accessible->valueInterface()->currentValue().toString().toStdString();
+ element.call<void>("setAttribute", std::string("aria-valuenow"), valueString);
+ } break;
+ case QAccessible::DescriptionChanged: {
+ setHtmlElementDescription(event->accessibleInterface());
+ } break;
+ default:
+ qDebug() << "TODO: implement handleSliderUpdate for event" << event->type();
+ break;
+ }
+
+}
+
+void QWasmAccessibility::handlePageTabUpdate(QAccessibleEvent *event)
+{
+ switch (event->type()) {
+ case QAccessible::NameChanged: {
+ setHtmlElementTextName(event->accessibleInterface());
+ } break;
+ case QAccessible::Focus: {
+ setHtmlElementTextName(event->accessibleInterface());
+ } break;
+ case QAccessible::DescriptionChanged: {
+ setHtmlElementDescription(event->accessibleInterface());
+ } break;
+ default:
+ qDebug() << "TODO: implement handlePageTabUpdate for event" << event->type();
+ break;
+ }
+}
+
+void QWasmAccessibility::handlePageTabListUpdate(QAccessibleEvent *event)
+{
+ switch (event->type()) {
+ case QAccessible::NameChanged: {
+ setHtmlElementTextName(event->accessibleInterface());
+ } break;
+ case QAccessible::Focus: {
+ setHtmlElementTextName(event->accessibleInterface());
+ } break;
+ case QAccessible::DescriptionChanged: {
+ setHtmlElementDescription(event->accessibleInterface());
+ } break;
+ default:
+ qDebug() << "TODO: implement handlePageTabUpdate for event" << event->type();
+ break;
+ }
+}
+
+void QWasmAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event)
+{
+ if (!m_accessibilityEnabled)
+ return;
+
+ QAccessibleInterface *iface = event->accessibleInterface();
+ if (!iface) {
+ qWarning() << "notifyAccessibilityUpdate with null a11y interface" ;
+ return;
+ }
+
+ // Handle some common event types. See
+ // https://doc.qt.io/qt-5/qaccessible.html#Event-enum
+ switch (event->type()) {
+ case QAccessible::ObjectShow:
+ setHtmlElementVisibility(iface, true);
+
+ // Sync up properties on show;
+ setHtmlElementGeometry(iface);
+ setHtmlElementTextName(iface);
+ setHtmlElementDescription(iface);
+
+ return;
+ break;
+ case QAccessible::ObjectHide:
+ setHtmlElementVisibility(iface, false);
+ return;
+ break;
+ // TODO: maybe handle more types here
+ default:
+ break;
+ };
+
+ // Switch on interface role, see
+ // https://doc.qt.io/qt-5/qaccessibleinterface.html#role
+ switch (iface->role()) {
+ case QAccessible::StaticText:
+ handleStaticTextUpdate(event);
+ break;
+ case QAccessible::Button:
+ handleStaticTextUpdate(event);
+ break;
+ case QAccessible::CheckBox:
+ handleCheckBoxUpdate(event);
+ break;
+ case QAccessible::EditableText:
+ handleLineEditUpdate(event);
+ break;
+ case QAccessible::Dialog:
+ handleDialogUpdate(event);
+ break;
+ case QAccessible::MenuItem:
+ case QAccessible::MenuBar:
+ case QAccessible::PopupMenu:
+ handleMenuUpdate(event);
+ break;
+ case QAccessible::ToolBar:
+ case QAccessible::ButtonMenu:
+ handleToolUpdate(event);
+ case QAccessible::RadioButton:
+ handleRadioButtonUpdate(event);
+ break;
+ case QAccessible::SpinBox:
+ handleSpinBoxUpdate(event);
+ break;
+ case QAccessible::Slider:
+ handleSliderUpdate(event);
+ break;
+ case QAccessible::PageTab:
+ handlePageTabUpdate(event);
+ break;
+ case QAccessible::PageTabList:
+ handlePageTabListUpdate(event);
+ break;
+ case QAccessible::ScrollBar:
+ handleScrollBarUpdate(event);
+ break;
+ default:
+ qCDebug(lcQpaAccessibility) << "TODO: implement notifyAccessibilityUpdate for role" << iface->role();
+ };
+}
+
+void QWasmAccessibility::setRootObject(QObject *root)
+{
+ m_rootObject = root;
+}
+
+void QWasmAccessibility::initialize()
+{
+
+}
+
+void QWasmAccessibility::cleanup()
+{
+
+}
+
+void QWasmAccessibility::onHtmlEventReceived(emscripten::val event)
+{
+ static_cast<QWasmAccessibility *>(QWasmIntegration::get()->accessibility())->handleEventFromHtmlElement(event);
+}
+
+EMSCRIPTEN_BINDINGS(qtButtonEvent) {
+ function("qtEventReceived", &QWasmAccessibility::onHtmlEventReceived);
+}
+
+#endif // QT_CONFIG(accessibility)
diff --git a/src/plugins/platforms/wasm/qwasmaccessibility.h b/src/plugins/platforms/wasm/qwasmaccessibility.h
new file mode 100644
index 0000000000..c4be7f0d72
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmaccessibility.h
@@ -0,0 +1,92 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef QWASMACCESIBILITY_H
+#define QWASMACCESIBILITY_H
+
+#include <QtCore/qtconfigmacros.h>
+#include <QtGui/qtguiglobal.h>
+
+#if QT_CONFIG(accessibility)
+
+#include <QtCore/qhash.h>
+#include <private/qstdweb_p.h>
+#include <qpa/qplatformaccessibility.h>
+
+#include <emscripten/val.h>
+#include <QLoggingCategory>
+
+#include <map>
+#include <emscripten/bind.h>
+
+Q_DECLARE_LOGGING_CATEGORY(lcQpaAccessibility)
+
+class QWasmAccessibility : public QPlatformAccessibility
+{
+public:
+ QWasmAccessibility();
+ ~QWasmAccessibility();
+
+ static QWasmAccessibility* get();
+
+ static void addAccessibilityEnableButton(QWindow *window);
+ static void removeAccessibilityEnableButton(QWindow *window);
+
+private:
+ void addAccessibilityEnableButtonImpl(QWindow *window);
+ void removeAccessibilityEnableButtonImpl(QWindow *window);
+ void enableAccessibility();
+
+ static emscripten::val getContainer(QWindow *window);
+ static emscripten::val getContainer(QAccessibleInterface *iface);
+ static emscripten::val getDocument(const emscripten::val &container);
+ static emscripten::val getDocument(QAccessibleInterface *iface);
+ static QWindow *getWindow(QAccessibleInterface *iface);
+
+ emscripten::val createHtmlElement(QAccessibleInterface *iface);
+ void destroyHtmlElement(QAccessibleInterface *iface);
+ emscripten::val ensureHtmlElement(QAccessibleInterface *iface);
+ void setHtmlElementVisibility(QAccessibleInterface *iface, bool visible);
+ void setHtmlElementGeometry(QAccessibleInterface *iface);
+ void setHtmlElementGeometry(emscripten::val element, QRect geometry);
+ void setHtmlElementTextName(QAccessibleInterface *iface);
+ void setHtmlElementTextNameLE(QAccessibleInterface *iface);
+ void setHtmlElementDescription(QAccessibleInterface *iface);
+
+ void handleStaticTextUpdate(QAccessibleEvent *event);
+ void handleButtonUpdate(QAccessibleEvent *event);
+ void handleCheckBoxUpdate(QAccessibleEvent *event);
+ void handleDialogUpdate(QAccessibleEvent *event);
+ void handleMenuUpdate(QAccessibleEvent *event);
+ void handleToolUpdate(QAccessibleEvent *event);
+ void handleLineEditUpdate(QAccessibleEvent *event);
+ void handleRadioButtonUpdate(QAccessibleEvent *event);
+ void handleSpinBoxUpdate(QAccessibleEvent *event);
+ void handlePageTabUpdate(QAccessibleEvent *event);
+ void handleSliderUpdate(QAccessibleEvent *event);
+ void handleScrollBarUpdate(QAccessibleEvent *event);
+ void handlePageTabListUpdate(QAccessibleEvent *event);
+
+ void handleEventFromHtmlElement(const emscripten::val event);
+
+ void populateAccessibilityTree(QAccessibleInterface *iface);
+ void notifyAccessibilityUpdate(QAccessibleEvent *event) override;
+ void setRootObject(QObject *o) override;
+ void initialize() override;
+ void cleanup() override;
+
+public: // public for EMSCRIPTEN_BINDINGS
+ static void onHtmlEventReceived(emscripten::val event);
+
+private:
+ static QWasmAccessibility *s_instance;
+ QObject *m_rootObject = nullptr;
+ bool m_accessibilityEnabled = false;
+ std::map<QWindow *, std::tuple<emscripten::val, std::shared_ptr<qstdweb::EventCallback>>> m_enableButtons;
+ QHash<QAccessibleInterface *, emscripten::val> m_elements;
+
+};
+
+#endif // QT_CONFIG(accessibility)
+
+#endif
diff --git a/src/plugins/platforms/wasm/qwasmbackingstore.cpp b/src/plugins/platforms/wasm/qwasmbackingstore.cpp
index a7423e9c47..a3c1ae8a50 100644
--- a/src/plugins/platforms/wasm/qwasmbackingstore.cpp
+++ b/src/plugins/platforms/wasm/qwasmbackingstore.cpp
@@ -1,50 +1,21 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the plugins of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL$
-** 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 General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 or (at your option) 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.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-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include "qwasmbackingstore.h"
#include "qwasmwindow.h"
#include "qwasmcompositor.h"
+#include "qwasmdom.h"
-#include <QtOpenGL/qopengltexture.h>
-#include <QtGui/qmatrix4x4.h>
#include <QtGui/qpainter.h>
-#include <private/qguiapplication_p.h>
-#include <qpa/qplatformscreen.h>
-
#include <QtGui/qbackingstore.h>
+#include <emscripten.h>
+#include <emscripten/wire.h>
+
QT_BEGIN_NAMESPACE
QWasmBackingStore::QWasmBackingStore(QWasmCompositor *compositor, QWindow *window)
- : QPlatformBackingStore(window)
- , m_compositor(compositor)
- , m_texture(new QOpenGLTexture(QOpenGLTexture::Target2D))
+ : QPlatformBackingStore(window), m_compositor(compositor)
{
QWasmWindow *wasmWindow = static_cast<QWasmWindow *>(window->handle());
if (wasmWindow)
@@ -53,12 +24,11 @@ QWasmBackingStore::QWasmBackingStore(QWasmCompositor *compositor, QWindow *windo
QWasmBackingStore::~QWasmBackingStore()
{
-}
-
-void QWasmBackingStore::destroy()
-{
- if (m_texture->isCreated())
- m_texture->destroy();
+ auto window = this->window();
+ QWasmIntegration::get()->removeBackingStore(window);
+ QWasmWindow *wasmWindow = static_cast<QWasmWindow *>(window->handle());
+ if (wasmWindow)
+ wasmWindow->setBackingStore(nullptr);
}
QPaintDevice *QWasmBackingStore::paintDevice()
@@ -73,33 +43,24 @@ void QWasmBackingStore::flush(QWindow *window, const QRegion &region, const QPoi
Q_UNUSED(offset);
m_dirty |= region;
- m_compositor->requestRedraw();
+ m_compositor->handleBackingStoreFlush(window);
}
-void QWasmBackingStore::updateTexture()
+void QWasmBackingStore::updateTexture(QWasmWindow *window)
{
if (m_dirty.isNull())
return;
- if (m_recreateTexture && m_texture->isCreated()) {
- m_recreateTexture = false;
- m_texture->destroy();
+ if (m_webImageDataArray.isUndefined()) {
+ m_webImageDataArray = window->context2d().call<emscripten::val>(
+ "createImageData", emscripten::val(m_image.width()),
+ emscripten::val(m_image.height()));
}
- if (!m_texture->isCreated()) {
- m_texture->setMinificationFilter(QOpenGLTexture::Nearest);
- m_texture->setMagnificationFilter(QOpenGLTexture::Nearest);
- m_texture->setWrapMode(QOpenGLTexture::ClampToEdge);
- m_texture->setData(m_image, QOpenGLTexture::DontGenerateMipMaps);
- m_texture->create();
- }
- m_texture->bind();
-
- QRegion fixed;
+ QRegion clippedDpiScaledRegion;
QRect imageRect = m_image.rect();
for (const QRect &rect : m_dirty) {
-
// Convert device-independent dirty region to device region
qreal dpr = m_image.devicePixelRatio();
QRect deviceRect = QRect(rect.topLeft() * dpr, rect.size() * dpr);
@@ -112,21 +73,11 @@ void QWasmBackingStore::updateTexture()
r.setWidth(imageRect.width());
}
- fixed |= r;
+ clippedDpiScaledRegion |= r;
}
- for (const QRect &rect : fixed) {
- // if the sub-rect is full-width we can pass the image data directly to
- // OpenGL instead of copying, since there is no gap between scanlines
- if (rect.width() == imageRect.width()) {
- glTexSubImage2D(GL_TEXTURE_2D, 0, 0, rect.y(), rect.width(), rect.height(), GL_RGBA, GL_UNSIGNED_BYTE,
- m_image.constScanLine(rect.y()));
- } else {
- glTexSubImage2D(GL_TEXTURE_2D, 0, rect.x(), rect.y(), rect.width(), rect.height(), GL_RGBA, GL_UNSIGNED_BYTE,
- m_image.copy(rect).constBits());
- }
- }
- /* End of code taken from QEGLPlatformBackingStore */
+ for (const QRect &dirtyRect : clippedDpiScaledRegion)
+ dom::drawImageToWebImageDataArray(m_image, m_webImageDataArray, dirtyRect);
m_dirty = QRegion();
}
@@ -135,28 +86,33 @@ void QWasmBackingStore::beginPaint(const QRegion &region)
{
m_dirty |= region;
// Keep backing store device pixel ratio in sync with window
- if (m_image.devicePixelRatio() != window()->devicePixelRatio())
+ if (m_image.devicePixelRatio() != window()->handle()->devicePixelRatio())
resize(backingStore()->size(), backingStore()->staticContents());
QPainter painter(&m_image);
- painter.setCompositionMode(QPainter::CompositionMode_Source);
- const QColor blank = Qt::transparent;
- for (const QRect &rect : region)
- painter.fillRect(rect, blank);
+
+ if (m_image.hasAlphaChannel()) {
+ painter.setCompositionMode(QPainter::CompositionMode_Source);
+ const QColor blank = Qt::transparent;
+ for (const QRect &rect : region)
+ painter.fillRect(rect, blank);
+ }
}
void QWasmBackingStore::resize(const QSize &size, const QRegion &staticContents)
{
- Q_UNUSED(staticContents)
+ Q_UNUSED(staticContents);
- m_image = QImage(size * window()->devicePixelRatio(), QImage::Format_RGB32);
- m_image.setDevicePixelRatio(window()->devicePixelRatio());
- m_recreateTexture = true;
+ QImage::Format format = QImage::Format_RGBA8888;
+ const auto platformScreenDPR = window()->handle()->devicePixelRatio();
+ m_image = QImage(size * platformScreenDPR, format);
+ m_image.setDevicePixelRatio(platformScreenDPR);
+ m_webImageDataArray = emscripten::val::undefined();
}
QImage QWasmBackingStore::toImage() const
{
- // used by QPlatformBackingStore::composeAndFlush
+ // used by QPlatformBackingStore::rhiFlush
return m_image;
}
@@ -165,10 +121,10 @@ const QImage &QWasmBackingStore::getImageRef() const
return m_image;
}
-const QOpenGLTexture *QWasmBackingStore::getUpdatedTexture()
+emscripten::val QWasmBackingStore::getUpdatedWebImage(QWasmWindow *window)
{
- updateTexture();
- return m_texture.data();
+ updateTexture(window);
+ return m_webImageDataArray;
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/wasm/qwasmbackingstore.h b/src/plugins/platforms/wasm/qwasmbackingstore.h
index b93c96b483..54e9fe4cb3 100644
--- a/src/plugins/platforms/wasm/qwasmbackingstore.h
+++ b/src/plugins/platforms/wasm/qwasmbackingstore.h
@@ -1,31 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the plugins of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL$
-** 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 General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 or (at your option) 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.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-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#ifndef QWASMBACKINGSTORE_H
#define QWASMBACKINGSTORE_H
@@ -33,18 +7,20 @@
#include <qpa/qplatformbackingstore.h>
#include <QtGui/qimage.h>
+#include <emscripten/val.h>
+
QT_BEGIN_NAMESPACE
class QOpenGLTexture;
class QRegion;
class QWasmCompositor;
+class QWasmWindow;
class QWasmBackingStore : public QPlatformBackingStore
{
public:
QWasmBackingStore(QWasmCompositor *compositor, QWindow *window);
~QWasmBackingStore();
- void destroy();
QPaintDevice *paintDevice() override;
@@ -54,17 +30,16 @@ public:
QImage toImage() const override;
const QImage &getImageRef() const;
- const QOpenGLTexture *getUpdatedTexture();
+ emscripten::val getUpdatedWebImage(QWasmWindow *window);
protected:
- void updateTexture();
+ void updateTexture(QWasmWindow *window);
private:
QWasmCompositor *m_compositor;
QImage m_image;
- QScopedPointer<QOpenGLTexture> m_texture;
QRegion m_dirty;
- bool m_recreateTexture = false;
+ emscripten::val m_webImageDataArray = emscripten::val::undefined();
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/wasm/qwasmbase64iconstore.cpp b/src/plugins/platforms/wasm/qwasmbase64iconstore.cpp
new file mode 100644
index 0000000000..8f05f082ea
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmbase64iconstore.cpp
@@ -0,0 +1,40 @@
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "qwasmbase64iconstore.h"
+
+#include <QtCore/qfile.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_GLOBAL_STATIC(Base64IconStore, globalWasmWindowIconStore);
+
+Base64IconStore::Base64IconStore()
+{
+ QString iconSources[static_cast<size_t>(IconType::Size)] = {
+ QStringLiteral(":/wasm-window/maximize.svg"), QStringLiteral(":/wasm-window/qtlogo.svg"),
+ QStringLiteral(":/wasm-window/restore.svg"), QStringLiteral(":/wasm-window/x.svg")
+ };
+
+ for (size_t iconType = static_cast<size_t>(IconType::First);
+ iconType < static_cast<size_t>(IconType::Size); ++iconType) {
+ QFile svgFile(iconSources[static_cast<size_t>(iconType)]);
+ if (!svgFile.open(QIODevice::ReadOnly))
+ Q_ASSERT(false); // A resource should always be opened.
+ m_storage[static_cast<size_t>(iconType)] = svgFile.readAll().toBase64();
+ }
+}
+
+Base64IconStore::~Base64IconStore() = default;
+
+Base64IconStore *Base64IconStore::get()
+{
+ return globalWasmWindowIconStore();
+}
+
+std::string_view Base64IconStore::getIcon(IconType type) const
+{
+ return m_storage[static_cast<size_t>(type)];
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/wasm/qwasmbase64iconstore.h b/src/plugins/platforms/wasm/qwasmbase64iconstore.h
new file mode 100644
index 0000000000..89704f2d2c
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmbase64iconstore.h
@@ -0,0 +1,37 @@
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef QWASMBASE64IMAGESTORE_H
+#define QWASMBASE64IMAGESTORE_H
+
+#include <string>
+#include <string_view>
+
+#include <QtCore/qtconfigmacros.h>
+
+QT_BEGIN_NAMESPACE
+class Base64IconStore
+{
+public:
+ enum class IconType {
+ Maximize,
+ First = Maximize,
+ QtLogo,
+ Restore,
+ X,
+ Size,
+ };
+
+ Base64IconStore();
+ ~Base64IconStore();
+
+ static Base64IconStore *get();
+
+ std::string_view getIcon(IconType type) const;
+
+private:
+ std::string m_storage[static_cast<size_t>(IconType::Size)];
+};
+
+QT_END_NAMESPACE
+#endif // QWASMBASE64IMAGESTORE_H
diff --git a/src/plugins/platforms/wasm/qwasmclipboard.cpp b/src/plugins/platforms/wasm/qwasmclipboard.cpp
index 890b01fa3c..1aa3ffa5b3 100644
--- a/src/plugins/platforms/wasm/qwasmclipboard.cpp
+++ b/src/plugins/platforms/wasm/qwasmclipboard.cpp
@@ -1,123 +1,79 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the plugins of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL$
-** 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 General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 or (at your option) 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.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-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include "qwasmclipboard.h"
+#include "qwasmdom.h"
+#include "qwasmevent.h"
#include "qwasmwindow.h"
-#include "qwasmstring.h"
-#include <emscripten.h>
-#include <emscripten/html5.h>
-#include <emscripten/bind.h>
+#include <private/qstdweb_p.h>
#include <QCoreApplication>
#include <qpa/qwindowsysteminterface.h>
+#include <QBuffer>
+#include <QString>
-using namespace emscripten;
-
-// there has got to be a better way...
-static QString g_clipboardText;
-static QString g_clipboardFormat;
+#include <emscripten/val.h>
-static val getClipboardData()
-{
- return QWasmString::fromQString(g_clipboardText);
-}
+QT_BEGIN_NAMESPACE
+using namespace emscripten;
-static val getClipboardFormat()
+static void commonCopyEvent(val event)
{
- return QWasmString::fromQString(g_clipboardFormat);
-}
+ QMimeData *_mimes = QWasmIntegration::get()->getWasmClipboard()->mimeData(QClipboard::Clipboard);
+ if (!_mimes)
+ return;
+
+ // doing it this way seems to sanitize the text better that calling data() like down below
+ if (_mimes->hasText()) {
+ event["clipboardData"].call<void>("setData", val("text/plain"),
+ _mimes->text().toEcmaString());
+ }
+ if (_mimes->hasHtml()) {
+ event["clipboardData"].call<void>("setData", val("text/html"), _mimes->html().toEcmaString());
+ }
-static void pasteClipboardData(emscripten::val format, emscripten::val dataPtr)
-{
- QString formatString = QWasmString::toQString(format);
- QByteArray dataArray = QByteArray::fromStdString(dataPtr.as<std::string>());
- QMimeData *mMimeData = new QMimeData;
- mMimeData->setData(formatString, dataArray);
- QWasmClipboard::qWasmClipboardPaste(mMimeData);
-}
+ for (auto mimetype : _mimes->formats()) {
+ if (mimetype.contains("text/"))
+ continue;
+ QByteArray ba = _mimes->data(mimetype);
+ if (!ba.isEmpty())
+ event["clipboardData"].call<void>("setData", mimetype.toEcmaString(),
+ val(ba.constData()));
+ }
-static void qClipboardPromiseResolve(emscripten::val something)
-{
- pasteClipboardData(emscripten::val("text/plain"), something);
+ event.call<void>("preventDefault");
}
static void qClipboardCutTo(val event)
{
- if (!QWasmIntegration::get()->getWasmClipboard()->hasClipboardApi) {
+ if (!QWasmIntegration::get()->getWasmClipboard()->hasClipboardApi()) {
// Send synthetic Ctrl+X to make the app cut data to Qt's clipboard
- QWindowSystemInterface::handleKeyEvent<QWindowSystemInterface::SynchronousDelivery>(
- 0, QEvent::KeyPress, Qt::Key_X, Qt::ControlModifier, "X");
- }
+ QWindowSystemInterface::handleKeyEvent(
+ 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.call<void>("preventDefault");
+ commonCopyEvent(event);
}
static void qClipboardCopyTo(val event)
{
- if (!QWasmIntegration::get()->getWasmClipboard()->hasClipboardApi) {
+ if (!QWasmIntegration::get()->getWasmClipboard()->hasClipboardApi()) {
// Send synthetic Ctrl+C to make the app copy data to Qt's clipboard
- QWindowSystemInterface::handleKeyEvent<QWindowSystemInterface::SynchronousDelivery>(
- 0, QEvent::KeyPress, Qt::Key_C, Qt::ControlModifier, "C");
+ QWindowSystemInterface::handleKeyEvent(
+ 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.call<void>("preventDefault");
+ commonCopyEvent(event);
}
static void qClipboardPasteTo(val event)
{
- bool hasClipboardApi = QWasmIntegration::get()->getWasmClipboard()->hasClipboardApi;
- val clipdata = hasClipboardApi ?
- val::global("Module").call<val>("qtGetClipboardData") :
- event["clipboardData"].call<val>("getData", val("text"));
+ event.call<void>("preventDefault"); // prevent browser from handling drop event
- const QString qstr = QWasmString::toQString(clipdata);
- if (qstr.length() > 0) {
- QMimeData *mMimeData = new QMimeData;
- mMimeData->setText(qstr);
- QWasmClipboard::qWasmClipboardPaste(mMimeData);
- }
+ QWasmIntegration::get()->getWasmClipboard()->sendClipboardData(event);
}
EMSCRIPTEN_BINDINGS(qtClipboardModule) {
- function("qtGetClipboardData", &getClipboardData);
- function("qtGetClipboardFormat", &getClipboardFormat);
- function("qtPasteClipboardData", &pasteClipboardData);
- function("qtClipboardPromiseResolve", &qClipboardPromiseResolve);
function("qtClipboardCutTo", &qClipboardCutTo);
function("qtClipboardCopyTo", &qClipboardCopyTo);
function("qtClipboardPasteTo", &qClipboardPasteTo);
@@ -126,18 +82,19 @@ EMSCRIPTEN_BINDINGS(qtClipboardModule) {
QWasmClipboard::QWasmClipboard()
{
val clipboard = val::global("navigator")["clipboard"];
- hasClipboardApi = (!clipboard.isUndefined() && !clipboard["readText"].isUndefined());
- initClipboardEvents();
+ const bool hasPermissionsApi = !val::global("navigator")["permissions"].isUndefined();
+ m_hasClipboardApi = !clipboard.isUndefined() && !clipboard["readText"].isUndefined();
+
+ if (m_hasClipboardApi && hasPermissionsApi)
+ initClipboardPermissions();
}
QWasmClipboard::~QWasmClipboard()
{
- g_clipboardText.clear();
- g_clipboardFormat.clear();
}
-QMimeData* QWasmClipboard::mimeData(QClipboard::Mode mode)
+QMimeData *QWasmClipboard::mimeData(QClipboard::Mode mode)
{
if (mode != QClipboard::Clipboard)
return nullptr;
@@ -145,17 +102,29 @@ QMimeData* QWasmClipboard::mimeData(QClipboard::Mode mode)
return QPlatformClipboard::mimeData(mode);
}
-void QWasmClipboard::setMimeData(QMimeData* mimeData, QClipboard::Mode mode)
+void QWasmClipboard::setMimeData(QMimeData *mimeData, QClipboard::Mode mode)
{
- if (mimeData->hasText()) {
- g_clipboardFormat = mimeData->formats().at(0);
- g_clipboardText = mimeData->text();
- } else if (mimeData->hasHtml()) {
- g_clipboardFormat = mimeData->formats().at(0);
- g_clipboardText = mimeData->html();
- }
-
+ // handle setText/ setData programmatically
QPlatformClipboard::setMimeData(mimeData, mode);
+ if (m_hasClipboardApi)
+ writeToClipboardApi();
+ else
+ writeToClipboard();
+}
+
+QWasmClipboard::ProcessKeyboardResult QWasmClipboard::processKeyboard(const KeyEvent &event)
+{
+ if (event.type != EventType::KeyDown || !event.modifiers.testFlag(Qt::ControlModifier))
+ return ProcessKeyboardResult::Ignored;
+
+ if (event.key != Qt::Key_C && event.key != Qt::Key_V && event.key != Qt::Key_X)
+ return ProcessKeyboardResult::Ignored;
+
+ const bool isPaste = event.key == Qt::Key_V;
+
+ return m_hasClipboardApi && !isPaste
+ ? ProcessKeyboardResult::NativeClipboardEventAndCopiedDataNeeded
+ : ProcessKeyboardResult::NativeClipboardEventNeeded;
}
bool QWasmClipboard::supportsMode(QClipboard::Mode mode) const
@@ -169,60 +138,167 @@ bool QWasmClipboard::ownsMode(QClipboard::Mode mode) const
return false;
}
-void QWasmClipboard::qWasmClipboardPaste(QMimeData *mData)
+void QWasmClipboard::initClipboardPermissions()
{
- QWasmIntegration::get()->clipboard()->setMimeData(mData, QClipboard::Clipboard);
+ val permissions = val::global("navigator")["permissions"];
- QWindowSystemInterface::handleKeyEvent<QWindowSystemInterface::SynchronousDelivery>(
- 0, QEvent::KeyPress, Qt::Key_V, Qt::ControlModifier, "V");
+ qstdweb::Promise::make(permissions, "query", { .catchFunc = [](emscripten::val) {} }, ([]() {
+ val readPermissionsMap = val::object();
+ readPermissionsMap.set("name", val("clipboard-read"));
+ return readPermissionsMap;
+ })());
+ qstdweb::Promise::make(permissions, "query", { .catchFunc = [](emscripten::val) {} }, ([]() {
+ val readPermissionsMap = val::object();
+ readPermissionsMap.set("name", val("clipboard-write"));
+ return readPermissionsMap;
+ })());
}
-void QWasmClipboard::initClipboardEvents()
+void QWasmClipboard::installEventHandlers(const emscripten::val &target)
{
- if (!hasClipboardApi)
- return;
-
- val permissions = val::global("navigator")["permissions"];
- val readPermissionsMap = val::object();
- readPermissionsMap.set("name", val("clipboard-read"));
- permissions.call<val>("query", readPermissionsMap);
+ emscripten::val cContext = val::undefined();
+ emscripten::val isChromium = val::global("window")["chrome"];
+ if (!isChromium.isUndefined()) {
+ cContext = val::global("document");
+ } else {
+ cContext = target;
+ }
+ // Fallback path for browsers which do not support direct clipboard access
+ cContext.call<void>("addEventListener", val("cut"),
+ val::module_property("qtClipboardCutTo"), true);
+ cContext.call<void>("addEventListener", val("copy"),
+ val::module_property("qtClipboardCopyTo"), true);
+ cContext.call<void>("addEventListener", val("paste"),
+ val::module_property("qtClipboardPasteTo"), true);
+}
- val writePermissionsMap = val::object();
- writePermissionsMap.set("name", val("clipboard-write"));
- permissions.call<val>("query", writePermissionsMap);
+bool QWasmClipboard::hasClipboardApi()
+{
+ return m_hasClipboardApi;
}
-void QWasmClipboard::installEventHandlers(const emscripten::val &canvas)
+void QWasmClipboard::writeToClipboardApi()
{
- if (hasClipboardApi)
+ Q_ASSERT(m_hasClipboardApi);
+
+ // copy event
+ // browser event handler detected ctrl c if clipboard API
+ // or Qt call from keyboard event handler
+
+ QMimeData *_mimes = mimeData(QClipboard::Clipboard);
+ if (!_mimes)
return;
- // Fallback path for browsers which do not support direct clipboard access
- canvas.call<void>("addEventListener", val("cut"),
- val::module_property("qtClipboardCutTo"));
- canvas.call<void>("addEventListener", val("copy"),
- val::module_property("qtClipboardCopyTo"));
- canvas.call<void>("addEventListener", val("paste"),
- val::module_property("qtClipboardPasteTo"));
+ emscripten::val clipboardWriteArray = emscripten::val::array();
+ QByteArray ba;
+
+ for (auto mimetype : _mimes->formats()) {
+ // we need to treat binary and text differently, as the blob method below
+ // fails for text mimetypes
+ // ignore text types
+
+ if (mimetype.contains("STRING", Qt::CaseSensitive) || mimetype.contains("TEXT", Qt::CaseSensitive))
+ continue;
+
+ if (_mimes->hasHtml()) { // prefer html over text
+ ba = _mimes->html().toLocal8Bit();
+ // force this mime
+ mimetype = "text/html";
+ } else if (mimetype.contains("text/plain")) {
+ ba = _mimes->text().toLocal8Bit();
+ } else if (mimetype.contains("image")) {
+ QImage img = qvariant_cast<QImage>( _mimes->imageData());
+ QBuffer buffer(&ba);
+ buffer.open(QIODevice::WriteOnly);
+ img.save(&buffer, "PNG");
+ mimetype = "image/png"; // chrome only allows png
+ // clipboard error "NotAllowedError" "Type application/x-qt-image not supported on write."
+ // safari silently fails
+ // so we use png internally for now
+ } else {
+ // DATA
+ ba = _mimes->data(mimetype);
+ }
+ // Create file data Blob
+
+ const char *content = ba.data();
+ int dataLength = ba.length();
+ if (dataLength < 1) {
+ qDebug() << "no content found";
+ return;
+ }
+
+ emscripten::val document = emscripten::val::global("document");
+ emscripten::val window = emscripten::val::global("window");
+
+ emscripten::val fileContentView =
+ emscripten::val(emscripten::typed_memory_view(dataLength, content));
+ emscripten::val fileContentCopy = emscripten::val::global("ArrayBuffer").new_(dataLength);
+ emscripten::val fileContentCopyView =
+ emscripten::val::global("Uint8Array").new_(fileContentCopy);
+ fileContentCopyView.call<void>("set", fileContentView);
+
+ emscripten::val contentArray = emscripten::val::array();
+ contentArray.call<void>("push", fileContentCopyView);
+
+ // we have a blob, now create a ClipboardItem
+ emscripten::val type = emscripten::val::array();
+ type.set("type", mimetype.toEcmaString());
+
+ emscripten::val contentBlob = emscripten::val::global("Blob").new_(contentArray, type);
+
+ emscripten::val clipboardItemObject = emscripten::val::object();
+ clipboardItemObject.set(mimetype.toEcmaString(), contentBlob);
+
+ val clipboardItemData = val::global("ClipboardItem").new_(clipboardItemObject);
+
+ clipboardWriteArray.call<void>("push", clipboardItemData);
+
+ // Clipboard write is only supported with one ClipboardItem at the moment
+ // but somehow this still works?
+ // break;
+ }
+
+ val navigator = val::global("navigator");
+
+ qstdweb::Promise::make(
+ navigator["clipboard"], "write",
+ {
+ .catchFunc = [](emscripten::val error) {
+ qWarning() << "clipboard error"
+ << QString::fromStdString(error["name"].as<std::string>())
+ << QString::fromStdString(error["message"].as<std::string>());
+ }
+ },
+ clipboardWriteArray);
}
-void QWasmClipboard::readTextFromClipboard()
+void QWasmClipboard::writeToClipboard()
{
- if (QWasmIntegration::get()->getWasmClipboard()->hasClipboardApi) {
- val navigator = val::global("navigator");
- val textPromise = navigator["clipboard"].call<val>("readText");
- val readTextResolve = val::global("Module")["qtClipboardPromiseResolve"];
- textPromise.call<val>("then", readTextResolve);
- }
+ // this works for firefox, chrome by generating
+ // copy event, but not safari
+ // execCommand has been deemed deprecated in the docs, but browsers do not seem
+ // interested in removing it. There is no replacement, so we use it here.
+ val document = val::global("document");
+ document.call<val>("execCommand", val("copy"));
}
-void QWasmClipboard::writeTextToClipboard()
+void QWasmClipboard::sendClipboardData(emscripten::val event)
{
- 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);
- }
+ qDebug() << "sendClipboardData";
+
+ dom::DataTransfer *transfer = new dom::DataTransfer(event["clipboardData"]);
+ const auto mimeCallback = std::function([transfer](QMimeData *data) {
+
+ // Persist clipboard data so that the app can read it when handling the CTRL+V
+ QWasmIntegration::get()->clipboard()->QPlatformClipboard::setMimeData(data, QClipboard::Clipboard);
+ QWindowSystemInterface::handleKeyEvent(0, QEvent::KeyPress, Qt::Key_V,
+ Qt::ControlModifier, "V");
+ QWindowSystemInterface::handleKeyEvent(0, QEvent::KeyRelease, Qt::Key_V,
+ Qt::ControlModifier, "V");
+ delete transfer;
+ });
+
+ transfer->toMimeDataWithFile(mimeCallback);
}
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/wasm/qwasmclipboard.h b/src/plugins/platforms/wasm/qwasmclipboard.h
index 3b28e2c381..86618dd560 100644
--- a/src/plugins/platforms/wasm/qwasmclipboard.h
+++ b/src/plugins/platforms/wasm/qwasmclipboard.h
@@ -1,31 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the plugins of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL$
-** 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 General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 or (at your option) 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.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-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#ifndef QWasmClipboard_H
#define QWasmClipboard_H
@@ -33,14 +7,25 @@
#include <QObject>
#include <qpa/qplatformclipboard.h>
+#include <private/qstdweb_p.h>
#include <QMimeData>
#include <emscripten/bind.h>
#include <emscripten/val.h>
+QT_BEGIN_NAMESPACE
+
+struct KeyEvent;
+
class QWasmClipboard : public QObject, public QPlatformClipboard
{
public:
+ enum class ProcessKeyboardResult {
+ Ignored,
+ NativeClipboardEventNeeded,
+ NativeClipboardEventAndCopiedDataNeeded,
+ };
+
QWasmClipboard();
virtual ~QWasmClipboard();
@@ -50,12 +35,19 @@ public:
bool supportsMode(QClipboard::Mode mode) const override;
bool ownsMode(QClipboard::Mode mode) const override;
- static void qWasmClipboardPaste(QMimeData *mData);
- void initClipboardEvents();
- void installEventHandlers(const emscripten::val &canvas);
- bool hasClipboardApi;
- void readTextFromClipboard();
- void writeTextToClipboard();
+ ProcessKeyboardResult processKeyboard(const KeyEvent &event);
+ static void installEventHandlers(const emscripten::val &target);
+ bool hasClipboardApi();
+ void sendClipboardData(emscripten::val event);
+
+private:
+ void initClipboardPermissions();
+ void writeToClipboardApi();
+ void writeToClipboard();
+
+ bool m_hasClipboardApi = false;
};
+QT_END_NAMESPACE
+
#endif // QWASMCLIPBOARD_H
diff --git a/src/plugins/platforms/wasm/qwasmcompositor.cpp b/src/plugins/platforms/wasm/qwasmcompositor.cpp
index 74890ead82..ef460f666f 100644
--- a/src/plugins/platforms/wasm/qwasmcompositor.cpp
+++ b/src/plugins/platforms/wasm/qwasmcompositor.cpp
@@ -1,98 +1,43 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the plugins of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL$
-** 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 General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 or (at your option) 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.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-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include "qwasmcompositor.h"
#include "qwasmwindow.h"
-#include "qwasmstylepixmaps_p.h"
-#include <QtOpenGL/qopengltexture.h>
-
-#include <QtGui/private/qwindow_p.h>
-#include <QtGui/qopenglcontext.h>
-#include <QtGui/qopenglfunctions.h>
-#include <QtGui/qoffscreensurface.h>
-#include <QtGui/qpainter.h>
-#include <private/qpixmapcache_p.h>
-
-#include <private/qguiapplication_p.h>
+#include <private/qeventdispatcher_wasm_p.h>
#include <qpa/qwindowsysteminterface.h>
-#include <QtCore/qcoreapplication.h>
-#include <QtGui/qguiapplication.h>
-Q_GUI_EXPORT int qt_defaultDpiX();
+#include <emscripten/html5.h>
-QWasmCompositedWindow::QWasmCompositedWindow()
- : window(nullptr)
- , parentWindow(nullptr)
- , flushPending(false)
- , visible(false)
-{
-}
+using namespace emscripten;
+
+bool QWasmCompositor::m_requestUpdateHoldEnabled = true;
-QWasmCompositor::QWasmCompositor(QWasmScreen *screen)
- :QObject(screen)
- , m_frameBuffer(nullptr)
- , m_blitter(new QOpenGLTextureBlitter)
- , m_needComposit(false)
- , m_inFlush(false)
- , m_inResize(false)
- , m_isEnabled(true)
- , m_targetDevicePixelRatio(1)
+QWasmCompositor::QWasmCompositor(QWasmScreen *screen) : QObject(screen)
{
+ QWindowSystemInterface::setSynchronousWindowSystemEvents(true);
}
QWasmCompositor::~QWasmCompositor()
{
- delete m_frameBuffer;
- destroy();
+ if (m_requestAnimationFrameId != -1)
+ emscripten_cancel_animation_frame(m_requestAnimationFrameId);
+
+ // TODO(mikolaj.boc): Investigate if m_isEnabled is needed at all. It seems like a frame should
+ // not be generated after this instead.
+ m_isEnabled = false; // prevent frame() from creating a new m_context
}
-void QWasmCompositor::destroy()
+void QWasmCompositor::onWindowTreeChanged(QWasmWindowTreeNodeChangeType changeType,
+ QWasmWindow *window)
{
- // Destroy OpenGL resources. This is done here in a separate function
- // which can be called while screen() still returns a valid screen
- // (which it might not, during destruction). A valid QScreen is
- // a requirement for QOffscreenSurface on Wasm since the native
- // context is tied to a single canvas.
- if (m_context) {
- QOffscreenSurface offScreenSurface(screen()->screen());
- offScreenSurface.setFormat(m_context->format());
- offScreenSurface.create();
- m_context->makeCurrent(&offScreenSurface);
- for (QWasmWindow *window : m_windowStack)
- window->destroy();
- m_blitter.reset(nullptr);
- m_context.reset(nullptr);
- }
-
- m_isEnabled = false; // prevent frame() from creating a new m_context
+ auto allWindows = screen()->allWindows();
+ setEnabled(std::any_of(allWindows.begin(), allWindows.end(), [](QWasmWindow *element) {
+ return !element->context2d().isUndefined();
+ }));
+ if (changeType == QWasmWindowTreeNodeChangeType::NodeRemoval)
+ m_requestUpdateWindows.remove(window);
}
void QWasmCompositor::setEnabled(bool enabled)
@@ -100,647 +45,112 @@ void QWasmCompositor::setEnabled(bool enabled)
m_isEnabled = enabled;
}
-void QWasmCompositor::addWindow(QWasmWindow *window, QWasmWindow *parentWindow)
+// requestUpdate delivery is initially disabled at startup, while Qt completes
+// startup tasks such as font loading. This function enables requestUpdate delivery
+// again.
+bool QWasmCompositor::releaseRequestUpdateHold()
{
- QWasmCompositedWindow compositedWindow;
- compositedWindow.window = window;
- compositedWindow.parentWindow = parentWindow;
- m_compositedWindows.insert(window, compositedWindow);
-
- if (parentWindow == 0)
- m_windowStack.append(window);
- else
- m_compositedWindows[parentWindow].childWindows.append(window);
-
- notifyTopWindowChanged(window);
+ const bool wasEnabled = m_requestUpdateHoldEnabled;
+ m_requestUpdateHoldEnabled = false;
+ return wasEnabled;
}
-void QWasmCompositor::removeWindow(QWasmWindow *window)
+void QWasmCompositor::requestUpdateWindow(QWasmWindow *window, UpdateRequestDeliveryType updateType)
{
- QWasmWindow *platformWindow = m_compositedWindows[window].parentWindow;
-
- if (platformWindow) {
- QWasmWindow *parentWindow = window;
- m_compositedWindows[parentWindow].childWindows.removeAll(window);
+ auto it = m_requestUpdateWindows.find(window);
+ if (it == m_requestUpdateWindows.end()) {
+ m_requestUpdateWindows.insert(window, updateType);
+ } else {
+ // Already registered, but upgrade ExposeEventDeliveryType to UpdateRequestDeliveryType.
+ // if needed, to make sure QWindow::updateRequest's are matched.
+ if (it.value() == ExposeEventDelivery && updateType == UpdateRequestDelivery)
+ it.value() = UpdateRequestDelivery;
}
- m_windowStack.removeAll(window);
- m_compositedWindows.remove(window);
-
- notifyTopWindowChanged(window);
+ requestUpdate();
}
-void QWasmCompositor::setVisible(QWasmWindow *window, bool visible)
+// Requests an update/new frame using RequestAnimationFrame
+void QWasmCompositor::requestUpdate()
{
- QWasmCompositedWindow &compositedWindow = m_compositedWindows[window];
- if (compositedWindow.visible == visible)
+ if (m_requestAnimationFrameId != -1)
return;
- compositedWindow.visible = visible;
- compositedWindow.flushPending = true;
- if (visible)
- compositedWindow.damage = compositedWindow.window->geometry();
- else
- m_globalDamage = compositedWindow.window->geometry(); // repaint previosly covered area.
-
- requestRedraw();
-}
-
-void QWasmCompositor::raise(QWasmWindow *window)
-{
- if (m_compositedWindows.size() <= 1)
+ if (m_requestUpdateHoldEnabled)
return;
- QWasmCompositedWindow &compositedWindow = m_compositedWindows[window];
- compositedWindow.damage = compositedWindow.window->geometry();
- m_windowStack.removeAll(window);
- m_windowStack.append(window);
-
- notifyTopWindowChanged(window);
-}
-
-void QWasmCompositor::lower(QWasmWindow *window)
-{
- if (m_compositedWindows.size() <= 1)
- return;
+ static auto frame = [](double frameTime, void *context) -> int {
+ Q_UNUSED(frameTime);
- m_windowStack.removeAll(window);
- m_windowStack.prepend(window);
- QWasmCompositedWindow &compositedWindow = m_compositedWindows[window];
- m_globalDamage = compositedWindow.window->geometry(); // repaint previosly covered area.
+ QWasmCompositor *compositor = reinterpret_cast<QWasmCompositor *>(context);
- notifyTopWindowChanged(window);
-}
-
-void QWasmCompositor::setParent(QWasmWindow *window, QWasmWindow *parent)
-{
- m_compositedWindows[window].parentWindow = parent;
-
- requestRedraw();
-}
-
-void QWasmCompositor::flush(QWasmWindow *window, const QRegion &region)
-{
- QWasmCompositedWindow &compositedWindow = m_compositedWindows[window];
- compositedWindow.flushPending = true;
- compositedWindow.damage = region;
-
- requestRedraw();
-}
-
-int QWasmCompositor::windowCount() const
-{
- return m_windowStack.count();
-}
-
-
-void QWasmCompositor::redrawWindowContent()
-{
- // Redraw window content by sending expose events. This redraw
- // will cause a backing store flush, which will call requestRedraw()
- // to composit.
- for (QWasmWindow *platformWindow : m_windowStack) {
- QWindow *window = platformWindow->window();
- QWindowSystemInterface::handleExposeEvent<QWindowSystemInterface::SynchronousDelivery>(
- window, QRect(QPoint(0, 0), window->geometry().size()));
- }
-}
-
-void QWasmCompositor::requestRedraw()
-{
- if (m_needComposit)
- return;
-
- m_needComposit = true;
- QCoreApplication::postEvent(this, new QEvent(QEvent::UpdateRequest));
-}
+ compositor->m_requestAnimationFrameId = -1;
+ compositor->deliverUpdateRequests();
-QWindow *QWasmCompositor::windowAt(QPoint globalPoint, int padding) const
-{
- int index = m_windowStack.count() - 1;
- // qDebug() << "window at" << "point" << p << "window count" << index;
-
- while (index >= 0) {
- const QWasmCompositedWindow &compositedWindow = m_compositedWindows[m_windowStack.at(index)];
- //qDebug() << "windwAt testing" << compositedWindow.window <<
-
- QRect geometry = compositedWindow.window->windowFrameGeometry()
- .adjusted(-padding, -padding, padding, padding);
-
- if (compositedWindow.visible && geometry.contains(globalPoint))
- return m_windowStack.at(index)->window();
- --index;
- }
-
- return 0;
-}
-
-QWindow *QWasmCompositor::keyWindow() const
-{
- return m_windowStack.at(m_windowStack.count() - 1)->window();
-}
-
-bool QWasmCompositor::event(QEvent *ev)
-{
- if (ev->type() == QEvent::UpdateRequest) {
- if (m_isEnabled)
- frame();
- return true;
- }
-
- return QObject::event(ev);
-}
-
-void QWasmCompositor::blit(QOpenGLTextureBlitter *blitter, QWasmScreen *screen, const QOpenGLTexture *texture, QRect targetGeometry)
-{
- QMatrix4x4 m;
- m.translate(-1.0f, -1.0f);
-
- m.scale(2.0f / (float)screen->geometry().width(),
- 2.0f / (float)screen->geometry().height());
-
- m.translate((float)targetGeometry.width() / 2.0f,
- (float)-targetGeometry.height() / 2.0f);
-
- m.translate(targetGeometry.x(), screen->geometry().height() - targetGeometry.y());
-
- m.scale(0.5f * (float)targetGeometry.width(),
- 0.5f * (float)targetGeometry.height());
-
- blitter->blit(texture->textureId(), m, QOpenGLTextureBlitter::OriginTopLeft);
-}
-
-void QWasmCompositor::drawWindowContent(QOpenGLTextureBlitter *blitter, QWasmScreen *screen, QWasmWindow *window)
-{
- QWasmBackingStore *backingStore = window->backingStore();
- if (!backingStore)
- return;
-
- QOpenGLTexture const *texture = backingStore->getUpdatedTexture();
- QPoint windowCanvasPosition = window->geometry().topLeft() - screen->geometry().topLeft();
- QRect windowCanvasGeometry = QRect(windowCanvasPosition, window->geometry().size());
- blit(blitter, screen, texture, windowCanvasGeometry);
-}
-
-QPalette QWasmCompositor::makeWindowPalette()
-{
- QPalette palette;
- palette.setColor(QPalette::Active, QPalette::Highlight,
- palette.color(QPalette::Active, QPalette::Highlight));
- palette.setColor(QPalette::Active, QPalette::Base,
- palette.color(QPalette::Active, QPalette::Highlight));
- palette.setColor(QPalette::Inactive, QPalette::Highlight,
- palette.color(QPalette::Inactive, QPalette::Dark));
- palette.setColor(QPalette::Inactive, QPalette::Base,
- palette.color(QPalette::Inactive, QPalette::Dark));
- palette.setColor(QPalette::Inactive, QPalette::HighlightedText,
- palette.color(QPalette::Inactive, QPalette::Window));
-
- return palette;
-}
-
-QRect QWasmCompositor::titlebarRect(QWasmTitleBarOptions tb, QWasmCompositor::SubControls subcontrol)
-{
- QRect ret;
- const int controlMargin = 2;
- const int controlHeight = tb.rect.height() - controlMargin *2;
- const int delta = controlHeight + controlMargin;
- int offset = 0;
-
- bool isMinimized = tb.state & Qt::WindowMinimized;
- bool isMaximized = tb.state & Qt::WindowMaximized;
-
- ret = tb.rect;
- switch (subcontrol) {
- case SC_TitleBarLabel:
- if (tb.flags & Qt::WindowSystemMenuHint)
- ret.adjust(delta, 0, -delta, 0);
- break;
- case SC_TitleBarCloseButton:
- if (tb.flags & Qt::WindowSystemMenuHint) {
- ret.adjust(0, 0, -delta, 0);
- offset += delta;
- }
- break;
- case SC_TitleBarMaxButton:
- if (!isMaximized && tb.flags & Qt::WindowMaximizeButtonHint) {
- ret.adjust(0, 0, -delta*2, 0);
- offset += (delta +delta);
- }
- break;
- case SC_TitleBarNormalButton:
- if (isMinimized && (tb.flags & Qt::WindowMinimizeButtonHint))
- offset += delta;
- else if (isMaximized && (tb.flags & Qt::WindowMaximizeButtonHint))
- ret.adjust(0, 0, -delta*2, 0);
- offset += (delta +delta);
- break;
- case SC_TitleBarSysMenu:
- if (tb.flags & Qt::WindowSystemMenuHint) {
- ret.setRect(tb.rect.left() + controlMargin, tb.rect.top() + controlMargin,
- controlHeight, controlHeight);
- }
- break;
- default:
- break;
+ return 0;
};
-
- if (subcontrol != SC_TitleBarLabel && subcontrol != SC_TitleBarSysMenu) {
- ret.setRect(tb.rect.right() - offset, tb.rect.top() + controlMargin,
- controlHeight, controlHeight);
- }
-
- if (qApp->layoutDirection() == Qt::LeftToRight)
- return ret;
-
- QRect rect = ret;
- rect.translate(2 * (tb.rect.right() - ret.right()) +
- ret.width() - tb.rect.width(), 0);
-
- return rect;
-}
-
-int dpiScaled(qreal value)
-{
- return value * (qreal(qt_defaultDpiX()) / 96.0);
+ m_requestAnimationFrameId = emscripten_request_animation_frame(frame, this);
}
-QWasmCompositor::QWasmTitleBarOptions QWasmCompositor::makeTitleBarOptions(const QWasmWindow *window)
+void QWasmCompositor::deliverUpdateRequests()
{
- int width = window->windowFrameGeometry().width();
- int border = window->borderWidth();
+ // We may get new update requests during the window content update below:
+ // prepare for recording the new update set by setting aside the current
+ // update set.
+ auto requestUpdateWindows = m_requestUpdateWindows;
+ m_requestUpdateWindows.clear();
- QWasmTitleBarOptions titleBarOptions;
-
- titleBarOptions.rect = QRect(border, border, width - 2 * border, window->titleHeight());
- titleBarOptions.flags = window->window()->flags();
- titleBarOptions.state = window->window()->windowState();
-
- bool isMaximized = titleBarOptions.state & Qt::WindowMaximized; // this gets reset when maximized
-
- if (titleBarOptions.flags & (Qt::WindowTitleHint))
- titleBarOptions.subControls |= SC_TitleBarLabel;
- if (titleBarOptions.flags & Qt::WindowMaximizeButtonHint) {
- if (isMaximized)
- titleBarOptions.subControls |= SC_TitleBarNormalButton;
- else
- titleBarOptions.subControls |= SC_TitleBarMaxButton;
+ // Update window content, either all windows or a spesific set of windows. Use the correct
+ // update type: QWindow subclasses expect that requested and delivered updateRequests matches
+ // exactly.
+ m_inDeliverUpdateRequest = true;
+ for (auto it = requestUpdateWindows.constBegin(); it != requestUpdateWindows.constEnd(); ++it) {
+ auto *window = it.key();
+ UpdateRequestDeliveryType updateType = it.value();
+ deliverUpdateRequest(window, updateType);
}
- if (titleBarOptions.flags & Qt::WindowSystemMenuHint) {
- titleBarOptions.subControls |= SC_TitleBarCloseButton;
- titleBarOptions.subControls |= SC_TitleBarSysMenu;
- }
-
-
- titleBarOptions.palette = QWasmCompositor::makeWindowPalette();
- if (window->window()->isActive())
- titleBarOptions.palette.setCurrentColorGroup(QPalette::Active);
- else
- titleBarOptions.palette.setCurrentColorGroup(QPalette::Inactive);
-
- if (window->activeSubControl() != QWasmCompositor::SC_None)
- titleBarOptions.subControls = window->activeSubControl();
-
- if (!window->window()->title().isEmpty())
- titleBarOptions.titleBarOptionsString = window->window()->title();
-
- return titleBarOptions;
+ m_inDeliverUpdateRequest = false;
+ frame(requestUpdateWindows.keys());
}
-void QWasmCompositor::drawWindowDecorations(QOpenGLTextureBlitter *blitter, QWasmScreen *screen, QWasmWindow *window)
+void QWasmCompositor::deliverUpdateRequest(QWasmWindow *window, UpdateRequestDeliveryType updateType)
{
- int width = window->windowFrameGeometry().width();
- int height = window->windowFrameGeometry().height();
- qreal dpr = window->devicePixelRatio();
-
- QImage image(QSize(width * dpr, height * dpr), QImage::Format_RGB32);
- image.setDevicePixelRatio(dpr);
- QPainter painter(&image);
- painter.fillRect(QRect(0, 0, width, height), painter.background());
-
- QWasmTitleBarOptions titleBarOptions = makeTitleBarOptions(window);
-
- drawTitlebarWindow(titleBarOptions, &painter);
+ QWindow *qwindow = window->window();
- QWasmFrameOptions frameOptions;
- frameOptions.rect = QRect(0, 0, width, height);
- frameOptions.lineWidth = dpiScaled(4.);
+ // Make sure the DPR value for the window is up to date on expose/repaint.
+ // FIXME: listen to native DPR change events instead, if/when available.
+ QWindowSystemInterface::handleWindowDevicePixelRatioChanged(qwindow);
- drawFrameWindow(frameOptions, &painter);
-
- painter.end();
-
- QOpenGLTexture texture(QOpenGLTexture::Target2D);
- texture.setMinificationFilter(QOpenGLTexture::Nearest);
- texture.setMagnificationFilter(QOpenGLTexture::Nearest);
- texture.setWrapMode(QOpenGLTexture::ClampToEdge);
- texture.setData(image, QOpenGLTexture::DontGenerateMipMaps);
- texture.create();
- texture.bind();
-
- glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, image.width(), image.height(), GL_RGBA, GL_UNSIGNED_BYTE,
- image.constScanLine(0));
-
- blit(blitter, screen, &texture, QRect(window->windowFrameGeometry().topLeft(), QSize(width, height)));
-}
-
-void QWasmCompositor::drawFrameWindow(QWasmFrameOptions options, QPainter *painter)
-{
- int x = options.rect.x();
- int y = options.rect.y();
- int w = options.rect.width();
- int h = options.rect.height();
- const QColor &c1 = options.palette.light().color();
- const QColor &c2 = options.palette.shadow().color();
- const QColor &c3 = options.palette.midlight().color();
- const QColor &c4 = options.palette.dark().color();
- const QBrush *fill = 0;
-
- const qreal devicePixelRatio = painter->device()->devicePixelRatioF();
- if (!qFuzzyCompare(devicePixelRatio, qreal(1))) {
- const qreal inverseScale = qreal(1) / devicePixelRatio;
- painter->scale(inverseScale, inverseScale);
- x = qRound(devicePixelRatio * x);
- y = qRound(devicePixelRatio * y);
- w = qRound(devicePixelRatio * w);
- h = qRound(devicePixelRatio * h);
+ // Update by deliverUpdateRequest and expose event according to requested update
+ // type. If the window has not yet been exposed then we must expose it first regardless
+ // of update type. The deliverUpdateRequest must still be sent in this case in order
+ // to maintain correct window update state.
+ QRect updateRect(QPoint(0, 0), qwindow->geometry().size());
+ if (updateType == UpdateRequestDelivery) {
+ if (qwindow->isExposed() == false)
+ QWindowSystemInterface::handleExposeEvent(qwindow, updateRect);
+ window->deliverUpdateRequest();
+ } else {
+ QWindowSystemInterface::handleExposeEvent(qwindow, updateRect);
}
-
- QPen oldPen = painter->pen();
- QPoint a[3] = { QPoint(x, y+h-2), QPoint(x, y), QPoint(x+w-2, y) };
- painter->setPen(c1);
- painter->drawPolyline(a, 3);
- QPoint b[3] = { QPoint(x, y+h-1), QPoint(x+w-1, y+h-1), QPoint(x+w-1, y) };
- painter->setPen(c2);
- painter->drawPolyline(b, 3);
- if (w > 4 && h > 4) {
- QPoint c[3] = { QPoint(x+1, y+h-3), QPoint(x+1, y+1), QPoint(x+w-3, y+1) };
- painter->setPen(c3);
- painter->drawPolyline(c, 3);
- QPoint d[3] = { QPoint(x+1, y+h-2), QPoint(x+w-2, y+h-2), QPoint(x+w-2, y+1) };
- painter->setPen(c4);
- painter->drawPolyline(d, 3);
- if (fill)
- painter->fillRect(QRect(x+2, y+2, w-4, h-4), *fill);
- }
- painter->setPen(oldPen);
}
-//from commonstyle.cpp
-static QPixmap cachedPixmapFromXPM(const char * const *xpm)
+void QWasmCompositor::handleBackingStoreFlush(QWindow *window)
{
- QPixmap result;
- const QString tag = QString::asprintf("xpm:0x%p", static_cast<const void*>(xpm));
- if (!QPixmapCache::find(tag, &result)) {
- result = QPixmap(xpm);
- QPixmapCache::insert(tag, result);
- }
- return result;
+ // Request update to flush the updated backing store content, unless we are currently
+ // processing an update, in which case the new content will flushed as a part of that update.
+ if (!m_inDeliverUpdateRequest)
+ requestUpdateWindow(static_cast<QWasmWindow *>(window->handle()));
}
-void QWasmCompositor::drawItemPixmap(QPainter *painter, const QRect &rect, int alignment,
- const QPixmap &pixmap) const
+void QWasmCompositor::frame(const QList<QWasmWindow *> &windows)
{
- qreal scale = pixmap.devicePixelRatio();
- QSize size = pixmap.size() / scale;
- int x = rect.x();
- int y = rect.y();
- int w = size.width();
- int h = size.height();
- if ((alignment & Qt::AlignVCenter) == Qt::AlignVCenter)
- y += rect.size().height()/2 - h/2;
- else if ((alignment & Qt::AlignBottom) == Qt::AlignBottom)
- y += rect.size().height() - h;
- if ((alignment & Qt::AlignRight) == Qt::AlignRight)
- x += rect.size().width() - w;
- else if ((alignment & Qt::AlignHCenter) == Qt::AlignHCenter)
- x += rect.size().width()/2 - w/2;
-
- QRect aligned = QRect(x, y, w, h);
- QRect inter = aligned.intersected(rect);
-
- painter->drawPixmap(inter.x(), inter.y(), pixmap, inter.x() - aligned.x(), inter.y() - aligned.y(), inter.width() * scale, inter.height() *scale);
-}
-
-
-void QWasmCompositor::drawTitlebarWindow(QWasmTitleBarOptions tb, QPainter *painter)
-{
- QRect ir;
- if (tb.subControls.testFlag(SC_TitleBarLabel)) {
- QColor left = tb.palette.highlight().color();
- QColor right = tb.palette.base().color();
-
- QBrush fillBrush(left);
- if (left != right) {
- QPoint p1(tb.rect.x(), tb.rect.top() + tb.rect.height()/2);
- QPoint p2(tb.rect.right(), tb.rect.top() + tb.rect.height()/2);
- QLinearGradient lg(p1, p2);
- lg.setColorAt(0, left);
- lg.setColorAt(1, right);
- fillBrush = lg;
- }
-
- painter->fillRect(tb.rect, fillBrush);
- ir = titlebarRect(tb, SC_TitleBarLabel);
- painter->setPen(tb.palette.highlightedText().color());
- painter->drawText(ir.x() + 2, ir.y(), ir.width() - 2, ir.height(),
- Qt::AlignLeft | Qt::AlignVCenter | Qt::TextSingleLine, tb.titleBarOptionsString);
- } // SC_TitleBarLabel
-
- bool down = false;
- QPixmap pixmap;
-
- if (tb.subControls.testFlag(SC_TitleBarCloseButton)
- && tb.flags & Qt::WindowSystemMenuHint) {
- ir = titlebarRect(tb, SC_TitleBarCloseButton);
- down = tb.subControls & SC_TitleBarCloseButton && (tb.state & State_Sunken);
- pixmap = cachedPixmapFromXPM(qt_close_xpm).scaled(QSize(10, 10));
- drawItemPixmap(painter, ir, Qt::AlignCenter, pixmap);
- } //SC_TitleBarCloseButton
-
- if (tb.subControls.testFlag(SC_TitleBarMaxButton)
- && tb.flags & Qt::WindowMaximizeButtonHint
- && !(tb.state & Qt::WindowMaximized)) {
- ir = titlebarRect(tb, SC_TitleBarMaxButton);
- down = tb.subControls & SC_TitleBarMaxButton && (tb.state & State_Sunken);
- pixmap = cachedPixmapFromXPM(qt_maximize_xpm).scaled(QSize(10, 10));
- drawItemPixmap(painter, ir, Qt::AlignCenter, pixmap);
- } //SC_TitleBarMaxButton
-
- bool drawNormalButton = (tb.subControls & SC_TitleBarNormalButton)
- && (((tb.flags & Qt::WindowMinimizeButtonHint)
- && (tb.flags & Qt::WindowMinimized))
- || ((tb.flags & Qt::WindowMaximizeButtonHint)
- && (tb.flags & Qt::WindowMaximized)));
-
- if (drawNormalButton) {
- ir = titlebarRect(tb, SC_TitleBarNormalButton);
- down = tb.subControls & SC_TitleBarNormalButton && (tb.state & State_Sunken);
- pixmap = cachedPixmapFromXPM(qt_normalizeup_xpm).scaled( QSize(10, 10));
-
- drawItemPixmap(painter, ir, Qt::AlignCenter, pixmap);
- } // SC_TitleBarNormalButton
-
- if (tb.subControls & SC_TitleBarSysMenu && tb.flags & Qt::WindowSystemMenuHint) {
- ir = titlebarRect(tb, SC_TitleBarSysMenu);
- pixmap = cachedPixmapFromXPM(qt_menu_xpm).scaled(QSize(10, 10));
- drawItemPixmap(painter, ir, Qt::AlignCenter, pixmap);
- }
-}
-
-void QWasmCompositor::drawShadePanel(QWasmTitleBarOptions options, QPainter *painter)
-{
- int lineWidth = 1;
- QPalette palette = options.palette;
- const QBrush *fill = &options.palette.brush(QPalette::Button);
-
- int x = options.rect.x();
- int y = options.rect.y();
- int w = options.rect.width();
- int h = options.rect.height();
-
- const qreal devicePixelRatio = painter->device()->devicePixelRatioF();
- if (!qFuzzyCompare(devicePixelRatio, qreal(1))) {
- const qreal inverseScale = qreal(1) / devicePixelRatio;
- painter->scale(inverseScale, inverseScale);
-
- x = qRound(devicePixelRatio * x);
- y = qRound(devicePixelRatio * y);
- w = qRound(devicePixelRatio * w);
- h = qRound(devicePixelRatio * h);
- lineWidth = qRound(devicePixelRatio * lineWidth);
- }
-
- QColor shade = palette.dark().color();
- QColor light = palette.light().color();
-
- if (fill) {
- if (fill->color() == shade)
- shade = palette.shadow().color();
- if (fill->color() == light)
- light = palette.midlight().color();
- }
- QPen oldPen = painter->pen();
- QVector<QLineF> lines;
- lines.reserve(2*lineWidth);
-
- painter->setPen(light);
- int x1, y1, x2, y2;
- int i;
- x1 = x;
- y1 = y2 = y;
- x2 = x + w - 2;
- for (i = 0; i < lineWidth; i++) // top shadow
- lines << QLineF(x1, y1++, x2--, y2++);
-
- x2 = x1;
- y1 = y + h - 2;
- for (i = 0; i < lineWidth; i++) // left shado
- lines << QLineF(x1++, y1, x2++, y2--);
-
- painter->drawLines(lines);
- lines.clear();
- painter->setPen(shade);
- x1 = x;
- y1 = y2 = y+h-1;
- x2 = x+w-1;
- for (i=0; i<lineWidth; i++) { // bottom shadow
- lines << QLineF(x1++, y1--, x2, y2--);
- }
- x1 = x2;
- y1 = y;
- y2 = y + h - lineWidth - 1;
- for (i = 0; i < lineWidth; i++) // right shadow
- lines << QLineF(x1--, y1++, x2--, y2);
-
- painter->drawLines(lines);
- if (fill) // fill with fill color
- painter->fillRect(x+lineWidth, y+lineWidth, w-lineWidth*2, h-lineWidth*2, *fill);
- painter->setPen(oldPen); // restore pen
-
-}
-
-void QWasmCompositor::drawWindow(QOpenGLTextureBlitter *blitter, QWasmScreen *screen, QWasmWindow *window)
-{
- if (window->window()->type() != Qt::Popup && !(window->m_windowState & Qt::WindowFullScreen))
- drawWindowDecorations(blitter, screen, window);
- drawWindowContent(blitter, screen, window);
-}
-
-void QWasmCompositor::frame()
-{
- if (!m_needComposit)
- return;
-
- m_needComposit = false;
-
- if (!m_isEnabled || m_windowStack.empty() || !screen())
- return;
-
- QWasmWindow *someWindow = nullptr;
-
- for (QWasmWindow *window : qAsConst(m_windowStack)) {
- if (window->window()->surfaceClass() == QSurface::Window
- && qt_window_private(static_cast<QWindow *>(window->window()))->receivedExpose) {
- someWindow = window;
- break;
- }
- }
-
- if (!someWindow)
- return;
-
- if (m_context.isNull()) {
- m_context.reset(new QOpenGLContext());
- m_context->setFormat(someWindow->window()->requestedFormat());
- m_context->setScreen(screen()->screen());
- m_context->create();
- }
-
- bool ok = m_context->makeCurrent(someWindow->window());
- if (!ok)
- return;
-
- if (!m_blitter->isCreated())
- m_blitter->create();
-
- qreal dpr = screen()->devicePixelRatio();
- glViewport(0, 0, screen()->geometry().width() * dpr, screen()->geometry().height() * dpr);
-
- m_context->functions()->glClearColor(0.2, 0.2, 0.2, 1.0);
- m_context->functions()->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
-
- m_blitter->bind();
- m_blitter->setRedBlueSwizzle(true);
-
- for (QWasmWindow *window : qAsConst(m_windowStack)) {
- QWasmCompositedWindow &compositedWindow = m_compositedWindows[window];
-
- if (!compositedWindow.visible)
- continue;
-
- drawWindow(m_blitter.data(), screen(), window);
- }
-
- m_blitter->release();
-
- if (someWindow && someWindow->window()->surfaceType() == QSurface::OpenGLSurface)
- m_context->swapBuffers(someWindow->window());
-}
-
-void QWasmCompositor::notifyTopWindowChanged(QWasmWindow *window)
-{
- QWindow *modalWindow;
- bool blocked = QGuiApplicationPrivate::instance()->isWindowBlocked(window->window(), &modalWindow);
-
- if (blocked) {
- raise(static_cast<QWasmWindow*>(modalWindow->handle()));
+ if (!m_isEnabled || !screen())
return;
- }
- requestRedraw();
- QWindowSystemInterface::handleWindowActivated(window->window());
+ for (QWasmWindow *window : windows)
+ window->paint();
}
QWasmScreen *QWasmCompositor::screen()
diff --git a/src/plugins/platforms/wasm/qwasmcompositor.h b/src/plugins/platforms/wasm/qwasmcompositor.h
index 250d244c9f..4953d65233 100644
--- a/src/plugins/platforms/wasm/qwasmcompositor.h
+++ b/src/plugins/platforms/wasm/qwasmcompositor.h
@@ -1,165 +1,59 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the plugins of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL$
-** 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 General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 or (at your option) 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.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-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#ifndef QWASMCOMPOSITOR_H
#define QWASMCOMPOSITOR_H
-#include <QtGui/qregion.h>
+#include "qwasmwindowstack.h"
+
#include <qpa/qplatformwindow.h>
-#include <QtOpenGL/qopengltextureblitter.h>
-#include <QtGui/qpalette.h>
-#include <QtGui/qpainter.h>
+#include <QMap>
QT_BEGIN_NAMESPACE
class QWasmWindow;
class QWasmScreen;
-class QOpenGLContext;
-class QOpenGLTexture;
-class QWasmCompositedWindow
-{
-public:
- QWasmCompositedWindow();
-
- QWasmWindow *window;
- QWasmWindow *parentWindow;
- QRegion damage;
- bool flushPending;
- bool visible;
- QList<QWasmWindow *> childWindows;
-};
+enum class QWasmWindowTreeNodeChangeType;
-class QWasmCompositor : public QObject
+class QWasmCompositor final : public QObject
{
Q_OBJECT
public:
QWasmCompositor(QWasmScreen *screen);
- ~QWasmCompositor();
- void destroy();
-
- enum QWasmSubControl {
- SC_None = 0x00000000,
- SC_TitleBarSysMenu = 0x00000001,
- SC_TitleBarMinButton = 0x00000002,
- SC_TitleBarMaxButton = 0x00000004,
- SC_TitleBarCloseButton = 0x00000008,
- SC_TitleBarNormalButton = 0x00000010,
- SC_TitleBarLabel = 0x00000100
- };
- Q_DECLARE_FLAGS(SubControls, QWasmSubControl)
-
- enum QWasmStateFlag {
- State_None = 0x00000000,
- State_Enabled = 0x00000001,
- State_Raised = 0x00000002,
- State_Sunken = 0x00000004
- };
- Q_DECLARE_FLAGS(StateFlags, QWasmStateFlag)
-
- struct QWasmTitleBarOptions {
- QRect rect;
- Qt::WindowFlags flags;
- int state;
- QPalette palette;
- QString titleBarOptionsString;
- QWasmCompositor::SubControls subControls;
- };
-
- struct QWasmFrameOptions {
- QRect rect;
- int lineWidth;
- QPalette palette;
- };
-
- void setEnabled(bool enabled);
-
- void addWindow(QWasmWindow *window, QWasmWindow *parentWindow = nullptr);
- void removeWindow(QWasmWindow *window);
+ ~QWasmCompositor() final;
void setVisible(QWasmWindow *window, bool visible);
- void raise(QWasmWindow *window);
- void lower(QWasmWindow *window);
- void setParent(QWasmWindow *window, QWasmWindow *parent);
- void flush(QWasmWindow *surface, const QRegion &region);
+ void onScreenDeleting();
- int windowCount() const;
+ QWasmScreen *screen();
+ void setEnabled(bool enabled);
+
+ static bool releaseRequestUpdateHold();
- void redrawWindowContent();
- void requestRedraw();
+ void requestUpdate();
+ enum UpdateRequestDeliveryType { ExposeEventDelivery, UpdateRequestDelivery };
+ void requestUpdateWindow(QWasmWindow *window, UpdateRequestDeliveryType updateType = ExposeEventDelivery);
- QWindow *windowAt(QPoint globalPoint, int padding = 0) const;
- QWindow *keyWindow() const;
+ void handleBackingStoreFlush(QWindow *window);
+ void onWindowTreeChanged(QWasmWindowTreeNodeChangeType changeType, QWasmWindow *window);
- bool event(QEvent *event);
+private:
+ void frame(const QList<QWasmWindow *> &windows);
- static QWasmTitleBarOptions makeTitleBarOptions(const QWasmWindow *window);
- static QRect titlebarRect(QWasmTitleBarOptions tb, QWasmCompositor::SubControls subcontrol);
+ void deregisterEventHandlers();
-private slots:
- void frame();
+ void deliverUpdateRequests();
+ void deliverUpdateRequest(QWasmWindow *window, UpdateRequestDeliveryType updateType);
-private:
- QWasmScreen *screen();
- void notifyTopWindowChanged(QWasmWindow *window);
- void drawWindow(QOpenGLTextureBlitter *blitter, QWasmScreen *screen, QWasmWindow *window);
- void drawWindowContent(QOpenGLTextureBlitter *blitter, QWasmScreen *screen, QWasmWindow *window);
- void blit(QOpenGLTextureBlitter *blitter, QWasmScreen *screen, const QOpenGLTexture *texture, QRect targetGeometry);
-
- void drawWindowDecorations(QOpenGLTextureBlitter *blitter, QWasmScreen *screen, QWasmWindow *window);
- void drwPanelButton();
-
- QImage *m_frameBuffer;
- QScopedPointer<QOpenGLContext> m_context;
- QScopedPointer<QOpenGLTextureBlitter> m_blitter;
-
- QHash<QWasmWindow *, QWasmCompositedWindow> m_compositedWindows;
- QList<QWasmWindow *> m_windowStack;
- QRegion m_globalDamage; // damage caused by expose, window close, etc.
- bool m_needComposit;
- bool m_inFlush;
- bool m_inResize;
- bool m_isEnabled;
- QSize m_targetSize;
- qreal m_targetDevicePixelRatio;
-
- static QPalette makeWindowPalette();
-
- void drawFrameWindow(QWasmFrameOptions options, QPainter *painter);
- void drawTitlebarWindow(QWasmTitleBarOptions options, QPainter *painter);
- void drawShadePanel(QWasmTitleBarOptions options, QPainter *painter);
- void drawItemPixmap(QPainter *painter, const QRect &rect,
- int alignment, const QPixmap &pixmap) const;
+ bool m_isEnabled = true;
+ QMap<QWasmWindow *, UpdateRequestDeliveryType> m_requestUpdateWindows;
+ int m_requestAnimationFrameId = -1;
+ bool m_inDeliverUpdateRequest = false;
+ static bool m_requestUpdateHoldEnabled;
};
-Q_DECLARE_OPERATORS_FOR_FLAGS(QWasmCompositor::SubControls)
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/wasm/qwasmcssstyle.cpp b/src/plugins/platforms/wasm/qwasmcssstyle.cpp
new file mode 100644
index 0000000000..e0e1a99f48
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmcssstyle.cpp
@@ -0,0 +1,248 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "qwasmcssstyle.h"
+
+#include "qwasmbase64iconstore.h"
+
+#include <QtCore/qstring.h>
+#include <QtCore/qfile.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace {
+const char *Style = R"css(
+.qt-screen {
+ --border-width: 4px;
+ --resize-outline-width: 8px;
+ --resize-outline-half-width: var(--resize-outline-width) / 2;
+
+ position: relative;
+ border: none;
+ caret-color: transparent;
+ cursor: default;
+ width: 100%;
+ height: 100%;
+ overflow: hidden;
+}
+
+.qt-screen div {
+ touch-action: none;
+}
+
+.qt-window {
+ position: absolute;
+ background-color: lightgray;
+}
+
+.qt-window-contents {
+ overflow: hidden;
+ position: relative;
+}
+
+.qt-window.transparent-for-input {
+ pointer-events: none;
+}
+
+.qt-window.has-shadow {
+ box-shadow: rgb(0 0 0 / 20%) 0px 10px 16px 0px, rgb(0 0 0 / 19%) 0px 6px 20px 0px;
+}
+
+.qt-window.has-border {
+ border: var(--border-width) solid lightgray;
+ caret-color: transparent;
+}
+
+.qt-window.frameless {
+ background-color: transparent;
+}
+
+.resize-outline {
+ position: absolute;
+ display: none;
+}
+
+.qt-window.no-resize > .resize-outline { display: none; }
+
+.qt-window.has-border:not(.maximized):not(.no-resize) .resize-outline {
+ display: block;
+}
+
+.resize-outline.nw {
+ left: calc(-1 * var(--resize-outline-half-width) - var(--border-width));
+ top: calc(-1 * var(--resize-outline-half-width) - var(--border-width));
+ width: var(--resize-outline-width);
+ height: var(--resize-outline-width);
+ cursor: nwse-resize;
+}
+
+.resize-outline.n {
+ left: var(--resize-outline-half-width);
+ top: calc(-1 * var(--resize-outline-half-width) - var(--border-width));
+ height: var(--resize-outline-width);
+ width: calc(100% + 2 * var(--border-width) - var(--resize-outline-width));
+ cursor: ns-resize;
+}
+
+.resize-outline.ne {
+ left: calc(100% + var(--border-width) - var(--resize-outline-half-width));
+ top: calc(-1 * var(--resize-outline-half-width) - var(--border-width));
+ width: var(--resize-outline-width);
+ height: var(--resize-outline-width);
+ cursor: nesw-resize;
+}
+
+.resize-outline.w {
+ left: calc(-1 * var(--resize-outline-half-width) - var(--border-width));
+ top: 0;
+ height: calc(100% + 2 * var(--border-width) - var(--resize-outline-width));
+ width: var(--resize-outline-width);
+ cursor: ew-resize;
+}
+
+.resize-outline.e {
+ left: calc(100% + var(--border-width) - var(--resize-outline-half-width));
+ top: 0;
+ height: calc(100% + 2 * var(--border-width) - var(--resize-outline-width));
+ width: var(--resize-outline-width);
+ cursor: ew-resize;
+}
+
+.resize-outline.sw {
+ left: calc(-1 * var(--resize-outline-half-width) - var(--border-width));
+ top: calc(100% + var(--border-width) - var(--resize-outline-half-width));
+ width: var(--resize-outline-width);
+ height: var(--resize-outline-width);
+ cursor: nesw-resize;
+}
+
+.resize-outline.s {
+ left: var(--resize-outline-half-width);
+ top: calc(100% + var(--border-width) - var(--resize-outline-half-width));
+ height: var(--resize-outline-width);
+ width: calc(100% + 2 * var(--border-width) - var(--resize-outline-width));
+ cursor: ns-resize;
+}
+
+.resize-outline.se {
+ left: calc(100% + var(--border-width) - var(--resize-outline-half-width));
+ top: calc(100% + var(--border-width) - var(--resize-outline-half-width));
+ width: var(--resize-outline-width);
+ height: var(--resize-outline-width);
+ cursor: nwse-resize;
+}
+
+.title-bar {
+ display: none;
+ align-items: center;
+ overflow: hidden;
+ height: 18px;
+ padding-bottom: 4px;
+}
+
+.qt-window.has-border > .title-bar {
+ display: flex;
+}
+
+.title-bar .window-name {
+ display: none;
+ font-family: 'Lucida Grande';
+ white-space: nowrap;
+ user-select: none;
+ overflow: hidden;
+}
+
+
+.qt-window.has-title .title-bar .window-name {
+ display: block;
+}
+
+.title-bar .spacer {
+ flex-grow: 1
+}
+
+.qt-window.inactive .title-bar {
+ opacity: 0.35;
+}
+
+.qt-window-canvas-container {
+ display: flex;
+ pointer-events: none;
+}
+
+.title-bar div {
+ pointer-events: none;
+}
+
+.qt-window-a11y-container {
+ position: absolute;
+ z-index: -1;
+}
+
+.title-bar .image-button {
+ width: 18px;
+ height: 18px;
+ display: flex;
+ justify-content: center;
+ user-select: none;
+ align-items: center;
+}
+
+.title-bar .image-button img {
+ width: 10px;
+ height: 10px;
+ user-select: none;
+ pointer-events: none;
+ -webkit-user-drag: none;
+ background-size: 10px 10px;
+}
+
+.title-bar .action-button {
+ pointer-events: all;
+}
+
+.qt-window.blocked div {
+ pointer-events: none;
+}
+
+.title-bar .action-button img {
+ transition: filter 0.08s ease-out;
+}
+
+.title-bar .action-button:hover img {
+ filter: invert(0.45);
+}
+
+.title-bar .action-button:active img {
+ filter: invert(0.6);
+}
+
+/* This will clip the content within 50% frame in 1x1 pixel area, preventing it
+ from being rendered on the page, but it should still be read by modern
+ screen readers */
+.hidden-visually-read-by-screen-reader {
+ visibility: visible;
+ clip: rect(1px, 1px, 1px, 1px);
+ clip-path: inset(50%);
+ height: 1px;
+ width: 1px;
+ margin: -1px;
+ overflow: hidden;
+ padding: 0;
+ position: absolute;
+}
+
+)css";
+
+} // namespace
+
+emscripten::val QWasmCSSStyle::createStyleElement(emscripten::val parent)
+{
+ auto document = parent["ownerDocument"];
+ auto screenStyle = document.call<emscripten::val>("createElement", emscripten::val("style"));
+
+ screenStyle.set("textContent", std::string(Style));
+ return screenStyle;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/wasm/qwasmcssstyle.h b/src/plugins/platforms/wasm/qwasmcssstyle.h
new file mode 100644
index 0000000000..fc4cc2d54c
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmcssstyle.h
@@ -0,0 +1,18 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef QWASMCSSSTYLE_H
+#define QWASMCSSSTYLE_H
+
+#include <QtCore/qglobal.h>
+
+#include <emscripten/val.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QWasmCSSStyle {
+emscripten::val createStyleElement(emscripten::val parent);
+}
+
+QT_END_NAMESPACE
+#endif // QWASMINLINESTYLEREGISTRY_H
diff --git a/src/plugins/platforms/wasm/qwasmcursor.cpp b/src/plugins/platforms/wasm/qwasmcursor.cpp
index 61204517ce..c258befa77 100644
--- a/src/plugins/platforms/wasm/qwasmcursor.cpp
+++ b/src/plugins/platforms/wasm/qwasmcursor.cpp
@@ -1,141 +1,101 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the plugins of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL$
-** 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 General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 or (at your option) 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.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-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include "qwasmcursor.h"
#include "qwasmscreen.h"
-#include "qwasmstring.h"
+#include "qwasmwindow.h"
+#include <QtCore/qbuffer.h>
#include <QtCore/qdebug.h>
+#include <QtCore/qstring.h>
#include <QtGui/qwindow.h>
#include <emscripten/emscripten.h>
#include <emscripten/bind.h>
+QT_BEGIN_NAMESPACE
using namespace emscripten;
-void QWasmCursor::changeCursor(QCursor *windowCursor, QWindow *window)
-{
- if (!windowCursor || !window)
- return;
- QScreen *screen = window->screen();
- if (!screen)
- return;
-
- // Bitmap and custom cursors are not implemented (will fall back to "auto")
- if (windowCursor->shape() == Qt::BitmapCursor || windowCursor->shape() >= Qt::CustomCursor)
- qWarning() << "QWasmCursor: bitmap and custom cursors are not supported";
-
- QByteArray htmlCursorName = cursorShapeToHtml(windowCursor->shape());
-
- if (htmlCursorName.isEmpty())
- htmlCursorName = "auto";
-
- // Set cursor on the canvas
- val canvas = QWasmScreen::get(screen)->canvas();
- val canvasStyle = canvas["style"];
- canvasStyle.set("cursor", val(htmlCursorName.constData()));
-}
-
-QByteArray QWasmCursor::cursorShapeToHtml(Qt::CursorShape shape)
+namespace {
+QByteArray cursorToCss(const QCursor *cursor)
{
- QByteArray cursorName;
-
+ auto shape = cursor->shape();
switch (shape) {
case Qt::ArrowCursor:
- cursorName = "default";
- break;
+ return "default";
case Qt::UpArrowCursor:
- cursorName = "n-resize";
- break;
+ return "n-resize";
case Qt::CrossCursor:
- cursorName = "crosshair";
- break;
+ return "crosshair";
case Qt::WaitCursor:
- cursorName = "wait";
- break;
+ return "wait";
case Qt::IBeamCursor:
- cursorName = "text";
- break;
+ return "text";
case Qt::SizeVerCursor:
- cursorName = "ns-resize";
- break;
+ return "ns-resize";
case Qt::SizeHorCursor:
- cursorName = "ew-resize";
- break;
+ return "ew-resize";
case Qt::SizeBDiagCursor:
- cursorName = "nesw-resize";
- break;
+ return "nesw-resize";
case Qt::SizeFDiagCursor:
- cursorName = "nwse-resize";
- break;
+ return "nwse-resize";
case Qt::SizeAllCursor:
- cursorName = "move";
- break;
+ return "move";
case Qt::BlankCursor:
- cursorName = "none";
- break;
+ return "none";
case Qt::SplitVCursor:
- cursorName = "row-resize";
- break;
+ return "row-resize";
case Qt::SplitHCursor:
- cursorName = "col-resize";
- break;
+ return "col-resize";
case Qt::PointingHandCursor:
- cursorName = "pointer";
- break;
+ return "pointer";
case Qt::ForbiddenCursor:
- cursorName = "not-allowed";
- break;
+ return "not-allowed";
case Qt::WhatsThisCursor:
- cursorName = "help";
- break;
+ return "help";
case Qt::BusyCursor:
- cursorName = "progress";
- break;
+ return "progress";
case Qt::OpenHandCursor:
- cursorName = "grab";
- break;
+ return "grab";
case Qt::ClosedHandCursor:
- cursorName = "grabbing";
- break;
+ return "grabbing";
case Qt::DragCopyCursor:
- cursorName = "copy";
- break;
+ return "copy";
case Qt::DragMoveCursor:
- cursorName = "default";
- break;
+ return "default";
case Qt::DragLinkCursor:
- cursorName = "alias";
- break;
+ return "alias";
+ case Qt::BitmapCursor: {
+ auto pixmap = cursor->pixmap();
+ QByteArray cursorAsPng;
+ QBuffer buffer(&cursorAsPng);
+ buffer.open(QBuffer::WriteOnly);
+ pixmap.save(&buffer, "PNG");
+ buffer.close();
+ auto cursorAsBase64 = cursorAsPng.toBase64();
+ auto hotSpot = cursor->hotSpot();
+ auto encodedCursor =
+ QString("url(data:image/png;base64,%1) %2 %3, auto")
+ .arg(QString::fromUtf8(cursorAsBase64),
+ QString::number(hotSpot.x()),
+ QString::number(hotSpot.y()));
+ return encodedCursor.toUtf8();
+ }
default:
- break;
+ static_assert(Qt::CustomCursor == 25,
+ "New cursor type added, handle it");
+ qWarning() << "QWasmCursor: " << shape << " unsupported";
+ return "default";
}
+}
+} // namespace
- return cursorName;
+void QWasmCursor::changeCursor(QCursor *windowCursor, QWindow *window)
+{
+ if (!window)
+ return;
+ if (QWasmWindow *wasmWindow = static_cast<QWasmWindow *>(window->handle()))
+ wasmWindow->setWindowCursor(windowCursor ? cursorToCss(windowCursor) : "default");
}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/wasm/qwasmcursor.h b/src/plugins/platforms/wasm/qwasmcursor.h
index 516e07aa31..6873602caf 100644
--- a/src/plugins/platforms/wasm/qwasmcursor.h
+++ b/src/plugins/platforms/wasm/qwasmcursor.h
@@ -1,43 +1,19 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the plugins of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL$
-** 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 General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 or (at your option) 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.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-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#ifndef QWASMCURSOR_H
#define QWASMCURSOR_H
#include <qpa/qplatformcursor.h>
+QT_BEGIN_NAMESPACE
+
class QWasmCursor : public QPlatformCursor
{
public:
void changeCursor(QCursor *windowCursor, QWindow *window) override;
-
- QByteArray cursorShapeToHtml(Qt::CursorShape shape);
};
+QT_END_NAMESPACE
+
#endif
diff --git a/src/plugins/platforms/wasm/qwasmdom.cpp b/src/plugins/platforms/wasm/qwasmdom.cpp
new file mode 100644
index 0000000000..6b2b3d0933
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmdom.cpp
@@ -0,0 +1,303 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "qwasmdom.h"
+
+#include <QtCore/qdir.h>
+#include <QtCore/qfile.h>
+#include <QtCore/qpoint.h>
+#include <QtCore/qrect.h>
+#include <QtGui/qimage.h>
+#include <private/qstdweb_p.h>
+#include <QtCore/qurl.h>
+
+#include <utility>
+#include <emscripten/wire.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace dom {
+namespace {
+std::string dropActionToDropEffect(Qt::DropAction action)
+{
+ switch (action) {
+ case Qt::DropAction::CopyAction:
+ return "copy";
+ case Qt::DropAction::IgnoreAction:
+ return "none";
+ case Qt::DropAction::LinkAction:
+ return "link";
+ case Qt::DropAction::MoveAction:
+ case Qt::DropAction::TargetMoveAction:
+ return "move";
+ case Qt::DropAction::ActionMask:
+ Q_ASSERT(false);
+ return "";
+ }
+}
+} // namespace
+
+DataTransfer::DataTransfer(emscripten::val webDataTransfer)
+ : webDataTransfer(webDataTransfer) {
+}
+
+DataTransfer::~DataTransfer() = default;
+
+DataTransfer::DataTransfer(const DataTransfer &other) = default;
+
+DataTransfer::DataTransfer(DataTransfer &&other) = default;
+
+DataTransfer &DataTransfer::operator=(const DataTransfer &other) = default;
+
+DataTransfer &DataTransfer::operator=(DataTransfer &&other) = default;
+
+void DataTransfer::setDragImage(emscripten::val element, const QPoint &hotspot)
+{
+ webDataTransfer.call<void>("setDragImage", element, emscripten::val(hotspot.x()),
+ emscripten::val(hotspot.y()));
+}
+
+void DataTransfer::setData(std::string format, std::string data)
+{
+ webDataTransfer.call<void>("setData", emscripten::val(std::move(format)),
+ emscripten::val(std::move(data)));
+}
+
+void DataTransfer::setDropAction(Qt::DropAction action)
+{
+ webDataTransfer.set("dropEffect", emscripten::val(dropActionToDropEffect(action)));
+}
+
+void DataTransfer::setDataFromMimeData(const QMimeData &mimeData)
+{
+ for (const auto &format : mimeData.formats()) {
+ auto data = mimeData.data(format);
+
+ auto encoded = format.startsWith("text/")
+ ? QString::fromLocal8Bit(data).toStdString()
+ : "QB64" + QString::fromLocal8Bit(data.toBase64()).toStdString();
+
+ setData(format.toStdString(), std::move(encoded));
+ }
+}
+
+// Converts a DataTransfer instance to a QMimeData instance. Invokes the
+// given callback when the conversion is complete. The callback takes ownership
+// of the QMimeData.
+void DataTransfer::toMimeDataWithFile(std::function<void(QMimeData *)> callback)
+{
+ enum class ItemKind {
+ File,
+ String,
+ };
+
+ class MimeContext {
+
+ public:
+ MimeContext(int itemCount, std::function<void(QMimeData *)> callback)
+ :m_remainingItemCount(itemCount), m_callback(callback)
+ {
+
+ }
+
+ void deref() {
+ if (--m_remainingItemCount > 0)
+ return;
+
+ mimeData->setUrls(fileUrls);
+
+ m_callback(mimeData);
+
+ // Delete files; we expect that the user callback reads/copies
+ // file content before returning.
+ // Fixme: tie file lifetime to lifetime of the QMimeData?
+ for (QUrl fileUrl: fileUrls)
+ QFile(fileUrl.toLocalFile()).remove();
+
+ delete this;
+ }
+
+ QMimeData *mimeData = new QMimeData();
+ QList<QUrl> fileUrls;
+
+ private:
+ int m_remainingItemCount;
+ std::function<void(QMimeData *)> m_callback;
+ };
+
+ const auto items = webDataTransfer["items"];
+ const int itemCount = items["length"].as<int>();
+ const int fileCount = webDataTransfer["files"]["length"].as<int>();
+ MimeContext *mimeContext = new MimeContext(itemCount, callback);
+
+ for (int i = 0; i < itemCount; ++i) {
+ const auto item = items[i];
+ const auto itemKind =
+ item["kind"].as<std::string>() == "string" ? ItemKind::String : ItemKind::File;
+ const auto itemMimeType = QString::fromStdString(item["type"].as<std::string>());
+
+ switch (itemKind) {
+ case ItemKind::File: {
+ qstdweb::File webfile(item.call<emscripten::val>("getAsFile"));
+
+ if (webfile.size() > 1e+9) { // limit file size to 1 GB
+ qWarning() << "File is too large (> 1GB) and will be skipped. File size is" << webfile.size();
+ mimeContext->deref();
+ continue;
+ }
+
+ QString mimeFormat = QString::fromStdString(webfile.type());
+ QString fileName = QString::fromStdString(webfile.name());
+
+ // there's a file, now read it
+ QByteArray fileContent(webfile.size(), Qt::Uninitialized);
+ webfile.stream(fileContent.data(), [=]() {
+
+ // If we get a single file, and that file is an image, then
+ // try to decode the image data. This handles the case where
+ // image data (i.e. not an image file) is pasted. The browsers
+ // will then create a fake "image.png" file which has the image
+ // data. As a side effect Qt will also decode the image for
+ // single-image-file drops, since there is no way to differentiate
+ // the fake "image.png" from a real one.
+ if (fileCount == 1 && mimeFormat.contains("image/")) {
+ QImage image;
+ if (image.loadFromData(fileContent))
+ mimeContext->mimeData->setImageData(image);
+ }
+
+ QDir qtTmpDir("/qt/tmp/"); // "tmp": indicate that these files won't stay around
+ qtTmpDir.mkpath(qtTmpDir.path());
+
+ QUrl fileUrl = QUrl::fromLocalFile(qtTmpDir.filePath(QString::fromStdString(webfile.name())));
+ mimeContext->fileUrls.append(fileUrl);
+
+ QFile file(fileUrl.toLocalFile());
+ if (!file.open(QFile::WriteOnly)) {
+ qWarning() << "File was not opened";
+ mimeContext->deref();
+ return;
+ }
+ if (file.write(fileContent) < 0) {
+ qWarning() << "Write failed";
+ file.close();
+ }
+ mimeContext->deref();
+ });
+ break;
+ }
+ case ItemKind::String:
+ if (itemMimeType.contains("STRING", Qt::CaseSensitive)
+ || itemMimeType.contains("TEXT", Qt::CaseSensitive)) {
+ mimeContext->deref();
+ break;
+ }
+ QString a;
+ QString data = QString::fromEcmaString(webDataTransfer.call<emscripten::val>(
+ "getData", emscripten::val(itemMimeType.toStdString())));
+
+ if (!data.isEmpty()) {
+ if (itemMimeType == "text/html")
+ mimeContext->mimeData->setHtml(data);
+ else if (itemMimeType.isEmpty() || itemMimeType == "text/plain")
+ mimeContext->mimeData->setText(data); // the type can be empty
+ else {
+ // TODO improve encoding
+ if (data.startsWith("QB64")) {
+ data.remove(0, 4);
+ mimeContext->mimeData->setData(itemMimeType,
+ QByteArray::fromBase64(QByteArray::fromStdString(
+ data.toStdString())));
+ } else {
+ mimeContext->mimeData->setData(itemMimeType, data.toLocal8Bit());
+ }
+ }
+ }
+ mimeContext->deref();
+ break;
+ }
+ } // for items
+}
+
+QMimeData *DataTransfer::toMimeDataPreview()
+{
+ auto data = new QMimeData();
+
+ QList<QUrl> uriList;
+ for (int i = 0; i < webDataTransfer["items"]["length"].as<int>(); ++i) {
+ const auto item = webDataTransfer["items"][i];
+ if (item["kind"].as<std::string>() == "file") {
+ uriList.append(QUrl("blob://placeholder"));
+ } else {
+ const auto itemMimeType = QString::fromStdString(item["type"].as<std::string>());
+ data->setData(itemMimeType, QByteArray());
+ }
+ }
+ data->setUrls(uriList);
+ return data;
+}
+
+void syncCSSClassWith(emscripten::val element, std::string cssClassName, bool flag)
+{
+ if (flag) {
+ element["classList"].call<void>("add", emscripten::val(std::move(cssClassName)));
+ return;
+ }
+
+ element["classList"].call<void>("remove", emscripten::val(std::move(cssClassName)));
+}
+
+QPointF mapPoint(emscripten::val source, emscripten::val target, const QPointF &point)
+{
+ const auto sourceBoundingRect =
+ QRectF::fromDOMRect(source.call<emscripten::val>("getBoundingClientRect"));
+ const auto targetBoundingRect =
+ QRectF::fromDOMRect(target.call<emscripten::val>("getBoundingClientRect"));
+
+ const auto offset = sourceBoundingRect.topLeft() - targetBoundingRect.topLeft();
+ return point + offset;
+}
+
+void drawImageToWebImageDataArray(const QImage &sourceImage, emscripten::val destinationImageData,
+ const QRect &sourceRect)
+{
+ Q_ASSERT_X(destinationImageData["constructor"]["name"].as<std::string>() == "ImageData",
+ Q_FUNC_INFO, "The destination should be an ImageData instance");
+
+ constexpr int BytesPerColor = 4;
+ if (sourceRect.width() == sourceImage.width()) {
+ // Copy a contiguous chunk of memory
+ // ...............
+ // OOOOOOOOOOOOOOO
+ // OOOOOOOOOOOOOOO -> image data
+ // OOOOOOOOOOOOOOO
+ // ...............
+ auto imageMemory = emscripten::typed_memory_view(sourceRect.width() * sourceRect.height()
+ * BytesPerColor,
+ sourceImage.constScanLine(sourceRect.y()));
+ destinationImageData["data"].call<void>(
+ "set", imageMemory, sourceRect.y() * sourceImage.width() * BytesPerColor);
+ } else {
+ // Go through the scanlines manually to set the individual lines in bulk. This is
+ // marginally less performant than the above.
+ // ...............
+ // ...OOOOOOOOO... r = 0 -> image data
+ // ...OOOOOOOOO... r = 1 -> image data
+ // ...OOOOOOOOO... r = 2 -> image data
+ // ...............
+ for (int row = 0; row < sourceRect.height(); ++row) {
+ auto scanlineMemory =
+ emscripten::typed_memory_view(sourceRect.width() * BytesPerColor,
+ sourceImage.constScanLine(row + sourceRect.y())
+ + BytesPerColor * sourceRect.x());
+ destinationImageData["data"].call<void>("set", scanlineMemory,
+ (sourceRect.y() + row) * sourceImage.width()
+ * BytesPerColor
+ + sourceRect.x() * BytesPerColor);
+ }
+ }
+}
+
+} // namespace dom
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/wasm/qwasmdom.h b/src/plugins/platforms/wasm/qwasmdom.h
new file mode 100644
index 0000000000..0a520815a3
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmdom.h
@@ -0,0 +1,63 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef QWASMDOM_H
+#define QWASMDOM_H
+
+#include <QtCore/qtconfigmacros.h>
+#include <QtCore/QPointF>
+#include <private/qstdweb_p.h>
+#include <QtCore/qnamespace.h>
+
+#include <emscripten/val.h>
+
+#include <functional>
+#include <memory>
+#include <string>
+
+#include <QMimeData>
+QT_BEGIN_NAMESPACE
+
+namespace qstdweb {
+ struct CancellationFlag;
+}
+
+
+class QPoint;
+class QRect;
+
+namespace dom {
+struct DataTransfer
+{
+ explicit DataTransfer(emscripten::val webDataTransfer);
+ ~DataTransfer();
+ DataTransfer(const DataTransfer &other);
+ DataTransfer(DataTransfer &&other);
+ DataTransfer &operator=(const DataTransfer &other);
+ DataTransfer &operator=(DataTransfer &&other);
+
+ void toMimeDataWithFile(std::function<void(QMimeData *)> callback);
+ QMimeData *toMimeDataPreview();
+ void setDragImage(emscripten::val element, const QPoint &hotspot);
+ void setData(std::string format, std::string data);
+ void setDropAction(Qt::DropAction dropAction);
+ void setDataFromMimeData(const QMimeData &mimeData);
+
+ emscripten::val webDataTransfer;
+};
+
+inline emscripten::val document()
+{
+ return emscripten::val::global("document");
+}
+
+void syncCSSClassWith(emscripten::val element, std::string cssClassName, bool flag);
+
+QPointF mapPoint(emscripten::val source, emscripten::val target, const QPointF &point);
+
+void drawImageToWebImageDataArray(const QImage &source, emscripten::val destinationImageData,
+ const QRect &sourceRect);
+} // namespace dom
+
+QT_END_NAMESPACE
+#endif // QWASMDOM_H
diff --git a/src/plugins/platforms/wasm/qwasmdrag.cpp b/src/plugins/platforms/wasm/qwasmdrag.cpp
new file mode 100644
index 0000000000..d07a46618f
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmdrag.cpp
@@ -0,0 +1,291 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "qwasmdrag.h"
+
+#include "qwasmbase64iconstore.h"
+#include "qwasmdom.h"
+#include "qwasmevent.h"
+#include "qwasmintegration.h"
+
+#include <qpa/qwindowsysteminterface.h>
+
+#include <QtCore/private/qstdweb_p.h>
+#include <QtCore/qeventloop.h>
+#include <QtCore/qmimedata.h>
+#include <QtCore/qtimer.h>
+#include <QFile>
+
+#include <functional>
+#include <string>
+#include <utility>
+
+QT_BEGIN_NAMESPACE
+
+namespace {
+
+QWindow *windowForDrag(QDrag *drag)
+{
+ QWindow *window = qobject_cast<QWindow *>(drag->source());
+ if (window)
+ return window;
+ if (drag->source()->metaObject()->indexOfMethod("_q_closestWindowHandle()") == -1)
+ return nullptr;
+
+ QMetaObject::invokeMethod(drag->source(), "_q_closestWindowHandle",
+ Q_RETURN_ARG(QWindow *, window));
+ return window;
+}
+
+} // namespace
+
+struct QWasmDrag::DragState
+{
+ class DragImage
+ {
+ public:
+ DragImage(const QPixmap &pixmap, const QMimeData *mimeData, QWindow *window);
+ ~DragImage();
+
+ emscripten::val htmlElement();
+
+ private:
+ emscripten::val generateDragImage(const QPixmap &pixmap, const QMimeData *mimeData);
+ emscripten::val generateDragImageFromText(const QMimeData *mimeData);
+ emscripten::val generateDefaultDragImage();
+ emscripten::val generateDragImageFromPixmap(const QPixmap &pixmap);
+
+ emscripten::val m_imageDomElement;
+ emscripten::val m_temporaryImageElementParent;
+ };
+
+ DragState(QDrag *drag, QWindow *window, std::function<void()> quitEventLoopClosure);
+ ~DragState();
+ DragState(const QWasmDrag &other) = delete;
+ DragState(QWasmDrag &&other) = delete;
+ DragState &operator=(const QWasmDrag &other) = delete;
+ DragState &operator=(QWasmDrag &&other) = delete;
+
+ QDrag *drag;
+ QWindow *window;
+ std::function<void()> quitEventLoopClosure;
+ std::unique_ptr<DragImage> dragImage;
+ Qt::DropAction dropAction = Qt::DropAction::IgnoreAction;
+};
+
+QWasmDrag::QWasmDrag() = default;
+
+QWasmDrag::~QWasmDrag() = default;
+
+QWasmDrag *QWasmDrag::instance()
+{
+ return static_cast<QWasmDrag *>(QWasmIntegration::get()->drag());
+}
+
+Qt::DropAction QWasmDrag::drag(QDrag *drag)
+{
+ Q_ASSERT_X(!m_dragState, Q_FUNC_INFO, "Drag already in progress");
+
+ QWindow *window = windowForDrag(drag);
+ if (!window)
+ return Qt::IgnoreAction;
+
+ Qt::DropAction dragResult = Qt::IgnoreAction;
+ if (qstdweb::haveJspi()) {
+ QEventLoop loop;
+ m_dragState = std::make_unique<DragState>(drag, window, [&loop]() { loop.quit(); });
+ loop.exec();
+ dragResult = m_dragState->dropAction;
+ m_dragState.reset();
+ }
+
+ if (dragResult == Qt::IgnoreAction)
+ dragResult = QBasicDrag::drag(drag);
+
+ return dragResult;
+}
+
+void QWasmDrag::onNativeDragStarted(DragEvent *event)
+{
+ Q_ASSERT_X(event->type == EventType::DragStart, Q_FUNC_INFO,
+ "The event is not a DragStart event");
+ // It is possible for a drag start event to arrive from another window.
+ if (!m_dragState || m_dragState->window != event->targetWindow) {
+ event->cancelDragStart();
+ return;
+ }
+
+ m_dragState->dragImage = std::make_unique<DragState::DragImage>(
+ m_dragState->drag->pixmap(), m_dragState->drag->mimeData(), event->targetWindow);
+ event->dataTransfer.setDragImage(m_dragState->dragImage->htmlElement(),
+ m_dragState->drag->hotSpot());
+ event->dataTransfer.setDataFromMimeData(*m_dragState->drag->mimeData());
+}
+
+void QWasmDrag::onNativeDragOver(DragEvent *event)
+{
+ auto mimeDataPreview = event->dataTransfer.toMimeDataPreview();
+
+ const Qt::DropActions actions = m_dragState
+ ? m_dragState->drag->supportedActions()
+ : (Qt::DropAction::CopyAction | Qt::DropAction::MoveAction
+ | Qt::DropAction::LinkAction);
+
+ const auto dragResponse = QWindowSystemInterface::handleDrag(
+ event->targetWindow, &*mimeDataPreview, event->pointInPage.toPoint(), actions,
+ event->mouseButton, event->modifiers);
+ event->acceptDragOver();
+ if (dragResponse.isAccepted()) {
+ event->dataTransfer.setDropAction(dragResponse.acceptedAction());
+ } else {
+ event->dataTransfer.setDropAction(Qt::DropAction::IgnoreAction);
+ }
+}
+
+void QWasmDrag::onNativeDrop(DragEvent *event)
+{
+ QWasmWindow *wasmWindow = QWasmWindow::fromWindow(event->targetWindow);
+
+ const auto screenElementPos = dom::mapPoint(
+ event->target(), wasmWindow->platformScreen()->element(), event->localPoint);
+ const auto screenPos =
+ wasmWindow->platformScreen()->mapFromLocal(screenElementPos);
+ const QPoint targetWindowPos = event->targetWindow->mapFromGlobal(screenPos).toPoint();
+
+ const Qt::DropActions actions = m_dragState
+ ? m_dragState->drag->supportedActions()
+ : (Qt::DropAction::CopyAction | Qt::DropAction::MoveAction
+ | Qt::DropAction::LinkAction);
+ Qt::MouseButton mouseButton = event->mouseButton;
+ QFlags<Qt::KeyboardModifier> modifiers = event->modifiers;
+
+ // Accept the native drop event: We are going to async read any dropped
+ // files, but the browser expects that accepted state is set before any
+ // async calls.
+ event->acceptDrop();
+
+ const auto dropCallback = [&m_dragState = m_dragState, wasmWindow, targetWindowPos,
+ actions, mouseButton, modifiers](QMimeData *mimeData) {
+
+ auto dropResponse = std::make_shared<QPlatformDropQtResponse>(true, Qt::DropAction::CopyAction);
+ *dropResponse = QWindowSystemInterface::handleDrop(wasmWindow->window(), mimeData,
+ targetWindowPos, actions,
+ mouseButton, modifiers);
+
+ if (dropResponse->isAccepted())
+ m_dragState->dropAction = dropResponse->acceptedAction();
+
+ delete mimeData;
+ };
+
+ event->dataTransfer.toMimeDataWithFile(dropCallback);
+}
+
+void QWasmDrag::onNativeDragFinished(DragEvent *event)
+{
+ m_dragState->dropAction = event->dropAction;
+ m_dragState->quitEventLoopClosure();
+}
+
+QWasmDrag::DragState::DragImage::DragImage(const QPixmap &pixmap, const QMimeData *mimeData,
+ QWindow *window)
+ : m_temporaryImageElementParent(QWasmWindow::fromWindow(window)->containerElement())
+{
+ m_imageDomElement = generateDragImage(pixmap, mimeData);
+
+ m_imageDomElement.set("className", "hidden-drag-image");
+ m_temporaryImageElementParent.call<void>("appendChild", m_imageDomElement);
+}
+
+QWasmDrag::DragState::DragImage::~DragImage()
+{
+ m_temporaryImageElementParent.call<void>("removeChild", m_imageDomElement);
+}
+
+emscripten::val QWasmDrag::DragState::DragImage::generateDragImage(const QPixmap &pixmap,
+ const QMimeData *mimeData)
+{
+ if (!pixmap.isNull())
+ return generateDragImageFromPixmap(pixmap);
+ if (mimeData->hasFormat("text/plain"))
+ return generateDragImageFromText(mimeData);
+ return generateDefaultDragImage();
+}
+
+emscripten::val
+QWasmDrag::DragState::DragImage::generateDragImageFromText(const QMimeData *mimeData)
+{
+ emscripten::val dragImageElement =
+ emscripten::val::global("document")
+ .call<emscripten::val>("createElement", emscripten::val("span"));
+
+ constexpr qsizetype MaxCharactersInDragImage = 100;
+
+ const auto text = QString::fromUtf8(mimeData->data("text/plain"));
+ dragImageElement.set(
+ "innerText",
+ text.first(qMin(qsizetype(MaxCharactersInDragImage), text.length())).toStdString());
+ return dragImageElement;
+}
+
+emscripten::val QWasmDrag::DragState::DragImage::generateDefaultDragImage()
+{
+ emscripten::val dragImageElement =
+ emscripten::val::global("document")
+ .call<emscripten::val>("createElement", emscripten::val("div"));
+
+ auto innerImgElement = emscripten::val::global("document")
+ .call<emscripten::val>("createElement", emscripten::val("img"));
+ innerImgElement.set("src",
+ "data:image/" + std::string("svg+xml") + ";base64,"
+ + std::string(Base64IconStore::get()->getIcon(
+ Base64IconStore::IconType::QtLogo)));
+
+ constexpr char DragImageSize[] = "50px";
+
+ dragImageElement["style"].set("width", DragImageSize);
+ innerImgElement["style"].set("width", DragImageSize);
+ dragImageElement["style"].set("display", "flex");
+
+ dragImageElement.call<void>("appendChild", innerImgElement);
+ return dragImageElement;
+}
+
+emscripten::val QWasmDrag::DragState::DragImage::generateDragImageFromPixmap(const QPixmap &pixmap)
+{
+ emscripten::val dragImageElement =
+ emscripten::val::global("document")
+ .call<emscripten::val>("createElement", emscripten::val("canvas"));
+ dragImageElement.set("width", pixmap.width());
+ dragImageElement.set("height", pixmap.height());
+
+ dragImageElement["style"].set(
+ "width", std::to_string(pixmap.width() / pixmap.devicePixelRatio()) + "px");
+ dragImageElement["style"].set(
+ "height", std::to_string(pixmap.height() / pixmap.devicePixelRatio()) + "px");
+
+ auto context2d = dragImageElement.call<emscripten::val>("getContext", emscripten::val("2d"));
+ auto imageData = context2d.call<emscripten::val>(
+ "createImageData", emscripten::val(pixmap.width()), emscripten::val(pixmap.height()));
+
+ dom::drawImageToWebImageDataArray(pixmap.toImage().convertedTo(QImage::Format::Format_RGBA8888),
+ imageData, QRect(0, 0, pixmap.width(), pixmap.height()));
+ context2d.call<void>("putImageData", imageData, emscripten::val(0), emscripten::val(0));
+
+ return dragImageElement;
+}
+
+emscripten::val QWasmDrag::DragState::DragImage::htmlElement()
+{
+ return m_imageDomElement;
+}
+
+QWasmDrag::DragState::DragState(QDrag *drag, QWindow *window,
+ std::function<void()> quitEventLoopClosure)
+ : drag(drag), window(window), quitEventLoopClosure(std::move(quitEventLoopClosure))
+{
+}
+
+QWasmDrag::DragState::~DragState() = default;
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/wasm/qwasmdrag.h b/src/plugins/platforms/wasm/qwasmdrag.h
new file mode 100644
index 0000000000..146a69ebe8
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmdrag.h
@@ -0,0 +1,47 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef QWINDOWSDRAG_H
+#define QWINDOWSDRAG_H
+
+#include <private/qstdweb_p.h>
+#include <private/qsimpledrag_p.h>
+
+#include <qpa/qplatformdrag.h>
+#include <QtGui/qdrag.h>
+
+#include <memory>
+
+QT_BEGIN_NAMESPACE
+
+struct DragEvent;
+
+class QWasmDrag final : public QSimpleDrag
+{
+public:
+ QWasmDrag();
+ ~QWasmDrag() override;
+ QWasmDrag(const QWasmDrag &other) = delete;
+ QWasmDrag(QWasmDrag &&other) = delete;
+ QWasmDrag &operator=(const QWasmDrag &other) = delete;
+ QWasmDrag &operator=(QWasmDrag &&other) = delete;
+
+ static QWasmDrag *instance();
+
+ void onNativeDragOver(DragEvent *event);
+ void onNativeDrop(DragEvent *event);
+ void onNativeDragStarted(DragEvent *event);
+ void onNativeDragFinished(DragEvent *event);
+
+ // QPlatformDrag:
+ Qt::DropAction drag(QDrag *drag) final;
+
+private:
+ struct DragState;
+
+ std::unique_ptr<DragState> m_dragState;
+};
+
+QT_END_NAMESPACE
+
+#endif // QWINDOWSDRAG_H
diff --git a/src/plugins/platforms/wasm/qwasmevent.cpp b/src/plugins/platforms/wasm/qwasmevent.cpp
new file mode 100644
index 0000000000..c1d6ce3a2a
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmevent.cpp
@@ -0,0 +1,338 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "qwasmevent.h"
+
+#include "qwasmkeytranslator.h"
+
+#include <QtCore/private/qmakearray_p.h>
+#include <QtCore/private/qstringiterator_p.h>
+#include <QtCore/qregularexpression.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace {
+constexpr std::string_view WebDeadKeyValue = "Dead";
+
+bool isDeadKeyEvent(const char *key)
+{
+ return qstrncmp(key, WebDeadKeyValue.data(), WebDeadKeyValue.size()) == 0;
+}
+
+Qt::Key getKeyFromCode(const std::string &code)
+{
+ if (auto mapping = QWasmKeyTranslator::mapWebKeyTextToQtKey(code.c_str()))
+ return *mapping;
+
+ static QRegularExpression regex(QString(QStringLiteral(R"re((?:Key|Digit)(\w))re")));
+ const auto codeQString = QString::fromStdString(code);
+ const auto match = regex.match(codeQString);
+
+ if (!match.hasMatch())
+ return Qt::Key_unknown;
+
+ constexpr size_t CharacterIndex = 1;
+ return static_cast<Qt::Key>(match.capturedView(CharacterIndex).at(0).toLatin1());
+}
+
+Qt::Key webKeyToQtKey(const std::string &code, const std::string &key, bool isDeadKey,
+ QFlags<Qt::KeyboardModifier> modifiers)
+{
+ if (isDeadKey) {
+ auto mapped = getKeyFromCode(code);
+ switch (mapped) {
+ case Qt::Key_U:
+ return Qt::Key_Dead_Diaeresis;
+ case Qt::Key_E:
+ return Qt::Key_Dead_Acute;
+ case Qt::Key_I:
+ return Qt::Key_Dead_Circumflex;
+ case Qt::Key_N:
+ return Qt::Key_Dead_Tilde;
+ case Qt::Key_QuoteLeft:
+ return modifiers.testFlag(Qt::ShiftModifier) ? Qt::Key_Dead_Tilde : Qt::Key_Dead_Grave;
+ case Qt::Key_6:
+ return Qt::Key_Dead_Circumflex;
+ case Qt::Key_Apostrophe:
+ return modifiers.testFlag(Qt::ShiftModifier) ? Qt::Key_Dead_Diaeresis
+ : Qt::Key_Dead_Acute;
+ case Qt::Key_AsciiTilde:
+ return Qt::Key_Dead_Tilde;
+ default:
+ return Qt::Key_unknown;
+ }
+ } else if (auto mapping = QWasmKeyTranslator::mapWebKeyTextToQtKey(key.c_str())) {
+ return *mapping;
+ }
+
+ // cast to unicode key
+ QString str = QString::fromUtf8(key.c_str()).toUpper();
+ if (str.length() > 1)
+ return Qt::Key_unknown;
+
+ QStringIterator i(str);
+ return static_cast<Qt::Key>(i.next(0));
+}
+} // namespace
+
+namespace KeyboardModifier
+{
+template <>
+QFlags<Qt::KeyboardModifier> getForEvent<EmscriptenKeyboardEvent>(
+ const EmscriptenKeyboardEvent& event)
+{
+ return internal::Helper<EmscriptenKeyboardEvent>::getModifierForEvent(event) |
+ (event.location == DOM_KEY_LOCATION_NUMPAD ? Qt::KeypadModifier : Qt::NoModifier);
+}
+} // namespace KeyboardModifier
+
+Event::Event(EventType type, emscripten::val webEvent)
+ : webEvent(webEvent), type(type)
+{
+}
+
+Event::~Event() = default;
+
+Event::Event(const Event &other) = default;
+
+Event::Event(Event &&other) = default;
+
+Event &Event::operator=(const Event &other) = default;
+
+Event &Event::operator=(Event &&other) = default;
+
+KeyEvent::KeyEvent(EventType type, emscripten::val event) : Event(type, event)
+{
+ const auto code = event["code"].as<std::string>();
+ const auto webKey = event["key"].as<std::string>();
+ deadKey = isDeadKeyEvent(webKey.c_str());
+
+ modifiers = KeyboardModifier::getForEvent(event);
+ key = webKeyToQtKey(code, webKey, deadKey, modifiers);
+
+ text = QString::fromUtf8(webKey);
+ if (text.size() > 1)
+ text.clear();
+
+ if (key == Qt::Key_Tab)
+ text = "\t";
+}
+
+KeyEvent::~KeyEvent() = default;
+
+KeyEvent::KeyEvent(const KeyEvent &other) = default;
+
+KeyEvent::KeyEvent(KeyEvent &&other) = default;
+
+KeyEvent &KeyEvent::operator=(const KeyEvent &other) = default;
+
+KeyEvent &KeyEvent::operator=(KeyEvent &&other) = default;
+
+std::optional<KeyEvent> KeyEvent::fromWebWithDeadKeyTranslation(emscripten::val event,
+ QWasmDeadKeySupport *deadKeySupport)
+{
+ const auto eventType = ([&event]() -> std::optional<EventType> {
+ const auto eventTypeString = event["type"].as<std::string>();
+
+ if (eventTypeString == "keydown")
+ return EventType::KeyDown;
+ else if (eventTypeString == "keyup")
+ return EventType::KeyUp;
+ return std::nullopt;
+ })();
+ if (!eventType)
+ return std::nullopt;
+
+ auto result = KeyEvent(*eventType, event);
+ deadKeySupport->applyDeadKeyTranslations(&result);
+
+ return result;
+}
+
+MouseEvent::MouseEvent(EventType type, emscripten::val event) : Event(type, event)
+{
+ mouseButton = MouseEvent::buttonFromWeb(event["button"].as<int>());
+ mouseButtons = MouseEvent::buttonsFromWeb(event["buttons"].as<unsigned short>());
+ // The current button state (event.buttons) may be out of sync for some PointerDown
+ // events where the "down" state is very brief, for example taps on Apple trackpads.
+ // Qt expects that the current button state is in sync with the event, so we sync
+ // it up here.
+ if (type == EventType::PointerDown)
+ mouseButtons |= mouseButton;
+ localPoint = QPointF(event["offsetX"].as<qreal>(), event["offsetY"].as<qreal>());
+ pointInPage = QPointF(event["pageX"].as<qreal>(), event["pageY"].as<qreal>());
+ pointInViewport = QPointF(event["clientX"].as<qreal>(), event["clientY"].as<qreal>());
+ modifiers = KeyboardModifier::getForEvent(event);
+}
+
+MouseEvent::~MouseEvent() = default;
+
+MouseEvent::MouseEvent(const MouseEvent &other) = default;
+
+MouseEvent::MouseEvent(MouseEvent &&other) = default;
+
+MouseEvent &MouseEvent::operator=(const MouseEvent &other) = default;
+
+MouseEvent &MouseEvent::operator=(MouseEvent &&other) = default;
+
+PointerEvent::PointerEvent(EventType type, emscripten::val event) : MouseEvent(type, event)
+{
+ pointerId = event["pointerId"].as<int>();
+ pointerType = ([type = event["pointerType"].as<std::string>()]() {
+ if (type == "mouse")
+ return PointerType::Mouse;
+ if (type == "touch")
+ return PointerType::Touch;
+ if (type == "pen")
+ return PointerType::Pen;
+ return PointerType::Other;
+ })();
+ width = event["width"].as<qreal>();
+ height = event["height"].as<qreal>();
+ pressure = event["pressure"].as<qreal>();
+ tiltX = event["tiltX"].as<qreal>();
+ tiltY = event["tiltY"].as<qreal>();
+ tangentialPressure = event["tangentialPressure"].as<qreal>();
+ twist = event["twist"].as<qreal>();
+ isPrimary = event["isPrimary"].as<bool>();
+}
+
+PointerEvent::~PointerEvent() = default;
+
+PointerEvent::PointerEvent(const PointerEvent &other) = default;
+
+PointerEvent::PointerEvent(PointerEvent &&other) = default;
+
+PointerEvent &PointerEvent::operator=(const PointerEvent &other) = default;
+
+PointerEvent &PointerEvent::operator=(PointerEvent &&other) = default;
+
+std::optional<PointerEvent> PointerEvent::fromWeb(emscripten::val event)
+{
+ const auto eventType = ([&event]() -> std::optional<EventType> {
+ const auto eventTypeString = event["type"].as<std::string>();
+
+ if (eventTypeString == "pointermove")
+ return EventType::PointerMove;
+ else if (eventTypeString == "pointerup")
+ return EventType::PointerUp;
+ else if (eventTypeString == "pointerdown")
+ return EventType::PointerDown;
+ else if (eventTypeString == "pointerenter")
+ return EventType::PointerEnter;
+ else if (eventTypeString == "pointerleave")
+ return EventType::PointerLeave;
+ return std::nullopt;
+ })();
+ if (!eventType)
+ return std::nullopt;
+
+ return PointerEvent(*eventType, event);
+}
+
+DragEvent::DragEvent(EventType type, emscripten::val event, QWindow *window)
+ : MouseEvent(type, event), dataTransfer(event["dataTransfer"]), targetWindow(window)
+{
+ dropAction = ([event]() {
+ const std::string effect = event["dataTransfer"]["dropEffect"].as<std::string>();
+
+ if (effect == "copy")
+ return Qt::CopyAction;
+ else if (effect == "move")
+ return Qt::MoveAction;
+ else if (effect == "link")
+ return Qt::LinkAction;
+ return Qt::IgnoreAction;
+ })();
+}
+
+DragEvent::~DragEvent() = default;
+
+DragEvent::DragEvent(const DragEvent &other) = default;
+
+DragEvent::DragEvent(DragEvent &&other) = default;
+
+DragEvent &DragEvent::operator=(const DragEvent &other) = default;
+
+DragEvent &DragEvent::operator=(DragEvent &&other) = default;
+
+std::optional<DragEvent> DragEvent::fromWeb(emscripten::val event, QWindow *targetWindow)
+{
+ const auto eventType = ([&event]() -> std::optional<EventType> {
+ const auto eventTypeString = event["type"].as<std::string>();
+
+ if (eventTypeString == "dragend")
+ return EventType::DragEnd;
+ if (eventTypeString == "dragover")
+ return EventType::DragOver;
+ if (eventTypeString == "dragstart")
+ return EventType::DragStart;
+ if (eventTypeString == "drop")
+ return EventType::Drop;
+ return std::nullopt;
+ })();
+ if (!eventType)
+ return std::nullopt;
+ return DragEvent(*eventType, event, targetWindow);
+}
+
+void DragEvent::cancelDragStart()
+{
+ Q_ASSERT_X(type == EventType::DragStart, Q_FUNC_INFO, "Only supported for DragStart");
+ webEvent.call<void>("preventDefault");
+}
+
+void DragEvent::acceptDragOver()
+{
+ Q_ASSERT_X(type == EventType::DragOver, Q_FUNC_INFO, "Only supported for DragOver");
+ webEvent.call<void>("preventDefault");
+}
+
+void DragEvent::acceptDrop()
+{
+ Q_ASSERT_X(type == EventType::Drop, Q_FUNC_INFO, "Only supported for Drop");
+ webEvent.call<void>("preventDefault");
+}
+
+WheelEvent::WheelEvent(EventType type, emscripten::val event) : MouseEvent(type, event)
+{
+ deltaMode = ([event]() {
+ const int deltaMode = event["deltaMode"].as<int>();
+ const auto jsWheelEventType = emscripten::val::global("WheelEvent");
+ if (deltaMode == jsWheelEventType["DOM_DELTA_PIXEL"].as<int>())
+ return DeltaMode::Pixel;
+ else if (deltaMode == jsWheelEventType["DOM_DELTA_LINE"].as<int>())
+ return DeltaMode::Line;
+ return DeltaMode::Page;
+ })();
+
+ delta = QPointF(event["deltaX"].as<qreal>(), event["deltaY"].as<qreal>());
+
+ webkitDirectionInvertedFromDevice = event["webkitDirectionInvertedFromDevice"].as<bool>();
+}
+
+WheelEvent::~WheelEvent() = default;
+
+WheelEvent::WheelEvent(const WheelEvent &other) = default;
+
+WheelEvent::WheelEvent(WheelEvent &&other) = default;
+
+WheelEvent &WheelEvent::operator=(const WheelEvent &other) = default;
+
+WheelEvent &WheelEvent::operator=(WheelEvent &&other) = default;
+
+std::optional<WheelEvent> WheelEvent::fromWeb(emscripten::val event)
+{
+ const auto eventType = ([&event]() -> std::optional<EventType> {
+ const auto eventTypeString = event["type"].as<std::string>();
+
+ if (eventTypeString == "wheel")
+ return EventType::Wheel;
+ return std::nullopt;
+ })();
+ if (!eventType)
+ return std::nullopt;
+ return WheelEvent(*eventType, event);
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/wasm/qwasmevent.h b/src/plugins/platforms/wasm/qwasmevent.h
new file mode 100644
index 0000000000..6ada5393e3
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmevent.h
@@ -0,0 +1,271 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef QWASMEVENT_H
+#define QWASMEVENT_H
+
+#include "qwasmplatform.h"
+#include "qwasmdom.h"
+
+#include <QtCore/qglobal.h>
+#include <QtCore/qnamespace.h>
+#include <QtGui/qevent.h>
+#include <private/qstdweb_p.h>
+#include <QPoint>
+
+#include <emscripten/html5.h>
+#include <emscripten/val.h>
+
+QT_BEGIN_NAMESPACE
+
+class QWasmDeadKeySupport;
+class QWindow;
+
+enum class EventType {
+ DragEnd,
+ DragOver,
+ DragStart,
+ Drop,
+ KeyDown,
+ KeyUp,
+ PointerDown,
+ PointerMove,
+ PointerUp,
+ PointerEnter,
+ PointerLeave,
+ PointerCancel,
+ Wheel,
+};
+
+enum class PointerType {
+ Mouse,
+ Touch,
+ Pen,
+ Other,
+};
+
+enum class WindowArea {
+ NonClient,
+ Client,
+};
+
+enum class DeltaMode { Pixel, Line, Page };
+
+namespace KeyboardModifier {
+namespace internal
+{
+ // Check for the existence of shiftKey, ctrlKey, altKey and metaKey in a type.
+ // Based on that, we can safely assume we are dealing with an emscripten event type.
+ template<typename T>
+ struct IsEmscriptenEvent
+ {
+ template<typename U, EM_BOOL U::*, EM_BOOL U::*, EM_BOOL U::*, EM_BOOL U::*>
+ struct SFINAE {};
+ template<typename U> static char Test(
+ SFINAE<U, &U::shiftKey, &U::ctrlKey, &U::altKey, &U::metaKey>*);
+ template<typename U> static int Test(...);
+ static const bool value = sizeof(Test<T>(0)) == sizeof(char);
+ };
+
+ template<class T, typename Enable = void>
+ struct Helper;
+
+ template<class T>
+ struct Helper<T, std::enable_if_t<IsEmscriptenEvent<T>::value>>
+ {
+ static QFlags<Qt::KeyboardModifier> getModifierForEvent(const T& event) {
+ QFlags<Qt::KeyboardModifier> keyModifier = Qt::NoModifier;
+ if (event.shiftKey)
+ keyModifier |= Qt::ShiftModifier;
+ if (event.ctrlKey)
+ keyModifier |= platform() == Platform::MacOS ? Qt::MetaModifier : Qt::ControlModifier;
+ if (event.altKey)
+ keyModifier |= Qt::AltModifier;
+ if (event.metaKey)
+ keyModifier |= platform() == Platform::MacOS ? Qt::ControlModifier : Qt::MetaModifier;
+
+ return keyModifier;
+ }
+ };
+
+ template<>
+ struct Helper<emscripten::val>
+ {
+ static QFlags<Qt::KeyboardModifier> getModifierForEvent(const emscripten::val& event) {
+ QFlags<Qt::KeyboardModifier> keyModifier = Qt::NoModifier;
+ if (event["shiftKey"].as<bool>())
+ keyModifier |= Qt::ShiftModifier;
+ if (event["ctrlKey"].as<bool>())
+ keyModifier |= platform() == Platform::MacOS ? Qt::MetaModifier : Qt::ControlModifier;
+ if (event["altKey"].as<bool>())
+ keyModifier |= Qt::AltModifier;
+ if (event["metaKey"].as<bool>())
+ keyModifier |= platform() == Platform::MacOS ? Qt::ControlModifier : Qt::MetaModifier;
+ if (event["constructor"]["name"].as<std::string>() == "KeyboardEvent" &&
+ event["location"].as<unsigned int>() == DOM_KEY_LOCATION_NUMPAD) {
+ keyModifier |= Qt::KeypadModifier;
+ }
+
+ return keyModifier;
+ }
+ };
+} // namespace internal
+
+template <typename Event>
+QFlags<Qt::KeyboardModifier> getForEvent(const Event& event)
+{
+ return internal::Helper<Event>::getModifierForEvent(event);
+}
+
+template <>
+QFlags<Qt::KeyboardModifier> getForEvent<EmscriptenKeyboardEvent>(
+ const EmscriptenKeyboardEvent& event);
+
+} // namespace KeyboardModifier
+
+struct Event
+{
+ Event(EventType type, emscripten::val webEvent);
+ ~Event();
+ Event(const Event &other);
+ Event(Event &&other);
+ Event &operator=(const Event &other);
+ Event &operator=(Event &&other);
+
+ emscripten::val webEvent;
+ EventType type;
+ emscripten::val target() const { return webEvent["target"]; }
+};
+
+struct KeyEvent : public Event
+{
+ static std::optional<KeyEvent>
+ fromWebWithDeadKeyTranslation(emscripten::val webEvent, QWasmDeadKeySupport *deadKeySupport);
+
+ KeyEvent(EventType type, emscripten::val webEvent);
+ ~KeyEvent();
+ KeyEvent(const KeyEvent &other);
+ KeyEvent(KeyEvent &&other);
+ KeyEvent &operator=(const KeyEvent &other);
+ KeyEvent &operator=(KeyEvent &&other);
+
+ Qt::Key key;
+ QFlags<Qt::KeyboardModifier> modifiers;
+ bool deadKey;
+ QString text;
+};
+
+struct MouseEvent : public Event
+{
+ MouseEvent(EventType type, emscripten::val webEvent);
+ ~MouseEvent();
+ MouseEvent(const MouseEvent &other);
+ MouseEvent(MouseEvent &&other);
+ MouseEvent &operator=(const MouseEvent &other);
+ MouseEvent &operator=(MouseEvent &&other);
+
+ static constexpr Qt::MouseButton buttonFromWeb(int webButton) {
+ switch (webButton) {
+ case 0:
+ return Qt::LeftButton;
+ case 1:
+ return Qt::MiddleButton;
+ case 2:
+ return Qt::RightButton;
+ default:
+ return Qt::NoButton;
+ }
+ }
+
+ static constexpr Qt::MouseButtons buttonsFromWeb(unsigned short webButtons) {
+ // Coincidentally, Qt and web bitfields match.
+ return Qt::MouseButtons::fromInt(webButtons);
+ }
+
+ static constexpr QEvent::Type mouseEventTypeFromEventType(
+ EventType eventType, WindowArea windowArea) {
+ switch (eventType) {
+ case EventType::PointerDown :
+ return windowArea == WindowArea::Client ?
+ QEvent::MouseButtonPress : QEvent::NonClientAreaMouseButtonPress;
+ case EventType::PointerUp :
+ return windowArea == WindowArea::Client ?
+ QEvent::MouseButtonRelease : QEvent::NonClientAreaMouseButtonRelease;
+ case EventType::PointerMove :
+ return windowArea == WindowArea::Client ?
+ QEvent::MouseMove : QEvent::NonClientAreaMouseMove;
+ default:
+ return QEvent::None;
+ }
+ }
+
+ QPointF localPoint;
+ QPointF pointInPage;
+ QPointF pointInViewport;
+ Qt::MouseButton mouseButton;
+ Qt::MouseButtons mouseButtons;
+ QFlags<Qt::KeyboardModifier> modifiers;
+};
+
+struct PointerEvent : public MouseEvent
+{
+ static std::optional<PointerEvent> fromWeb(emscripten::val webEvent);
+
+ PointerEvent(EventType type, emscripten::val webEvent);
+ ~PointerEvent();
+ PointerEvent(const PointerEvent &other);
+ PointerEvent(PointerEvent &&other);
+ PointerEvent &operator=(const PointerEvent &other);
+ PointerEvent &operator=(PointerEvent &&other);
+
+ PointerType pointerType;
+ int pointerId;
+ qreal pressure;
+ qreal tiltX;
+ qreal tiltY;
+ qreal tangentialPressure;
+ qreal twist;
+ qreal width;
+ qreal height;
+ bool isPrimary;
+};
+
+struct DragEvent : public MouseEvent
+{
+ static std::optional<DragEvent> fromWeb(emscripten::val webEvent, QWindow *targetQWindow);
+
+ DragEvent(EventType type, emscripten::val webEvent, QWindow *targetQWindow);
+ ~DragEvent();
+ DragEvent(const DragEvent &other);
+ DragEvent(DragEvent &&other);
+ DragEvent &operator=(const DragEvent &other);
+ DragEvent &operator=(DragEvent &&other);
+
+ void cancelDragStart();
+ void acceptDragOver();
+ void acceptDrop();
+
+ Qt::DropAction dropAction;
+ dom::DataTransfer dataTransfer;
+ QWindow *targetWindow;
+};
+
+struct WheelEvent : public MouseEvent
+{
+ static std::optional<WheelEvent> fromWeb(emscripten::val webEvent);
+
+ WheelEvent(EventType type, emscripten::val webEvent);
+ ~WheelEvent();
+ WheelEvent(const WheelEvent &other);
+ WheelEvent(WheelEvent &&other);
+ WheelEvent &operator=(const WheelEvent &other);
+ WheelEvent &operator=(WheelEvent &&other);
+
+ DeltaMode deltaMode;
+ bool webkitDirectionInvertedFromDevice;
+ QPointF delta;
+};
+
+QT_END_NAMESPACE
+
+#endif // QWASMEVENT_H
diff --git a/src/plugins/platforms/wasm/qwasmeventdispatcher.cpp b/src/plugins/platforms/wasm/qwasmeventdispatcher.cpp
index ca8db9b215..1f2d3095d6 100644
--- a/src/plugins/platforms/wasm/qwasmeventdispatcher.cpp
+++ b/src/plugins/platforms/wasm/qwasmeventdispatcher.cpp
@@ -1,206 +1,35 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the plugins of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL$
-** 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 General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 or (at your option) 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.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-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include "qwasmeventdispatcher.h"
+#include "qwasmintegration.h"
-#include <QtCore/qcoreapplication.h>
+#include <QtGui/qpa/qwindowsysteminterface.h>
-#include <emscripten.h>
+QT_BEGIN_NAMESPACE
-#if QT_CONFIG(thread)
-#if (__EMSCRIPTEN_major__ > 1 || __EMSCRIPTEN_minor__ > 38 || __EMSCRIPTEN_minor__ == 38 && __EMSCRIPTEN_tiny__ >= 22)
-# define EMSCRIPTEN_HAS_ASYNC_RUN_IN_MAIN_RUNTIME_THREAD
-#endif
-#endif
-
-#ifdef EMSCRIPTEN_HAS_ASYNC_RUN_IN_MAIN_RUNTIME_THREAD
-#include <emscripten/threading.h>
-#endif
-
-class QWasmEventDispatcherPrivate : public QEventDispatcherUNIXPrivate
-{
-
-};
-
-QWasmEventDispatcher *g_htmlEventDispatcher;
-
-QWasmEventDispatcher::QWasmEventDispatcher(QObject *parent)
- : QUnixEventDispatcherQPA(parent)
+// Note: All event dispatcher functionality is implemented in QEventDispatcherWasm
+// in QtCore, except for processPostedEvents() below which uses API from QtGui.
+bool QWasmEventDispatcher::processPostedEvents()
{
-
- g_htmlEventDispatcher = this;
+ QEventDispatcherWasm::processPostedEvents();
+ return QWindowSystemInterface::sendWindowSystemEvents(QEventLoop::AllEvents);
}
-QWasmEventDispatcher::~QWasmEventDispatcher()
+void QWasmEventDispatcher::onLoaded()
{
- g_htmlEventDispatcher = nullptr;
-}
-
-bool QWasmEventDispatcher::registerRequestUpdateCallback(std::function<void(void)> callback)
-{
- if (!g_htmlEventDispatcher || !g_htmlEventDispatcher->m_hasMainLoop)
- return false;
-
- g_htmlEventDispatcher->m_requestUpdateCallbacks.append(callback);
- emscripten_resume_main_loop();
- return true;
-}
+ // This function is called when the application is ready to paint
+ // the first frame. Send the qtlaoder onLoaded event first (via
+ // the base class implementation), and then enable/call requestUpdate
+ // to deliver a frame.
+ QEventDispatcherWasm::onLoaded();
-void QWasmEventDispatcher::maintainTimers()
-{
- if (!g_htmlEventDispatcher || !g_htmlEventDispatcher->m_hasMainLoop)
- return;
+ // Make sure all screens have a defined size; and pick
+ // up size changes due to onLoaded event handling.
+ QWasmIntegration *wasmIntegration = QWasmIntegration::get();
+ wasmIntegration->resizeAllScreens();
- g_htmlEventDispatcher->doMaintainTimers();
+ wasmIntegration->releaseRequesetUpdateHold();
}
-bool QWasmEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags)
-{
- // WaitForMoreEvents is not supported (except for in combination with EventLoopExec below),
- // and we don't want the unix event dispatcher base class to attempt to wait either.
- flags &= ~QEventLoop::WaitForMoreEvents;
-
- // Handle normal processEvents.
- if (!(flags & QEventLoop::EventLoopExec))
- return QUnixEventDispatcherQPA::processEvents(flags);
-
- // Handle processEvents from QEventLoop::exec():
- //
- // At this point the application has created its root objects on
- // the stack and has called app.exec() which has called into this
- // function via QEventLoop.
- //
- // The application now expects that exec() will not return until
- // app exit time. However, the browser expects that we return
- // control to it periodically, also after initial setup in main().
-
- // EventLoopExec for nested event loops is not supported.
- Q_ASSERT(!m_hasMainLoop);
- m_hasMainLoop = true;
-
- // Call emscripten_set_main_loop_arg() with a callback which processes
- // events. Also set simulateInfiniteLoop to true which makes emscripten
- // return control to the browser without unwinding the C++ stack.
- auto callback = [](void *eventDispatcher) {
- QWasmEventDispatcher *that = static_cast<QWasmEventDispatcher *>(eventDispatcher);
-
- // Save and clear updateRequest callbacks so we can register new ones
- auto requestUpdateCallbacksCopy = that->m_requestUpdateCallbacks;
- that->m_requestUpdateCallbacks.clear();
-
- // Repaint all windows
- for (auto callback : qAsConst(requestUpdateCallbacksCopy))
- callback();
-
- // Pause main loop if no updates were requested. Updates will be
- // restarted again by registerRequestUpdateCallback().
- if (that->m_requestUpdateCallbacks.isEmpty())
- emscripten_pause_main_loop();
-
- that->doMaintainTimers();
- };
- int fps = 0; // update using requestAnimationFrame
- int simulateInfiniteLoop = 1;
- emscripten_set_main_loop_arg(callback, this, fps, simulateInfiniteLoop);
-
- // Note: the above call never returns, not even at app exit
- return false;
-}
-
-void QWasmEventDispatcher::doMaintainTimers()
-{
- Q_D(QWasmEventDispatcher);
-
- // This functon schedules native timers in order to wake up to
- // process events and activate Qt timers. This is done using the
- // emscripten_async_call() API which schedules a new timer.
- // There is unfortunately no way to cancel or update a current
- // native timer.
-
- // Schedule a zero-timer to continue processing any pending events.
- if (!m_hasZeroTimer && hasPendingEvents()) {
- auto callback = [](void *eventDispatcher) {
- QWasmEventDispatcher *that = static_cast<QWasmEventDispatcher *>(eventDispatcher);
- that->m_hasZeroTimer = false;
- that->QUnixEventDispatcherQPA::processEvents(QEventLoop::AllEvents);
-
- // Processing events may have posted new events or created new timers
- that->doMaintainTimers();
- };
-
- emscripten_async_call(callback, this, 0);
- m_hasZeroTimer = true;
- return;
- }
-
- auto timespecToNanosec = [](timespec ts) -> uint64_t { return ts.tv_sec * 1000 + ts.tv_nsec / (1000 * 1000); };
-
- // Get current time and time-to-first-Qt-timer. This polls for system
- // time, and we use this time as the current time for the duration of this call.
- timespec toWait;
- bool hasTimers = d->timerList.timerWait(toWait);
- if (!hasTimers)
- return; // no timer needed
-
- uint64_t currentTime = timespecToNanosec(d->timerList.currentTime);
- uint64_t toWaitDuration = timespecToNanosec(toWait);
-
- // The currently scheduled timer target is stored in m_currentTargetTime.
- // We can re-use it if the new target is equivalent or later.
- uint64_t newTargetTime = currentTime + toWaitDuration;
- if (newTargetTime >= m_currentTargetTime)
- return; // existing timer is good
-
- // Schedule a native timer with a callback which processes events (and timers)
- auto callback = [](void *eventDispatcher) {
- QWasmEventDispatcher *that = static_cast<QWasmEventDispatcher *>(eventDispatcher);
- that->m_currentTargetTime = std::numeric_limits<uint64_t>::max();
- that->QUnixEventDispatcherQPA::processEvents(QEventLoop::AllEvents);
-
- // Processing events may have posted new events or created new timers
- that->doMaintainTimers();
- };
- emscripten_async_call(callback, this, toWaitDuration);
- m_currentTargetTime = newTargetTime;
-}
-
-void QWasmEventDispatcher::wakeUp()
-{
-#ifdef EMSCRIPTEN_HAS_ASYNC_RUN_IN_MAIN_RUNTIME_THREAD
- if (!emscripten_is_main_runtime_thread())
- emscripten_async_run_in_main_runtime_thread_(EM_FUNC_SIG_VI, (void*)(&QWasmEventDispatcher::mainThreadWakeUp), this);
-#endif
- QEventDispatcherUNIX::wakeUp();
-}
-
-void QWasmEventDispatcher::mainThreadWakeUp(void *eventDispatcher)
-{
- emscripten_resume_main_loop(); // Service possible requestUpdate Calls
- static_cast<QWasmEventDispatcher *>(eventDispatcher)->processEvents(QEventLoop::AllEvents);
-}
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/wasm/qwasmeventdispatcher.h b/src/plugins/platforms/wasm/qwasmeventdispatcher.h
index f72d92ce07..cbf10482e3 100644
--- a/src/plugins/platforms/wasm/qwasmeventdispatcher.h
+++ b/src/plugins/platforms/wasm/qwasmeventdispatcher.h
@@ -1,64 +1,18 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the plugins of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL$
-** 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 General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 or (at your option) 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.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-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#ifndef QWASMEVENTDISPATCHER_H
#define QWASMEVENTDISPATCHER_H
-#include <QtCore/qhash.h>
-#include <QtCore/qloggingcategory.h>
-#include <QtEventDispatcherSupport/private/qunixeventdispatcher_qpa_p.h>
+#include <QtCore/private/qeventdispatcher_wasm_p.h>
QT_BEGIN_NAMESPACE
-class QWasmEventDispatcherPrivate;
-
-class QWasmEventDispatcher : public QUnixEventDispatcherQPA
+class QWasmEventDispatcher : public QEventDispatcherWasm
{
- Q_DECLARE_PRIVATE(QWasmEventDispatcher)
-public:
- explicit QWasmEventDispatcher(QObject *parent = nullptr);
- ~QWasmEventDispatcher();
-
- static bool registerRequestUpdateCallback(std::function<void(void)> callback);
- static void maintainTimers();
-
protected:
- bool processEvents(QEventLoop::ProcessEventsFlags flags) override;
- void doMaintainTimers();
- void wakeUp() override;
- static void mainThreadWakeUp(void *eventDispatcher);
-
-private:
- bool m_hasMainLoop = false;
- bool m_hasZeroTimer = false;
- uint64_t m_currentTargetTime = std::numeric_limits<uint64_t>::max();
- QVector<std::function<void(void)>> m_requestUpdateCallbacks;
+ bool processPostedEvents() override;
+ void onLoaded() override;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/wasm/qwasmeventtranslator.cpp b/src/plugins/platforms/wasm/qwasmeventtranslator.cpp
deleted file mode 100644
index 3e6043b083..0000000000
--- a/src/plugins/platforms/wasm/qwasmeventtranslator.cpp
+++ /dev/null
@@ -1,967 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the plugins of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL$
-** 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 General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 or (at your option) 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.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-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qwasmeventtranslator.h"
-#include "qwasmeventdispatcher.h"
-#include "qwasmcompositor.h"
-#include "qwasmintegration.h"
-#include "qwasmclipboard.h"
-#include "qwasmstring.h"
-
-#include <QtGui/qevent.h>
-#include <qpa/qwindowsysteminterface.h>
-#include <QtCore/qcoreapplication.h>
-#include <QtCore/qglobal.h>
-#include <QtCore/qobject.h>
-
-#include <QtCore/qdeadlinetimer.h>
-#include <private/qmakearray_p.h>
-#include <QtCore/qnamespace.h>
-
-#include <emscripten/bind.h>
-
-#include <iostream>
-
-using namespace emscripten;
-
-QT_BEGIN_NAMESPACE
-
-typedef struct emkb2qt {
- const char *em;
- unsigned int qt;
-
- constexpr bool operator <=(const emkb2qt &that) const noexcept
- {
- return !(strcmp(that) > 0);
- }
-
- bool operator <(const emkb2qt &that) const noexcept
- {
- return ::strcmp(em, that.em) < 0;
- }
- constexpr int strcmp(const emkb2qt &that, const int i = 0) const
- {
- return em[i] == 0 && that.em[i] == 0 ? 0
- : em[i] == 0 ? -1
- : that.em[i] == 0 ? 1
- : em[i] < that.em[i] ? -1
- : em[i] > that.em[i] ? 1
- : strcmp(that, i + 1);
- }
-} emkb2qt_t;
-
-template<unsigned int Qt, char ... EmChar>
-struct Emkb2Qt
-{
- static constexpr const char storage[sizeof ... (EmChar) + 1] = {EmChar..., '\0'};
- using Type = emkb2qt_t;
- static constexpr Type data() noexcept { return Type{storage, Qt}; }
-};
-
-template<unsigned int Qt, char ... EmChar> constexpr char Emkb2Qt<Qt, EmChar...>::storage[];
-
-static constexpr const auto KeyTbl = qMakeArray(
- QSortedData<
- Emkb2Qt< Qt::Key_Escape, 'E','s','c','a','p','e' >,
- Emkb2Qt< Qt::Key_Tab, 'T','a','b' >,
- Emkb2Qt< Qt::Key_Backspace, 'B','a','c','k','s','p','a','c','e' >,
- Emkb2Qt< Qt::Key_Return, 'E','n','t','e','r' >,
- Emkb2Qt< Qt::Key_Insert, 'I','n','s','e','r','t' >,
- Emkb2Qt< Qt::Key_Delete, 'D','e','l','e','t','e' >,
- Emkb2Qt< Qt::Key_Pause, 'P','a','u','s','e' >,
- Emkb2Qt< Qt::Key_Pause, 'C','l','e','a','r' >,
- Emkb2Qt< Qt::Key_Home, 'H','o','m','e' >,
- Emkb2Qt< Qt::Key_End, 'E','n','d' >,
- Emkb2Qt< Qt::Key_Left, 'A','r','r','o','w','L','e','f','t' >,
- Emkb2Qt< Qt::Key_Up, 'A','r','r','o','w','U','p' >,
- Emkb2Qt< Qt::Key_Right, 'A','r','r','o','w','R','i','g','h','t' >,
- Emkb2Qt< Qt::Key_Down, 'A','r','r','o','w','D','o','w','n' >,
- Emkb2Qt< Qt::Key_PageUp, 'P','a','g','e','U','p' >,
- Emkb2Qt< Qt::Key_PageDown, 'P','a','g','e','D','o','w','n' >,
- Emkb2Qt< Qt::Key_Shift, 'S','h','i','f','t' >,
- Emkb2Qt< Qt::Key_Control, 'C','o','n','t','r','o','l' >,
- Emkb2Qt< Qt::Key_Meta, 'O','S'>,
- Emkb2Qt< Qt::Key_Alt, 'A','l','t','L','e','f','t' >,
- Emkb2Qt< Qt::Key_Alt, 'A','l','t' >,
- Emkb2Qt< Qt::Key_CapsLock, 'C','a','p','s','L','o','c','k' >,
- Emkb2Qt< Qt::Key_NumLock, 'N','u','m','L','o','c','k' >,
- Emkb2Qt< Qt::Key_ScrollLock, 'S','c','r','o','l','l','L','o','c','k' >,
- Emkb2Qt< Qt::Key_F1, 'F','1' >,
- Emkb2Qt< Qt::Key_F2, 'F','2' >,
- Emkb2Qt< Qt::Key_F3, 'F','3' >,
- Emkb2Qt< Qt::Key_F4, 'F','4' >,
- Emkb2Qt< Qt::Key_F5, 'F','5' >,
- Emkb2Qt< Qt::Key_F6, 'F','6' >,
- Emkb2Qt< Qt::Key_F7, 'F','7' >,
- Emkb2Qt< Qt::Key_F8, 'F','8' >,
- Emkb2Qt< Qt::Key_F9, 'F','9' >,
- Emkb2Qt< Qt::Key_F10, 'F','1','0' >,
- Emkb2Qt< Qt::Key_F11, 'F','1','1' >,
- Emkb2Qt< Qt::Key_F12, 'F','1','2' >,
- Emkb2Qt< Qt::Key_F13, 'F','1','3' >,
- Emkb2Qt< Qt::Key_F14, 'F','1','4' >,
- Emkb2Qt< Qt::Key_F15, 'F','1','5' >,
- Emkb2Qt< Qt::Key_F16, 'F','1','6' >,
- Emkb2Qt< Qt::Key_F17, 'F','1','7' >,
- Emkb2Qt< Qt::Key_F18, 'F','1','8' >,
- Emkb2Qt< Qt::Key_F19, 'F','1','9' >,
- Emkb2Qt< Qt::Key_F20, 'F','2','0' >,
- Emkb2Qt< Qt::Key_F21, 'F','2','1' >,
- Emkb2Qt< Qt::Key_F22, 'F','2','2' >,
- Emkb2Qt< Qt::Key_F23, 'F','2','3' >,
- Emkb2Qt< Qt::Key_Space, ' ' >,
- Emkb2Qt< Qt::Key_Comma, ',' >,
- Emkb2Qt< Qt::Key_Minus, '-' >,
- Emkb2Qt< Qt::Key_Period, '.' >,
- Emkb2Qt< Qt::Key_Slash, '/' >,
- Emkb2Qt< Qt::Key_0, 'D','i','g','i','t','0' >,
- Emkb2Qt< Qt::Key_1, 'D','i','g','i','t','1' >,
- Emkb2Qt< Qt::Key_2, 'D','i','g','i','t','2' >,
- Emkb2Qt< Qt::Key_3, 'D','i','g','i','t','3' >,
- Emkb2Qt< Qt::Key_4, 'D','i','g','i','t','4' >,
- Emkb2Qt< Qt::Key_5, 'D','i','g','i','t','5' >,
- Emkb2Qt< Qt::Key_6, 'D','i','g','i','t','6' >,
- Emkb2Qt< Qt::Key_7, 'D','i','g','i','t','7' >,
- Emkb2Qt< Qt::Key_8, 'D','i','g','i','t','8' >,
- Emkb2Qt< Qt::Key_9, 'D','i','g','i','t','9' >,
- Emkb2Qt< Qt::Key_Semicolon, ';' >,
- Emkb2Qt< Qt::Key_Equal, '=' >,
- Emkb2Qt< Qt::Key_A, 'K','e','y','A' >,
- Emkb2Qt< Qt::Key_B, 'K','e','y','B' >,
- Emkb2Qt< Qt::Key_C, 'K','e','y','C' >,
- Emkb2Qt< Qt::Key_D, 'K','e','y','D' >,
- Emkb2Qt< Qt::Key_E, 'K','e','y','E' >,
- Emkb2Qt< Qt::Key_F, 'K','e','y','F' >,
- Emkb2Qt< Qt::Key_G, 'K','e','y','G' >,
- Emkb2Qt< Qt::Key_H, 'K','e','y','H' >,
- Emkb2Qt< Qt::Key_I, 'K','e','y','I' >,
- Emkb2Qt< Qt::Key_J, 'K','e','y','J' >,
- Emkb2Qt< Qt::Key_K, 'K','e','y','K' >,
- Emkb2Qt< Qt::Key_L, 'K','e','y','L' >,
- Emkb2Qt< Qt::Key_M, 'K','e','y','M' >,
- Emkb2Qt< Qt::Key_N, 'K','e','y','N' >,
- Emkb2Qt< Qt::Key_O, 'K','e','y','O' >,
- Emkb2Qt< Qt::Key_P, 'K','e','y','P' >,
- Emkb2Qt< Qt::Key_Q, 'K','e','y','Q' >,
- Emkb2Qt< Qt::Key_R, 'K','e','y','R' >,
- Emkb2Qt< Qt::Key_S, 'K','e','y','S' >,
- Emkb2Qt< Qt::Key_T, 'K','e','y','T' >,
- Emkb2Qt< Qt::Key_U, 'K','e','y','U' >,
- Emkb2Qt< Qt::Key_V, 'K','e','y','V' >,
- Emkb2Qt< Qt::Key_W, 'K','e','y','W' >,
- Emkb2Qt< Qt::Key_X, 'K','e','y','X' >,
- Emkb2Qt< Qt::Key_Y, 'K','e','y','Y' >,
- Emkb2Qt< Qt::Key_Z, 'K','e','y','Z' >,
- Emkb2Qt< Qt::Key_BracketLeft, '[' >,
- Emkb2Qt< Qt::Key_Backslash, '\\' >,
- Emkb2Qt< Qt::Key_BracketRight, ']' >,
- Emkb2Qt< Qt::Key_Apostrophe, '\'' >,
- Emkb2Qt< Qt::Key_QuoteLeft, 'B','a','c','k','q','u','o','t','e' >,
- Emkb2Qt< Qt::Key_multiply, 'N','u','m','p','a','d','M','u','l','t','i','p','l','y' >,
- Emkb2Qt< Qt::Key_Minus, 'N','u','m','p','a','d','S','u','b','t','r','a','c','t' >,
- Emkb2Qt< Qt::Key_Period, 'N','u','m','p','a','d','D','e','c','i','m','a','l' >,
- Emkb2Qt< Qt::Key_Plus, 'N','u','m','p','a','d','A','d','d' >,
- Emkb2Qt< Qt::Key_division, 'N','u','m','p','a','d','D','i','v','i','d','e' >,
- Emkb2Qt< Qt::Key_Equal, 'N','u','m','p','a','d','E','q','u','a','l' >,
- Emkb2Qt< Qt::Key_0, 'N','u','m','p','a','d','0' >,
- Emkb2Qt< Qt::Key_1, 'N','u','m','p','a','d','1' >,
- Emkb2Qt< Qt::Key_2, 'N','u','m','p','a','d','2' >,
- Emkb2Qt< Qt::Key_3, 'N','u','m','p','a','d','3' >,
- Emkb2Qt< Qt::Key_4, 'N','u','m','p','a','d','4' >,
- Emkb2Qt< Qt::Key_5, 'N','u','m','p','a','d','5' >,
- Emkb2Qt< Qt::Key_6, 'N','u','m','p','a','d','6' >,
- Emkb2Qt< Qt::Key_7, 'N','u','m','p','a','d','7' >,
- Emkb2Qt< Qt::Key_8, 'N','u','m','p','a','d','8' >,
- Emkb2Qt< Qt::Key_9, 'N','u','m','p','a','d','9' >,
- Emkb2Qt< Qt::Key_Comma, 'N','u','m','p','a','d','C','o','m','m','a' >,
- Emkb2Qt< Qt::Key_Enter, 'N','u','m','p','a','d','E','n','t','e','r' >,
- Emkb2Qt< Qt::Key_Paste, 'P','a','s','t','e' >,
- Emkb2Qt< Qt::Key_AltGr, 'A','l','t','R','i','g','h','t' >,
- Emkb2Qt< Qt::Key_Help, 'H','e','l','p' >,
- Emkb2Qt< Qt::Key_Equal, '=' >,
- Emkb2Qt< Qt::Key_yen, 'I','n','t','l','Y','e','n' >,
-
- Emkb2Qt< Qt::Key_Exclam, '\x21' >,
- Emkb2Qt< Qt::Key_QuoteDbl, '\x22' >,
- Emkb2Qt< Qt::Key_NumberSign, '\x23' >,
- Emkb2Qt< Qt::Key_Dollar, '\x24' >,
- Emkb2Qt< Qt::Key_Percent, '\x25' >,
- Emkb2Qt< Qt::Key_Ampersand, '\x26' >,
- Emkb2Qt< Qt::Key_ParenLeft, '\x28' >,
- Emkb2Qt< Qt::Key_ParenRight, '\x29' >,
- Emkb2Qt< Qt::Key_Asterisk, '\x2a' >,
- Emkb2Qt< Qt::Key_Plus, '\x2b' >,
- Emkb2Qt< Qt::Key_Colon, '\x3a' >,
- Emkb2Qt< Qt::Key_Semicolon, '\x3b' >,
- Emkb2Qt< Qt::Key_Less, '\x3c' >,
- Emkb2Qt< Qt::Key_Equal, '\x3d' >,
- Emkb2Qt< Qt::Key_Greater, '\x3e' >,
- Emkb2Qt< Qt::Key_Question, '\x3f' >,
- Emkb2Qt< Qt::Key_At, '\x40' >,
- Emkb2Qt< Qt::Key_BracketLeft, '\x5b' >,
- Emkb2Qt< Qt::Key_Backslash, '\x5c' >,
- Emkb2Qt< Qt::Key_BracketRight, '\x5d' >,
- Emkb2Qt< Qt::Key_AsciiCircum, '\x5e' >,
- Emkb2Qt< Qt::Key_Underscore, '\x5f' >,
- Emkb2Qt< Qt::Key_QuoteLeft, '\x60'>,
- Emkb2Qt< Qt::Key_BraceLeft, '\x7b'>,
- Emkb2Qt< Qt::Key_Bar, '\x7c'>,
- Emkb2Qt< Qt::Key_BraceRight, '\x7d'>,
- Emkb2Qt< Qt::Key_AsciiTilde, '\x7e'>,
- Emkb2Qt< Qt::Key_Space, '\x20' >,
- Emkb2Qt< Qt::Key_Comma, '\x2c' >,
- Emkb2Qt< Qt::Key_Minus, '\x2d' >,
- Emkb2Qt< Qt::Key_Period, '\x2e' >,
- Emkb2Qt< Qt::Key_Slash, '\x2f' >,
- Emkb2Qt< Qt::Key_Apostrophe, '\x27' >,
- Emkb2Qt< Qt::Key_Menu, 'C','o','n','t','e','x','t','M','e','n','u' >,
-
- Emkb2Qt< Qt::Key_Agrave, '\xc3','\xa0' >,
- Emkb2Qt< Qt::Key_Aacute, '\xc3','\xa1' >,
- Emkb2Qt< Qt::Key_Acircumflex, '\xc3','\xa2' >,
- Emkb2Qt< Qt::Key_Adiaeresis, '\xc3','\xa4' >,
- Emkb2Qt< Qt::Key_AE, '\xc3','\xa6' >,
- Emkb2Qt< Qt::Key_Atilde, '\xc3','\xa3' >,
- Emkb2Qt< Qt::Key_Aring, '\xc3','\xa5' >,
- Emkb2Qt< Qt::Key_Ccedilla, '\xc3','\xa7' >,
- Emkb2Qt< Qt::Key_Egrave, '\xc3','\xa8' >,
- Emkb2Qt< Qt::Key_Eacute, '\xc3','\xa9' >,
- Emkb2Qt< Qt::Key_Ecircumflex, '\xc3','\xaa' >,
- Emkb2Qt< Qt::Key_Ediaeresis, '\xc3','\xab' >,
- Emkb2Qt< Qt::Key_Icircumflex, '\xc3','\xae' >,
- Emkb2Qt< Qt::Key_Idiaeresis, '\xc3','\xaf' >,
- Emkb2Qt< Qt::Key_Ocircumflex, '\xc3','\xb4' >,
- Emkb2Qt< Qt::Key_Odiaeresis, '\xc3','\xb6' >,
- Emkb2Qt< Qt::Key_Ograve, '\xc3','\xb2' >,
- Emkb2Qt< Qt::Key_Oacute, '\xc3','\xb3' >,
- Emkb2Qt< Qt::Key_Ooblique, '\xc3','\xb8' >,
- Emkb2Qt< Qt::Key_Otilde, '\xc3','\xb5' >,
- Emkb2Qt< Qt::Key_Ucircumflex, '\xc3','\xbb' >,
- Emkb2Qt< Qt::Key_Udiaeresis, '\xc3','\xbc' >,
- Emkb2Qt< Qt::Key_Ugrave, '\xc3','\xb9' >,
- Emkb2Qt< Qt::Key_Uacute, '\xc3','\xba' >,
- Emkb2Qt< Qt::Key_Ntilde, '\xc3','\xb1' >,
- Emkb2Qt< Qt::Key_ydiaeresis, '\xc3','\xbf' >
- >::Data{}
- );
-
-static constexpr const auto DeadKeyShiftTbl = qMakeArray(
- QSortedData<
- // shifted
- Emkb2Qt< Qt::Key_Agrave, '\xc3','\x80' >,
- Emkb2Qt< Qt::Key_Aacute, '\xc3','\x81' >,
- Emkb2Qt< Qt::Key_Acircumflex, '\xc3','\x82' >,
- Emkb2Qt< Qt::Key_Adiaeresis, '\xc3','\x84' >,
- Emkb2Qt< Qt::Key_AE, '\xc3','\x86' >,
- Emkb2Qt< Qt::Key_Atilde, '\xc3','\x83' >,
- Emkb2Qt< Qt::Key_Aring, '\xc3','\x85' >,
- Emkb2Qt< Qt::Key_Egrave, '\xc3','\x88' >,
- Emkb2Qt< Qt::Key_Eacute, '\xc3','\x89' >,
- Emkb2Qt< Qt::Key_Ecircumflex, '\xc3','\x8a' >,
- Emkb2Qt< Qt::Key_Ediaeresis, '\xc3','\x8b' >,
- Emkb2Qt< Qt::Key_Icircumflex, '\xc3','\x8e' >,
- Emkb2Qt< Qt::Key_Idiaeresis, '\xc3','\x8f' >,
- Emkb2Qt< Qt::Key_Ocircumflex, '\xc3','\x94' >,
- Emkb2Qt< Qt::Key_Odiaeresis, '\xc3','\x96' >,
- Emkb2Qt< Qt::Key_Ograve, '\xc3','\x92' >,
- Emkb2Qt< Qt::Key_Oacute, '\xc3','\x93' >,
- Emkb2Qt< Qt::Key_Ooblique, '\xc3','\x98' >,
- Emkb2Qt< Qt::Key_Otilde, '\xc3','\x95' >,
- Emkb2Qt< Qt::Key_Ucircumflex, '\xc3','\x9b' >,
- Emkb2Qt< Qt::Key_Udiaeresis, '\xc3','\x9c' >,
- Emkb2Qt< Qt::Key_Ugrave, '\xc3','\x99' >,
- Emkb2Qt< Qt::Key_Uacute, '\xc3','\x9a' >,
- Emkb2Qt< Qt::Key_Ntilde, '\xc3','\x91' >,
- Emkb2Qt< Qt::Key_Ccedilla, '\xc3','\x87' >,
- Emkb2Qt< Qt::Key_ydiaeresis, '\xc3','\x8f' >
- >::Data{}
-);
-
-// macOS CTRL <-> META switching. We most likely want to enable
-// the existing switching code in QtGui, but for now do it here.
-static bool g_usePlatformMacCtrlMetaSwitching = false;
-
-bool g_useNaturalScrolling = true; // natural scrolling is default on linux/windows
-
-static void mouseWheelEvent(emscripten::val event) {
-
- emscripten::val wheelInterted = event["webkitDirectionInvertedFromDevice"];
-
- if (wheelInterted.as<bool>()) {
- g_useNaturalScrolling = true;
- }
-}
-
-EMSCRIPTEN_BINDINGS(qtMouseModule) {
- function("qtMouseWheelEvent", &mouseWheelEvent);
-}
-
-QWasmEventTranslator::QWasmEventTranslator(QWasmScreen *screen)
- : QObject(screen)
- , draggedWindow(nullptr)
- , lastWindow(nullptr)
- , pressedButtons(Qt::NoButton)
- , resizeMode(QWasmWindow::ResizeNone)
-{
- touchDevice = new QTouchDevice;
- touchDevice->setType(QTouchDevice::TouchScreen);
- touchDevice->setCapabilities(QTouchDevice::Position | QTouchDevice::Area | QTouchDevice::NormalizedPosition);
- QWindowSystemInterface::registerTouchDevice(touchDevice);
-
- initEventHandlers();
-}
-
-void QWasmEventTranslator::initEventHandlers()
-{
- QByteArray canvasSelector = "#" + screen()->canvasId().toUtf8();
-
- // The Platform Detect: expand coverage and move as needed
- enum Platform {
- GenericPlatform,
- MacOSPlatform
- };
- Platform platform = Platform(emscripten::val::global("navigator")["platform"]
- .call<bool>("includes", emscripten::val("Mac")));
- g_usePlatformMacCtrlMetaSwitching = (platform == MacOSPlatform);
-
- if (platform == MacOSPlatform) {
- g_useNaturalScrolling = false; // make this !default on macOS
-
- if (emscripten::val::global("window")["safari"].isUndefined()) {
- val canvas = screen()->canvas();
- canvas.call<void>("addEventListener",
- val("wheel"),
- val::module_property("qtMouseWheelEvent"));
- }
- }
-
- emscripten_set_keydown_callback(canvasSelector.constData(), (void *)this, 1, &keyboard_cb);
- emscripten_set_keyup_callback(canvasSelector.constData(), (void *)this, 1, &keyboard_cb);
-
- emscripten_set_mousedown_callback(canvasSelector.constData(), (void *)this, 1, &mouse_cb);
- emscripten_set_mouseup_callback(canvasSelector.constData(), (void *)this, 1, &mouse_cb);
- emscripten_set_mousemove_callback(canvasSelector.constData(), (void *)this, 1, &mouse_cb);
-
- emscripten_set_focus_callback(canvasSelector.constData(), (void *)this, 1, &focus_cb);
-
- emscripten_set_wheel_callback(canvasSelector.constData(), (void *)this, 1, &wheel_cb);
-
- emscripten_set_touchstart_callback(canvasSelector.constData(), (void *)this, 1, &touchCallback);
- emscripten_set_touchend_callback(canvasSelector.constData(), (void *)this, 1, &touchCallback);
- emscripten_set_touchmove_callback(canvasSelector.constData(), (void *)this, 1, &touchCallback);
- emscripten_set_touchcancel_callback(canvasSelector.constData(), (void *)this, 1, &touchCallback);
-}
-
-template <typename Event>
-QFlags<Qt::KeyboardModifier> QWasmEventTranslator::translatKeyModifier(const Event *event)
-{
- QFlags<Qt::KeyboardModifier> keyModifier = Qt::NoModifier;
- if (event->shiftKey)
- keyModifier |= Qt::ShiftModifier;
- if (event->ctrlKey) {
- if (g_usePlatformMacCtrlMetaSwitching)
- keyModifier |= Qt::MetaModifier;
- else
- keyModifier |= Qt::ControlModifier;
- }
- if (event->altKey)
- keyModifier |= Qt::AltModifier;
- if (event->metaKey) {
- if (g_usePlatformMacCtrlMetaSwitching)
- keyModifier |= Qt::ControlModifier;
- else
- keyModifier |= Qt::MetaModifier;
- }
- return keyModifier;
-}
-
-QFlags<Qt::KeyboardModifier> QWasmEventTranslator::translateKeyboardEventModifier(const EmscriptenKeyboardEvent *keyEvent)
-{
- QFlags<Qt::KeyboardModifier> keyModifier = translatKeyModifier(keyEvent);
- if (keyEvent->location == DOM_KEY_LOCATION_NUMPAD) {
- keyModifier |= Qt::KeypadModifier;
- }
-
- return keyModifier;
-}
-
-QFlags<Qt::KeyboardModifier> QWasmEventTranslator::translateMouseEventModifier(const EmscriptenMouseEvent *mouseEvent)
-{
- return translatKeyModifier(mouseEvent);
-}
-
-int QWasmEventTranslator::keyboard_cb(int eventType, const EmscriptenKeyboardEvent *keyEvent, void *userData)
-{
- QWasmEventTranslator *wasmTranslator = reinterpret_cast<QWasmEventTranslator *>(userData);
- bool accepted = wasmTranslator->processKeyboard(eventType, keyEvent);
-
- return accepted ? 1 : 0;
-}
-
-QWasmScreen *QWasmEventTranslator::screen()
-{
- return static_cast<QWasmScreen *>(parent());
-}
-
-Qt::Key QWasmEventTranslator::translateEmscriptKey(const EmscriptenKeyboardEvent *emscriptKey)
-{
- Qt::Key qtKey = Qt::Key_unknown;
-
- if (qstrncmp(emscriptKey->code, "Key", 3) == 0 || qstrncmp(emscriptKey->code, "Numpad", 6) == 0 ||
- qstrncmp(emscriptKey->code, "Digit", 5) == 0) {
-
- emkb2qt_t searchKey{emscriptKey->code, 0}; // search emcsripten code
- auto it1 = std::lower_bound(KeyTbl.cbegin(), KeyTbl.cend(), searchKey);
- if (it1 != KeyTbl.end() && !(searchKey < *it1)) {
- qtKey = static_cast<Qt::Key>(it1->qt);
- }
- } else if (qstrncmp(emscriptKey->key, "Dead", 4) == 0 ) {
- emkb2qt_t searchKey1{emscriptKey->code, 0};
- for (auto it1 = KeyTbl.cbegin(); it1 != KeyTbl.end(); ++it1)
- if (it1 != KeyTbl.end() && (qstrcmp(searchKey1.em, it1->em) == 0)) {
- qtKey = static_cast<Qt::Key>(it1->qt);
- }
- }
-
- if (qtKey == Qt::Key_unknown) {
- emkb2qt_t searchKey{emscriptKey->key, 0}; // search unicode key
- auto it1 = std::lower_bound(KeyTbl.cbegin(), KeyTbl.cend(), searchKey);
- if (it1 != KeyTbl.end() && !(searchKey < *it1)) {
- qtKey = static_cast<Qt::Key>(it1->qt);
- }
- }
- if (qtKey == Qt::Key_unknown) {//try harder with shifted number keys
- emkb2qt_t searchKey1{emscriptKey->key, 0};
- for (auto it1 = KeyTbl.cbegin(); it1 != KeyTbl.end(); ++it1)
- if (it1 != KeyTbl.end() && (qstrcmp(searchKey1.em, it1->em) == 0)) {
- qtKey = static_cast<Qt::Key>(it1->qt);
- }
- }
-
- return qtKey;
-}
-
-Qt::MouseButton QWasmEventTranslator::translateMouseButton(unsigned short button)
-{
- if (button == 0)
- return Qt::LeftButton;
- else if (button == 1)
- return Qt::MiddleButton;
- else if (button == 2)
- return Qt::RightButton;
-
- return Qt::NoButton;
-}
-
-int QWasmEventTranslator::mouse_cb(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData)
-{
- QWasmEventTranslator *translator = (QWasmEventTranslator*)userData;
- translator->processMouse(eventType,mouseEvent);
- QWasmEventDispatcher::maintainTimers();
- return 0;
-}
-
-void resizeWindow(QWindow *window, QWasmWindow::ResizeMode mode,
- QRect startRect, QPoint amount)
-{
- if (mode == QWasmWindow::ResizeNone)
- return;
-
- bool top = mode == QWasmWindow::ResizeTopLeft ||
- mode == QWasmWindow::ResizeTop ||
- mode == QWasmWindow::ResizeTopRight;
-
- bool bottom = mode == QWasmWindow::ResizeBottomLeft ||
- mode == QWasmWindow::ResizeBottom ||
- mode == QWasmWindow::ResizeBottomRight;
-
- bool left = mode == QWasmWindow::ResizeLeft ||
- mode == QWasmWindow::ResizeTopLeft ||
- mode == QWasmWindow::ResizeBottomLeft;
-
- bool right = mode == QWasmWindow::ResizeRight ||
- mode == QWasmWindow::ResizeTopRight ||
- mode == QWasmWindow::ResizeBottomRight;
-
- int x1 = startRect.left();
- int y1 = startRect.top();
- int x2 = startRect.right();
- int y2 = startRect.bottom();
-
- if (left)
- x1 += amount.x();
- if (top)
- y1 += amount.y();
- if (right)
- x2 += amount.x();
- if (bottom)
- y2 += amount.y();
-
- int w = x2-x1;
- int h = y2-y1;
-
- if (w < window->minimumWidth()) {
- if (left)
- x1 -= window->minimumWidth() - w;
-
- w = window->minimumWidth();
- }
-
- if (h < window->minimumHeight()) {
- if (top)
- y1 -= window->minimumHeight() - h;
-
- h = window->minimumHeight();
- }
-
- window->setGeometry(x1, y1, w, h);
-}
-
-void QWasmEventTranslator::processMouse(int eventType, const EmscriptenMouseEvent *mouseEvent)
-{
- auto timestamp = emscripten_date_now();
- QPoint targetPoint(mouseEvent->targetX, mouseEvent->targetY);
- QPoint globalPoint = screen()->geometry().topLeft() + targetPoint;
-
- QEvent::Type buttonEventType = QEvent::None;
- Qt::MouseButton button = translateMouseButton(mouseEvent->button);
- Qt::KeyboardModifiers modifiers = translateMouseEventModifier(mouseEvent);
-
- QWindow *window2 = screen()->compositor()->windowAt(globalPoint, 5);
-
- if (window2 == nullptr) {
- window2 = lastWindow;
- } else {
- lastWindow = window2;
- }
-
- QPoint localPoint = window2->mapFromGlobal(globalPoint);
- bool interior = window2->geometry().contains(globalPoint);
-
- QWasmWindow *htmlWindow = static_cast<QWasmWindow*>(window2->handle());
- switch (eventType) {
- case EMSCRIPTEN_EVENT_MOUSEDOWN:
- {
- if (window2)
- window2->requestActivate();
-
- pressedButtons.setFlag(button);
-
- if (mouseEvent->button == 0) {
- pressedWindow = window2;
- buttonEventType = QEvent::MouseButtonPress;
- if (!(htmlWindow->m_windowState & Qt::WindowFullScreen) && !(htmlWindow->m_windowState & Qt::WindowMaximized)) {
- if (htmlWindow && window2->flags().testFlag(Qt::WindowTitleHint) && htmlWindow->isPointOnTitle(globalPoint))
- draggedWindow = window2;
- else if (htmlWindow && htmlWindow->isPointOnResizeRegion(globalPoint)) {
- draggedWindow = window2;
- resizeMode = htmlWindow->resizeModeAtPoint(globalPoint);
- resizePoint = globalPoint;
- resizeStartRect = window2->geometry();
- }
- }
- }
-
- htmlWindow->injectMousePressed(localPoint, globalPoint, button, modifiers);
- break;
- }
- case EMSCRIPTEN_EVENT_MOUSEUP:
- {
- pressedButtons.setFlag(translateMouseButton(mouseEvent->button), false);
- buttonEventType = QEvent::MouseButtonRelease;
- QWasmWindow *oldWindow = nullptr;
-
- if (mouseEvent->button == 0 && pressedWindow) {
- oldWindow = static_cast<QWasmWindow*>(pressedWindow->handle());
- pressedWindow = nullptr;
- }
-
- if (mouseEvent->button == 0) {
- draggedWindow = nullptr;
- resizeMode = QWasmWindow::ResizeNone;
- }
-
- if (oldWindow)
- oldWindow->injectMouseReleased(localPoint, globalPoint, button, modifiers);
- break;
- }
- case EMSCRIPTEN_EVENT_MOUSEMOVE: // drag event
- {
- buttonEventType = QEvent::MouseMove;
- if (!(htmlWindow->m_windowState & Qt::WindowFullScreen) && !(htmlWindow->m_windowState & Qt::WindowMaximized)) {
- if (resizeMode == QWasmWindow::ResizeNone && draggedWindow) {
- draggedWindow->setX(draggedWindow->x() + mouseEvent->movementX);
- draggedWindow->setY(draggedWindow->y() + mouseEvent->movementY);
- }
-
- if (resizeMode != QWasmWindow::ResizeNone && !(htmlWindow->m_windowState & Qt::WindowFullScreen)) {
- QPoint delta = QPoint(mouseEvent->targetX, mouseEvent->targetY) - resizePoint;
- resizeWindow(draggedWindow, resizeMode, resizeStartRect, delta);
- }
- }
- break;
- }
- default: // MOUSELEAVE MOUSEENTER
- break;
- };
- if (!window2 && buttonEventType == QEvent::MouseButtonRelease) {
- window2 = lastWindow;
- lastWindow = nullptr;
- interior = true;
- }
- if (window2 && interior) {
- QWindowSystemInterface::handleMouseEvent<QWindowSystemInterface::SynchronousDelivery>(
- window2, timestamp, localPoint, globalPoint, pressedButtons, button, buttonEventType, modifiers);
- }
-}
-
-int QWasmEventTranslator::focus_cb(int /*eventType*/, const EmscriptenFocusEvent */*focusEvent*/, void */*userData*/)
-{
- return 0;
-}
-
-int QWasmEventTranslator::wheel_cb(int eventType, const EmscriptenWheelEvent *wheelEvent, void *userData)
-{
- Q_UNUSED(eventType)
-
- QWasmEventTranslator *eventTranslator = static_cast<QWasmEventTranslator *>(userData);
- EmscriptenMouseEvent mouseEvent = wheelEvent->mouse;
-
- int scrollFactor = 0;
- switch (wheelEvent->deltaMode) {
- case DOM_DELTA_PIXEL://chrome safari
- scrollFactor = 1;
- break;
- case DOM_DELTA_LINE: //firefox
- scrollFactor = 12;
- break;
- case DOM_DELTA_PAGE:
- scrollFactor = 20;
- break;
- };
-
- if (g_useNaturalScrolling) //macOS platform has document oriented scrolling
- scrollFactor = -scrollFactor;
-
- QWasmEventTranslator *translator = (QWasmEventTranslator*)userData;
- Qt::KeyboardModifiers modifiers = translator->translateMouseEventModifier(&mouseEvent);
- auto timestamp = emscripten_date_now();
- QPoint targetPoint(mouseEvent.targetX, mouseEvent.targetY);
- QPoint globalPoint = eventTranslator->screen()->geometry().topLeft() + targetPoint;
-
- QWindow *window2 = eventTranslator->screen()->compositor()->windowAt(globalPoint, 5);
- if (!window2)
- return 0;
- QPoint localPoint = window2->mapFromGlobal(globalPoint);
-
- QPoint pixelDelta;
-
- if (wheelEvent->deltaY != 0) pixelDelta.setY(wheelEvent->deltaY * scrollFactor);
- if (wheelEvent->deltaX != 0) pixelDelta.setX(wheelEvent->deltaX * scrollFactor);
-
- QWindowSystemInterface::handleWheelEvent(window2, timestamp, localPoint,
- globalPoint, QPoint(), pixelDelta, modifiers);
- QWasmEventDispatcher::maintainTimers();
-
- return 1;
-}
-
-int QWasmEventTranslator::touchCallback(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData)
-{
- auto translator = reinterpret_cast<QWasmEventTranslator*>(userData);
- return translator->handleTouch(eventType, touchEvent);
-}
-
-int QWasmEventTranslator::handleTouch(int eventType, const EmscriptenTouchEvent *touchEvent)
-{
- QList<QWindowSystemInterface::TouchPoint> touchPointList;
- touchPointList.reserve(touchEvent->numTouches);
- QWindow *window2;
-
- for (int i = 0; i < touchEvent->numTouches; i++) {
-
- const EmscriptenTouchPoint *touches = &touchEvent->touches[i];
-
- QPoint targetPoint(touches->targetX, touches->targetY);
- QPoint globalPoint = screen()->geometry().topLeft() + targetPoint;
-
- window2 = this->screen()->compositor()->windowAt(globalPoint, 5);
- if (window2 == nullptr)
- continue;
-
- QWindowSystemInterface::TouchPoint touchPoint;
-
- touchPoint.area = QRect(0, 0, 8, 8);
- touchPoint.id = touches->identifier;
- touchPoint.pressure = 1.0;
-
- touchPoint.area.moveCenter(globalPoint);
-
- const auto tp = pressedTouchIds.constFind(touchPoint.id);
- if (tp != pressedTouchIds.constEnd())
- touchPoint.normalPosition = tp.value();
-
- QPointF localPoint = QPointF(window2->mapFromGlobal(globalPoint));
- QPointF normalPosition(localPoint.x() / window2->width(),
- localPoint.y() / window2->height());
-
- const bool stationaryTouchPoint = (normalPosition == touchPoint.normalPosition);
- touchPoint.normalPosition = normalPosition;
-
- switch (eventType) {
- case EMSCRIPTEN_EVENT_TOUCHSTART:
- if (tp != pressedTouchIds.constEnd()) {
- touchPoint.state = (stationaryTouchPoint
- ? Qt::TouchPointStationary
- : Qt::TouchPointMoved);
- } else {
- touchPoint.state = Qt::TouchPointPressed;
- }
- pressedTouchIds.insert(touchPoint.id, touchPoint.normalPosition);
-
- break;
- case EMSCRIPTEN_EVENT_TOUCHEND:
- touchPoint.state = Qt::TouchPointReleased;
- pressedTouchIds.remove(touchPoint.id);
- break;
- case EMSCRIPTEN_EVENT_TOUCHMOVE:
- touchPoint.state = (stationaryTouchPoint
- ? Qt::TouchPointStationary
- : Qt::TouchPointMoved);
-
- pressedTouchIds.insert(touchPoint.id, touchPoint.normalPosition);
- break;
- default:
- break;
- }
-
- touchPointList.append(touchPoint);
- }
-
- QFlags<Qt::KeyboardModifier> keyModifier = translatKeyModifier(touchEvent);
-
- QWindowSystemInterface::handleTouchEvent<QWindowSystemInterface::SynchronousDelivery>(
- window2, getTimestamp(), touchDevice, touchPointList, keyModifier);
-
- if (eventType == EMSCRIPTEN_EVENT_TOUCHCANCEL)
- QWindowSystemInterface::handleTouchCancelEvent(window2, getTimestamp(), touchDevice, keyModifier);
-
- QWasmEventDispatcher::maintainTimers();
- return 1;
-}
-
-quint64 QWasmEventTranslator::getTimestamp()
-{
- return QDeadlineTimer::current().deadlineNSecs() / 1000;
-}
-
-struct KeyMapping { Qt::Key from, to; };
-
-constexpr KeyMapping tildeKeyTable[] = { // ~
- { Qt::Key_A, Qt::Key_Atilde },
- { Qt::Key_N, Qt::Key_Ntilde },
- { Qt::Key_O, Qt::Key_Otilde },
-};
-constexpr KeyMapping graveKeyTable[] = { // `
- { Qt::Key_A, Qt::Key_Agrave },
- { Qt::Key_E, Qt::Key_Egrave },
- { Qt::Key_I, Qt::Key_Igrave },
- { Qt::Key_O, Qt::Key_Ograve },
- { Qt::Key_U, Qt::Key_Ugrave },
-};
-constexpr KeyMapping acuteKeyTable[] = { // '
- { Qt::Key_A, Qt::Key_Aacute },
- { Qt::Key_E, Qt::Key_Eacute },
- { Qt::Key_I, Qt::Key_Iacute },
- { Qt::Key_O, Qt::Key_Oacute },
- { Qt::Key_U, Qt::Key_Uacute },
- { Qt::Key_Y, Qt::Key_Yacute },
-};
-constexpr KeyMapping diaeresisKeyTable[] = { // umlaut ¨
- { Qt::Key_A, Qt::Key_Adiaeresis },
- { Qt::Key_E, Qt::Key_Ediaeresis },
- { Qt::Key_I, Qt::Key_Idiaeresis },
- { Qt::Key_O, Qt::Key_Odiaeresis },
- { Qt::Key_U, Qt::Key_Udiaeresis },
- { Qt::Key_Y, Qt::Key_ydiaeresis },
-};
-constexpr KeyMapping circumflexKeyTable[] = { // ^
- { Qt::Key_A, Qt::Key_Acircumflex },
- { Qt::Key_E, Qt::Key_Ecircumflex },
- { Qt::Key_I, Qt::Key_Icircumflex },
- { Qt::Key_O, Qt::Key_Ocircumflex },
- { Qt::Key_U, Qt::Key_Ucircumflex },
-};
-
-static Qt::Key find_impl(const KeyMapping *first, const KeyMapping *last, Qt::Key key) noexcept
-{
- while (first != last) {
- if (first->from == key)
- return first->to;
- ++first;
- }
- return Qt::Key_unknown;
-}
-
-template <size_t N>
-static Qt::Key find(const KeyMapping (&map)[N], Qt::Key key) noexcept
-{
- return find_impl(map, map + N, key);
-}
-
-Qt::Key QWasmEventTranslator::translateDeadKey(Qt::Key deadKey, Qt::Key accentBaseKey)
-{
- Qt::Key wasmKey = Qt::Key_unknown;
- switch (deadKey) {
-#ifdef Q_OS_MACOS
- case Qt::Key_QuoteLeft: // ` macOS: Key_Dead_Grave
-#else
- case Qt::Key_O: // ´ Key_Dead_Grave
-#endif
- wasmKey = find(graveKeyTable, accentBaseKey);
- break;
- case Qt::Key_E: // ´ Key_Dead_Acute
- wasmKey = find(acuteKeyTable, accentBaseKey);
- break;
- case Qt::Key_AsciiTilde:
- case Qt::Key_N:// Key_Dead_Tilde
- wasmKey = find(tildeKeyTable, accentBaseKey);
- break;
-#ifndef Q_OS_MACOS
- case Qt::Key_QuoteLeft:
-#endif
- case Qt::Key_U:// ¨ Key_Dead_Diaeresis
- wasmKey = find(diaeresisKeyTable, accentBaseKey);
- break;
- case Qt::Key_I:// macOS Key_Dead_Circumflex
- case Qt::Key_6:// linux
- case Qt::Key_Apostrophe:// linux
- wasmKey = find(circumflexKeyTable, accentBaseKey);
- break;
- default:
- break;
-
- };
- return wasmKey;
-}
-
-bool QWasmEventTranslator::processKeyboard(int eventType, const EmscriptenKeyboardEvent *keyEvent)
-{
- Qt::Key qtKey = translateEmscriptKey(keyEvent);
-
- Qt::KeyboardModifiers modifiers = translateKeyboardEventModifier(keyEvent);
-
- QString keyText;
- QEvent::Type keyType = QEvent::None;
- switch (eventType) {
- case EMSCRIPTEN_EVENT_KEYPRESS:
- case EMSCRIPTEN_EVENT_KEYDOWN: // down
- keyType = QEvent::KeyPress;
-
- if (m_emDeadKey != Qt::Key_unknown) {
-
- Qt::Key transformedKey = translateDeadKey(m_emDeadKey, qtKey);
-
- if (transformedKey != Qt::Key_unknown)
- qtKey = transformedKey;
-
- if (keyEvent->shiftKey == 0) {
- for (auto it = KeyTbl.cbegin(); it != KeyTbl.end(); ++it) {
- if (it != KeyTbl.end() && (qtKey == static_cast<Qt::Key>(it->qt))) {
- keyText = it->em;
- m_emDeadKey = Qt::Key_unknown;
- break;
- }
- }
- } else {
- for (auto it = DeadKeyShiftTbl.cbegin(); it != DeadKeyShiftTbl.end(); ++it) {
- if (it != DeadKeyShiftTbl.end() && (qtKey == static_cast<Qt::Key>(it->qt))) {
- keyText = it->em;
- m_emDeadKey = Qt::Key_unknown;
- break;
- }
- }
- }
- }
- if (qstrncmp(keyEvent->key, "Dead", 4) == 0 || qtKey == Qt::Key_AltGr) {
- qtKey = translateEmscriptKey(keyEvent);
- m_emStickyDeadKey = true;
- if (keyEvent->shiftKey == 1 && qtKey == Qt::Key_QuoteLeft)
- qtKey = Qt::Key_AsciiTilde;
- m_emDeadKey = qtKey;
- }
- break;
- case EMSCRIPTEN_EVENT_KEYUP: // up
- keyType = QEvent::KeyRelease;
- if (m_emStickyDeadKey && qtKey != Qt::Key_Alt) {
- m_emStickyDeadKey = false;
- }
- break;
- default:
- break;
- };
-
- if (keyType == QEvent::None)
- return 0;
-
- QFlags<Qt::KeyboardModifier> mods = translateKeyboardEventModifier(keyEvent);
-
- // Clipboard fallback path: cut/copy/paste are handled by clipboard event
- // handlers if direct clipboard access is not available.
- if (!QWasmIntegration::get()->getWasmClipboard()->hasClipboardApi && modifiers & Qt::ControlModifier &&
- (qtKey == Qt::Key_X || qtKey == Qt::Key_C || qtKey == Qt::Key_V)) {
- return 0;
- }
-
- bool accepted = false;
-
- if (keyType == QEvent::KeyPress &&
- mods.testFlag(Qt::ControlModifier)
- && qtKey == Qt::Key_V) {
- QWasmIntegration::get()->getWasmClipboard()->readTextFromClipboard();
- } else {
- if (keyText.isEmpty())
- keyText = QString(keyEvent->key);
- if (keyText.size() > 1)
- keyText.clear();
- accepted = QWindowSystemInterface::handleKeyEvent<QWindowSystemInterface::SynchronousDelivery>(
- 0, keyType, qtKey, modifiers, keyText);
- }
- if (keyType == QEvent::KeyPress &&
- mods.testFlag(Qt::ControlModifier)
- && qtKey == Qt::Key_C) {
- QWasmIntegration::get()->getWasmClipboard()->writeTextToClipboard();
- }
-
- QWasmEventDispatcher::maintainTimers();
-
- return accepted;
-}
-
-QT_END_NAMESPACE
diff --git a/src/plugins/platforms/wasm/qwasmeventtranslator.h b/src/plugins/platforms/wasm/qwasmeventtranslator.h
deleted file mode 100644
index 568ae00732..0000000000
--- a/src/plugins/platforms/wasm/qwasmeventtranslator.h
+++ /dev/null
@@ -1,99 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the plugins of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL$
-** 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 General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 or (at your option) 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.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-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QWASMEVENTTRANSLATOR_H
-#define QWASMEVENTTRANSLATOR_H
-
-#include <QtCore/qobject.h>
-#include <QtCore/qrect.h>
-#include <QtCore/qpoint.h>
-#include <emscripten/html5.h>
-#include "qwasmwindow.h"
-#include <QtGui/qtouchdevice.h>
-#include <QHash>
-
-QT_BEGIN_NAMESPACE
-
-class QWindow;
-
-class QWasmEventTranslator : public QObject
-{
- Q_OBJECT
-
-public:
-
- explicit QWasmEventTranslator(QWasmScreen *screen);
-
- static int keyboard_cb(int eventType, const EmscriptenKeyboardEvent *keyEvent, void *userData);
- static int mouse_cb(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData);
- static int focus_cb(int eventType, const EmscriptenFocusEvent *focusEvent, void *userData);
- static int wheel_cb(int eventType, const EmscriptenWheelEvent *wheelEvent, void *userData);
-
- static int touchCallback(int eventType, const EmscriptenTouchEvent *ev, void *userData);
-
- void processEvents();
- void initEventHandlers();
- int handleTouch(int eventType, const EmscriptenTouchEvent *touchEvent);
-
-Q_SIGNALS:
- void getWindowAt(const QPoint &point, QWindow **window);
-private:
- QWasmScreen *screen();
- Qt::Key translateEmscriptKey(const EmscriptenKeyboardEvent *emscriptKey);
- template <typename Event>
- QFlags<Qt::KeyboardModifier> translatKeyModifier(const Event *event);
- QFlags<Qt::KeyboardModifier> translateKeyboardEventModifier(const EmscriptenKeyboardEvent *keyEvent);
- QFlags<Qt::KeyboardModifier> translateMouseEventModifier(const EmscriptenMouseEvent *mouseEvent);
- Qt::MouseButton translateMouseButton(unsigned short button);
-
- void processMouse(int eventType, const EmscriptenMouseEvent *mouseEvent);
- bool processKeyboard(int eventType, const EmscriptenKeyboardEvent *keyEvent);
-
- Qt::Key translateDeadKey(Qt::Key deadKey, Qt::Key accentBaseKey);
-
- QMap <int, QPointF> pressedTouchIds;
-
-private:
- QWindow *draggedWindow;
- QWindow *pressedWindow;
- QWindow *lastWindow;
- Qt::MouseButtons pressedButtons;
-
- QWasmWindow::ResizeMode resizeMode;
- QPoint resizePoint;
- QRect resizeStartRect;
- QTouchDevice *touchDevice;
- quint64 getTimestamp();
-
- Qt::Key m_emDeadKey = Qt::Key_unknown;
- bool m_emStickyDeadKey = false;
-};
-
-QT_END_NAMESPACE
-#endif // QWASMEVENTTRANSLATOR_H
diff --git a/src/plugins/platforms/wasm/qwasmfontdatabase.cpp b/src/plugins/platforms/wasm/qwasmfontdatabase.cpp
index 53e875ead6..3f3dc10f71 100644
--- a/src/plugins/platforms/wasm/qwasmfontdatabase.cpp
+++ b/src/plugins/platforms/wasm/qwasmfontdatabase.cpp
@@ -1,47 +1,272 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the plugins of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL$
-** 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 General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 or (at your option) 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.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-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include "qwasmfontdatabase.h"
+#include "qwasmintegration.h"
#include <QtCore/qfile.h>
+#include <QtCore/private/qstdweb_p.h>
+#include <QtCore/private/qeventdispatcher_wasm_p.h>
+#include <QtGui/private/qguiapplication_p.h>
+
+#include <emscripten.h>
+#include <emscripten/val.h>
+#include <emscripten/bind.h>
+
+#include <map>
+#include <array>
QT_BEGIN_NAMESPACE
-void QWasmFontDatabase::populateFontDatabase()
+using namespace emscripten;
+using namespace Qt::StringLiterals;
+
+
+namespace {
+
+class FontData
+{
+public:
+ FontData(val fontData)
+ :m_fontData(fontData) {}
+
+ QString family() const
+ {
+ return QString::fromStdString(m_fontData["family"].as<std::string>());
+ }
+
+ QString fullName() const
+ {
+ return QString::fromStdString(m_fontData["fullName"].as<std::string>());
+ }
+
+ QString postscriptName() const
+ {
+ return QString::fromStdString(m_fontData["postscriptName"].as<std::string>());
+ }
+
+ QString style() const
+ {
+ return QString::fromStdString(m_fontData["style"].as<std::string>());
+ }
+
+ val value() const
+ {
+ return m_fontData;
+ }
+
+private:
+ val m_fontData;
+};
+
+val makeObject(const char *key, const char *value)
+{
+ val obj = val::object();
+ obj.set(key, std::string(value));
+ return obj;
+}
+
+void printError(val err) {
+ qCWarning(lcQpaFonts)
+ << QString::fromStdString(err["name"].as<std::string>())
+ << QString::fromStdString(err["message"].as<std::string>());
+ QWasmFontDatabase::endAllFontFileLoading();
+}
+
+void checkFontAccessPermitted(std::function<void(bool)> callback)
+{
+ const val permissions = val::global("navigator")["permissions"];
+ if (permissions.isUndefined()) {
+ callback(false);
+ return;
+ }
+
+ qstdweb::Promise::make(permissions, "query", {
+ .thenFunc = [callback](val status) {
+ callback(status["state"].as<std::string>() == "granted");
+ },
+ }, makeObject("name", "local-fonts"));
+}
+
+void queryLocalFonts(std::function<void(const QList<FontData> &)> callback)
+{
+ emscripten::val window = emscripten::val::global("window");
+ qstdweb::Promise::make(window, "queryLocalFonts", {
+ .thenFunc = [callback](emscripten::val fontArray) {
+ QList<FontData> fonts;
+ const int count = fontArray["length"].as<int>();
+ fonts.reserve(count);
+ for (int i = 0; i < count; ++i)
+ fonts.append(FontData(fontArray.call<emscripten::val>("at", i)));
+ callback(fonts);
+ },
+ .catchFunc = printError
+ });
+}
+
+void readBlob(val blob, std::function<void(const QByteArray &)> callback)
+{
+ qstdweb::Promise::make(blob, "arrayBuffer", {
+ .thenFunc = [callback](emscripten::val fontArrayBuffer) {
+ QByteArray fontData = qstdweb::Uint8Array(qstdweb::ArrayBuffer(fontArrayBuffer)).copyToQByteArray();
+ callback(fontData);
+ },
+ .catchFunc = printError
+ });
+}
+
+void readFont(FontData font, std::function<void(const QByteArray &)> callback)
+{
+ qstdweb::Promise::make(font.value(), "blob", {
+ .thenFunc = [callback](val blob) {
+ readBlob(blob, [callback](const QByteArray &data) {
+ callback(data);
+ });
+ },
+ .catchFunc = printError
+ });
+}
+
+emscripten::val getLocalFontsConfigProperty(const char *name) {
+ emscripten::val qt = val::module_property("qt");
+ if (qt.isUndefined())
+ return emscripten::val();
+ emscripten::val localFonts = qt["localFonts"];
+ if (localFonts.isUndefined())
+ return emscripten::val();
+ return localFonts[name];
+};
+
+bool getLocalFontsBoolConfigPropertyWithDefault(const char *name, bool defaultValue) {
+ emscripten::val prop = getLocalFontsConfigProperty(name);
+ if (prop.isUndefined())
+ return defaultValue;
+ return prop.as<bool>();
+};
+
+QString getLocalFontsStringConfigPropertyWithDefault(const char *name, QString defaultValue) {
+ emscripten::val prop = getLocalFontsConfigProperty(name);
+ if (prop.isUndefined())
+ return defaultValue;
+ return QString::fromStdString(prop.as<std::string>());
+};
+
+QStringList getLocalFontsStringListConfigPropertyWithDefault(const char *name, QStringList defaultValue) {
+ emscripten::val array = getLocalFontsConfigProperty(name);
+ if (array.isUndefined())
+ return defaultValue;
+
+ QStringList list;
+ int size = array["length"].as<int>();
+ for (int i = 0; i < size; ++i) {
+ emscripten::val element = array.call<emscripten::val>("at", i);
+ QString string = QString::fromStdString(element.as<std::string>());
+ if (!string.isEmpty())
+ list.append(string);
+ }
+ return list;
+};
+
+} // namespace
+
+QWasmFontDatabase::QWasmFontDatabase()
+:QFreeTypeFontDatabase()
{
- // Load font file from resources. Currently
- // all fonts needs to be bundled with the nexe
- // as Qt resources.
+ m_localFontsApiSupported = val::global("window")["queryLocalFonts"].isUndefined() == false;
+ if (m_localFontsApiSupported)
+ beginFontDatabaseStartupTask();
+}
+QWasmFontDatabase *QWasmFontDatabase::get()
+{
+ return static_cast<QWasmFontDatabase *>(QWasmIntegration::get()->fontDatabase());
+}
+
+// Populates the font database with local fonts. Will make the browser ask
+// the user for permission if needed. Does nothing if the Local Font Access API
+// is not supported.
+void QWasmFontDatabase::populateLocalfonts()
+{
+ // Decide which font families to populate based on user preferences
+ QStringList selectedLocalFontFamilies;
+ bool allFamilies = false;
+
+ switch (m_localFontFamilyLoadSet) {
+ case NoFontFamilies:
+ default:
+ // keep empty selectedLocalFontFamilies
+ break;
+ case DefaultFontFamilies: {
+ const QStringList webSafeFontFamilies =
+ {"Arial", "Verdana", "Tahoma", "Trebuchet", "Times New Roman",
+ "Georgia", "Garamond", "Courier New"};
+ selectedLocalFontFamilies = webSafeFontFamilies;
+ } break;
+ case AllFontFamilies:
+ allFamilies = true;
+ break;
+ }
+
+ selectedLocalFontFamilies += m_extraLocalFontFamilies;
+
+ if (selectedLocalFontFamilies.isEmpty() && !allFamilies) {
+ endAllFontFileLoading();
+ return;
+ }
+
+ populateLocalFontFamilies(selectedLocalFontFamilies, allFamilies);
+}
+
+namespace {
+ QStringList toStringList(emscripten::val array)
+ {
+ QStringList list;
+ int size = array["length"].as<int>();
+ for (int i = 0; i < size; ++i) {
+ emscripten::val element = array.call<emscripten::val>("at", i);
+ QString string = QString::fromStdString(element.as<std::string>());
+ if (!string.isEmpty())
+ list.append(string);
+ }
+ return list;
+ }
+}
+
+void QWasmFontDatabase::populateLocalFontFamilies(emscripten::val families)
+{
+ if (!m_localFontsApiSupported)
+ return;
+ populateLocalFontFamilies(toStringList(families), false);
+}
+
+void QWasmFontDatabase::populateLocalFontFamilies(const QStringList &fontFamilies, bool allFamilies)
+{
+ queryLocalFonts([fontFamilies, allFamilies](const QList<FontData> &fonts) {
+ refFontFileLoading();
+ QList<FontData> filteredFonts;
+ std::copy_if(fonts.begin(), fonts.end(), std::back_inserter(filteredFonts),
+ [fontFamilies, allFamilies](FontData fontData) {
+ return allFamilies || fontFamilies.contains(fontData.family());
+ });
+
+ for (const FontData &font: filteredFonts) {
+ refFontFileLoading();
+ readFont(font, [font](const QByteArray &fontData){
+ QFreeTypeFontDatabase::registerFontFamily(font.family());
+ QFreeTypeFontDatabase::addTTFile(fontData, QByteArray());
+ derefFontFileLoading();
+ });
+ }
+ derefFontFileLoading();
+ });
+
+}
+
+void QWasmFontDatabase::populateFontDatabase()
+{
+ // Load bundled font file from resources.
const QString fontFileNames[] = {
QStringLiteral(":/fonts/DejaVuSansMono.ttf"),
- QStringLiteral(":/fonts/Vera.ttf"),
QStringLiteral(":/fonts/DejaVuSans.ttf"),
};
for (const QString &fontFileName : fontFileNames) {
@@ -51,11 +276,45 @@ void QWasmFontDatabase::populateFontDatabase()
QFreeTypeFontDatabase::addTTFile(theFont.readAll(), fontFileName.toLatin1());
}
+
+ // Get config options for controlling local fonts usage
+ m_queryLocalFontsPermission = getLocalFontsBoolConfigPropertyWithDefault("requestPermission", false);
+ QString fontFamilyLoadSet = getLocalFontsStringConfigPropertyWithDefault("familiesCollection", "DefaultFontFamilies");
+ m_extraLocalFontFamilies = getLocalFontsStringListConfigPropertyWithDefault("extraFamilies", QStringList());
+
+ if (fontFamilyLoadSet == "NoFontFamilies") {
+ m_localFontFamilyLoadSet = NoFontFamilies;
+ } else if (fontFamilyLoadSet == "DefaultFontFamilies") {
+ m_localFontFamilyLoadSet = DefaultFontFamilies;
+ } else if (fontFamilyLoadSet == "AllFontFamilies") {
+ m_localFontFamilyLoadSet = AllFontFamilies;
+ } else {
+ m_localFontFamilyLoadSet = NoFontFamilies;
+ qWarning() << "Unknown fontFamilyLoadSet value" << fontFamilyLoadSet;
+ }
+
+ if (!m_localFontsApiSupported)
+ return;
+
+ // Populate the font database with local fonts. Either try unconditianlly
+ // if displyaing a fonts permissions dialog at startup is allowed, or else
+ // only if we already have permission.
+ if (m_queryLocalFontsPermission) {
+ populateLocalfonts();
+ } else {
+ checkFontAccessPermitted([this](bool granted) {
+ if (granted)
+ populateLocalfonts();
+ else
+ endAllFontFileLoading();
+ });
+ }
}
QFontEngine *QWasmFontDatabase::fontEngine(const QFontDef &fontDef, void *handle)
{
- return QFreeTypeFontDatabase::fontEngine(fontDef, handle);
+ QFontEngine *fontEngine = QFreeTypeFontDatabase::fontEngine(fontDef, handle);
+ return fontEngine;
}
QStringList QWasmFontDatabase::fallbacksForFamily(const QString &family, QFont::Style style,
@@ -65,21 +324,17 @@ QStringList QWasmFontDatabase::fallbacksForFamily(const QString &family, QFont::
QStringList fallbacks
= QFreeTypeFontDatabase::fallbacksForFamily(family, style, styleHint, script);
- // Add the vera.ttf font (loaded in populateFontDatabase above) as a falback font
+ // Add the DejaVuSans.ttf font (loaded in populateFontDatabase above) as a falback font
// to all other fonts (except itself).
- const QString veraFontFamily = QStringLiteral("Bitstream Vera Sans");
- if (family != veraFontFamily)
- fallbacks.append(veraFontFamily);
+ static const QString wasmFallbackFonts[] = { "DejaVu Sans" };
+ for (auto wasmFallbackFont : wasmFallbackFonts) {
+ if (family != wasmFallbackFont && !fallbacks.contains(wasmFallbackFont))
+ fallbacks.append(wasmFallbackFont);
+ }
return fallbacks;
}
-QStringList QWasmFontDatabase::addApplicationFont(const QByteArray &fontData,
- const QString &fileName)
-{
- return QFreeTypeFontDatabase::addApplicationFont(fontData, fileName);
-}
-
void QWasmFontDatabase::releaseHandle(void *handle)
{
QFreeTypeFontDatabase::releaseHandle(handle);
@@ -87,7 +342,63 @@ void QWasmFontDatabase::releaseHandle(void *handle)
QFont QWasmFontDatabase::defaultFont() const
{
- return QFont(QLatin1String("Bitstream Vera Sans"));
+ return QFont("DejaVu Sans"_L1);
}
+namespace {
+ int g_pendingFonts = 0;
+ bool g_fontStartupTaskCompleted = false;
+}
+
+// Registers font loading as a startup task, which makes Qt delay
+// sending onLoaded event until font loading has completed.
+void QWasmFontDatabase::beginFontDatabaseStartupTask()
+{
+ g_fontStartupTaskCompleted = false;
+ QEventDispatcherWasm::registerStartupTask();
+}
+
+// Ends the font loading startup task.
+void QWasmFontDatabase::endFontDatabaseStartupTask()
+{
+ if (!g_fontStartupTaskCompleted) {
+ g_fontStartupTaskCompleted = true;
+ QEventDispatcherWasm::completeStarupTask();
+ }
+}
+
+// Registers that a font file will be loaded.
+void QWasmFontDatabase::refFontFileLoading()
+{
+ g_pendingFonts += 1;
+}
+
+// Registers that one font file has been loaded, and sends notifactions
+// when all pending font files have been loaded.
+void QWasmFontDatabase::derefFontFileLoading()
+{
+ if (--g_pendingFonts <= 0) {
+ QFontCache::instance()->clear();
+ emit qGuiApp->fontDatabaseChanged();
+ endFontDatabaseStartupTask();
+ }
+}
+
+// Unconditionally ends local font loading, for instance if there
+// are no fonts to load or if there was an unexpected error.
+void QWasmFontDatabase::endAllFontFileLoading()
+{
+ bool hadPandingfonts = g_pendingFonts > 0;
+ if (hadPandingfonts) {
+ // The hadPandingfonts counter might no longer be correct; disable counting
+ // and send notifications unconditionally.
+ g_pendingFonts = 0;
+ QFontCache::instance()->clear();
+ emit qGuiApp->fontDatabaseChanged();
+ }
+
+ endFontDatabaseStartupTask();
+}
+
+
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/wasm/qwasmfontdatabase.h b/src/plugins/platforms/wasm/qwasmfontdatabase.h
index cbd187a022..a1c8f1ff48 100644
--- a/src/plugins/platforms/wasm/qwasmfontdatabase.h
+++ b/src/plugins/platforms/wasm/qwasmfontdatabase.h
@@ -1,50 +1,49 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the plugins of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL$
-** 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 General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 or (at your option) 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.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-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#ifndef QWASMFONTDATABASE_H
#define QWASMFONTDATABASE_H
-#include <QtFontDatabaseSupport/private/qfreetypefontdatabase_p.h>
+#include <QtGui/private/qfreetypefontdatabase_p.h>
+
+#include <emscripten/val.h>
QT_BEGIN_NAMESPACE
class QWasmFontDatabase : public QFreeTypeFontDatabase
{
public:
+ QWasmFontDatabase();
+ static QWasmFontDatabase *get();
+
void populateFontDatabase() override;
QFontEngine *fontEngine(const QFontDef &fontDef, void *handle) override;
QStringList fallbacksForFamily(const QString &family, QFont::Style style,
QFont::StyleHint styleHint,
QChar::Script script) const override;
- QStringList addApplicationFont(const QByteArray &fontData, const QString &fileName) override;
void releaseHandle(void *handle) override;
QFont defaultFont() const override;
+
+ void populateLocalfonts();
+ void populateLocalFontFamilies(emscripten::val families);
+ void populateLocalFontFamilies(const QStringList &famliies, bool allFamilies);
+
+ static void beginFontDatabaseStartupTask();
+ static void endFontDatabaseStartupTask();
+ static void refFontFileLoading();
+ static void derefFontFileLoading();
+ static void endAllFontFileLoading();
+
+private:
+ bool m_localFontsApiSupported = false;
+ bool m_queryLocalFontsPermission = false;
+ enum FontFamilyLoadSet {
+ NoFontFamilies,
+ DefaultFontFamilies,
+ AllFontFamilies,
+ };
+ FontFamilyLoadSet m_localFontFamilyLoadSet;
+ QStringList m_extraLocalFontFamilies;
};
QT_END_NAMESPACE
#endif
diff --git a/src/plugins/platforms/wasm/qwasminputcontext.cpp b/src/plugins/platforms/wasm/qwasminputcontext.cpp
new file mode 100644
index 0000000000..ae72e7b7f9
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasminputcontext.cpp
@@ -0,0 +1,161 @@
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <emscripten/bind.h>
+
+#include "qwasminputcontext.h"
+#include "qwasmintegration.h"
+#include "qwasmplatform.h"
+#include <QRectF>
+#include <qpa/qplatforminputcontext.h>
+#include "qwasmscreen.h"
+#include <qguiapplication.h>
+#include <qwindow.h>
+#include <QKeySequence>
+#include <qpa/qwindowsysteminterface.h>
+
+QT_BEGIN_NAMESPACE
+using namespace qstdweb;
+
+static void inputCallback(emscripten::val event)
+{
+ // android sends all the characters typed since the user started typing in this element
+ int length = event["target"]["value"]["length"].as<int>();
+ if (length <= 0)
+ return;
+
+ emscripten::val _incomingCharVal = event["data"];
+ if (_incomingCharVal != emscripten::val::undefined() && _incomingCharVal != emscripten::val::null()) {
+
+ QString str = QString::fromStdString(_incomingCharVal.as<std::string>());
+ QWasmInputContext *wasmInput =
+ reinterpret_cast<QWasmInputContext*>(event["target"]["data-qinputcontext"].as<quintptr>());
+ wasmInput->inputStringChanged(str, EMSCRIPTEN_EVENT_KEYDOWN, wasmInput);
+ }
+ // this clears the input string, so backspaces do not send a character
+ // but stops suggestions
+ event["target"].set("value", "");
+}
+
+EMSCRIPTEN_BINDINGS(clipboard_module) {
+ function("qtInputContextCallback", &inputCallback);
+}
+
+QWasmInputContext::QWasmInputContext()
+{
+ emscripten::val document = emscripten::val::global("document");
+ m_inputElement = document.call<emscripten::val>("createElement", std::string("input"));
+ m_inputElement.set("type", "text");
+ m_inputElement.set("style", "position:absolute;left:-1000px;top:-1000px"); // offscreen
+ m_inputElement.set("contenteditable","true");
+
+ if (platform() == Platform::MacOS || platform() == Platform::iOS) {
+ auto callback = [=](emscripten::val) {
+ m_inputElement["parentElement"].call<void>("removeChild", m_inputElement);
+ inputPanelIsOpen = false;
+ };
+ m_blurEventHandler.reset(new EventCallback(m_inputElement, "blur", callback));
+
+ } else {
+
+ const std::string inputType = platform() == Platform::Windows ? "textInput" : "input";
+
+ document.call<void>("addEventListener", inputType,
+ emscripten::val::module_property("qtInputContextCallback"),
+ emscripten::val(false));
+ m_inputElement.set("data-qinputcontext",
+ emscripten::val(quintptr(reinterpret_cast<void *>(this))));
+ emscripten::val body = document["body"];
+ body.call<void>("appendChild", m_inputElement);
+ }
+
+ QObject::connect(qGuiApp, &QGuiApplication::focusWindowChanged, this,
+ &QWasmInputContext::focusWindowChanged);
+}
+
+QWasmInputContext::~QWasmInputContext()
+{
+ if (platform() == Platform::Android || platform() == Platform::Windows)
+ emscripten_set_keydown_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, 0, 0, NULL);
+}
+
+void QWasmInputContext::focusWindowChanged(QWindow *focusWindow)
+{
+ m_focusWindow = focusWindow;
+}
+
+emscripten::val QWasmInputContext::inputHandlerElementForFocusedWindow()
+{
+ if (!m_focusWindow)
+ return emscripten::val::undefined();
+ return static_cast<QWasmWindow *>(m_focusWindow->handle())->inputHandlerElement();
+}
+
+void QWasmInputContext::update(Qt::InputMethodQueries queries)
+{
+ QPlatformInputContext::update(queries);
+}
+
+void QWasmInputContext::showInputPanel()
+{
+ if (platform() == Platform::Windows
+ && !inputPanelIsOpen) { // call this only once for win32
+ m_inputElement.call<void>("focus");
+ return;
+ }
+ // this is called each time the keyboard is touched
+
+ // Add the input element as a child of the screen for the
+ // currently focused window and give it focus. The browser
+ // will not display the input element, but mobile browsers
+ // should display the virtual keyboard. Key events will be
+ // captured by the keyboard event handler installed on the
+ // screen element.
+
+ if (platform() == Platform::MacOS // keep for compatibility
+ || platform() == Platform::iOS
+ || platform() == Platform::Windows) {
+ emscripten::val inputWrapper = inputHandlerElementForFocusedWindow();
+ if (inputWrapper.isUndefined())
+ return;
+ inputWrapper.call<void>("appendChild", m_inputElement);
+ }
+
+ m_inputElement.call<void>("focus");
+ inputPanelIsOpen = true;
+}
+
+void QWasmInputContext::hideInputPanel()
+{
+ if (QWasmIntegration::get()->touchPoints < 1)
+ return;
+ m_inputElement.call<void>("blur");
+ inputPanelIsOpen = false;
+}
+
+void QWasmInputContext::inputStringChanged(QString &inputString, int eventType, QWasmInputContext *context)
+{
+ Q_UNUSED(context)
+ QKeySequence keys = QKeySequence::fromString(inputString);
+ Qt::Key thisKey = keys[0].key();
+
+ // synthesize this keyevent as android is not normal
+ if (inputString.size() > 2 && (thisKey < Qt::Key_F35
+ || thisKey > Qt::Key_Back)) {
+ inputString.clear();
+ }
+ if (inputString == QStringLiteral("Escape")) {
+ thisKey = Qt::Key_Escape;
+ inputString.clear();
+ } else if (thisKey == Qt::Key(0)) {
+ thisKey = Qt::Key_Return;
+ }
+
+ QWindowSystemInterface::handleKeyEvent(
+ 0, eventType == EMSCRIPTEN_EVENT_KEYDOWN ? QEvent::KeyPress : QEvent::KeyRelease,
+ thisKey, keys[0].keyboardModifiers(),
+ eventType == EMSCRIPTEN_EVENT_KEYDOWN ? inputString : QStringLiteral(""));
+}
+
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/wasm/qwasminputcontext.h b/src/plugins/platforms/wasm/qwasminputcontext.h
new file mode 100644
index 0000000000..10dd1a0950
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasminputcontext.h
@@ -0,0 +1,48 @@
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef QWASMINPUTCONTEXT_H
+#define QWASMINPUTCONTEXT_H
+
+
+#include <qpa/qplatforminputcontext.h>
+#include <QtCore/qpointer.h>
+#include <private/qstdweb_p.h>
+#include <emscripten/bind.h>
+#include <emscripten/html5.h>
+#include <emscripten/emscripten.h>
+
+QT_BEGIN_NAMESPACE
+
+class QWasmInputContext : public QPlatformInputContext
+{
+ Q_DISABLE_COPY(QWasmInputContext)
+ Q_OBJECT
+public:
+ explicit QWasmInputContext();
+ ~QWasmInputContext() override;
+
+ void update(Qt::InputMethodQueries) override;
+
+ void showInputPanel() override;
+ void hideInputPanel() override;
+ bool isValid() const override { return true; }
+
+ void focusWindowChanged(QWindow *focusWindow);
+ void inputStringChanged(QString &, int eventType, QWasmInputContext *context);
+ emscripten::val m_inputElement = emscripten::val::null();
+
+private:
+ emscripten::val inputHandlerElementForFocusedWindow();
+
+ bool m_inputPanelVisible = false;
+
+ QPointer<QWindow> m_focusWindow;
+ std::unique_ptr<qstdweb::EventCallback> m_blurEventHandler;
+ std::unique_ptr<qstdweb::EventCallback> m_inputEventHandler;
+ bool inputPanelIsOpen = false;
+};
+
+QT_END_NAMESPACE
+
+#endif // QWASMINPUTCONTEXT_H
diff --git a/src/plugins/platforms/wasm/qwasmintegration.cpp b/src/plugins/platforms/wasm/qwasmintegration.cpp
index d1901d840e..f5cc3e2eee 100644
--- a/src/plugins/platforms/wasm/qwasmintegration.cpp
+++ b/src/plugins/platforms/wasm/qwasmintegration.cpp
@@ -1,85 +1,61 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the plugins of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL$
-** 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 General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 or (at your option) 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.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-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include "qwasmintegration.h"
-#include "qwasmeventtranslator.h"
#include "qwasmeventdispatcher.h"
#include "qwasmcompositor.h"
#include "qwasmopenglcontext.h"
#include "qwasmtheme.h"
#include "qwasmclipboard.h"
+#include "qwasmaccessibility.h"
#include "qwasmservices.h"
#include "qwasmoffscreensurface.h"
-#include "qwasmstring.h"
-
+#include "qwasmplatform.h"
#include "qwasmwindow.h"
-#ifndef QT_NO_OPENGL
-# include "qwasmbackingstore.h"
-# include <QtPlatformCompositorSupport/qpa/qplatformbackingstoreopenglsupport.h>
-#endif
+#include "qwasmbackingstore.h"
#include "qwasmfontdatabase.h"
-#if defined(Q_OS_UNIX)
-#include <QtEventDispatcherSupport/private/qgenericunixeventdispatcher_p.h>
-#endif
+#include "qwasmdrag.h"
+
#include <qpa/qplatformwindow.h>
#include <QtGui/qscreen.h>
#include <qpa/qwindowsysteminterface.h>
#include <QtCore/qcoreapplication.h>
#include <qpa/qplatforminputcontextfactory_p.h>
+#include <qpa/qwindowsysteminterface_p.h>
#include <emscripten/bind.h>
#include <emscripten/val.h>
// this is where EGL headers are pulled in, make sure it is last
#include "qwasmscreen.h"
+#include <private/qsimpledrag_p.h>
-using namespace emscripten;
QT_BEGIN_NAMESPACE
-static void browserBeforeUnload(emscripten::val)
+extern void qt_set_sequence_auto_mnemonic(bool);
+
+using namespace emscripten;
+
+using namespace Qt::StringLiterals;
+
+static void setContainerElements(emscripten::val elementArray)
{
- QWasmIntegration::QWasmBrowserExit();
+ QWasmIntegration::get()->setContainerElements(elementArray);
}
-static void addCanvasElement(emscripten::val canvas)
+static void addContainerElement(emscripten::val element)
{
- QWasmIntegration::get()->addScreen(canvas);
+ QWasmIntegration::get()->addContainerElement(element);
}
-static void removeCanvasElement(emscripten::val canvas)
+static void removeContainerElement(emscripten::val element)
{
- QWasmIntegration::get()->removeScreen(canvas);
+ QWasmIntegration::get()->removeContainerElement(element);
}
-static void resizeCanvasElement(emscripten::val canvas)
+static void resizeContainerElement(emscripten::val element)
{
- QWasmIntegration::get()->resizeScreen(canvas);
+ QWasmIntegration::get()->resizeScreen(element);
}
static void qtUpdateDpi()
@@ -87,75 +63,114 @@ static void qtUpdateDpi()
QWasmIntegration::get()->updateDpi();
}
+static void resizeAllScreens(emscripten::val event)
+{
+ Q_UNUSED(event);
+ QWasmIntegration::get()->resizeAllScreens();
+}
+
+static void loadLocalFontFamilies(emscripten::val event)
+{
+ QWasmIntegration::get()->loadLocalFontFamilies(event);
+}
+
EMSCRIPTEN_BINDINGS(qtQWasmIntegraton)
{
- function("qtBrowserBeforeUnload", &browserBeforeUnload);
- function("qtAddCanvasElement", &addCanvasElement);
- function("qtRemoveCanvasElement", &removeCanvasElement);
- function("qtResizeCanvasElement", &resizeCanvasElement);
+ function("qtSetContainerElements", &setContainerElements);
+ function("qtAddContainerElement", &addContainerElement);
+ function("qtRemoveContainerElement", &removeContainerElement);
+ function("qtResizeContainerElement", &resizeContainerElement);
function("qtUpdateDpi", &qtUpdateDpi);
+ function("qtResizeAllScreens", &resizeAllScreens);
+ function("qtLoadLocalFontFamilies", &loadLocalFontFamilies);
}
QWasmIntegration *QWasmIntegration::s_instance;
QWasmIntegration::QWasmIntegration()
- : m_fontDb(nullptr),
- m_desktopServices(nullptr),
- m_clipboard(new QWasmClipboard)
+ : m_fontDb(nullptr)
+ , m_desktopServices(nullptr)
+ , m_clipboard(new QWasmClipboard)
+#if QT_CONFIG(accessibility)
+ , m_accessibility(new QWasmAccessibility)
+#endif
{
s_instance = this;
- // We expect that qtloader.js has populated Module.qtCanvasElements with one or more canvases.
- emscripten::val qtCanvaseElements = val::module_property("qtCanvasElements");
- emscripten::val canvas = val::module_property("canvas"); // TODO: remove for Qt 6.0
-
- if (!qtCanvaseElements.isUndefined()) {
- int screenCount = qtCanvaseElements["length"].as<int>();
- for (int i = 0; i < screenCount; ++i) {
- addScreen(qtCanvaseElements[i].as<emscripten::val>());
+ if (platform() == Platform::MacOS)
+ qt_set_sequence_auto_mnemonic(false);
+
+ touchPoints = emscripten::val::global("navigator")["maxTouchPoints"].as<int>();
+ QWindowSystemInterfacePrivate::TabletEvent::setPlatformSynthesizesMouse(false);
+
+ // Create screens for container elements. Each container element will ultimately become a
+ // div element. Qt historically supported supplying canvas for screen elements - these elements
+ // will be transformed into divs and warnings about deprecation will be printed. See
+ // QWasmScreen ctor.
+ emscripten::val filtered = emscripten::val::array();
+ emscripten::val qtContainerElements = val::module_property("qtContainerElements");
+ if (qtContainerElements.isArray()) {
+ for (int i = 0; i < qtContainerElements["length"].as<int>(); ++i) {
+ emscripten::val element = qtContainerElements[i].as<emscripten::val>();
+ if (element.isNull() || element.isUndefined())
+ qWarning() << "Skipping null or undefined element in qtContainerElements";
+ else
+ filtered.call<void>("push", element);
}
- } else if (!canvas.isUndefined()) {
- qWarning() << "Module.canvas is deprecated. A future version of Qt will stop reading this property. "
- << "Instead, set Module.qtCanvasElements to be an array of canvas elements, or use qtloader.js.";
- addScreen(canvas);
+ } else {
+ // No screens, which may or may not be intended
+ qWarning() << "The qtContainerElements module property was not set or is invalid. "
+ "Proceeding with no screens.";
}
-
- emscripten::val::global("window").set("onbeforeunload", val::module_property("qtBrowserBeforeUnload"));
+ setContainerElements(filtered);
// install browser window resize handler
- auto onWindowResize = [](int eventType, const EmscriptenUiEvent *e, void *userData) -> int {
- Q_UNUSED(eventType);
- Q_UNUSED(e);
- Q_UNUSED(userData);
-
- // This resize event is called when the HTML window is resized. Depending
- // on the page layout the canvas(es) might also have been resized, so we
- // update the Qt screen sizes (and canvas render sizes).
- if (QWasmIntegration *integration = QWasmIntegration::get())
- 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,
+ [](int, const EmscriptenUiEvent *, void *) -> int {
+ // This resize event is called when the HTML window is
+ // resized. Depending on the page layout the elements might
+ // also have been resized, so we update the Qt screen sizes
+ // (and canvas render sizes).
+ if (QWasmIntegration *integration = QWasmIntegration::get())
+ integration->resizeAllScreens();
+ return 0;
+ });
+
+ // install visualViewport resize handler which picks up size and scale change on mobile.
+ emscripten::val visualViewport = emscripten::val::global("window")["visualViewport"];
+ if (!visualViewport.isUndefined()) {
+ visualViewport.call<void>("addEventListener", val("resize"),
+ val::module_property("qtResizeAllScreens"));
+ }
+ m_drag = std::make_unique<QWasmDrag>();
}
QWasmIntegration::~QWasmIntegration()
{
+ // Remove event listener
+ 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;
+ if (m_platformInputContext)
+ delete m_platformInputContext;
+#if QT_CONFIG(accessibility)
+ delete m_accessibility;
+#endif
+
+ for (const auto &elementAndScreen : m_screens)
+ elementAndScreen.wasmScreen->deleteScreen();
- for (const auto &canvasAndScreen : m_screens)
- QWindowSystemInterface::handleScreenRemoved(canvasAndScreen.second);
m_screens.clear();
s_instance = nullptr;
}
-void QWasmIntegration::QWasmBrowserExit()
-{
- QCoreApplication *app = QCoreApplication::instance();
- app->quit();
-}
-
bool QWasmIntegration::hasCapability(QPlatformIntegration::Capability cap) const
{
switch (cap) {
@@ -172,35 +187,52 @@ bool QWasmIntegration::hasCapability(QPlatformIntegration::Capability cap) const
QPlatformWindow *QWasmIntegration::createPlatformWindow(QWindow *window) const
{
- QWasmCompositor *compositor = QWasmScreen::get(window->screen())->compositor();
- return new QWasmWindow(window, compositor, m_backingStores.value(window));
+ auto *wasmScreen = QWasmScreen::get(window->screen());
+ QWasmCompositor *compositor = wasmScreen->compositor();
+ return new QWasmWindow(window, wasmScreen->deadKeySupport(), compositor,
+ m_backingStores.value(window));
}
QPlatformBackingStore *QWasmIntegration::createPlatformBackingStore(QWindow *window) const
{
-#ifndef QT_NO_OPENGL
QWasmCompositor *compositor = QWasmScreen::get(window->screen())->compositor();
QWasmBackingStore *backingStore = new QWasmBackingStore(compositor, window);
- backingStore->setOpenGLSupport(new QPlatformBackingStoreOpenGLSupport(backingStore));
m_backingStores.insert(window, backingStore);
return backingStore;
-#else
- return nullptr;
-#endif
+}
+
+void QWasmIntegration::removeBackingStore(QWindow* window)
+{
+ m_backingStores.remove(window);
+}
+
+void QWasmIntegration::releaseRequesetUpdateHold()
+{
+ if (QWasmCompositor::releaseRequestUpdateHold())
+ {
+ for (const auto &elementAndScreen : m_screens) {
+ elementAndScreen.wasmScreen->compositor()->requestUpdate();
+ }
+ }
}
#ifndef QT_NO_OPENGL
QPlatformOpenGLContext *QWasmIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const
{
- return new QWasmOpenGLContext(context->format());
+ return new QWasmOpenGLContext(context);
}
#endif
void QWasmIntegration::initialize()
{
- QString icStr = QPlatformInputContextFactory::requested();
- if (!icStr.isNull())
- m_inputContext.reset(QPlatformInputContextFactory::create(icStr));
+ auto icStrs = QPlatformInputContextFactory::requested();
+ if (icStrs.isEmpty() && touchPoints < 1)
+ return;
+
+ if (!icStrs.isEmpty())
+ m_inputContext.reset(QPlatformInputContextFactory::create(icStrs));
+ else
+ m_inputContext.reset(new QWasmInputContext());
}
QPlatformInputContext *QWasmIntegration::inputContext() const
@@ -210,7 +242,7 @@ QPlatformInputContext *QWasmIntegration::inputContext() const
QPlatformOffscreenSurface *QWasmIntegration::createPlatformOffscreenSurface(QOffscreenSurface *surface) const
{
- return new QWasmOffscrenSurface(surface);
+ return new QWasmOffscreenSurface(surface);
}
QPlatformFontDatabase *QWasmIntegration::fontDatabase() const
@@ -228,16 +260,20 @@ QAbstractEventDispatcher *QWasmIntegration::createEventDispatcher() const
QVariant QWasmIntegration::styleHint(QPlatformIntegration::StyleHint hint) const
{
- if (hint == ShowIsFullScreen)
+ switch (hint) {
+ case ShowIsFullScreen:
return true;
-
- return QPlatformIntegration::styleHint(hint);
+ case UnderlineShortcut:
+ return platform() != Platform::MacOS;
+ default:
+ return QPlatformIntegration::styleHint(hint);
+ }
}
Qt::WindowState QWasmIntegration::defaultWindowState(Qt::WindowFlags flags) const
{
- // Don't maximize dialogs
- if (flags & Qt::Dialog & ~Qt::Window)
+ // Don't maximize dialogs or popups
+ if (flags.testFlag(Qt::Dialog) || flags.testFlag(Qt::Popup))
return Qt::WindowNoState;
return QPlatformIntegration::defaultWindowState(flags);
@@ -245,12 +281,12 @@ Qt::WindowState QWasmIntegration::defaultWindowState(Qt::WindowFlags flags) cons
QStringList QWasmIntegration::themeNames() const
{
- return QStringList() << QLatin1String("webassembly");
+ return QStringList() << "webassembly"_L1;
}
QPlatformTheme *QWasmIntegration::createPlatformTheme(const QString &name) const
{
- if (name == QLatin1String("webassembly"))
+ if (name == "webassembly"_L1)
return new QWasmTheme;
return QPlatformIntegration::createPlatformTheme(name);
}
@@ -267,37 +303,100 @@ QPlatformClipboard* QWasmIntegration::clipboard() const
return m_clipboard;
}
-void QWasmIntegration::addScreen(const emscripten::val &canvas)
+#ifndef QT_NO_ACCESSIBILITY
+QPlatformAccessibility *QWasmIntegration::accessibility() const
+{
+ return m_accessibility;
+}
+#endif
+
+void QWasmIntegration::setContainerElements(emscripten::val elementArray)
{
- QWasmScreen *screen = new QWasmScreen(canvas);
- m_screens.append(qMakePair(canvas, screen));
- m_clipboard->installEventHandlers(canvas);
+ const auto *primaryScreenBefore = m_screens.isEmpty() ? nullptr : m_screens[0].wasmScreen;
+ QList<ScreenMapping> newScreens;
+
+ QList<QWasmScreen *> screensToDelete;
+ std::transform(m_screens.begin(), m_screens.end(), std::back_inserter(screensToDelete),
+ [](const ScreenMapping &mapping) { return mapping.wasmScreen; });
+
+ for (int i = 0; i < elementArray["length"].as<int>(); ++i) {
+ const auto element = elementArray[i];
+ const auto it = std::find_if(
+ m_screens.begin(), m_screens.end(),
+ [&element](const ScreenMapping &screen) { return screen.emscriptenVal == element; });
+ QWasmScreen *screen;
+ if (it != m_screens.end()) {
+ screen = it->wasmScreen;
+ screensToDelete.erase(std::remove_if(screensToDelete.begin(), screensToDelete.end(),
+ [screen](const QWasmScreen *removedScreen) {
+ return removedScreen == screen;
+ }),
+ screensToDelete.end());
+ } else {
+ screen = new QWasmScreen(element);
+ QWindowSystemInterface::handleScreenAdded(screen);
+ }
+ newScreens.push_back({element, screen});
+ }
+
+ std::for_each(screensToDelete.begin(), screensToDelete.end(),
+ [](QWasmScreen *removed) { removed->deleteScreen(); });
+
+ m_screens = newScreens;
+ auto *primaryScreenAfter = m_screens.isEmpty() ? nullptr : m_screens[0].wasmScreen;
+ if (primaryScreenAfter && primaryScreenAfter != primaryScreenBefore)
+ QWindowSystemInterface::handlePrimaryScreenChanged(primaryScreenAfter);
+}
+
+void QWasmIntegration::addContainerElement(emscripten::val element)
+{
+ Q_ASSERT_X(m_screens.end()
+ == std::find_if(m_screens.begin(), m_screens.end(),
+ [&element](const ScreenMapping &screen) {
+ return screen.emscriptenVal == element;
+ }),
+ Q_FUNC_INFO, "Double-add of an element");
+
+ QWasmScreen *screen = new QWasmScreen(element);
QWindowSystemInterface::handleScreenAdded(screen);
+ m_screens.push_back({element, screen});
}
-void QWasmIntegration::removeScreen(const emscripten::val &canvas)
+void QWasmIntegration::removeContainerElement(emscripten::val element)
{
- auto it = std::find_if(m_screens.begin(), m_screens.end(),
- [&] (const QPair<emscripten::val, QWasmScreen *> &candidate) { return candidate.first.equals(canvas); });
+ const auto *primaryScreenBefore = m_screens.isEmpty() ? nullptr : m_screens[0].wasmScreen;
+
+ const auto it =
+ std::find_if(m_screens.begin(), m_screens.end(),
+ [&element](const ScreenMapping &screen) { return screen.emscriptenVal == element; });
if (it == m_screens.end()) {
- qWarning() << "Attempting to remove non-existing screen for canvas" << QWasmString::toQString(canvas["id"]);;
+ qWarning() << "Attempt to remove a nonexistent screen.";
return;
}
- QWasmScreen *exScreen = it->second;
- m_screens.erase(it);
- exScreen->destroy(); // clean up before deleting the screen
- QWindowSystemInterface::handleScreenRemoved(exScreen);
+
+ QWasmScreen *removedScreen = it->wasmScreen;
+ removedScreen->deleteScreen();
+
+ m_screens.erase(std::remove_if(m_screens.begin(), m_screens.end(),
+ [removedScreen](const ScreenMapping &mapping) {
+ return removedScreen == mapping.wasmScreen;
+ }),
+ m_screens.end());
+ auto *primaryScreenAfter = m_screens.isEmpty() ? nullptr : m_screens[0].wasmScreen;
+ if (primaryScreenAfter && primaryScreenAfter != primaryScreenBefore)
+ QWindowSystemInterface::handlePrimaryScreenChanged(primaryScreenAfter);
}
-void QWasmIntegration::resizeScreen(const emscripten::val &canvas)
+void QWasmIntegration::resizeScreen(const emscripten::val &element)
{
auto it = std::find_if(m_screens.begin(), m_screens.end(),
- [&] (const QPair<emscripten::val, QWasmScreen *> &candidate) { return candidate.first.equals(canvas); });
+ [&] (const ScreenMapping &candidate) { return candidate.emscriptenVal.equals(element); });
if (it == m_screens.end()) {
- qWarning() << "Attempting to resize non-existing screen for canvas" << QWasmString::toQString(canvas["id"]);;
+ qWarning() << "Attempting to resize non-existing screen for element"
+ << QString::fromEcmaString(element["id"]);
return;
}
- it->second->updateQScreenAndCanvasRenderSize();
+ it->wasmScreen->updateQScreenAndCanvasRenderSize();
}
void QWasmIntegration::updateDpi()
@@ -306,14 +405,31 @@ void QWasmIntegration::updateDpi()
if (dpi.isUndefined())
return;
qreal dpiValue = dpi.as<qreal>();
- for (const auto &canvasAndScreen : m_screens)
- QWindowSystemInterface::handleScreenLogicalDotsPerInchChange(canvasAndScreen.second->screen(), dpiValue, dpiValue);
+ for (const auto &elementAndScreen : m_screens)
+ QWindowSystemInterface::handleScreenLogicalDotsPerInchChange(elementAndScreen.wasmScreen->screen(), dpiValue, dpiValue);
}
void QWasmIntegration::resizeAllScreens()
{
- for (const auto &canvasAndScreen : m_screens)
- canvasAndScreen.second->updateQScreenAndCanvasRenderSize();
+ for (const auto &elementAndScreen : m_screens)
+ elementAndScreen.wasmScreen->updateQScreenAndCanvasRenderSize();
+}
+
+void QWasmIntegration::loadLocalFontFamilies(emscripten::val families)
+{
+ m_fontDb->populateLocalFontFamilies(families);
+}
+
+quint64 QWasmIntegration::getTimestamp()
+{
+ return emscripten_performance_now();
+}
+
+#if QT_CONFIG(draganddrop)
+QPlatformDrag *QWasmIntegration::drag() const
+{
+ return m_drag.get();
}
+#endif // QT_CONFIG(draganddrop)
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/wasm/qwasmintegration.h b/src/plugins/platforms/wasm/qwasmintegration.h
index 08b68cb5f7..870bd0d16b 100644
--- a/src/plugins/platforms/wasm/qwasmintegration.h
+++ b/src/plugins/platforms/wasm/qwasmintegration.h
@@ -1,43 +1,21 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the plugins of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL$
-** 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 General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 or (at your option) 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.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-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#ifndef QWASMINTEGRATION_H
#define QWASMINTEGRATION_H
#include "qwasmwindow.h"
+#include "qwasminputcontext.h"
+
#include <qpa/qplatformintegration.h>
#include <qpa/qplatformscreen.h>
#include <qpa/qplatforminputcontext.h>
#include <QtCore/qhash.h>
+#include <private/qstdweb_p.h>
+
#include <emscripten.h>
#include <emscripten/html5.h>
#include <emscripten/val.h>
@@ -52,7 +30,9 @@ class QWasmScreen;
class QWasmCompositor;
class QWasmBackingStore;
class QWasmClipboard;
+class QWasmAccessibility;
class QWasmServices;
+class QWasmDrag;
class QWasmIntegration : public QObject, public QPlatformIntegration
{
@@ -76,29 +56,56 @@ public:
QPlatformTheme *createPlatformTheme(const QString &name) const override;
QPlatformServices *services() const override;
QPlatformClipboard *clipboard() const override;
+#ifndef QT_NO_ACCESSIBILITY
+ QPlatformAccessibility *accessibility() const override;
+#endif
void initialize() override;
QPlatformInputContext *inputContext() const override;
- QWasmClipboard *getWasmClipboard() { return m_clipboard; }
+#if QT_CONFIG(draganddrop)
+ QPlatformDrag *drag() const override;
+#endif
+ QWasmClipboard *getWasmClipboard() { return m_clipboard; }
+ QWasmInputContext *getWasmInputContext() { return m_platformInputContext; }
static QWasmIntegration *get() { return s_instance; }
- static void QWasmBrowserExit();
- void addScreen(const emscripten::val &canvas);
- void removeScreen(const emscripten::val &canvas);
+ void setContainerElements(emscripten::val elementArray);
+ void addContainerElement(emscripten::val elementArray);
+ void removeContainerElement(emscripten::val elementArray);
void resizeScreen(const emscripten::val &canvas);
- void resizeAllScreens();
void updateDpi();
+ void resizeAllScreens();
+ void loadLocalFontFamilies(emscripten::val families);
+ void removeBackingStore(QWindow* window);
+ void releaseRequesetUpdateHold();
+ static quint64 getTimestamp();
+
+ int touchPoints;
private:
+ struct ScreenMapping {
+ emscripten::val emscriptenVal;
+ QWasmScreen *wasmScreen;
+ };
+
mutable QWasmFontDatabase *m_fontDb;
mutable QWasmServices *m_desktopServices;
mutable QHash<QWindow *, QWasmBackingStore *> m_backingStores;
- QVector<QPair<emscripten::val, QWasmScreen *>> m_screens;
+ QList<ScreenMapping> m_screens;
mutable QWasmClipboard *m_clipboard;
+ mutable QWasmAccessibility *m_accessibility;
+
qreal m_fontDpi = -1;
mutable QScopedPointer<QPlatformInputContext> m_inputContext;
static QWasmIntegration *s_instance;
+
+ mutable QWasmInputContext *m_platformInputContext = nullptr;
+
+#if QT_CONFIG(draganddrop)
+ std::unique_ptr<QWasmDrag> m_drag;
+#endif
+
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/wasm/qwasmkeytranslator.cpp b/src/plugins/platforms/wasm/qwasmkeytranslator.cpp
new file mode 100644
index 0000000000..8f5240d2d0
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmkeytranslator.cpp
@@ -0,0 +1,295 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "qwasmkeytranslator.h"
+#include "qwasmevent.h"
+
+#include <QtCore/private/qmakearray_p.h>
+#include <QtCore/qglobal.h>
+#include <QtCore/qobject.h>
+
+#include <algorithm>
+
+QT_BEGIN_NAMESPACE
+
+namespace {
+struct WebKb2QtData
+{
+ static constexpr char StringTerminator = '\0';
+
+ const char *web;
+ unsigned int qt;
+
+ constexpr bool operator<=(const WebKb2QtData &that) const noexcept
+ {
+ return !(strcmp(that) > 0);
+ }
+
+ bool operator<(const WebKb2QtData &that) const noexcept { return ::strcmp(web, that.web) < 0; }
+
+ constexpr bool operator==(const WebKb2QtData &that) const noexcept { return strcmp(that) == 0; }
+
+ constexpr int strcmp(const WebKb2QtData &that, const int i = 0) const
+ {
+ return web[i] == StringTerminator && that.web[i] == StringTerminator ? 0
+ : web[i] == StringTerminator ? -1
+ : that.web[i] == StringTerminator ? 1
+ : web[i] < that.web[i] ? -1
+ : web[i] > that.web[i] ? 1
+ : strcmp(that, i + 1);
+ }
+};
+
+template<unsigned int Qt, char... WebChar>
+struct Web2Qt
+{
+ static constexpr const char storage[sizeof...(WebChar) + 1] = { WebChar..., '\0' };
+ using Type = WebKb2QtData;
+ static constexpr Type data() noexcept { return Type{ storage, Qt }; }
+};
+
+template<unsigned int Qt, char... WebChar>
+constexpr char Web2Qt<Qt, WebChar...>::storage[];
+
+static constexpr const auto WebToQtKeyCodeMappings = qMakeArray(
+ QSortedData<Web2Qt<Qt::Key_Alt, 'A', 'l', 't', 'L', 'e', 'f', 't'>,
+ Web2Qt<Qt::Key_Alt, 'A', 'l', 't'>,
+ Web2Qt<Qt::Key_AltGr, 'A', 'l', 't', 'R', 'i', 'g', 'h', 't'>,
+ Web2Qt<Qt::Key_Apostrophe, 'Q', 'u', 'o', 't', 'e'>,
+ Web2Qt<Qt::Key_Backspace, 'B', 'a', 'c', 'k', 's', 'p', 'a', 'c', 'e'>,
+ Web2Qt<Qt::Key_CapsLock, 'C', 'a', 'p', 's', 'L', 'o', 'c', 'k'>,
+ Web2Qt<Qt::Key_Control, 'C', 'o', 'n', 't', 'r', 'o', 'l'>,
+ Web2Qt<Qt::Key_Delete, 'D', 'e', 'l', 'e', 't', 'e'>,
+ Web2Qt<Qt::Key_Down, 'A', 'r', 'r', 'o', 'w', 'D', 'o', 'w', 'n'>,
+ Web2Qt<Qt::Key_Escape, 'E', 's', 'c', 'a', 'p', 'e'>,
+ Web2Qt<Qt::Key_F1, 'F', '1'>, Web2Qt<Qt::Key_F2, 'F', '2'>,
+ Web2Qt<Qt::Key_F11, 'F', '1', '1'>, Web2Qt<Qt::Key_F12, 'F', '1', '2'>,
+ Web2Qt<Qt::Key_F13, 'F', '1', '3'>, Web2Qt<Qt::Key_F14, 'F', '1', '4'>,
+ Web2Qt<Qt::Key_F15, 'F', '1', '5'>, Web2Qt<Qt::Key_F16, 'F', '1', '6'>,
+ Web2Qt<Qt::Key_F17, 'F', '1', '7'>, Web2Qt<Qt::Key_F18, 'F', '1', '8'>,
+ Web2Qt<Qt::Key_F19, 'F', '1', '9'>, Web2Qt<Qt::Key_F20, 'F', '2', '0'>,
+ Web2Qt<Qt::Key_F21, 'F', '2', '1'>, Web2Qt<Qt::Key_F22, 'F', '2', '2'>,
+ Web2Qt<Qt::Key_F23, 'F', '2', '3'>,
+ Web2Qt<Qt::Key_F3, 'F', '3'>, Web2Qt<Qt::Key_F4, 'F', '4'>,
+ Web2Qt<Qt::Key_F5, 'F', '5'>, Web2Qt<Qt::Key_F6, 'F', '6'>,
+ Web2Qt<Qt::Key_F7, 'F', '7'>, Web2Qt<Qt::Key_F8, 'F', '8'>,
+ Web2Qt<Qt::Key_F9, 'F', '9'>, Web2Qt<Qt::Key_F10, 'F', '1', '0'>,
+ Web2Qt<Qt::Key_Help, 'H', 'e', 'l', 'p'>,
+ Web2Qt<Qt::Key_Home, 'H', 'o', 'm', 'e'>, Web2Qt<Qt::Key_End, 'E', 'n', 'd'>,
+ Web2Qt<Qt::Key_Insert, 'I', 'n', 's', 'e', 'r', 't'>,
+ Web2Qt<Qt::Key_Left, 'A', 'r', 'r', 'o', 'w', 'L', 'e', 'f', 't'>,
+ Web2Qt<Qt::Key_Meta, 'M', 'e', 't', 'a'>, Web2Qt<Qt::Key_Meta, 'O', 'S'>,
+ Web2Qt<Qt::Key_Menu, 'C', 'o', 'n', 't', 'e', 'x', 't', 'M', 'e', 'n', 'u'>,
+ Web2Qt<Qt::Key_NumLock, 'N', 'u', 'm', 'L', 'o', 'c', 'k'>,
+ Web2Qt<Qt::Key_PageDown, 'P', 'a', 'g', 'e', 'D', 'o', 'w', 'n'>,
+ Web2Qt<Qt::Key_PageUp, 'P', 'a', 'g', 'e', 'U', 'p'>,
+ Web2Qt<Qt::Key_Paste, 'P', 'a', 's', 't', 'e'>,
+ Web2Qt<Qt::Key_Pause, 'C', 'l', 'e', 'a', 'r'>,
+ Web2Qt<Qt::Key_Pause, 'P', 'a', 'u', 's', 'e'>,
+ Web2Qt<Qt::Key_QuoteLeft, 'B', 'a', 'c', 'k', 'q', 'u', 'o', 't', 'e'>,
+ Web2Qt<Qt::Key_QuoteLeft, 'I', 'n', 't', 'l', 'B', 'a', 'c', 'k', 's', 'l', 'a', 's', 'h'>,
+ Web2Qt<Qt::Key_Return, 'E', 'n', 't', 'e', 'r'>,
+ Web2Qt<Qt::Key_Right, 'A', 'r', 'r', 'o', 'w', 'R', 'i', 'g', 'h', 't'>,
+ Web2Qt<Qt::Key_ScrollLock, 'S', 'c', 'r', 'o', 'l', 'l', 'L', 'o', 'c', 'k'>,
+ Web2Qt<Qt::Key_Shift, 'S', 'h', 'i', 'f', 't'>,
+ Web2Qt<Qt::Key_Tab, 'T', 'a', 'b'>,
+ Web2Qt<Qt::Key_Up, 'A', 'r', 'r', 'o', 'w', 'U', 'p'>,
+ Web2Qt<Qt::Key_yen, 'I', 'n', 't', 'l', 'Y', 'e', 'n'>>::Data{});
+
+static constexpr const auto DiacriticalCharsKeyToTextLowercase = qMakeArray(
+ QSortedData<
+ Web2Qt<Qt::Key_Aacute, '\xc3', '\xa1'>,
+ Web2Qt<Qt::Key_Acircumflex, '\xc3', '\xa2'>,
+ Web2Qt<Qt::Key_Adiaeresis, '\xc3', '\xa4'>,
+ Web2Qt<Qt::Key_AE, '\xc3', '\xa6'>,
+ Web2Qt<Qt::Key_Agrave, '\xc3', '\xa0'>,
+ Web2Qt<Qt::Key_Aring, '\xc3', '\xa5'>,
+ Web2Qt<Qt::Key_Atilde, '\xc3', '\xa3'>,
+ Web2Qt<Qt::Key_Ccedilla, '\xc3', '\xa7'>,
+ Web2Qt<Qt::Key_Eacute, '\xc3', '\xa9'>,
+ Web2Qt<Qt::Key_Ecircumflex, '\xc3', '\xaa'>,
+ Web2Qt<Qt::Key_Ediaeresis, '\xc3', '\xab'>,
+ Web2Qt<Qt::Key_Egrave, '\xc3', '\xa8'>,
+ Web2Qt<Qt::Key_Iacute, '\xc3', '\xad'>,
+ Web2Qt<Qt::Key_Icircumflex, '\xc3', '\xae'>,
+ Web2Qt<Qt::Key_Idiaeresis, '\xc3', '\xaf'>,
+ Web2Qt<Qt::Key_Igrave, '\xc3', '\xac'>,
+ Web2Qt<Qt::Key_Ntilde, '\xc3', '\xb1'>,
+ Web2Qt<Qt::Key_Oacute, '\xc3', '\xb3'>,
+ Web2Qt<Qt::Key_Ocircumflex, '\xc3', '\xb4'>,
+ Web2Qt<Qt::Key_Odiaeresis, '\xc3', '\xb6'>,
+ Web2Qt<Qt::Key_Ograve, '\xc3', '\xb2'>,
+ Web2Qt<Qt::Key_Ooblique, '\xc3', '\xb8'>,
+ Web2Qt<Qt::Key_Otilde, '\xc3', '\xb5'>,
+ Web2Qt<Qt::Key_Uacute, '\xc3', '\xba'>,
+ Web2Qt<Qt::Key_Ucircumflex, '\xc3', '\xbb'>,
+ Web2Qt<Qt::Key_Udiaeresis, '\xc3', '\xbc'>,
+ Web2Qt<Qt::Key_Ugrave, '\xc3', '\xb9'>,
+ Web2Qt<Qt::Key_Yacute, '\xc3', '\xbd'>,
+ Web2Qt<Qt::Key_ydiaeresis, '\xc3', '\xbf'>>::Data{});
+
+static constexpr const auto DiacriticalCharsKeyToTextUppercase = qMakeArray(
+ QSortedData<
+ Web2Qt<Qt::Key_Aacute, '\xc3', '\x81'>,
+ Web2Qt<Qt::Key_Acircumflex, '\xc3', '\x82'>,
+ Web2Qt<Qt::Key_Adiaeresis, '\xc3', '\x84'>,
+ Web2Qt<Qt::Key_AE, '\xc3', '\x86'>,
+ Web2Qt<Qt::Key_Agrave, '\xc3', '\x80'>,
+ Web2Qt<Qt::Key_Aring, '\xc3', '\x85'>,
+ Web2Qt<Qt::Key_Atilde, '\xc3', '\x83'>,
+ Web2Qt<Qt::Key_Ccedilla, '\xc3', '\x87'>,
+ Web2Qt<Qt::Key_Eacute, '\xc3', '\x89'>,
+ Web2Qt<Qt::Key_Ecircumflex, '\xc3', '\x8a'>,
+ Web2Qt<Qt::Key_Ediaeresis, '\xc3', '\x8b'>,
+ Web2Qt<Qt::Key_Egrave, '\xc3', '\x88'>,
+ Web2Qt<Qt::Key_Iacute, '\xc3', '\x8d'>,
+ Web2Qt<Qt::Key_Icircumflex, '\xc3', '\x8e'>,
+ Web2Qt<Qt::Key_Idiaeresis, '\xc3', '\x8f'>,
+ Web2Qt<Qt::Key_Igrave, '\xc3', '\x8c'>,
+ Web2Qt<Qt::Key_Ntilde, '\xc3', '\x91'>,
+ Web2Qt<Qt::Key_Oacute, '\xc3', '\x93'>,
+ Web2Qt<Qt::Key_Ocircumflex, '\xc3', '\x94'>,
+ Web2Qt<Qt::Key_Odiaeresis, '\xc3', '\x96'>,
+ Web2Qt<Qt::Key_Ograve, '\xc3', '\x92'>,
+ Web2Qt<Qt::Key_Ooblique, '\xc3', '\x98'>,
+ Web2Qt<Qt::Key_Otilde, '\xc3', '\x95'>,
+ Web2Qt<Qt::Key_Uacute, '\xc3', '\x9a'>,
+ Web2Qt<Qt::Key_Ucircumflex, '\xc3', '\x9b'>,
+ Web2Qt<Qt::Key_Udiaeresis, '\xc3', '\x9c'>,
+ Web2Qt<Qt::Key_Ugrave, '\xc3', '\x99'>,
+ Web2Qt<Qt::Key_Yacute, '\xc3', '\x9d'>,
+ Web2Qt<Qt::Key_ydiaeresis, '\xc5', '\xb8'>>::Data{});
+
+static_assert(DiacriticalCharsKeyToTextLowercase.size()
+ == DiacriticalCharsKeyToTextUppercase.size(),
+ "Add the new key to both arrays");
+
+struct KeyMapping
+{
+ Qt::Key from, to;
+};
+
+constexpr KeyMapping tildeKeyTable[] = {
+ // ~
+ { Qt::Key_A, Qt::Key_Atilde },
+ { Qt::Key_N, Qt::Key_Ntilde },
+ { Qt::Key_O, Qt::Key_Otilde },
+};
+constexpr KeyMapping graveKeyTable[] = {
+ // `
+ { Qt::Key_A, Qt::Key_Agrave }, { Qt::Key_E, Qt::Key_Egrave }, { Qt::Key_I, Qt::Key_Igrave },
+ { Qt::Key_O, Qt::Key_Ograve }, { Qt::Key_U, Qt::Key_Ugrave },
+};
+constexpr KeyMapping acuteKeyTable[] = {
+ // '
+ { Qt::Key_A, Qt::Key_Aacute }, { Qt::Key_E, Qt::Key_Eacute }, { Qt::Key_I, Qt::Key_Iacute },
+ { Qt::Key_O, Qt::Key_Oacute }, { Qt::Key_U, Qt::Key_Uacute }, { Qt::Key_Y, Qt::Key_Yacute },
+};
+constexpr KeyMapping diaeresisKeyTable[] = {
+ // umlaut ¨
+ { Qt::Key_A, Qt::Key_Adiaeresis }, { Qt::Key_E, Qt::Key_Ediaeresis },
+ { Qt::Key_I, Qt::Key_Idiaeresis }, { Qt::Key_O, Qt::Key_Odiaeresis },
+ { Qt::Key_U, Qt::Key_Udiaeresis }, { Qt::Key_Y, Qt::Key_ydiaeresis },
+};
+constexpr KeyMapping circumflexKeyTable[] = {
+ // ^
+ { Qt::Key_A, Qt::Key_Acircumflex }, { Qt::Key_E, Qt::Key_Ecircumflex },
+ { Qt::Key_I, Qt::Key_Icircumflex }, { Qt::Key_O, Qt::Key_Ocircumflex },
+ { Qt::Key_U, Qt::Key_Ucircumflex },
+};
+
+static Qt::Key find_impl(const KeyMapping *first, const KeyMapping *last, Qt::Key key) noexcept
+{
+ while (first != last) {
+ if (first->from == key)
+ return first->to;
+ ++first;
+ }
+ return Qt::Key_unknown;
+}
+
+template<size_t N>
+static Qt::Key find(const KeyMapping (&map)[N], Qt::Key key) noexcept
+{
+ return find_impl(map, map + N, key);
+}
+
+Qt::Key translateBaseKeyUsingDeadKey(Qt::Key accentBaseKey, Qt::Key deadKey)
+{
+ switch (deadKey) {
+ case Qt::Key_Dead_Grave:
+ return find(graveKeyTable, accentBaseKey);
+ case Qt::Key_Dead_Acute:
+ return find(acuteKeyTable, accentBaseKey);
+ case Qt::Key_Dead_Tilde:
+ return find(tildeKeyTable, accentBaseKey);
+ case Qt::Key_Dead_Diaeresis:
+ return find(diaeresisKeyTable, accentBaseKey);
+ case Qt::Key_Dead_Circumflex:
+ return find(circumflexKeyTable, accentBaseKey);
+ default:
+ return Qt::Key_unknown;
+ };
+}
+
+template<class T>
+std::optional<QString> findKeyTextByKeyId(const T &mappingArray, Qt::Key qtKey)
+{
+ const auto it = std::find_if(mappingArray.cbegin(), mappingArray.cend(),
+ [qtKey](const WebKb2QtData &data) { return data.qt == qtKey; });
+ return it != mappingArray.cend() ? it->web : std::optional<QString>();
+}
+} // namespace
+
+std::optional<Qt::Key> QWasmKeyTranslator::mapWebKeyTextToQtKey(const char *toFind)
+{
+ const WebKb2QtData searchKey{ toFind, 0 };
+ const auto it = std::lower_bound(WebToQtKeyCodeMappings.cbegin(), WebToQtKeyCodeMappings.cend(),
+ searchKey);
+ return it != WebToQtKeyCodeMappings.cend() && searchKey == *it ? static_cast<Qt::Key>(it->qt)
+ : std::optional<Qt::Key>();
+}
+
+QWasmDeadKeySupport::QWasmDeadKeySupport() = default;
+
+QWasmDeadKeySupport::~QWasmDeadKeySupport() = default;
+
+void QWasmDeadKeySupport::applyDeadKeyTranslations(KeyEvent *event)
+{
+ if (event->deadKey) {
+ m_activeDeadKey = event->key;
+ } else if (m_activeDeadKey != Qt::Key_unknown
+ && (((m_keyModifiedByDeadKeyOnPress == Qt::Key_unknown
+ && event->type == EventType::KeyDown))
+ || (m_keyModifiedByDeadKeyOnPress == event->key
+ && event->type == EventType::KeyUp))) {
+ const Qt::Key baseKey = event->key;
+ const Qt::Key translatedKey = translateBaseKeyUsingDeadKey(baseKey, m_activeDeadKey);
+ if (translatedKey != Qt::Key_unknown) {
+ event->key = translatedKey;
+
+ auto foundText = event->modifiers.testFlag(Qt::ShiftModifier)
+ ? findKeyTextByKeyId(DiacriticalCharsKeyToTextUppercase, event->key)
+ : findKeyTextByKeyId(DiacriticalCharsKeyToTextLowercase, event->key);
+ Q_ASSERT(foundText.has_value());
+ event->text = foundText->size() == 1 ? *foundText : QString();
+ }
+
+ if (!event->text.isEmpty()) {
+ if (event->type == EventType::KeyDown) {
+ // Assume the first keypress with an active dead key is treated as modified,
+ // regardless of whether it has actually been modified or not. Take into account
+ // only events that produce actual key text.
+ if (!event->text.isEmpty())
+ m_keyModifiedByDeadKeyOnPress = baseKey;
+ } else {
+ Q_ASSERT(event->type == EventType::KeyUp);
+ Q_ASSERT(m_keyModifiedByDeadKeyOnPress == baseKey);
+ m_keyModifiedByDeadKeyOnPress = Qt::Key_unknown;
+ m_activeDeadKey = Qt::Key_unknown;
+ }
+ }
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/wasm/qwasmkeytranslator.h b/src/plugins/platforms/wasm/qwasmkeytranslator.h
new file mode 100644
index 0000000000..11a89e6193
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmkeytranslator.h
@@ -0,0 +1,34 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef QWASMKEYTRANSLATOR_H
+#define QWASMKEYTRANSLATOR_H
+
+#include <QtCore/qnamespace.h>
+#include <QtCore/qtypes.h>
+
+#include <optional>
+
+QT_BEGIN_NAMESPACE
+
+struct KeyEvent;
+
+namespace QWasmKeyTranslator {
+std::optional<Qt::Key> mapWebKeyTextToQtKey(const char *toFind);
+}
+
+class QWasmDeadKeySupport
+{
+public:
+ explicit QWasmDeadKeySupport();
+ ~QWasmDeadKeySupport();
+
+ void applyDeadKeyTranslations(KeyEvent *event);
+
+private:
+ Qt::Key m_activeDeadKey = Qt::Key_unknown;
+ Qt::Key m_keyModifiedByDeadKeyOnPress = Qt::Key_unknown;
+};
+
+QT_END_NAMESPACE
+#endif // QWASMKEYTRANSLATOR_H
diff --git a/src/plugins/platforms/wasm/qwasmoffscreensurface.cpp b/src/plugins/platforms/wasm/qwasmoffscreensurface.cpp
index a205e5ddea..dcfc4433e6 100644
--- a/src/plugins/platforms/wasm/qwasmoffscreensurface.cpp
+++ b/src/plugins/platforms/wasm/qwasmoffscreensurface.cpp
@@ -1,41 +1,35 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the plugins of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL$
-** 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 General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 or (at your option) 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.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-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include "qwasmoffscreensurface.h"
-QWasmOffscrenSurface::QWasmOffscrenSurface(QOffscreenSurface *offscreenSurface)
- :QPlatformOffscreenSurface(offscreenSurface)
+QT_BEGIN_NAMESPACE
+
+QWasmOffscreenSurface::QWasmOffscreenSurface(QOffscreenSurface *offscreenSurface)
+ : QPlatformOffscreenSurface(offscreenSurface), m_offscreenCanvas(emscripten::val::undefined())
{
+ const auto offscreenCanvasClass = emscripten::val::global("OffscreenCanvas");
+ // The OffscreenCanvas is not supported on some browsers, most notably on Safari.
+ if (!offscreenCanvasClass)
+ return;
+
+ m_offscreenCanvas = offscreenCanvasClass.new_(offscreenSurface->size().width(),
+ offscreenSurface->size().height());
+
+ m_specialTargetId = std::string("!qtoffscreen_") + std::to_string(uintptr_t(this));
+ emscripten::val::module_property("specialHTMLTargets")
+ .set(m_specialTargetId, m_offscreenCanvas);
}
-QWasmOffscrenSurface::~QWasmOffscrenSurface()
+QWasmOffscreenSurface::~QWasmOffscreenSurface()
{
+ emscripten::val::module_property("specialHTMLTargets").delete_(m_specialTargetId);
+}
+bool QWasmOffscreenSurface::isValid() const
+{
+ return !m_offscreenCanvas.isNull() && !m_offscreenCanvas.isUndefined();
}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/wasm/qwasmoffscreensurface.h b/src/plugins/platforms/wasm/qwasmoffscreensurface.h
index 9d3e805be0..1c71310448 100644
--- a/src/plugins/platforms/wasm/qwasmoffscreensurface.h
+++ b/src/plugins/platforms/wasm/qwasmoffscreensurface.h
@@ -1,47 +1,30 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the plugins of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL$
-** 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 General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 or (at your option) 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.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-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#ifndef QWASMOFFSCREENSURFACE_H
#define QWASMOFFSCREENSURFACE_H
#include <qpa/qplatformoffscreensurface.h>
+#include <emscripten/val.h>
+
+#include <string>
+
QT_BEGIN_NAMESPACE
class QOffscreenSurface;
-class QWasmOffscrenSurface : public QPlatformOffscreenSurface
+class QWasmOffscreenSurface final : public QPlatformOffscreenSurface
{
public:
- explicit QWasmOffscrenSurface(QOffscreenSurface *offscreenSurface);
- ~QWasmOffscrenSurface();
-private:
+ explicit QWasmOffscreenSurface(QOffscreenSurface *offscreenSurface);
+ ~QWasmOffscreenSurface() final;
+ const std::string &id() const { return m_specialTargetId; }
+ bool isValid() const override;
+
+private:
+ std::string m_specialTargetId;
+ emscripten::val m_offscreenCanvas;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/wasm/qwasmopenglcontext.cpp b/src/plugins/platforms/wasm/qwasmopenglcontext.cpp
index 4ddd56fd8c..8a4664ec8c 100644
--- a/src/plugins/platforms/wasm/qwasmopenglcontext.cpp
+++ b/src/plugins/platforms/wasm/qwasmopenglcontext.cpp
@@ -1,120 +1,148 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the plugins of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL$
-** 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 General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 or (at your option) 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.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-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include "qwasmopenglcontext.h"
+
+#include "qwasmoffscreensurface.h"
#include "qwasmintegration.h"
#include <EGL/egl.h>
+#include <emscripten/bind.h>
#include <emscripten/val.h>
+namespace {
+void qtDoNothing(emscripten::val) { }
+} // namespace
+
+EMSCRIPTEN_BINDINGS(qwasmopenglcontext)
+{
+ function("qtDoNothing", &qtDoNothing);
+}
+
QT_BEGIN_NAMESPACE
-QWasmOpenGLContext::QWasmOpenGLContext(const QSurfaceFormat &format)
- : m_requestedFormat(format)
+QWasmOpenGLContext::QWasmOpenGLContext(QOpenGLContext *context)
+ : m_actualFormat(context->format()), m_qGlContext(context)
{
- m_requestedFormat.setRenderableType(QSurfaceFormat::OpenGLES);
+ m_actualFormat.setRenderableType(QSurfaceFormat::OpenGLES);
// if we set one, we need to set the other as well since in webgl, these are tied together
- if (format.depthBufferSize() < 0 && format.stencilBufferSize() > 0)
- m_requestedFormat.setDepthBufferSize(16);
-
- if (format.stencilBufferSize() < 0 && format.depthBufferSize() > 0)
- m_requestedFormat.setStencilBufferSize(8);
+ if (m_actualFormat.depthBufferSize() < 0 && m_actualFormat.stencilBufferSize() > 0)
+ m_actualFormat.setDepthBufferSize(16);
+ if (m_actualFormat.stencilBufferSize() < 0 && m_actualFormat.depthBufferSize() > 0)
+ m_actualFormat.setStencilBufferSize(8);
}
QWasmOpenGLContext::~QWasmOpenGLContext()
{
- if (m_context) {
- // Destroy GL context. Work around bug in emscripten_webgl_destroy_context
- // which removes all event handlers on the canvas by temporarily removing
- // emscripten's JSEvents global object.
- emscripten::val jsEvents = emscripten::val::global("window")["JSEvents"];
- emscripten::val::global("window").set("JSEvents", emscripten::val::undefined());
- emscripten_webgl_destroy_context(m_context);
- emscripten::val::global("window").set("JSEvents", jsEvents);
- m_context = 0;
- }
+ // Destroy GL context. Work around bug in emscripten_webgl_destroy_context
+ // which removes all event handlers on the canvas by temporarily replacing the function
+ // that does the removal with a function that does nothing.
+ destroyWebGLContext(m_ownedWebGLContext.handle);
}
-bool QWasmOpenGLContext::maybeCreateEmscriptenContext(QPlatformSurface *surface)
+bool QWasmOpenGLContext::isOpenGLVersionSupported(QSurfaceFormat format)
{
- // Native emscripten/WebGL contexts are tied to a single screen/canvas. The first
- // call to this function creates a native canvas for the given screen, subsequent
- // calls verify that the surface is on/off the same screen.
- QPlatformScreen *screen = surface->screen();
- if (m_context && !screen)
- return false; // Alternative: return true to support makeCurrent on QOffScreenSurface with
- // no screen. However, Qt likes to substitute QGuiApplication::primaryScreen()
- // for null screens, which foils this plan.
- if (!screen)
- return false;
- if (m_context)
- return m_screen == screen;
+ // Version check: support WebGL 1 and 2:
+ // (ES) 2.0 -> WebGL 1.0
+ // (ES) 3.0 -> WebGL 2.0
+ // [we don't expect that new WebGL versions will be created]
+ return ((format.majorVersion() == 2 && format.minorVersion() == 0) ||
+ (format.majorVersion() == 3 && format.minorVersion() == 0));
+}
+
+EMSCRIPTEN_WEBGL_CONTEXT_HANDLE
+QWasmOpenGLContext::obtainEmscriptenContext(QPlatformSurface *surface)
+{
+ if (m_ownedWebGLContext.surface == surface)
+ return m_ownedWebGLContext.handle;
+
+ if (surface->surface()->surfaceClass() == QSurface::Offscreen) {
+ // Reuse the existing context for offscreen drawing, even if it happens to be a canvas
+ // context. This is because it is impossible to re-home an existing context to the
+ // new surface and works as an emulation measure.
+ if (m_ownedWebGLContext.handle)
+ return m_ownedWebGLContext.handle;
+
+ // The non-shared offscreen context is heavily limited on WASM, but we provide it
+ // anyway for potential pixel readbacks.
+ m_ownedWebGLContext =
+ QOpenGLContextData{ .surface = surface,
+ .handle = createEmscriptenContext(
+ static_cast<QWasmOffscreenSurface *>(surface)->id(),
+ m_actualFormat) };
+ } else {
+ destroyWebGLContext(m_ownedWebGLContext.handle);
+
+ // Create a full on-screen context for the window canvas.
+ m_ownedWebGLContext = QOpenGLContextData{
+ .surface = surface,
+ .handle = createEmscriptenContext(static_cast<QWasmWindow *>(surface)->canvasSelector(),
+ m_actualFormat)
+ };
+ }
+
+ EmscriptenWebGLContextAttributes actualAttributes;
+
+ EMSCRIPTEN_RESULT attributesResult = emscripten_webgl_get_context_attributes(m_ownedWebGLContext.handle, &actualAttributes);
+ if (attributesResult == EMSCRIPTEN_RESULT_SUCCESS) {
+ if (actualAttributes.majorVersion == 1) {
+ m_actualFormat.setMajorVersion(2);
+ } else if (actualAttributes.majorVersion == 2) {
+ m_actualFormat.setMajorVersion(3);
+ }
+ m_actualFormat.setMinorVersion(0);
+ }
- QString canvasId = QWasmScreen::get(screen)->canvasId();
- m_context = createEmscriptenContext(canvasId, m_requestedFormat);
- m_screen = screen;
- return true;
+ return m_ownedWebGLContext.handle;
}
-EMSCRIPTEN_WEBGL_CONTEXT_HANDLE QWasmOpenGLContext::createEmscriptenContext(const QString &canvasId, QSurfaceFormat format)
+void QWasmOpenGLContext::destroyWebGLContext(EMSCRIPTEN_WEBGL_CONTEXT_HANDLE contextHandle)
+{
+ if (!contextHandle)
+ return;
+ emscripten::val jsEvents = emscripten::val::module_property("JSEvents");
+ emscripten::val savedRemoveAllHandlersOnTargetFunction = jsEvents["removeAllHandlersOnTarget"];
+ jsEvents.set("removeAllHandlersOnTarget", emscripten::val::module_property("qtDoNothing"));
+ emscripten_webgl_destroy_context(contextHandle);
+ jsEvents.set("removeAllHandlersOnTarget", savedRemoveAllHandlersOnTargetFunction);
+}
+
+EMSCRIPTEN_WEBGL_CONTEXT_HANDLE
+QWasmOpenGLContext::createEmscriptenContext(const std::string &canvasSelector,
+ QSurfaceFormat format)
{
EmscriptenWebGLContextAttributes attributes;
emscripten_webgl_init_context_attributes(&attributes); // Populate with default attributes
- attributes.preferLowPowerToHighPerformance = false;
+ attributes.powerPreference = EM_WEBGL_POWER_PREFERENCE_HIGH_PERFORMANCE;
attributes.failIfMajorPerformanceCaveat = false;
attributes.antialias = true;
attributes.enableExtensionsByDefault = true;
-
- if (format.majorVersion() == 3) {
- attributes.majorVersion = 2;
- }
-
+ attributes.majorVersion = 2; // try highest supported version ES3.0 / WebGL 2.0
+ attributes.minorVersion = 0; // emscripten only supports minor version 0
// WebGL doesn't allow separate attach buffers to STENCIL_ATTACHMENT and DEPTH_ATTACHMENT
// we need both or none
- bool useDepthStencil = (format.depthBufferSize() > 0 || format.stencilBufferSize() > 0);
+ const bool useDepthStencil = (format.depthBufferSize() > 0 || format.stencilBufferSize() > 0);
// WebGL offers enable/disable control but not size control for these
attributes.alpha = format.alphaBufferSize() > 0;
attributes.depth = useDepthStencil;
attributes.stencil = useDepthStencil;
+ EMSCRIPTEN_RESULT contextResult = emscripten_webgl_create_context(canvasSelector.c_str(), &attributes);
- QByteArray convasSelector = "#" + canvasId.toUtf8();
- EMSCRIPTEN_WEBGL_CONTEXT_HANDLE context = emscripten_webgl_create_context(convasSelector.constData(), &attributes);
-
- return context;
+ if (contextResult <= 0) {
+ // fallback to opengles2/webgl1
+ // for devices that do not support opengles3/webgl2
+ attributes.majorVersion = 1;
+ contextResult = emscripten_webgl_create_context(canvasSelector.c_str(), &attributes);
+ }
+ return contextResult;
}
QSurfaceFormat QWasmOpenGLContext::format() const
{
- return m_requestedFormat;
+ return m_actualFormat;
}
GLuint QWasmOpenGLContext::defaultFramebufferObject(QPlatformSurface *surface) const
@@ -124,11 +152,22 @@ GLuint QWasmOpenGLContext::defaultFramebufferObject(QPlatformSurface *surface) c
bool QWasmOpenGLContext::makeCurrent(QPlatformSurface *surface)
{
- bool ok = maybeCreateEmscriptenContext(surface);
- if (!ok)
+ static bool sentSharingWarning = false;
+ if (!sentSharingWarning && isSharing()) {
+ qWarning() << "The functionality for sharing OpenGL contexts is limited, see documentation";
+ sentSharingWarning = true;
+ }
+
+ if (auto *shareContext = m_qGlContext->shareContext())
+ return shareContext->makeCurrent(surface->surface());
+
+ const auto context = obtainEmscriptenContext(surface);
+ if (!context)
return false;
- return emscripten_webgl_make_context_current(m_context) == EMSCRIPTEN_RESULT_SUCCESS;
+ m_usedWebGLContextHandle = context;
+
+ return emscripten_webgl_make_context_current(context) == EMSCRIPTEN_RESULT_SUCCESS;
}
void QWasmOpenGLContext::swapBuffers(QPlatformSurface *surface)
@@ -144,14 +183,17 @@ void QWasmOpenGLContext::doneCurrent()
bool QWasmOpenGLContext::isSharing() const
{
- return false;
+ return m_qGlContext->shareContext();
}
bool QWasmOpenGLContext::isValid() const
{
+ if (!isOpenGLVersionSupported(m_actualFormat))
+ return false;
+
// Note: we get isValid() calls before we see the surface and can
// create a native context, so no context is also a valid state.
- return !m_context || !emscripten_is_webgl_context_lost(m_context);
+ return !m_usedWebGLContextHandle || !emscripten_is_webgl_context_lost(m_usedWebGLContextHandle);
}
QFunctionPointer QWasmOpenGLContext::getProcAddress(const char *procName)
diff --git a/src/plugins/platforms/wasm/qwasmopenglcontext.h b/src/plugins/platforms/wasm/qwasmopenglcontext.h
index d27007e8ea..2a8bcc5d9b 100644
--- a/src/plugins/platforms/wasm/qwasmopenglcontext.h
+++ b/src/plugins/platforms/wasm/qwasmopenglcontext.h
@@ -1,31 +1,8 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the plugins of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL$
-** 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 General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 or (at your option) 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.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-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef QWASMOPENGLCONTEXT_H
+#define QWASMOPENGLCONTEXT_H
#include <qpa/qplatformopenglcontext.h>
@@ -34,11 +11,13 @@
QT_BEGIN_NAMESPACE
+class QOpenGLContext;
class QPlatformScreen;
+class QPlatformSurface;
class QWasmOpenGLContext : public QPlatformOpenGLContext
{
public:
- QWasmOpenGLContext(const QSurfaceFormat &format);
+ explicit QWasmOpenGLContext(QOpenGLContext *context);
~QWasmOpenGLContext();
QSurfaceFormat format() const override;
@@ -51,13 +30,25 @@ public:
QFunctionPointer getProcAddress(const char *procName) override;
private:
- bool maybeCreateEmscriptenContext(QPlatformSurface *surface);
- static EMSCRIPTEN_WEBGL_CONTEXT_HANDLE createEmscriptenContext(const QString &canvasId, QSurfaceFormat format);
-
- QSurfaceFormat m_requestedFormat;
- QPlatformScreen *m_screen = nullptr;
- EMSCRIPTEN_WEBGL_CONTEXT_HANDLE m_context = 0;
+ struct QOpenGLContextData
+ {
+ QPlatformSurface *surface = nullptr;
+ EMSCRIPTEN_WEBGL_CONTEXT_HANDLE handle = 0;
+ };
+
+ static bool isOpenGLVersionSupported(QSurfaceFormat format);
+ EMSCRIPTEN_WEBGL_CONTEXT_HANDLE obtainEmscriptenContext(QPlatformSurface *surface);
+ static EMSCRIPTEN_WEBGL_CONTEXT_HANDLE
+ createEmscriptenContext(const std::string &canvasSelector, QSurfaceFormat format);
+
+ static void destroyWebGLContext(EMSCRIPTEN_WEBGL_CONTEXT_HANDLE contextHandle);
+
+ QSurfaceFormat m_actualFormat;
+ QOpenGLContext *m_qGlContext;
+ QOpenGLContextData m_ownedWebGLContext;
+ EMSCRIPTEN_WEBGL_CONTEXT_HANDLE m_usedWebGLContextHandle = 0;
};
QT_END_NAMESPACE
+#endif // QWASMOPENGLCONTEXT_H
diff --git a/src/plugins/platforms/wasm/qwasmplatform.cpp b/src/plugins/platforms/wasm/qwasmplatform.cpp
new file mode 100644
index 0000000000..e54992be1d
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmplatform.cpp
@@ -0,0 +1,32 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "qwasmplatform.h"
+
+QT_BEGIN_NAMESPACE
+
+Platform platform()
+{
+ static const Platform qtDetectedPlatform = ([]() {
+ // The Platform Detect: expand coverage as needed
+ emscripten::val rawPlatform = emscripten::val::global("navigator")["platform"];
+
+ if (rawPlatform.call<bool>("includes", emscripten::val("Mac")))
+ return Platform::MacOS;
+ if (rawPlatform.call<bool>("includes", emscripten::val("iPhone"))
+ || rawPlatform.call<bool>("includes", emscripten::val("iPad")))
+ return Platform::iOS;
+ if (rawPlatform.call<bool>("includes", emscripten::val("Win32")))
+ return Platform::Windows;
+ if (rawPlatform.call<bool>("includes", emscripten::val("Linux"))) {
+ emscripten::val uAgent = emscripten::val::global("navigator")["userAgent"];
+ if (uAgent.call<bool>("includes", emscripten::val("Android")))
+ return Platform::Android;
+ return Platform::Linux;
+ }
+ return Platform::Generic;
+ })();
+ return qtDetectedPlatform;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/wasm/qwasmplatform.h b/src/plugins/platforms/wasm/qwasmplatform.h
new file mode 100644
index 0000000000..5b32e43633
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmplatform.h
@@ -0,0 +1,29 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef QWASMPLATFORM_H
+#define QWASMPLATFORM_H
+
+#include <QtCore/qglobal.h>
+#include <QtCore/qnamespace.h>
+
+#include <QPoint>
+
+#include <emscripten/val.h>
+
+QT_BEGIN_NAMESPACE
+
+enum class Platform {
+ Generic,
+ MacOS,
+ Windows,
+ Linux,
+ Android,
+ iOS
+};
+
+Platform platform();
+
+QT_END_NAMESPACE
+
+#endif // QWASMPLATFORM_H
diff --git a/src/plugins/platforms/wasm/qwasmscreen.cpp b/src/plugins/platforms/wasm/qwasmscreen.cpp
index a2bcd4fcb4..ddf8140c48 100644
--- a/src/plugins/platforms/wasm/qwasmscreen.cpp
+++ b/src/plugins/platforms/wasm/qwasmscreen.cpp
@@ -1,72 +1,126 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the plugins of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL$
-** 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 General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 or (at your option) 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.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-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include "qwasmscreen.h"
-#include "qwasmwindow.h"
-#include "qwasmeventtranslator.h"
+
#include "qwasmcompositor.h"
+#include "qwasmcssstyle.h"
#include "qwasmintegration.h"
-#include "qwasmstring.h"
+#include "qwasmkeytranslator.h"
+#include "qwasmwindow.h"
#include <emscripten/bind.h>
#include <emscripten/val.h>
-#include <QtEglSupport/private/qeglconvenience_p.h>
-#ifndef QT_NO_OPENGL
-# include <QtEglSupport/private/qeglplatformcontext_p.h>
-#endif
#include <qpa/qwindowsysteminterface.h>
#include <QtCore/qcoreapplication.h>
#include <QtGui/qguiapplication.h>
#include <private/qhighdpiscaling_p.h>
-using namespace emscripten;
+#include <tuple>
QT_BEGIN_NAMESPACE
-QWasmScreen::QWasmScreen(const emscripten::val &canvas)
- : m_canvas(canvas)
+using namespace emscripten;
+
+const char *QWasmScreen::m_canvasResizeObserverCallbackContextPropertyName =
+ "data-qtCanvasResizeObserverCallbackContext";
+
+QWasmScreen::QWasmScreen(const emscripten::val &containerOrCanvas)
+ : m_container(containerOrCanvas),
+ m_intermediateContainer(emscripten::val::undefined()),
+ m_shadowContainer(emscripten::val::undefined()),
+ m_compositor(new QWasmCompositor(this)),
+ m_deadKeySupport(std::make_unique<QWasmDeadKeySupport>())
{
- m_compositor = new QWasmCompositor(this);
- m_eventTranslator = new QWasmEventTranslator(this);
+ auto document = m_container["ownerDocument"];
+ // Each screen is represented by a div container. All of the windows exist therein as
+ // its children. Qt versions < 6.5 used to represent screens as canvas. Support that by
+ // transforming the canvas into a div.
+ if (m_container["tagName"].call<std::string>("toLowerCase") == "canvas") {
+ qWarning() << "Support for canvas elements as an element backing screen is deprecated. The "
+ "canvas provided for the screen will be transformed into a div.";
+ auto container = document.call<emscripten::val>("createElement", emscripten::val("div"));
+ m_container["parentNode"].call<void>("replaceChild", container, m_container);
+ m_container = container;
+ }
+
+ // Create an intermediate container which we can remove during cleanup in ~QWasmScreen().
+ // This is required due to the attachShadow() call below; there is no corresponding
+ // "detachShadow()" API to return the container to its previous state.
+ m_intermediateContainer = document.call<emscripten::val>("createElement", emscripten::val("div"));
+ m_intermediateContainer.set("id", std::string("qt-shadow-container"));
+ emscripten::val intermediateContainerStyle = m_intermediateContainer["style"];
+ intermediateContainerStyle.set("width", std::string("100%"));
+ intermediateContainerStyle.set("height", std::string("100%"));
+ m_container.call<void>("appendChild", m_intermediateContainer);
+
+ auto shadowOptions = emscripten::val::object();
+ shadowOptions.set("mode", "open");
+ auto shadow = m_intermediateContainer.call<emscripten::val>("attachShadow", shadowOptions);
+
+ m_shadowContainer = document.call<emscripten::val>("createElement", emscripten::val("div"));
+
+ shadow.call<void>("appendChild", QWasmCSSStyle::createStyleElement(m_shadowContainer));
+
+ shadow.call<void>("appendChild", m_shadowContainer);
+
+ m_shadowContainer.set("id", std::string("qt-screen-") + std::to_string(uintptr_t(this)));
+
+ m_shadowContainer["classList"].call<void>("add", std::string("qt-screen"));
+
+ // Disable the default context menu; Qt applications typically
+ // provide custom right-click behavior.
+ m_onContextMenu = std::make_unique<qstdweb::EventCallback>(
+ m_shadowContainer, "contextmenu",
+ [](emscripten::val event) { event.call<void>("preventDefault"); });
+ // Create "specialHTMLTargets" mapping for the canvas - the element might be unreachable based
+ // on its id only under some conditions, like the target being embedded in a shadow DOM or a
+ // subframe.
+ emscripten::val::module_property("specialHTMLTargets")
+ .set(eventTargetId().toStdString(), m_shadowContainer);
+
+ emscripten::val::module_property("specialHTMLTargets")
+ .set(outerScreenId().toStdString(), m_container);
+
updateQScreenAndCanvasRenderSize();
- m_canvas.call<void>("focus");
+ m_shadowContainer.call<void>("focus");
+
+ m_touchDevice = std::make_unique<QPointingDevice>(
+ "touchscreen", 1, QInputDevice::DeviceType::TouchScreen,
+ QPointingDevice::PointerType::Finger,
+ QPointingDevice::Capability::Position | QPointingDevice::Capability::Area
+ | QPointingDevice::Capability::NormalizedPosition,
+ 10, 0);
+ m_tabletDevice = std::make_unique<QPointingDevice>(
+ "stylus", 2, QInputDevice::DeviceType::Stylus,
+ QPointingDevice::PointerType::Pen,
+ QPointingDevice::Capability::Position | QPointingDevice::Capability::Pressure
+ | QPointingDevice::Capability::NormalizedPosition
+ | QInputDevice::Capability::MouseEmulation
+ | QInputDevice::Capability::Hover | QInputDevice::Capability::Rotation
+ | QInputDevice::Capability::XTilt | QInputDevice::Capability::YTilt
+ | QInputDevice::Capability::TangentialPressure,
+ 0, 0);
+
+ QWindowSystemInterface::registerInputDevice(m_touchDevice.get());
}
QWasmScreen::~QWasmScreen()
{
- destroy();
+ m_intermediateContainer.call<void>("remove");
+
+ emscripten::val::module_property("specialHTMLTargets")
+ .set(eventTargetId().toStdString(), emscripten::val::undefined());
+
+ m_shadowContainer.set(m_canvasResizeObserverCallbackContextPropertyName,
+ emscripten::val(intptr_t(0)));
}
-void QWasmScreen::destroy()
+void QWasmScreen::deleteScreen()
{
- m_compositor->destroy();
+ // Deletes |this|!
+ QWindowSystemInterface::handleScreenRemoved(this);
}
QWasmScreen *QWasmScreen::get(QPlatformScreen *screen)
@@ -76,27 +130,31 @@ QWasmScreen *QWasmScreen::get(QPlatformScreen *screen)
QWasmScreen *QWasmScreen::get(QScreen *screen)
{
+ if (!screen)
+ return nullptr;
return get(screen->handle());
}
QWasmCompositor *QWasmScreen::compositor()
{
- return m_compositor;
+ return m_compositor.get();
}
-QWasmEventTranslator *QWasmScreen::eventTranslator()
+emscripten::val QWasmScreen::element() const
{
- return m_eventTranslator;
+ return m_shadowContainer;
}
-emscripten::val QWasmScreen::canvas() const
+QString QWasmScreen::eventTargetId() const
{
- return m_canvas;
+ // Return a globally unique id for the canvas. We can choose any string,
+ // as long as it starts with a "!".
+ return QString("!qtcanvas_%1").arg(uintptr_t(this));
}
-QString QWasmScreen::canvasId() const
+QString QWasmScreen::outerScreenId() const
{
- return QWasmString::toQString(m_canvas["id"]);
+ return QString("!outerscreen_%1").arg(uintptr_t(this));
}
QRect QWasmScreen::geometry() const
@@ -127,17 +185,28 @@ QDpi QWasmScreen::logicalDpi() const
qreal QWasmScreen::devicePixelRatio() const
{
- // FIXME: The effective device pixel ratio may be different from the
- // HTML window dpr if the OpenGL driver/GPU allocates a less than
- // full resolution surface. Use emscripten_webgl_get_drawing_buffer_size()
- // and compute the dpr instead.
- double htmlWindowDpr = emscripten::val::global("window")["devicePixelRatio"].as<double>();
- return qreal(htmlWindowDpr);
+ // window.devicePixelRatio gives us the scale factor between CSS and device pixels.
+ // This property reflects hardware configuration, and also browser zoom on desktop.
+ //
+ // window.visualViewport.scale gives us the zoom factor on mobile. If the html page is
+ // configured with "<meta name="viewport" content="width=device-width">" then this scale
+ // factor will be 1. Omitting the viewport configuration typically results on a zoomed-out
+ // viewport, with a scale factor <1. User pinch-zoom will change the scale factor; an event
+ // handler is installed in the QWasmIntegration constructor. Changing zoom level on desktop
+ // does not appear to change visualViewport.scale.
+ //
+ // The effective devicePixelRatio is the product of these two scale factors, upper-bounded
+ // by window.devicePixelRatio in order to avoid e.g. allocating a 10x widget backing store.
+ double dpr = emscripten::val::global("window")["devicePixelRatio"].as<double>();
+ emscripten::val visualViewport = emscripten::val::global("window")["visualViewport"];
+ double scale = visualViewport.isUndefined() ? 1.0 : visualViewport["scale"].as<double>();
+ double effectiveDevicePixelRatio = std::min(dpr * scale, dpr);
+ return qreal(effectiveDevicePixelRatio);
}
QString QWasmScreen::name() const
{
- return canvasId();
+ return QString::fromEcmaString(m_shadowContainer["id"]);
}
QPlatformCursor *QWasmScreen::cursor() const
@@ -154,12 +223,30 @@ void QWasmScreen::resizeMaximizedWindows()
QWindow *QWasmScreen::topWindow() const
{
- return m_compositor->keyWindow();
+ return activeChild() ? activeChild()->window() : nullptr;
}
QWindow *QWasmScreen::topLevelAt(const QPoint &p) const
{
- return m_compositor->windowAt(p);
+ const auto found =
+ std::find_if(childStack().begin(), childStack().end(), [&p](const QWasmWindow *window) {
+ const QRect geometry = window->windowFrameGeometry();
+
+ return window->isVisible() && geometry.contains(p);
+ });
+ return found != childStack().end() ? (*found)->window() : nullptr;
+}
+
+QPointF QWasmScreen::mapFromLocal(const QPointF &p) const
+{
+ return geometry().topLeft() + p;
+}
+
+QPointF QWasmScreen::clipPoint(const QPointF &p) const
+{
+ const auto geometryF = screen()->geometry().toRectF();
+ return QPointF(qBound(geometryF.left(), p.x(), geometryF.right()),
+ qBound(geometryF.top(), p.y(), geometryF.bottom()));
}
void QWasmScreen::invalidateSize()
@@ -170,10 +257,23 @@ void QWasmScreen::invalidateSize()
void QWasmScreen::setGeometry(const QRect &rect)
{
m_geometry = rect;
- QWindowSystemInterface::handleScreenGeometryChange(QPlatformScreen::screen(), geometry(), availableGeometry());
+ QWindowSystemInterface::handleScreenGeometryChange(QPlatformScreen::screen(), geometry(),
+ availableGeometry());
resizeMaximizedWindows();
}
+void QWasmScreen::onSubtreeChanged(QWasmWindowTreeNodeChangeType changeType,
+ QWasmWindowTreeNode *parent, QWasmWindow *child)
+{
+ Q_UNUSED(parent);
+ if (changeType == QWasmWindowTreeNodeChangeType::NodeInsertion && parent == this
+ && childStack().size() == 1) {
+ child->window()->setFlag(Qt::WindowStaysOnBottomHint);
+ }
+ QWasmWindowTreeNode::onSubtreeChanged(changeType, parent, child);
+ m_compositor->onWindowTreeChanged(changeType, child);
+}
+
void QWasmScreen::updateQScreenAndCanvasRenderSize()
{
// The HTML canvas has two sizes: the CSS size and the canvas render size.
@@ -182,27 +282,92 @@ void QWasmScreen::updateQScreenAndCanvasRenderSize()
// size must be set manually and is not auto-updated on CSS size change.
// Setting the render size to a value larger than the CSS size enables high-dpi
// rendering.
-
- QByteArray canvasSelector = "#" + canvasId().toUtf8();
double css_width;
double css_height;
- emscripten_get_element_css_size(canvasSelector.constData(), &css_width, &css_height);
+ emscripten_get_element_css_size(outerScreenId().toUtf8().constData(), &css_width, &css_height);
QSizeF cssSize(css_width, css_height);
QSizeF canvasSize = cssSize * devicePixelRatio();
- m_canvas.set("width", canvasSize.width());
- m_canvas.set("height", canvasSize.height());
+ m_shadowContainer.set("width", canvasSize.width());
+ m_shadowContainer.set("height", canvasSize.height());
+
+ // Returns the html elements document/body position
+ auto getElementBodyPosition = [](const emscripten::val &element) -> QPoint {
+ emscripten::val bodyRect =
+ element["ownerDocument"]["body"].call<emscripten::val>("getBoundingClientRect");
+ emscripten::val canvasRect = element.call<emscripten::val>("getBoundingClientRect");
+ return QPoint(canvasRect["left"].as<int>() - bodyRect["left"].as<int>(),
+ canvasRect["top"].as<int>() - bodyRect["top"].as<int>());
+ };
+
+ setGeometry(QRect(getElementBodyPosition(m_shadowContainer), cssSize.toSize()));
+}
- QPoint offset;
- offset.setX(m_canvas["offsetTop"].as<int>());
- offset.setY(m_canvas["offsetLeft"].as<int>());
+void QWasmScreen::canvasResizeObserverCallback(emscripten::val entries, emscripten::val)
+{
+ int count = entries["length"].as<int>();
+ if (count == 0)
+ return;
+ emscripten::val entry = entries[0];
+ QWasmScreen *screen = reinterpret_cast<QWasmScreen *>(
+ entry["target"][m_canvasResizeObserverCallbackContextPropertyName].as<intptr_t>());
+ if (!screen) {
+ qWarning() << "QWasmScreen::canvasResizeObserverCallback: missing screen pointer";
+ return;
+ }
- emscripten::val rect = m_canvas.call<emscripten::val>("getBoundingClientRect");
- QPoint position(rect["left"].as<int>() - offset.x(), rect["top"].as<int>() - offset.y());
+ // We could access contentBoxSize|contentRect|devicePixelContentBoxSize on the entry here, but
+ // these are not universally supported across all browsers. Get the sizes from the canvas
+ // instead.
+ screen->updateQScreenAndCanvasRenderSize();
+}
- setGeometry(QRect(position, cssSize.toSize()));
- m_compositor->redrawWindowContent();
+EMSCRIPTEN_BINDINGS(qtCanvasResizeObserverCallback)
+{
+ emscripten::function("qtCanvasResizeObserverCallback",
+ &QWasmScreen::canvasResizeObserverCallback);
+}
+
+void QWasmScreen::installCanvasResizeObserver()
+{
+ emscripten::val ResizeObserver = emscripten::val::global("ResizeObserver");
+ if (ResizeObserver == emscripten::val::undefined())
+ return; // ResizeObserver API is not available
+ emscripten::val resizeObserver =
+ ResizeObserver.new_(emscripten::val::module_property("qtCanvasResizeObserverCallback"));
+ if (resizeObserver == emscripten::val::undefined())
+ return; // Something went horribly wrong
+
+ // We need to get back to this instance from the (static) resize callback;
+ // set a "data-" property on the canvas element.
+ m_shadowContainer.set(m_canvasResizeObserverCallbackContextPropertyName,
+ emscripten::val(intptr_t(this)));
+
+ resizeObserver.call<void>("observe", m_shadowContainer);
+}
+
+emscripten::val QWasmScreen::containerElement()
+{
+ return m_shadowContainer;
+}
+
+QWasmWindowTreeNode *QWasmScreen::parentNode()
+{
+ return nullptr;
+}
+
+QList<QWasmWindow *> QWasmScreen::allWindows()
+{
+ QList<QWasmWindow *> windows;
+ for (auto *child : childStack()) {
+ QWindowList list = child->window()->findChildren<QWindow *>(Qt::FindChildrenRecursively);
+ std::transform(
+ list.begin(), list.end(), std::back_inserter(windows),
+ [](const QWindow *window) { return static_cast<QWasmWindow *>(window->handle()); });
+ windows.push_back(child);
+ }
+ return windows;
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/wasm/qwasmscreen.h b/src/plugins/platforms/wasm/qwasmscreen.h
index ea7ffc4193..da171d3f50 100644
--- a/src/plugins/platforms/wasm/qwasmscreen.h
+++ b/src/plugins/platforms/wasm/qwasmscreen.h
@@ -1,41 +1,18 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the plugins of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL$
-** 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 General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 or (at your option) 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.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-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#ifndef QWASMSCREEN_H
#define QWASMSCREEN_H
#include "qwasmcursor.h"
+#include "qwasmwindowtreenode.h"
+
#include <qpa/qplatformscreen.h>
#include <QtCore/qscopedpointer.h>
#include <QtCore/qtextstream.h>
+#include <QtCore/private/qstdweb_p.h>
#include <emscripten/val.h>
@@ -45,24 +22,29 @@ class QPlatformOpenGLContext;
class QWasmWindow;
class QWasmBackingStore;
class QWasmCompositor;
-class QWasmEventTranslator;
+class QWasmDeadKeySupport;
class QOpenGLContext;
-class QWasmScreen : public QObject, public QPlatformScreen
+class QWasmScreen : public QObject, public QPlatformScreen, public QWasmWindowTreeNode
{
Q_OBJECT
public:
- QWasmScreen(const emscripten::val &canvas);
+ QWasmScreen(const emscripten::val &containerOrCanvas);
~QWasmScreen();
- void destroy();
+ void deleteScreen();
static QWasmScreen *get(QPlatformScreen *screen);
static QWasmScreen *get(QScreen *screen);
- emscripten::val canvas() const;
- QString canvasId() const;
+ emscripten::val element() const;
+ QString eventTargetId() const;
+ QString outerScreenId() const;
+ QPointingDevice *touchDevice() { return m_touchDevice.get(); }
+ QPointingDevice *tabletDevice() { return m_tabletDevice.get(); }
QWasmCompositor *compositor();
- QWasmEventTranslator *eventTranslator();
+ QWasmDeadKeySupport *deadKeySupport() { return m_deadKeySupport.get(); }
+
+ QList<QWasmWindow *> allWindows();
QRect geometry() const override;
int depth() const override;
@@ -76,20 +58,39 @@ public:
QWindow *topWindow() const;
QWindow *topLevelAt(const QPoint &p) const override;
+ // QWasmWindowTreeNode:
+ emscripten::val containerElement() final;
+ QWasmWindowTreeNode *parentNode() final;
+
+ QPointF mapFromLocal(const QPointF &p) const;
+ QPointF clipPoint(const QPointF &p) const;
+
void invalidateSize();
void updateQScreenAndCanvasRenderSize();
+ void installCanvasResizeObserver();
+ static void canvasResizeObserverCallback(emscripten::val entries, emscripten::val);
public slots:
void setGeometry(const QRect &rect);
private:
- emscripten::val m_canvas;
- QWasmCompositor *m_compositor = nullptr;
- QWasmEventTranslator *m_eventTranslator = nullptr;
+ // QWasmWindowTreeNode:
+ void onSubtreeChanged(QWasmWindowTreeNodeChangeType changeType, QWasmWindowTreeNode *parent,
+ QWasmWindow *child) final;
+
+ emscripten::val m_container;
+ emscripten::val m_intermediateContainer;
+ emscripten::val m_shadowContainer;
+ std::unique_ptr<QWasmCompositor> m_compositor;
+ std::unique_ptr<QPointingDevice> m_touchDevice;
+ std::unique_ptr<QPointingDevice> m_tabletDevice;
+ std::unique_ptr<QWasmDeadKeySupport> m_deadKeySupport;
QRect m_geometry = QRect(0, 0, 100, 100);
int m_depth = 32;
QImage::Format m_format = QImage::Format_RGB32;
QWasmCursor m_cursor;
+ static const char *m_canvasResizeObserverCallbackContextPropertyName;
+ std::unique_ptr<qstdweb::EventCallback> m_onContextMenu;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/wasm/qwasmservices.cpp b/src/plugins/platforms/wasm/qwasmservices.cpp
index 4eee3fe972..e767295e41 100644
--- a/src/plugins/platforms/wasm/qwasmservices.cpp
+++ b/src/plugins/platforms/wasm/qwasmservices.cpp
@@ -1,34 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the plugins of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL$
-** 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 General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 or (at your option) 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.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-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include "qwasmservices.h"
-#include "qwasmstring.h"
#include <QtCore/QUrl>
#include <QtCore/QDebug>
@@ -39,8 +12,8 @@ QT_BEGIN_NAMESPACE
bool QWasmServices::openUrl(const QUrl &url)
{
- emscripten::val jsUrl = QWasmString::fromQString(url.toString());
- emscripten::val::global("window").call<void>("open", jsUrl, emscripten::val("_blank"));
+ emscripten::val::global("window").call<void>("open", url.toString().toEcmaString(),
+ emscripten::val("_blank"));
return true;
}
diff --git a/src/plugins/platforms/wasm/qwasmservices.h b/src/plugins/platforms/wasm/qwasmservices.h
index 3b37f21f82..16d4ac5171 100644
--- a/src/plugins/platforms/wasm/qwasmservices.h
+++ b/src/plugins/platforms/wasm/qwasmservices.h
@@ -1,31 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the plugins of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL$
-** 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 General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 or (at your option) 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.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-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#ifndef QWASMDESKTOPSERVICES_H
#define QWASMDESKTOPSERVICES_H
diff --git a/src/plugins/platforms/wasm/qwasmstring.cpp b/src/plugins/platforms/wasm/qwasmstring.cpp
deleted file mode 100644
index b1be405eeb..0000000000
--- a/src/plugins/platforms/wasm/qwasmstring.cpp
+++ /dev/null
@@ -1,62 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the plugins of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL$
-** 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 General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 or (at your option) 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.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-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qwasmstring.h"
-
-QT_BEGIN_NAMESPACE
-
-using namespace emscripten;
-
-val QWasmString::fromQString(const QString &str)
-{
- static const val UTF16ToString(
- val::global("Module")["UTF16ToString"]);
-
- auto ptr = quintptr(str.utf16());
- return UTF16ToString(val(ptr));
-}
-
-QString QWasmString::toQString(const val &v)
-{
- QString result;
- if (!v.isString())
- return result;
-
- static const val stringToUTF16(
- val::global("Module")["stringToUTF16"]);
- static const val length("length");
-
- int len = v[length].as<int>();
- result.resize(len);
- auto ptr = quintptr(result.utf16());
- stringToUTF16(v, val(ptr), val((len + 1) * 2));
- return result;
-}
-
-QT_END_NAMESPACE
diff --git a/src/plugins/platforms/wasm/qwasmstring.h b/src/plugins/platforms/wasm/qwasmstring.h
deleted file mode 100644
index de5da92830..0000000000
--- a/src/plugins/platforms/wasm/qwasmstring.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the plugins of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL$
-** 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 General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 or (at your option) 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.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-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#pragma once
-
-#include <qstring.h>
-
-#include <emscripten/val.h>
-
-QT_BEGIN_NAMESPACE
-
-class QWasmString
-{
-public:
- static emscripten::val fromQString(const QString &str);
- static QString toQString(const emscripten::val &v);
-};
-QT_END_NAMESPACE
-
diff --git a/src/plugins/platforms/wasm/qwasmstylepixmaps_p.h b/src/plugins/platforms/wasm/qwasmstylepixmaps_p.h
deleted file mode 100644
index 2b5860f42f..0000000000
--- a/src/plugins/platforms/wasm/qwasmstylepixmaps_p.h
+++ /dev/null
@@ -1,183 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the plugins of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL$
-** 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 General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 or (at your option) 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.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-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QWASMSTYLEPIXMAPS_P_H
-#define QWASMSTYLEPIXMAPS_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.
-//
-
-/* XPM */
-static const char * const qt_menu_xpm[] = {
-"16 16 72 1",
-" c None",
-". c #65AF36",
-"+ c #66B036",
-"@ c #77B94C",
-"# c #A7D28C",
-"$ c #BADBA4",
-"% c #A4D088",
-"& c #72B646",
-"* c #9ACB7A",
-"= c #7FBD56",
-"- c #85C05F",
-"; c #F4F9F0",
-"> c #FFFFFF",
-", c #E5F1DC",
-"' c #ECF5E7",
-") c #7ABA50",
-"! c #83BF5C",
-"~ c #AED595",
-"{ c #D7EACA",
-"] c #A9D28D",
-"^ c #BCDDA8",
-"/ c #C4E0B1",
-"( c #81BE59",
-"_ c #D0E7C2",
-": c #D4E9C6",
-"< c #6FB542",
-"[ c #6EB440",
-"} c #88C162",
-"| c #98CA78",
-"1 c #F4F9F1",
-"2 c #8FC56C",
-"3 c #F1F8EC",
-"4 c #E8F3E1",
-"5 c #D4E9C7",
-"6 c #74B748",
-"7 c #80BE59",
-"8 c #73B747",
-"9 c #6DB43F",
-"0 c #CBE4BA",
-"a c #80BD58",
-"b c #6DB33F",
-"c c #FEFFFE",
-"d c #68B138",
-"e c #F9FCF7",
-"f c #91C66F",
-"g c #E8F3E0",
-"h c #DCEDD0",
-"i c #91C66E",
-"j c #A3CF86",
-"k c #C9E3B8",
-"l c #B0D697",
-"m c #E3F0DA",
-"n c #95C873",
-"o c #E6F2DE",
-"p c #9ECD80",
-"q c #BEDEAA",
-"r c #C7E2B6",
-"s c #79BA4F",
-"t c #6EB441",
-"u c #BCDCA7",
-"v c #FAFCF8",
-"w c #F6FAF3",
-"x c #84BF5D",
-"y c #EDF6E7",
-"z c #FAFDF9",
-"A c #88C263",
-"B c #98CA77",
-"C c #CDE5BE",
-"D c #67B037",
-"E c #D9EBCD",
-"F c #6AB23C",
-"G c #77B94D",
-" .++++++++++++++",
-".+++++++++++++++",
-"+++@#$%&+++*=+++",
-"++-;>,>')+!>~+++",
-"++{>]+^>/(_>:~<+",
-"+[>>}+|>123>456+",
-"+7>>8+->>90>~+++",
-"+a>>b+a>c[0>~+++",
-"+de>=+f>g+0>~+++",
-"++h>i+j>k+0>~+++",
-"++l>mno>p+q>rst+",
-"++duv>wl++xy>zA+",
-"++++B>Cb++++&D++",
-"+++++0zE++++++++",
-"++++++FG+++++++.",
-"++++++++++++++. "};
-
-static const char * const qt_close_xpm[] = {
-"10 10 2 1",
-"# c #000000",
-". c None",
-"..........",
-".##....##.",
-"..##..##..",
-"...####...",
-"....##....",
-"...####...",
-"..##..##..",
-".##....##.",
-"..........",
-".........."};
-
-static const char * const qt_maximize_xpm[]={
-"10 10 2 1",
-"# c #000000",
-". c None",
-"#########.",
-"#########.",
-"#.......#.",
-"#.......#.",
-"#.......#.",
-"#.......#.",
-"#.......#.",
-"#.......#.",
-"#########.",
-".........."};
-
-
-static const char * const qt_normalizeup_xpm[] = {
-"10 10 2 1",
-"# c #000000",
-". c None",
-"...######.",
-"...######.",
-"...#....#.",
-".######.#.",
-".######.#.",
-".#....###.",
-".#....#...",
-".#....#...",
-".######...",
-".........."};
-
-
-#endif // QWASMSTYLEPIXMAPS_P_H
diff --git a/src/plugins/platforms/wasm/qwasmtheme.cpp b/src/plugins/platforms/wasm/qwasmtheme.cpp
index 978d60d686..b188dcb4b6 100644
--- a/src/plugins/platforms/wasm/qwasmtheme.cpp
+++ b/src/plugins/platforms/wasm/qwasmtheme.cpp
@@ -1,43 +1,19 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the plugins of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL$
-** 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 General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 or (at your option) 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.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-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include "qwasmtheme.h"
#include <QtCore/qvariant.h>
#include <QFontDatabase>
+#include <QList>
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
QWasmTheme::QWasmTheme()
{
- QFontDatabase fdb;
- for (auto family : fdb.families())
- if (fdb.isFixedPitch(family))
+ for (auto family : QFontDatabase::families())
+ if (QFontDatabase::isFixedPitch(family))
fixedFont = new QFont(family);
}
@@ -50,7 +26,9 @@ QWasmTheme::~QWasmTheme()
QVariant QWasmTheme::themeHint(ThemeHint hint) const
{
if (hint == QPlatformTheme::StyleNames)
- return QVariant(QStringList() << QLatin1String("fusion"));
+ return QVariant(QStringList() << "Fusion"_L1);
+ if (hint == QPlatformTheme::UiEffects)
+ return QVariant(int(HoverEffect));
return QPlatformTheme::themeHint(hint);
}
diff --git a/src/plugins/platforms/wasm/qwasmtheme.h b/src/plugins/platforms/wasm/qwasmtheme.h
index 7123a1f3d4..90ecbe6ddf 100644
--- a/src/plugins/platforms/wasm/qwasmtheme.h
+++ b/src/plugins/platforms/wasm/qwasmtheme.h
@@ -1,31 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the plugins of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL$
-** 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 General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 or (at your option) 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.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-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#ifndef QWASMTHEME_H
#define QWASMTHEME_H
diff --git a/src/plugins/platforms/wasm/qwasmwindow.cpp b/src/plugins/platforms/wasm/qwasmwindow.cpp
index 594db65cfd..b8197c5113 100644
--- a/src/plugins/platforms/wasm/qwasmwindow.cpp
+++ b/src/plugins/platforms/wasm/qwasmwindow.cpp
@@ -1,96 +1,232 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the plugins of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL$
-** 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 General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 or (at your option) 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.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-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <qpa/qwindowsysteminterface.h>
#include <private/qguiapplication_p.h>
-#include <QtGui/private/qopenglcontext_p.h>
+#include <QtCore/qfile.h>
#include <QtGui/private/qwindow_p.h>
-#include <QtGui/qopenglcontext.h>
-
+#include <QtGui/private/qhighdpiscaling_p.h>
+#include <private/qpixmapcache_p.h>
+#include <QtGui/qopenglfunctions.h>
+#include <QBuffer>
+
+#include "qwasmbase64iconstore.h"
+#include "qwasmdom.h"
+#include "qwasmclipboard.h"
+#include "qwasmintegration.h"
+#include "qwasmkeytranslator.h"
#include "qwasmwindow.h"
+#include "qwasmwindowclientarea.h"
#include "qwasmscreen.h"
#include "qwasmcompositor.h"
+#include "qwasmevent.h"
#include "qwasmeventdispatcher.h"
+#include "qwasmaccessibility.h"
+#include "qwasmclipboard.h"
#include <iostream>
+#include <sstream>
-Q_GUI_EXPORT int qt_defaultDpiX();
+#include <emscripten/val.h>
+
+#include <QtCore/private/qstdweb_p.h>
QT_BEGIN_NAMESPACE
-QWasmWindow::QWasmWindow(QWindow *w, QWasmCompositor *compositor, QWasmBackingStore *backingStore)
+namespace {
+QWasmWindowStack::PositionPreference positionPreferenceFromWindowFlags(Qt::WindowFlags flags)
+{
+ if (flags.testFlag(Qt::WindowStaysOnTopHint))
+ return QWasmWindowStack::PositionPreference::StayOnTop;
+ if (flags.testFlag(Qt::WindowStaysOnBottomHint))
+ return QWasmWindowStack::PositionPreference::StayOnBottom;
+ return QWasmWindowStack::PositionPreference::Regular;
+}
+} // namespace
+
+Q_GUI_EXPORT int qt_defaultDpiX();
+
+QWasmWindow::QWasmWindow(QWindow *w, QWasmDeadKeySupport *deadKeySupport,
+ QWasmCompositor *compositor, QWasmBackingStore *backingStore)
: QPlatformWindow(w),
m_window(w),
m_compositor(compositor),
- m_backingStore(backingStore)
+ m_backingStore(backingStore),
+ m_deadKeySupport(deadKeySupport),
+ m_document(dom::document()),
+ m_qtWindow(m_document.call<emscripten::val>("createElement", emscripten::val("div"))),
+ m_windowContents(m_document.call<emscripten::val>("createElement", emscripten::val("div"))),
+ m_canvasContainer(m_document.call<emscripten::val>("createElement", emscripten::val("div"))),
+ m_a11yContainer(m_document.call<emscripten::val>("createElement", emscripten::val("div"))),
+ m_canvas(m_document.call<emscripten::val>("createElement", emscripten::val("canvas")))
{
- m_needsCompositor = w->surfaceType() != QSurface::OpenGLSurface;
+ m_qtWindow.set("className", "qt-window");
+ m_qtWindow["style"].set("display", std::string("none"));
+
+ m_nonClientArea = std::make_unique<NonClientArea>(this, m_qtWindow);
+ m_nonClientArea->titleBar()->setTitle(window()->title());
+
+ m_clientArea = std::make_unique<ClientArea>(this, compositor->screen(), m_windowContents);
+
+ m_windowContents.set("className", "qt-window-contents");
+ m_qtWindow.call<void>("appendChild", m_windowContents);
+
+ m_canvas["classList"].call<void>("add", emscripten::val("qt-window-content"));
+
+ // Set contenteditable so that the canvas gets clipboard events,
+ // then hide the resulting focus frame.
+ m_canvas.set("contentEditable", std::string("true"));
+ m_canvas["style"].set("outline", std::string("none"));
+
+ QWasmClipboard::installEventHandlers(m_canvas);
+
+ // set inputMode to none to stop mobile keyboard opening
+ // when user clicks anywhere on the canvas.
+ m_canvas.set("inputMode", std::string("none"));
+
+ // Hide the canvas from screen readers.
+ m_canvas.call<void>("setAttribute", std::string("aria-hidden"), std::string("true"));
+
+ m_windowContents.call<void>("appendChild", m_canvasContainer);
+
+ m_canvasContainer["classList"].call<void>("add", emscripten::val("qt-window-canvas-container"));
+ m_canvasContainer.call<void>("appendChild", m_canvas);
+
+ m_canvasContainer.call<void>("appendChild", m_a11yContainer);
+ m_a11yContainer["classList"].call<void>("add", emscripten::val("qt-window-a11y-container"));
+
+ const bool rendersTo2dContext = w->surfaceType() != QSurface::OpenGLSurface;
+ if (rendersTo2dContext)
+ m_context2d = m_canvas.call<emscripten::val>("getContext", emscripten::val("2d"));
static int serialNo = 0;
- m_winid = ++serialNo;
+ m_winId = ++serialNo;
+ m_qtWindow.set("id", "qt-window-" + std::to_string(m_winId));
+ emscripten::val::module_property("specialHTMLTargets").set(canvasSelector(), m_canvas);
+
+ m_flags = window()->flags();
+
+ const auto pointerCallback = std::function([this](emscripten::val event) {
+ if (processPointer(*PointerEvent::fromWeb(event)))
+ event.call<void>("preventDefault");
+ });
+
+ m_pointerEnterCallback =
+ std::make_unique<qstdweb::EventCallback>(m_qtWindow, "pointerenter", pointerCallback);
+ m_pointerLeaveCallback =
+ std::make_unique<qstdweb::EventCallback>(m_qtWindow, "pointerleave", pointerCallback);
+
+ m_wheelEventCallback = std::make_unique<qstdweb::EventCallback>(
+ m_qtWindow, "wheel", [this](emscripten::val event) {
+ if (processWheel(*WheelEvent::fromWeb(event)))
+ event.call<void>("preventDefault");
+ });
+
+ const auto keyCallback = std::function([this](emscripten::val event) {
+ if (processKey(*KeyEvent::fromWebWithDeadKeyTranslation(event, m_deadKeySupport)))
+ event.call<void>("preventDefault");
+ event.call<void>("stopPropagation");
+ });
+
+ emscripten::val keyFocusWindow;
+ if (QWasmIntegration::get()->inputContext()) {
+ QWasmInputContext *wasmContext =
+ static_cast<QWasmInputContext *>(QWasmIntegration::get()->inputContext());
+ // if there is an touchscreen input context,
+ // use that window for key input
+ keyFocusWindow = wasmContext->m_inputElement;
+ } else {
+ keyFocusWindow = m_qtWindow;
+ }
- m_compositor->addWindow(this);
+ m_keyDownCallback =
+ std::make_unique<qstdweb::EventCallback>(keyFocusWindow, "keydown", keyCallback);
+ m_keyUpCallback = std::make_unique<qstdweb::EventCallback>(keyFocusWindow, "keyup", keyCallback);
- // Pure OpenGL windows draw directly using egl, disable the compositor.
- m_compositor->setEnabled(w->surfaceType() != QSurface::OpenGLSurface);
+ setParent(parent());
}
QWasmWindow::~QWasmWindow()
{
- m_compositor->removeWindow(this);
+ emscripten::val::module_property("specialHTMLTargets").delete_(canvasSelector());
+ m_canvasContainer.call<void>("removeChild", m_canvas);
+ m_context2d = emscripten::val::undefined();
+ commitParent(nullptr);
+ if (m_requestAnimationFrameId > -1)
+ emscripten_cancel_animation_frame(m_requestAnimationFrameId);
+#if QT_CONFIG(accessibility)
+ QWasmAccessibility::removeAccessibilityEnableButton(window());
+#endif
}
-void QWasmWindow::destroy()
+QSurfaceFormat QWasmWindow::format() const
{
- if (m_backingStore)
- m_backingStore->destroy();
+ return window()->requestedFormat();
}
-void QWasmWindow::initialize()
+QWasmWindow *QWasmWindow::fromWindow(QWindow *window)
+{
+ return static_cast<QWasmWindow *>(window->handle());
+}
+
+void QWasmWindow::onRestoreClicked()
{
- QRect rect = windowGeometry();
+ window()->setWindowState(Qt::WindowNoState);
+}
- QPlatformWindow::setGeometry(rect);
+void QWasmWindow::onMaximizeClicked()
+{
+ window()->setWindowState(Qt::WindowMaximized);
+}
- const QSize minimumSize = windowMinimumSize();
- if (rect.width() > 0 || rect.height() > 0) {
- rect.setWidth(qBound(1, rect.width(), 2000));
- rect.setHeight(qBound(1, rect.height(), 2000));
- } else if (minimumSize.width() > 0 || minimumSize.height() > 0) {
- rect.setSize(minimumSize);
- }
+void QWasmWindow::onToggleMaximized()
+{
+ window()->setWindowState(m_state.testFlag(Qt::WindowMaximized) ? Qt::WindowNoState
+ : Qt::WindowMaximized);
+}
+
+void QWasmWindow::onCloseClicked()
+{
+ window()->close();
+}
+
+void QWasmWindow::onNonClientAreaInteraction()
+{
+ requestActivateWindow();
+ QGuiApplicationPrivate::instance()->closeAllPopups();
+}
+
+bool QWasmWindow::onNonClientEvent(const PointerEvent &event)
+{
+ QPointF pointInScreen = platformScreen()->mapFromLocal(
+ dom::mapPoint(event.target(), platformScreen()->element(), event.localPoint));
+ return QWindowSystemInterface::handleMouseEvent(
+ window(), QWasmIntegration::getTimestamp(), window()->mapFromGlobal(pointInScreen),
+ pointInScreen, event.mouseButtons, event.mouseButton,
+ MouseEvent::mouseEventTypeFromEventType(event.type, WindowArea::NonClient),
+ event.modifiers);
+}
+
+void QWasmWindow::initialize()
+{
+ auto initialGeometry = QPlatformWindow::initialGeometry(window(),
+ windowGeometry(), defaultWindowSize, defaultWindowSize);
+ m_normalGeometry = initialGeometry;
setWindowState(window()->windowStates());
setWindowFlags(window()->flags());
setWindowTitle(window()->title());
+ setMask(QHighDpi::toNativeLocalRegion(window()->mask(), window()));
+
if (window()->isTopLevel())
setWindowIcon(window()->icon());
- m_normalGeometry = rect;
+ QPlatformWindow::setGeometry(m_normalGeometry);
+
+#if QT_CONFIG(accessibility)
+ // Add accessibility-enable button. The user can activate this
+ // button to opt-in to accessibility.
+ if (window()->isTopLevel())
+ QWasmAccessibility::addAccessibilityEnableButton(window());
+#endif
}
QWasmScreen *QWasmWindow::platformScreen() const
@@ -98,311 +234,468 @@ QWasmScreen *QWasmWindow::platformScreen() const
return static_cast<QWasmScreen *>(window()->screen()->handle());
}
-void QWasmWindow::setGeometry(const QRect &rect)
+void QWasmWindow::paint()
{
- QRect r = rect;
- if (m_needsCompositor) {
- int yMin = window()->geometry().top() - window()->frameGeometry().top();
-
- if (r.y() < yMin)
- r.moveTop(yMin);
- }
- QWindowSystemInterface::handleGeometryChange(window(), r);
- QPlatformWindow::setGeometry(r);
+ if (!m_backingStore || !isVisible() || m_context2d.isUndefined())
+ return;
- QWindowSystemInterface::flushWindowSystemEvents();
- invalidate();
+ auto image = m_backingStore->getUpdatedWebImage(this);
+ if (image.isUndefined())
+ return;
+ m_context2d.call<void>("putImageData", image, emscripten::val(0), emscripten::val(0));
}
-void QWasmWindow::setVisible(bool visible)
+void QWasmWindow::setZOrder(int z)
{
- QRect newGeom;
+ m_qtWindow["style"].set("zIndex", std::to_string(z));
+}
- if (visible) {
- const bool forceFullScreen = !m_needsCompositor;//make gl apps fullscreen for now
+void QWasmWindow::setWindowCursor(QByteArray cssCursorName)
+{
+ m_windowContents["style"].set("cursor", emscripten::val(cssCursorName.constData()));
+}
- if (forceFullScreen || (m_windowState & Qt::WindowFullScreen))
- newGeom = platformScreen()->geometry();
- else if (m_windowState & Qt::WindowMaximized)
- newGeom = platformScreen()->availableGeometry();
+void QWasmWindow::setGeometry(const QRect &rect)
+{
+ const auto margins = frameMargins();
+
+ const QRect clientAreaRect = ([this, &rect, &margins]() {
+ if (m_state.testFlag(Qt::WindowFullScreen))
+ return platformScreen()->geometry();
+ if (m_state.testFlag(Qt::WindowMaximized))
+ return platformScreen()->availableGeometry().marginsRemoved(frameMargins());
+
+ auto offset = rect.topLeft() - (!parent() ? screen()->geometry().topLeft() : QPoint());
+
+ // In viewport
+ auto containerGeometryInViewport =
+ QRectF::fromDOMRect(parentNode()->containerElement().call<emscripten::val>(
+ "getBoundingClientRect"))
+ .toRect();
+
+ auto rectInViewport = QRect(containerGeometryInViewport.topLeft() + offset, rect.size());
+
+ QRect cappedGeometry(rectInViewport);
+ if (!parent()) {
+ // Clamp top level windows top position to the screen bounds
+ cappedGeometry.moveTop(
+ std::max(std::min(rectInViewport.y(), containerGeometryInViewport.bottom()),
+ containerGeometryInViewport.y() + margins.top()));
+ }
+ cappedGeometry.setSize(
+ cappedGeometry.size().expandedTo(windowMinimumSize()).boundedTo(windowMaximumSize()));
+ return QRect(QPoint(rect.x(), rect.y() + cappedGeometry.y() - rectInViewport.y()),
+ rect.size());
+ })();
+ m_nonClientArea->onClientAreaWidthChange(clientAreaRect.width());
+
+ const auto frameRect =
+ clientAreaRect
+ .adjusted(-margins.left(), -margins.top(), margins.right(), margins.bottom())
+ .translated(!parent() ? -screen()->geometry().topLeft() : QPoint());
+
+ m_qtWindow["style"].set("left", std::to_string(frameRect.left()) + "px");
+ m_qtWindow["style"].set("top", std::to_string(frameRect.top()) + "px");
+ m_canvasContainer["style"].set("width", std::to_string(clientAreaRect.width()) + "px");
+ m_canvasContainer["style"].set("height", std::to_string(clientAreaRect.height()) + "px");
+ m_a11yContainer["style"].set("width", std::to_string(clientAreaRect.width()) + "px");
+ m_a11yContainer["style"].set("height", std::to_string(clientAreaRect.height()) + "px");
+
+ // Important for the title flexbox to shrink correctly
+ m_windowContents["style"].set("width", std::to_string(clientAreaRect.width()) + "px");
+
+ QSizeF canvasSize = clientAreaRect.size() * devicePixelRatio();
+
+ m_canvas.set("width", canvasSize.width());
+ m_canvas.set("height", canvasSize.height());
+
+ bool shouldInvalidate = true;
+ if (!m_state.testFlag(Qt::WindowFullScreen) && !m_state.testFlag(Qt::WindowMaximized)) {
+ shouldInvalidate = m_normalGeometry.size() != clientAreaRect.size();
+ m_normalGeometry = clientAreaRect;
}
- QPlatformWindow::setVisible(visible);
+ QWindowSystemInterface::handleGeometryChange(window(), clientAreaRect);
+ if (shouldInvalidate)
+ invalidate();
+ else
+ m_compositor->requestUpdateWindow(this);
+}
- m_compositor->setVisible(this, visible);
+void QWasmWindow::setVisible(bool visible)
+{
+ // TODO(mikolajboc): isVisible()?
+ const bool nowVisible = m_qtWindow["style"]["display"].as<std::string>() == "block";
+ if (visible == nowVisible)
+ return;
- if (!newGeom.isEmpty())
- setGeometry(newGeom); // may or may not generate an expose
+ m_compositor->requestUpdateWindow(this, QWasmCompositor::ExposeEventDelivery);
+ m_qtWindow["style"].set("display", visible ? "block" : "none");
+ if (window()->isActive())
+ m_canvas.call<void>("focus");
+ if (visible)
+ applyWindowState();
+}
- invalidate();
+bool QWasmWindow::isVisible() const
+{
+ return window()->isVisible();
}
QMargins QWasmWindow::frameMargins() const
{
- int border = hasTitleBar() ? 4. * (qreal(qt_defaultDpiX()) / 96.0) : 0;
- int titleBarHeight = hasTitleBar() ? titleHeight() : 0;
-
- QMargins margins;
- margins.setLeft(border);
- margins.setRight(border);
- margins.setTop(2*border + titleBarHeight);
- margins.setBottom(border);
-
- return margins;
+ const auto frameRect =
+ QRectF::fromDOMRect(m_qtWindow.call<emscripten::val>("getBoundingClientRect"));
+ const auto canvasRect =
+ QRectF::fromDOMRect(m_windowContents.call<emscripten::val>("getBoundingClientRect"));
+ return QMarginsF(canvasRect.left() - frameRect.left(), canvasRect.top() - frameRect.top(),
+ frameRect.right() - canvasRect.right(),
+ frameRect.bottom() - canvasRect.bottom())
+ .toMargins();
}
void QWasmWindow::raise()
{
- m_compositor->raise(this);
- QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(0, 0), geometry().size()));
+ bringToTop();
invalidate();
+ if (QWasmIntegration::get()->inputContext())
+ m_canvas.call<void>("focus");
}
void QWasmWindow::lower()
{
- m_compositor->lower(this);
- QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(0, 0), geometry().size()));
+ sendToBottom();
invalidate();
}
WId QWasmWindow::winId() const
{
- return m_winid;
+ return m_winId;
}
void QWasmWindow::propagateSizeHints()
{
-// get rid of base class warning
+ // setGeometry() will take care of minimum and maximum size constraints
+ setGeometry(windowGeometry());
+ m_nonClientArea->propagateSizeHints();
}
-void QWasmWindow::injectMousePressed(const QPoint &local, const QPoint &global,
- Qt::MouseButton button, Qt::KeyboardModifiers mods)
+void QWasmWindow::setOpacity(qreal level)
{
- Q_UNUSED(local);
- Q_UNUSED(mods);
+ m_qtWindow["style"].set("opacity", qBound(0.0, level, 1.0));
+}
- if (!hasTitleBar() || button != Qt::LeftButton)
- return;
+void QWasmWindow::invalidate()
+{
+ m_compositor->requestUpdateWindow(this);
+}
+
+void QWasmWindow::onActivationChanged(bool active)
+{
+ dom::syncCSSClassWith(m_qtWindow, "inactive", !active);
+}
- if (maxButtonRect().contains(global))
- m_activeControl = QWasmCompositor::SC_TitleBarMaxButton;
- else if (minButtonRect().contains(global))
- m_activeControl = QWasmCompositor::SC_TitleBarMinButton;
- else if (closeButtonRect().contains(global))
- m_activeControl = QWasmCompositor::SC_TitleBarCloseButton;
- else if (normButtonRect().contains(global))
- m_activeControl = QWasmCompositor::SC_TitleBarNormalButton;
+void QWasmWindow::setWindowFlags(Qt::WindowFlags flags)
+{
+ if (flags.testFlag(Qt::WindowStaysOnTopHint) != m_flags.testFlag(Qt::WindowStaysOnTopHint)
+ || flags.testFlag(Qt::WindowStaysOnBottomHint)
+ != m_flags.testFlag(Qt::WindowStaysOnBottomHint)) {
+ onPositionPreferenceChanged(positionPreferenceFromWindowFlags(flags));
+ }
+ m_flags = flags;
+ dom::syncCSSClassWith(m_qtWindow, "frameless", !hasFrame());
+ dom::syncCSSClassWith(m_qtWindow, "has-border", hasBorder());
+ dom::syncCSSClassWith(m_qtWindow, "has-shadow", hasShadow());
+ dom::syncCSSClassWith(m_qtWindow, "has-title", hasTitleBar());
+ dom::syncCSSClassWith(m_qtWindow, "transparent-for-input",
+ flags.testFlag(Qt::WindowTransparentForInput));
- invalidate();
+ m_nonClientArea->titleBar()->setMaximizeVisible(hasMaximizeButton());
+ m_nonClientArea->titleBar()->setCloseVisible(m_flags.testFlag(Qt::WindowCloseButtonHint));
}
-void QWasmWindow::injectMouseReleased(const QPoint &local, const QPoint &global,
- Qt::MouseButton button, Qt::KeyboardModifiers mods)
+void QWasmWindow::setWindowState(Qt::WindowStates newState)
{
- Q_UNUSED(local);
- Q_UNUSED(mods);
+ // Child windows can not have window states other than Qt::WindowActive
+ if (parent())
+ newState &= Qt::WindowActive;
- if (!hasTitleBar() || button != Qt::LeftButton)
- return;
+ const Qt::WindowStates oldState = m_state;
- if (closeButtonRect().contains(global) && m_activeControl == QWasmCompositor::SC_TitleBarCloseButton) {
- window()->close();
+ if (newState.testFlag(Qt::WindowMinimized)) {
+ newState.setFlag(Qt::WindowMinimized, false);
+ qWarning("Qt::WindowMinimized is not implemented in wasm");
+ window()->setWindowStates(newState);
return;
}
- if (maxButtonRect().contains(global) && m_activeControl == QWasmCompositor::SC_TitleBarMaxButton) {
- window()->setWindowState(Qt::WindowMaximized);
- platformScreen()->resizeMaximizedWindows();
- }
-
- if (normButtonRect().contains(global) && m_activeControl == QWasmCompositor::SC_TitleBarNormalButton) {
- window()->setWindowState(Qt::WindowNoState);
- setGeometry(normalGeometry());
- }
+ if (newState == oldState)
+ return;
- m_activeControl = QWasmCompositor::SC_None;
+ m_state = newState;
+ m_previousWindowState = oldState;
- invalidate();
+ applyWindowState();
}
-int QWasmWindow::titleHeight() const
+void QWasmWindow::setWindowTitle(const QString &title)
{
- return 18. * (qreal(qt_defaultDpiX()) / 96.0);//dpiScaled(18.);
+ m_nonClientArea->titleBar()->setTitle(title);
}
-int QWasmWindow::borderWidth() const
+void QWasmWindow::setWindowIcon(const QIcon &icon)
{
- return 4. * (qreal(qt_defaultDpiX()) / 96.0);// dpiScaled(4.);
+ const auto dpi = screen()->devicePixelRatio();
+ auto pixmap = icon.pixmap(10 * dpi, 10 * dpi);
+ if (pixmap.isNull()) {
+ m_nonClientArea->titleBar()->setIcon(
+ Base64IconStore::get()->getIcon(Base64IconStore::IconType::QtLogo), "svg+xml");
+ return;
+ }
+
+ QByteArray bytes;
+ QBuffer buffer(&bytes);
+ pixmap.save(&buffer, "png");
+ m_nonClientArea->titleBar()->setIcon(bytes.toBase64().toStdString(), "png");
}
-QRegion QWasmWindow::titleGeometry() const
+void QWasmWindow::applyWindowState()
{
- int border = borderWidth();
+ QRect newGeom;
+
+ const bool isFullscreen = m_state.testFlag(Qt::WindowFullScreen);
+ const bool isMaximized = m_state.testFlag(Qt::WindowMaximized);
+ if (isFullscreen)
+ newGeom = platformScreen()->geometry();
+ else if (isMaximized)
+ newGeom = platformScreen()->availableGeometry().marginsRemoved(frameMargins());
+ else
+ newGeom = normalGeometry();
- QRegion result(window()->frameGeometry().x() + border,
- window()->frameGeometry().y() + border,
- window()->frameGeometry().width() - 2*border,
- titleHeight());
+ dom::syncCSSClassWith(m_qtWindow, "has-border", hasBorder());
+ dom::syncCSSClassWith(m_qtWindow, "maximized", isMaximized);
- result -= titleControlRegion();
+ m_nonClientArea->titleBar()->setRestoreVisible(isMaximized);
+ m_nonClientArea->titleBar()->setMaximizeVisible(hasMaximizeButton());
- return result;
+ if (isVisible())
+ QWindowSystemInterface::handleWindowStateChanged(window(), m_state, m_previousWindowState);
+ setGeometry(newGeom);
}
-QRegion QWasmWindow::resizeRegion() const
+void QWasmWindow::commitParent(QWasmWindowTreeNode *parent)
{
- int border = borderWidth();
- QRegion result(window()->frameGeometry().adjusted(-border, -border, border, border));
- result -= window()->frameGeometry().adjusted(border, border, -border, -border);
-
- return result;
+ onParentChanged(m_commitedParent, parent, positionPreferenceFromWindowFlags(window()->flags()));
+ m_commitedParent = parent;
}
-bool QWasmWindow::isPointOnTitle(QPoint point) const
+bool QWasmWindow::processKey(const KeyEvent &event)
{
- bool ok = titleGeometry().contains(point);
- return ok;
+ constexpr bool ProceedToNativeEvent = false;
+ Q_ASSERT(event.type == EventType::KeyDown || event.type == EventType::KeyUp);
+
+ const auto clipboardResult =
+ QWasmIntegration::get()->getWasmClipboard()->processKeyboard(event);
+
+ using ProcessKeyboardResult = QWasmClipboard::ProcessKeyboardResult;
+ if (clipboardResult == ProcessKeyboardResult::NativeClipboardEventNeeded)
+ return ProceedToNativeEvent;
+
+ const auto result = QWindowSystemInterface::handleKeyEvent(
+ 0, event.type == EventType::KeyDown ? QEvent::KeyPress : QEvent::KeyRelease, event.key,
+ event.modifiers, event.text);
+ return clipboardResult == ProcessKeyboardResult::NativeClipboardEventAndCopiedDataNeeded
+ ? ProceedToNativeEvent
+ : result;
}
-bool QWasmWindow::isPointOnResizeRegion(QPoint point) const
+bool QWasmWindow::processPointer(const PointerEvent &event)
{
- return resizeRegion().contains(point);
+ if (event.pointerType != PointerType::Mouse && event.pointerType != PointerType::Pen)
+ return false;
+
+ switch (event.type) {
+ case EventType::PointerEnter: {
+ const auto pointInScreen = platformScreen()->mapFromLocal(
+ dom::mapPoint(event.target(), platformScreen()->element(), event.localPoint));
+ QWindowSystemInterface::handleEnterEvent(
+ window(), m_window->mapFromGlobal(pointInScreen), pointInScreen);
+ break;
+ }
+ case EventType::PointerLeave:
+ QWindowSystemInterface::handleLeaveEvent(window());
+ break;
+ default:
+ break;
+ }
+
+ return false;
}
-QWasmWindow::ResizeMode QWasmWindow::resizeModeAtPoint(QPoint point) const
+bool QWasmWindow::processWheel(const WheelEvent &event)
{
- QPoint p1 = window()->frameGeometry().topLeft() - QPoint(5, 5);
- QPoint p2 = window()->frameGeometry().bottomRight() + QPoint(5, 5);
- int corner = 20;
+ // Web scroll deltas are inverted from Qt deltas - negate.
+ const int scrollFactor = -([&event]() {
+ switch (event.deltaMode) {
+ case DeltaMode::Pixel:
+ return 1;
+ case DeltaMode::Line:
+ return 12;
+ case DeltaMode::Page:
+ return 20;
+ };
+ })();
- QRect top(p1, QPoint(p2.x(), p1.y() + corner));
- QRect middle(QPoint(p1.x(), p1.y() + corner), QPoint(p2.x(), p2.y() - corner));
- QRect bottom(QPoint(p1.x(), p2.y() - corner), p2);
+ const auto pointInScreen = platformScreen()->mapFromLocal(
+ dom::mapPoint(event.target(), platformScreen()->element(), event.localPoint));
- QRect left(p1, QPoint(p1.x() + corner, p2.y()));
- QRect center(QPoint(p1.x() + corner, p1.y()), QPoint(p2.x() - corner, p2.y()));
- QRect right(QPoint(p2.x() - corner, p1.y()), p2);
-
- if (top.contains(point)) {
- // Top
- if (left.contains(point))
- return ResizeTopLeft;
- if (center.contains(point))
- return ResizeTop;
- if (right.contains(point))
- return ResizeTopRight;
- } else if (middle.contains(point)) {
- // Middle
- if (left.contains(point))
- return ResizeLeft;
- if (right.contains(point))
- return ResizeRight;
- } else if (bottom.contains(point)) {
- // Bottom
- if (left.contains(point))
- return ResizeBottomLeft;
- if (center.contains(point))
- return ResizeBottom;
- if (right.contains(point))
- return ResizeBottomRight;
- }
+ return QWindowSystemInterface::handleWheelEvent(
+ window(), QWasmIntegration::getTimestamp(), window()->mapFromGlobal(pointInScreen),
+ pointInScreen, (event.delta * scrollFactor).toPoint(),
+ (event.delta * scrollFactor).toPoint(), event.modifiers, Qt::NoScrollPhase,
+ Qt::MouseEventNotSynthesized, event.webkitDirectionInvertedFromDevice);
+}
- return ResizeNone;
+QRect QWasmWindow::normalGeometry() const
+{
+ return m_normalGeometry;
}
-QRect getSubControlRect(const QWasmWindow *window, QWasmCompositor::SubControls subControl)
+qreal QWasmWindow::devicePixelRatio() const
{
- QWasmCompositor::QWasmTitleBarOptions options = QWasmCompositor::makeTitleBarOptions(window);
+ return screen()->devicePixelRatio();
+}
- QRect r = QWasmCompositor::titlebarRect(options, subControl);
- r.translate(window->window()->frameGeometry().x(), window->window()->frameGeometry().y());
+void QWasmWindow::requestUpdate()
+{
+ m_compositor->requestUpdateWindow(this, QWasmCompositor::UpdateRequestDelivery);
+}
- return r;
+bool QWasmWindow::hasFrame() const
+{
+ return !m_flags.testFlag(Qt::FramelessWindowHint);
}
-QRect QWasmWindow::maxButtonRect() const
+bool QWasmWindow::hasBorder() const
{
- return getSubControlRect(this, QWasmCompositor::SC_TitleBarMaxButton);
+ return hasFrame() && !m_state.testFlag(Qt::WindowFullScreen) && !m_flags.testFlag(Qt::SubWindow)
+ && !windowIsPopupType(m_flags) && !parent();
}
-QRect QWasmWindow::minButtonRect() const
+bool QWasmWindow::hasTitleBar() const
{
- return getSubControlRect(this, QWasmCompositor::SC_TitleBarMinButton);
+ return hasBorder() && m_flags.testFlag(Qt::WindowTitleHint);
}
-QRect QWasmWindow::closeButtonRect() const
+bool QWasmWindow::hasShadow() const
{
- return getSubControlRect(this, QWasmCompositor::SC_TitleBarCloseButton);
+ return hasBorder() && !m_flags.testFlag(Qt::NoDropShadowWindowHint);
}
-QRect QWasmWindow::normButtonRect() const
+bool QWasmWindow::hasMaximizeButton() const
{
- return getSubControlRect(this, QWasmCompositor::SC_TitleBarNormalButton);
+ return !m_state.testFlag(Qt::WindowMaximized) && m_flags.testFlag(Qt::WindowMaximizeButtonHint);
}
-QRect QWasmWindow::sysMenuRect() const
+bool QWasmWindow::windowIsPopupType(Qt::WindowFlags flags) const
{
- return getSubControlRect(this, QWasmCompositor::SC_TitleBarSysMenu);
+ if (flags.testFlag(Qt::Tool))
+ return false; // Qt::Tool has the Popup bit set but isn't an actual Popup window
+
+ return (flags.testFlag(Qt::Popup));
}
-QRegion QWasmWindow::titleControlRegion() const
+void QWasmWindow::requestActivateWindow()
{
- QRegion result;
- result += closeButtonRect();
- result += minButtonRect();
- result += maxButtonRect();
- result += sysMenuRect();
+ QWindow *modalWindow;
+ if (QGuiApplicationPrivate::instance()->isWindowBlocked(window(), &modalWindow)) {
+ static_cast<QWasmWindow *>(modalWindow->handle())->requestActivateWindow();
+ return;
+ }
+
+ raise();
+ setAsActiveNode();
+
+ if (!QWasmIntegration::get()->inputContext())
+ m_canvas.call<void>("focus");
- return result;
+ QPlatformWindow::requestActivateWindow();
}
-void QWasmWindow::invalidate()
+bool QWasmWindow::setMouseGrabEnabled(bool grab)
{
- m_compositor->requestRedraw();
+ Q_UNUSED(grab);
+ return false;
}
-QWasmCompositor::SubControls QWasmWindow::activeSubControl() const
+bool QWasmWindow::windowEvent(QEvent *event)
{
- return m_activeControl;
+ switch (event->type()) {
+ case QEvent::WindowBlocked:
+ m_qtWindow["classList"].call<void>("add", emscripten::val("blocked"));
+ return false; // Propagate further
+ case QEvent::WindowUnblocked:;
+ m_qtWindow["classList"].call<void>("remove", emscripten::val("blocked"));
+ return false; // Propagate further
+ default:
+ return QPlatformWindow::windowEvent(event);
+ }
}
-void QWasmWindow::setWindowState(Qt::WindowStates states)
+void QWasmWindow::setMask(const QRegion &region)
{
- m_windowState = Qt::WindowNoState;
- if (states & Qt::WindowMinimized)
- m_windowState = Qt::WindowMinimized;
- else if (states & Qt::WindowFullScreen)
- m_windowState = Qt::WindowFullScreen;
- else if (states & Qt::WindowMaximized)
- m_windowState = Qt::WindowMaximized;
+ if (region.isEmpty()) {
+ m_qtWindow["style"].set("clipPath", emscripten::val(""));
+ return;
+ }
+
+ std::ostringstream cssClipPath;
+ cssClipPath << "path('";
+ for (const auto &rect : region) {
+ const auto cssRect = rect.adjusted(0, 0, 1, 1);
+ cssClipPath << "M " << cssRect.left() << " " << cssRect.top() << " ";
+ cssClipPath << "L " << cssRect.right() << " " << cssRect.top() << " ";
+ cssClipPath << "L " << cssRect.right() << " " << cssRect.bottom() << " ";
+ cssClipPath << "L " << cssRect.left() << " " << cssRect.bottom() << " z ";
+ }
+ cssClipPath << "')";
+ m_qtWindow["style"].set("clipPath", emscripten::val(cssClipPath.str()));
}
-QRect QWasmWindow::normalGeometry() const
+void QWasmWindow::setParent(const QPlatformWindow *)
{
- return m_normalGeometry;
+ commitParent(parentNode());
}
-qreal QWasmWindow::devicePixelRatio() const
+std::string QWasmWindow::canvasSelector() const
{
- return screen()->devicePixelRatio();
+ return "!qtwindow" + std::to_string(m_winId);
}
-void QWasmWindow::requestUpdate()
+emscripten::val QWasmWindow::containerElement()
{
- QPointer<QWindow> windowPointer(window());
- bool registered = QWasmEventDispatcher::registerRequestUpdateCallback([=](){
- if (windowPointer.isNull())
- return;
+ return m_windowContents;
+}
- deliverUpdateRequest();
- });
+QWasmWindowTreeNode *QWasmWindow::parentNode()
+{
+ if (parent())
+ return static_cast<QWasmWindow *>(parent());
+ return platformScreen();
+}
- if (!registered)
- QPlatformWindow::requestUpdate();
+QWasmWindow *QWasmWindow::asWasmWindow()
+{
+ return this;
}
-bool QWasmWindow::hasTitleBar() const
+void QWasmWindow::onParentChanged(QWasmWindowTreeNode *previous, QWasmWindowTreeNode *current,
+ QWasmWindowStack::PositionPreference positionPreference)
{
- return !(m_windowState & Qt::WindowFullScreen) && (window()->flags().testFlag(Qt::WindowTitleHint) && m_needsCompositor);
+ if (previous)
+ previous->containerElement().call<void>("removeChild", m_qtWindow);
+ if (current)
+ current->containerElement().call<void>("appendChild", m_qtWindow);
+ QWasmWindowTreeNode::onParentChanged(previous, current, positionPreference);
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/wasm/qwasmwindow.h b/src/plugins/platforms/wasm/qwasmwindow.h
index a098172649..ab0dc68e83 100644
--- a/src/plugins/platforms/wasm/qwasmwindow.h
+++ b/src/plugins/platforms/wasm/qwasmwindow.h
@@ -1,128 +1,175 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the plugins of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL$
-** 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 General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 or (at your option) 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.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-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#ifndef QWASMWINDOW_H
#define QWASMWINDOW_H
#include "qwasmintegration.h"
#include <qpa/qplatformwindow.h>
+#include <qpa/qplatformwindow_p.h>
#include <emscripten/html5.h>
#include "qwasmbackingstore.h"
#include "qwasmscreen.h"
#include "qwasmcompositor.h"
+#include "qwasmwindownonclientarea.h"
+#include "qwasmwindowstack.h"
+#include "qwasmwindowtreenode.h"
+
+#include <QtCore/private/qstdweb_p.h>
+#include "QtGui/qopenglcontext.h"
+#include <QtOpenGL/qopengltextureblitter.h>
+
+#include <emscripten/val.h>
+
+#include <memory>
QT_BEGIN_NAMESPACE
-class QWasmCompositor;
+namespace qstdweb {
+class EventCallback;
+}
+
+class ClientArea;
+struct KeyEvent;
+struct PointerEvent;
+class QWasmDeadKeySupport;
+struct WheelEvent;
-class QWasmWindow : public QPlatformWindow
+class QWasmWindow final : public QPlatformWindow,
+ public QWasmWindowTreeNode,
+ public QNativeInterface::Private::QWasmWindow
{
public:
- enum ResizeMode {
- ResizeNone,
- ResizeTopLeft,
- ResizeTop,
- ResizeTopRight,
- ResizeRight,
- ResizeBottomRight,
- ResizeBottom,
- ResizeBottomLeft,
- ResizeLeft
- };
-
- QWasmWindow(QWindow *w, QWasmCompositor *compositor, QWasmBackingStore *backingStore);
- ~QWasmWindow();
- void destroy();
-
+ QWasmWindow(QWindow *w, QWasmDeadKeySupport *deadKeySupport, QWasmCompositor *compositor,
+ QWasmBackingStore *backingStore);
+ ~QWasmWindow() final;
+
+ static QWasmWindow *fromWindow(QWindow *window);
+ QSurfaceFormat format() const override;
+
+ void paint();
+ void setZOrder(int order);
+ void setWindowCursor(QByteArray cssCursorName);
+ void onActivationChanged(bool active);
+ bool isVisible() const;
+
+ void onNonClientAreaInteraction();
+ void onRestoreClicked();
+ void onMaximizeClicked();
+ void onToggleMaximized();
+ void onCloseClicked();
+ bool onNonClientEvent(const PointerEvent &event);
+
+ // QPlatformWindow:
void initialize() override;
-
void setGeometry(const QRect &) override;
void setVisible(bool visible) override;
QMargins frameMargins() const override;
-
WId winId() const override;
-
void propagateSizeHints() override;
+ void setOpacity(qreal level) override;
void raise() override;
void lower() override;
QRect normalGeometry() const override;
qreal devicePixelRatio() const override;
void requestUpdate() override;
+ void requestActivateWindow() override;
+ void setWindowFlags(Qt::WindowFlags flags) override;
+ void setWindowState(Qt::WindowStates state) override;
+ void setWindowTitle(const QString &title) override;
+ void setWindowIcon(const QIcon &icon) override;
+ bool setKeyboardGrabEnabled(bool) override { return false; }
+ bool setMouseGrabEnabled(bool grab) final;
+ bool windowEvent(QEvent *event) final;
+ void setMask(const QRegion &region) final;
+ void setParent(const QPlatformWindow *window) final;
QWasmScreen *platformScreen() const;
void setBackingStore(QWasmBackingStore *store) { m_backingStore = store; }
QWasmBackingStore *backingStore() const { return m_backingStore; }
QWindow *window() const { return m_window; }
- void injectMousePressed(const QPoint &local, const QPoint &global,
- Qt::MouseButton button, Qt::KeyboardModifiers mods);
- void injectMouseReleased(const QPoint &local, const QPoint &global,
- Qt::MouseButton button, Qt::KeyboardModifiers mods);
-
- int titleHeight() const;
- int borderWidth() const;
- QRegion titleGeometry() const;
- QRegion resizeRegion() const;
- bool isPointOnTitle(QPoint point) const;
- bool isPointOnResizeRegion(QPoint point) const;
- ResizeMode resizeModeAtPoint(QPoint point) const;
- QRect maxButtonRect() const;
- QRect minButtonRect() const;
- QRect closeButtonRect() const;
- QRect sysMenuRect() const;
- QRect normButtonRect() const;
- QRegion titleControlRegion() const;
- QWasmCompositor::SubControls activeSubControl() const;
+ std::string canvasSelector() const;
- void setWindowState(Qt::WindowStates state) override;
- bool setKeyboardGrabEnabled(bool) override { return false; }
- bool setMouseGrabEnabled(bool) override { return false; }
+ emscripten::val context2d() const { return m_context2d; }
+ emscripten::val a11yContainer() const { return m_a11yContainer; }
+ emscripten::val inputHandlerElement() const { return m_windowContents; }
+
+ // QNativeInterface::Private::QWasmWindow
+ emscripten::val document() const override { return m_document; }
+ emscripten::val clientArea() const override { return m_qtWindow; }
+
+ // QWasmWindowTreeNode:
+ emscripten::val containerElement() final;
+ QWasmWindowTreeNode *parentNode() final;
+
+private:
+ friend class QWasmScreen;
+ static constexpr auto defaultWindowSize = 160;
+
+ // QWasmWindowTreeNode:
+ QWasmWindow *asWasmWindow() final;
+ void onParentChanged(QWasmWindowTreeNode *previous, QWasmWindowTreeNode *current,
+ QWasmWindowStack::PositionPreference positionPreference) final;
-protected:
void invalidate();
+ bool hasFrame() const;
bool hasTitleBar() const;
+ bool hasBorder() const;
+ bool hasShadow() const;
+ bool hasMaximizeButton() const;
+ void applyWindowState();
+ void commitParent(QWasmWindowTreeNode *parent);
-protected:
- friend class QWasmScreen;
+ bool processKey(const KeyEvent &event);
+ bool processPointer(const PointerEvent &event);
+ bool processWheel(const WheelEvent &event);
- QWindow* m_window = nullptr;
+ QWindow *m_window = nullptr;
QWasmCompositor *m_compositor = nullptr;
QWasmBackingStore *m_backingStore = nullptr;
+ QWasmDeadKeySupport *m_deadKeySupport;
QRect m_normalGeometry {0, 0, 0 ,0};
- Qt::WindowState m_windowState = Qt::WindowNoState;
- QWasmCompositor::SubControls m_activeControl = QWasmCompositor::SC_None;
- WId m_winid = 0;
+ emscripten::val m_document;
+ emscripten::val m_qtWindow;
+ emscripten::val m_windowContents;
+ emscripten::val m_canvasContainer;
+ emscripten::val m_a11yContainer;
+ emscripten::val m_canvas;
+ emscripten::val m_context2d = emscripten::val::undefined();
+
+ std::unique_ptr<NonClientArea> m_nonClientArea;
+ std::unique_ptr<ClientArea> m_clientArea;
+
+ QWasmWindowTreeNode *m_commitedParent = nullptr;
+
+ std::unique_ptr<qstdweb::EventCallback> m_keyDownCallback;
+ std::unique_ptr<qstdweb::EventCallback> m_keyUpCallback;
+
+ std::unique_ptr<qstdweb::EventCallback> m_pointerLeaveCallback;
+ std::unique_ptr<qstdweb::EventCallback> m_pointerEnterCallback;
+
+ std::unique_ptr<qstdweb::EventCallback> m_dropCallback;
+
+ std::unique_ptr<qstdweb::EventCallback> m_wheelEventCallback;
+
+ Qt::WindowStates m_state = Qt::WindowNoState;
+ Qt::WindowStates m_previousWindowState = Qt::WindowNoState;
+
+ Qt::WindowFlags m_flags = Qt::Widget;
+
+ QPoint m_lastPointerMovePoint;
+
+ WId m_winId = 0;
+ bool m_wantCapture = false;
bool m_hasTitle = false;
bool m_needsCompositor = false;
+ long m_requestAnimationFrameId = -1;
friend class QWasmCompositor;
friend class QWasmEventTranslator;
+ bool windowIsPopupType(Qt::WindowFlags flags) const;
};
+
QT_END_NAMESPACE
#endif // QWASMWINDOW_H
diff --git a/src/plugins/platforms/wasm/qwasmwindowclientarea.cpp b/src/plugins/platforms/wasm/qwasmwindowclientarea.cpp
new file mode 100644
index 0000000000..6da3e24c05
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmwindowclientarea.cpp
@@ -0,0 +1,195 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "qwasmwindowclientarea.h"
+
+#include "qwasmdom.h"
+#include "qwasmevent.h"
+#include "qwasmscreen.h"
+#include "qwasmwindow.h"
+#include "qwasmdrag.h"
+
+#include <QtGui/private/qguiapplication_p.h>
+#include <QtGui/qpointingdevice.h>
+
+#include <QtCore/qassert.h>
+
+QT_BEGIN_NAMESPACE
+
+ClientArea::ClientArea(QWasmWindow *window, QWasmScreen *screen, emscripten::val element)
+ : m_screen(screen), m_window(window), m_element(element)
+{
+ const auto callback = std::function([this](emscripten::val event) {
+ processPointer(*PointerEvent::fromWeb(event));
+ event.call<void>("preventDefault");
+ event.call<void>("stopPropagation");
+ });
+
+ m_pointerDownCallback =
+ std::make_unique<qstdweb::EventCallback>(element, "pointerdown", callback);
+ m_pointerMoveCallback =
+ std::make_unique<qstdweb::EventCallback>(element, "pointermove", callback);
+ m_pointerUpCallback = std::make_unique<qstdweb::EventCallback>(element, "pointerup", callback);
+ m_pointerCancelCallback =
+ std::make_unique<qstdweb::EventCallback>(element, "pointercancel", callback);
+
+ element.call<void>("setAttribute", emscripten::val("draggable"), emscripten::val("true"));
+
+ m_dragStartCallback = std::make_unique<qstdweb::EventCallback>(
+ element, "dragstart", [this](emscripten::val webEvent) {
+ webEvent.call<void>("preventDefault");
+ auto event = *DragEvent::fromWeb(webEvent, m_window->window());
+ QWasmDrag::instance()->onNativeDragStarted(&event);
+ });
+ m_dragOverCallback = std::make_unique<qstdweb::EventCallback>(
+ element, "dragover", [this](emscripten::val webEvent) {
+ webEvent.call<void>("preventDefault");
+ auto event = *DragEvent::fromWeb(webEvent, m_window->window());
+ QWasmDrag::instance()->onNativeDragOver(&event);
+ });
+ m_dropCallback = std::make_unique<qstdweb::EventCallback>(
+ element, "drop", [this](emscripten::val webEvent) {
+ webEvent.call<void>("preventDefault");
+ auto event = *DragEvent::fromWeb(webEvent, m_window->window());
+ QWasmDrag::instance()->onNativeDrop(&event);
+ });
+ m_dragEndCallback = std::make_unique<qstdweb::EventCallback>(
+ element, "dragend", [this](emscripten::val webEvent) {
+ webEvent.call<void>("preventDefault");
+ auto event = *DragEvent::fromWeb(webEvent, m_window->window());
+ QWasmDrag::instance()->onNativeDragFinished(&event);
+ });
+
+}
+
+bool ClientArea::processPointer(const PointerEvent &event)
+{
+
+ switch (event.type) {
+ case EventType::PointerDown:
+ m_element.call<void>("setPointerCapture", event.pointerId);
+ if ((m_window->window()->flags() & Qt::WindowDoesNotAcceptFocus)
+ != Qt::WindowDoesNotAcceptFocus
+ && m_window->window()->isTopLevel())
+ m_window->window()->requestActivate();
+ break;
+ case EventType::PointerUp:
+ m_element.call<void>("releasePointerCapture", event.pointerId);
+ break;
+ default:
+ break;
+ };
+
+ const bool eventAccepted = deliverEvent(event);
+ if (!eventAccepted && event.type == EventType::PointerDown)
+ QGuiApplicationPrivate::instance()->closeAllPopups();
+ return eventAccepted;
+}
+
+bool ClientArea::deliverEvent(const PointerEvent &event)
+{
+ const auto pointInScreen = m_screen->mapFromLocal(
+ dom::mapPoint(event.target(), m_screen->element(), event.localPoint));
+
+ const auto geometryF = m_screen->geometry().toRectF();
+ const QPointF targetPointClippedToScreen(
+ qBound(geometryF.left(), pointInScreen.x(), geometryF.right()),
+ qBound(geometryF.top(), pointInScreen.y(), geometryF.bottom()));
+
+ if (event.pointerType == PointerType::Mouse) {
+ const QEvent::Type eventType =
+ MouseEvent::mouseEventTypeFromEventType(event.type, WindowArea::Client);
+
+ return eventType != QEvent::None
+ && QWindowSystemInterface::handleMouseEvent(
+ m_window->window(), QWasmIntegration::getTimestamp(),
+ m_window->window()->mapFromGlobal(targetPointClippedToScreen),
+ targetPointClippedToScreen, event.mouseButtons, event.mouseButton,
+ eventType, event.modifiers);
+ }
+
+ if (event.pointerType == PointerType::Pen) {
+ qreal pressure;
+ switch (event.type) {
+ case EventType::PointerDown :
+ case EventType::PointerMove :
+ pressure = event.pressure;
+ break;
+ case EventType::PointerUp :
+ pressure = 0.0;
+ break;
+ default:
+ return false;
+ }
+ // Tilt in the browser is in the range +-90, but QTabletEvent only goes to +-60.
+ qreal xTilt = qBound(-60.0, event.tiltX, 60.0);
+ qreal yTilt = qBound(-60.0, event.tiltY, 60.0);
+ // Barrel rotation is reported as 0 to 359, but QTabletEvent wants a signed value.
+ qreal rotation = event.twist > 180.0 ? 360.0 - event.twist : event.twist;
+ return QWindowSystemInterface::handleTabletEvent(
+ m_window->window(), QWasmIntegration::getTimestamp(), m_screen->tabletDevice(),
+ m_window->window()->mapFromGlobal(targetPointClippedToScreen),
+ targetPointClippedToScreen, event.mouseButtons, pressure, xTilt, yTilt,
+ event.tangentialPressure, rotation, event.modifiers);
+ }
+
+ QWindowSystemInterface::TouchPoint *touchPoint;
+
+ QPointF pointInTargetWindowCoords =
+ QPointF(m_window->window()->mapFromGlobal(targetPointClippedToScreen));
+ QPointF normalPosition(pointInTargetWindowCoords.x() / m_window->window()->width(),
+ pointInTargetWindowCoords.y() / m_window->window()->height());
+
+ const auto tp = m_pointerIdToTouchPoints.find(event.pointerId);
+ if (event.pointerType != PointerType::Pen && tp != m_pointerIdToTouchPoints.end()) {
+ touchPoint = &tp.value();
+ } else {
+ touchPoint = &m_pointerIdToTouchPoints
+ .insert(event.pointerId, QWindowSystemInterface::TouchPoint())
+ .value();
+
+ // Assign touch point id. TouchPoint::id is int, but QGuiApplicationPrivate::processTouchEvent()
+ // will not synthesize mouse events for touch points with negative id; use the absolute value for
+ // the touch point id.
+ touchPoint->id = qAbs(event.pointerId);
+
+ touchPoint->state = QEventPoint::State::Pressed;
+ }
+
+ const bool stationaryTouchPoint = (normalPosition == touchPoint->normalPosition);
+ touchPoint->normalPosition = normalPosition;
+ touchPoint->area = QRectF(targetPointClippedToScreen, QSizeF(event.width, event.height))
+ .translated(-event.width / 2, -event.height / 2);
+ touchPoint->pressure = event.pressure;
+
+ switch (event.type) {
+ case EventType::PointerUp:
+ touchPoint->state = QEventPoint::State::Released;
+ break;
+ case EventType::PointerMove:
+ touchPoint->state = (stationaryTouchPoint ? QEventPoint::State::Stationary
+ : QEventPoint::State::Updated);
+ break;
+ default:
+ break;
+ }
+
+ QList<QWindowSystemInterface::TouchPoint> touchPointList;
+ touchPointList.reserve(m_pointerIdToTouchPoints.size());
+ std::transform(m_pointerIdToTouchPoints.begin(), m_pointerIdToTouchPoints.end(),
+ std::back_inserter(touchPointList),
+ [](const QWindowSystemInterface::TouchPoint &val) { return val; });
+
+ if (event.type == EventType::PointerUp)
+ m_pointerIdToTouchPoints.remove(event.pointerId);
+
+ return event.type == EventType::PointerCancel
+ ? QWindowSystemInterface::handleTouchCancelEvent(
+ m_window->window(), QWasmIntegration::getTimestamp(), m_screen->touchDevice(),
+ event.modifiers)
+ : QWindowSystemInterface::handleTouchEvent(
+ m_window->window(), QWasmIntegration::getTimestamp(), m_screen->touchDevice(),
+ touchPointList, event.modifiers);
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/wasm/qwasmwindowclientarea.h b/src/plugins/platforms/wasm/qwasmwindowclientarea.h
new file mode 100644
index 0000000000..ba745a59a8
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmwindowclientarea.h
@@ -0,0 +1,52 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef QWASMWINDOWCLIENTAREA_H
+#define QWASMWINDOWCLIENTAREA_H
+
+#include <QtCore/qnamespace.h>
+#include <qpa/qwindowsysteminterface.h>
+#include <QtCore/QMap>
+
+#include <emscripten/val.h>
+
+#include <memory>
+
+QT_BEGIN_NAMESPACE
+
+namespace qstdweb {
+class EventCallback;
+}
+
+struct PointerEvent;
+class QWasmScreen;
+class QWasmWindow;
+
+class ClientArea
+{
+public:
+ ClientArea(QWasmWindow *window, QWasmScreen *screen, emscripten::val element);
+
+private:
+ bool processPointer(const PointerEvent &event);
+ bool deliverEvent(const PointerEvent &event);
+
+ std::unique_ptr<qstdweb::EventCallback> m_pointerDownCallback;
+ std::unique_ptr<qstdweb::EventCallback> m_pointerMoveCallback;
+ std::unique_ptr<qstdweb::EventCallback> m_pointerUpCallback;
+ std::unique_ptr<qstdweb::EventCallback> m_pointerCancelCallback;
+
+ std::unique_ptr<qstdweb::EventCallback> m_dragOverCallback;
+ std::unique_ptr<qstdweb::EventCallback> m_dragStartCallback;
+ std::unique_ptr<qstdweb::EventCallback> m_dragEndCallback;
+ std::unique_ptr<qstdweb::EventCallback> m_dropCallback;
+
+ QMap<int, QWindowSystemInterface::TouchPoint> m_pointerIdToTouchPoints;
+
+ QWasmScreen *m_screen;
+ QWasmWindow *m_window;
+ emscripten::val m_element;
+};
+
+QT_END_NAMESPACE
+#endif // QWASMWINDOWNONCLIENTAREA_H
diff --git a/src/plugins/platforms/wasm/qwasmwindownonclientarea.cpp b/src/plugins/platforms/wasm/qwasmwindownonclientarea.cpp
new file mode 100644
index 0000000000..00fa8fb236
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmwindownonclientarea.cpp
@@ -0,0 +1,460 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "qwasmwindownonclientarea.h"
+
+#include "qwasmbase64iconstore.h"
+#include "qwasmdom.h"
+#include "qwasmevent.h"
+#include "qwasmintegration.h"
+
+#include <qpa/qwindowsysteminterface.h>
+
+#include <QtCore/qassert.h>
+
+QT_BEGIN_NAMESPACE
+
+WebImageButton::Callbacks::Callbacks() = default;
+WebImageButton::Callbacks::Callbacks(std::function<void()> onInteraction,
+ std::function<void()> onClick)
+ : m_onInteraction(std::move(onInteraction)), m_onClick(std::move(onClick))
+{
+ Q_ASSERT_X(!!m_onInteraction == !!m_onClick, Q_FUNC_INFO,
+ "Both callbacks need to be either null or non-null");
+}
+WebImageButton::Callbacks::~Callbacks() = default;
+
+WebImageButton::Callbacks::Callbacks(Callbacks &&) = default;
+WebImageButton::Callbacks &WebImageButton::Callbacks::operator=(Callbacks &&) = default;
+
+void WebImageButton::Callbacks::onInteraction()
+{
+ return m_onInteraction();
+}
+
+void WebImageButton::Callbacks::onClick()
+{
+ return m_onClick();
+}
+
+WebImageButton::WebImageButton()
+ : m_containerElement(
+ dom::document().call<emscripten::val>("createElement", emscripten::val("div"))),
+ m_imgElement(dom::document().call<emscripten::val>("createElement", emscripten::val("img")))
+{
+ m_imgElement.set("draggable", false);
+
+ m_containerElement["classList"].call<void>("add", emscripten::val("image-button"));
+ m_containerElement.call<void>("appendChild", m_imgElement);
+}
+
+WebImageButton::~WebImageButton() = default;
+
+void WebImageButton::setCallbacks(Callbacks callbacks)
+{
+ if (callbacks) {
+ if (!m_webClickEventCallback) {
+ m_webMouseDownEventCallback = std::make_unique<qstdweb::EventCallback>(
+ m_containerElement, "pointerdown", [this](emscripten::val event) {
+ event.call<void>("preventDefault");
+ event.call<void>("stopPropagation");
+ m_callbacks.onInteraction();
+ });
+ m_webClickEventCallback = std::make_unique<qstdweb::EventCallback>(
+ m_containerElement, "click", [this](emscripten::val event) {
+ m_callbacks.onClick();
+ event.call<void>("stopPropagation");
+ });
+ }
+ } else {
+ m_webMouseDownEventCallback.reset();
+ m_webClickEventCallback.reset();
+ }
+ dom::syncCSSClassWith(m_containerElement, "action-button", !!callbacks);
+ m_callbacks = std::move(callbacks);
+}
+
+void WebImageButton::setImage(std::string_view imageData, std::string_view format)
+{
+ m_imgElement.set("src",
+ "data:image/" + std::string(format) + ";base64," + std::string(imageData));
+}
+
+void WebImageButton::setVisible(bool visible)
+{
+ m_containerElement["style"].set("display", visible ? "flex" : "none");
+}
+
+Resizer::ResizerElement::ResizerElement(emscripten::val parentElement, Qt::Edges edges,
+ Resizer *resizer)
+ : m_element(dom::document().call<emscripten::val>("createElement", emscripten::val("div"))),
+ m_edges(edges),
+ m_resizer(resizer)
+{
+ Q_ASSERT_X(m_resizer, Q_FUNC_INFO, "Resizer cannot be null");
+
+ m_element["classList"].call<void>("add", emscripten::val("resize-outline"));
+ m_element["classList"].call<void>("add", emscripten::val(cssClassNameForEdges(edges)));
+
+ parentElement.call<void>("appendChild", m_element);
+
+ m_mouseDownEvent = std::make_unique<qstdweb::EventCallback>(
+ m_element, "pointerdown", [this](emscripten::val event) {
+ if (!onPointerDown(*PointerEvent::fromWeb(event)))
+ return;
+ m_resizer->onInteraction();
+ event.call<void>("preventDefault");
+ event.call<void>("stopPropagation");
+ });
+ m_mouseMoveEvent = std::make_unique<qstdweb::EventCallback>(
+ m_element, "pointermove", [this](emscripten::val event) {
+ if (onPointerMove(*PointerEvent::fromWeb(event)))
+ event.call<void>("preventDefault");
+ });
+ m_mouseUpEvent = std::make_unique<qstdweb::EventCallback>(
+ m_element, "pointerup", [this](emscripten::val event) {
+ if (onPointerUp(*PointerEvent::fromWeb(event))) {
+ event.call<void>("preventDefault");
+ event.call<void>("stopPropagation");
+ }
+ });
+}
+
+Resizer::ResizerElement::~ResizerElement()
+{
+ m_element["parentElement"].call<emscripten::val>("removeChild", m_element);
+}
+
+Resizer::ResizerElement::ResizerElement(ResizerElement &&other) = default;
+
+bool Resizer::ResizerElement::onPointerDown(const PointerEvent &event)
+{
+ m_element.call<void>("setPointerCapture", event.pointerId);
+ m_capturedPointerId = event.pointerId;
+
+ m_resizer->startResize(m_edges, event);
+ return true;
+}
+
+bool Resizer::ResizerElement::onPointerMove(const PointerEvent &event)
+{
+ if (m_capturedPointerId != event.pointerId)
+ return false;
+
+ m_resizer->continueResize(event);
+ return true;
+}
+
+bool Resizer::ResizerElement::onPointerUp(const PointerEvent &event)
+{
+ if (m_capturedPointerId != event.pointerId)
+ return false;
+
+ m_resizer->finishResize();
+ m_element.call<void>("releasePointerCapture", event.pointerId);
+ m_capturedPointerId = -1;
+ return true;
+}
+
+Resizer::Resizer(QWasmWindow *window, emscripten::val parentElement)
+ : m_window(window), m_windowElement(parentElement)
+{
+ Q_ASSERT_X(m_window, Q_FUNC_INFO, "Window must not be null");
+
+ constexpr std::array<int, 8> ResizeEdges = { Qt::TopEdge | Qt::LeftEdge,
+ Qt::TopEdge,
+ Qt::TopEdge | Qt::RightEdge,
+ Qt::LeftEdge,
+ Qt::RightEdge,
+ Qt::BottomEdge | Qt::LeftEdge,
+ Qt::BottomEdge,
+ Qt::BottomEdge | Qt::RightEdge };
+ std::transform(std::begin(ResizeEdges), std::end(ResizeEdges), std::back_inserter(m_elements),
+ [parentElement, this](int edges) {
+ return std::make_unique<ResizerElement>(parentElement,
+ Qt::Edges::fromInt(edges), this);
+ });
+}
+
+Resizer::~Resizer() = default;
+
+ResizeConstraints Resizer::getResizeConstraints() {
+ const auto *window = m_window->window();
+ const auto minShrink = QPoint(window->minimumWidth() - window->geometry().width(),
+ window->minimumHeight() - window->geometry().height());
+ const auto maxGrow = QPoint(window->maximumWidth() - window->geometry().width(),
+ window->maximumHeight() - window->geometry().height());
+
+ const auto frameRect =
+ QRectF::fromDOMRect(m_windowElement.call<emscripten::val>("getBoundingClientRect"));
+ auto containerGeometry =
+ QRectF::fromDOMRect(m_window->parentNode()->containerElement().call<emscripten::val>(
+ "getBoundingClientRect"));
+
+ const int maxGrowTop = frameRect.top() - containerGeometry.top();
+
+ return ResizeConstraints{minShrink, maxGrow, maxGrowTop};
+}
+
+void Resizer::onInteraction()
+{
+ m_window->onNonClientAreaInteraction();
+}
+
+void Resizer::startResize(Qt::Edges resizeEdges, const PointerEvent &event)
+{
+ Q_ASSERT_X(!m_currentResizeData, Q_FUNC_INFO, "Another resize in progress");
+
+ m_currentResizeData.reset(new ResizeData{
+ .edges = resizeEdges,
+ .originInScreenCoords = dom::mapPoint(
+ event.target(), m_window->platformScreen()->element(), event.localPoint),
+ });
+
+ const auto resizeConstraints = getResizeConstraints();
+ m_currentResizeData->minShrink = resizeConstraints.minShrink;
+
+ m_currentResizeData->maxGrow =
+ QPoint(resizeConstraints.maxGrow.x(),
+ std::min(resizeEdges & Qt::Edge::TopEdge ? resizeConstraints.maxGrowTop : INT_MAX,
+ resizeConstraints.maxGrow.y()));
+
+ m_currentResizeData->initialBounds = m_window->window()->geometry();
+}
+
+void Resizer::continueResize(const PointerEvent &event)
+{
+ const auto pointInScreen =
+ dom::mapPoint(event.target(), m_window->platformScreen()->element(), event.localPoint);
+ const auto amount = (pointInScreen - m_currentResizeData->originInScreenCoords).toPoint();
+ const QPoint cappedGrowVector(
+ std::min(m_currentResizeData->maxGrow.x(),
+ std::max(m_currentResizeData->minShrink.x(),
+ (m_currentResizeData->edges & Qt::Edge::LeftEdge) ? -amount.x()
+ : (m_currentResizeData->edges & Qt::Edge::RightEdge)
+ ? amount.x()
+ : 0)),
+ std::min(m_currentResizeData->maxGrow.y(),
+ std::max(m_currentResizeData->minShrink.y(),
+ (m_currentResizeData->edges & Qt::Edge::TopEdge) ? -amount.y()
+ : (m_currentResizeData->edges & Qt::Edge::BottomEdge)
+ ? amount.y()
+ : 0)));
+
+ auto bounds = m_currentResizeData->initialBounds.adjusted(
+ (m_currentResizeData->edges & Qt::Edge::LeftEdge) ? -cappedGrowVector.x() : 0,
+ (m_currentResizeData->edges & Qt::Edge::TopEdge) ? -cappedGrowVector.y() : 0,
+ (m_currentResizeData->edges & Qt::Edge::RightEdge) ? cappedGrowVector.x() : 0,
+ (m_currentResizeData->edges & Qt::Edge::BottomEdge) ? cappedGrowVector.y() : 0);
+
+ m_window->window()->setGeometry(bounds);
+}
+
+void Resizer::finishResize()
+{
+ Q_ASSERT_X(m_currentResizeData, Q_FUNC_INFO, "No resize in progress");
+ m_currentResizeData.reset();
+}
+
+TitleBar::TitleBar(QWasmWindow *window, emscripten::val parentElement)
+ : m_window(window),
+ m_element(dom::document().call<emscripten::val>("createElement", emscripten::val("div"))),
+ m_label(dom::document().call<emscripten::val>("createElement", emscripten::val("div")))
+{
+ m_icon = std::make_unique<WebImageButton>();
+ m_icon->setImage(Base64IconStore::get()->getIcon(Base64IconStore::IconType::QtLogo), "svg+xml");
+ m_element.call<void>("appendChild", m_icon->htmlElement());
+ m_element.set("className", "title-bar");
+
+ auto spacer = dom::document().call<emscripten::val>("createElement", emscripten::val("div"));
+ spacer["style"].set("width", "4px");
+ m_element.call<void>("appendChild", spacer);
+
+ m_label.set("className", "window-name");
+
+ m_element.call<void>("appendChild", m_label);
+
+ spacer = dom::document().call<emscripten::val>("createElement", emscripten::val("div"));
+ spacer.set("className", "spacer");
+ m_element.call<void>("appendChild", spacer);
+
+ m_restore = std::make_unique<WebImageButton>();
+ m_restore->setImage(Base64IconStore::get()->getIcon(Base64IconStore::IconType::Restore),
+ "svg+xml");
+ m_restore->setCallbacks(
+ WebImageButton::Callbacks([this]() { m_window->onNonClientAreaInteraction(); },
+ [this]() { m_window->onRestoreClicked(); }));
+
+ m_element.call<void>("appendChild", m_restore->htmlElement());
+
+ m_maximize = std::make_unique<WebImageButton>();
+ m_maximize->setImage(Base64IconStore::get()->getIcon(Base64IconStore::IconType::Maximize),
+ "svg+xml");
+ m_maximize->setCallbacks(
+ WebImageButton::Callbacks([this]() { m_window->onNonClientAreaInteraction(); },
+ [this]() { m_window->onMaximizeClicked(); }));
+
+ m_element.call<void>("appendChild", m_maximize->htmlElement());
+
+ m_close = std::make_unique<WebImageButton>();
+ m_close->setImage(Base64IconStore::get()->getIcon(Base64IconStore::IconType::X), "svg+xml");
+ m_close->setCallbacks(
+ WebImageButton::Callbacks([this]() { m_window->onNonClientAreaInteraction(); },
+ [this]() { m_window->onCloseClicked(); }));
+
+ m_element.call<void>("appendChild", m_close->htmlElement());
+
+ parentElement.call<void>("appendChild", m_element);
+
+ m_mouseDownEvent = std::make_unique<qstdweb::EventCallback>(
+ m_element, "pointerdown", [this](emscripten::val event) {
+ if (!onPointerDown(*PointerEvent::fromWeb(event)))
+ return;
+ m_window->onNonClientAreaInteraction();
+ event.call<void>("preventDefault");
+ event.call<void>("stopPropagation");
+ });
+ m_mouseMoveEvent = std::make_unique<qstdweb::EventCallback>(
+ m_element, "pointermove", [this](emscripten::val event) {
+ if (onPointerMove(*PointerEvent::fromWeb(event))) {
+ event.call<void>("preventDefault");
+ }
+ });
+ m_mouseUpEvent = std::make_unique<qstdweb::EventCallback>(
+ m_element, "pointerup", [this](emscripten::val event) {
+ if (onPointerUp(*PointerEvent::fromWeb(event))) {
+ event.call<void>("preventDefault");
+ event.call<void>("stopPropagation");
+ }
+ });
+ m_doubleClickEvent = std::make_unique<qstdweb::EventCallback>(
+ m_element, "dblclick", [this](emscripten::val event) {
+ if (onDoubleClick()) {
+ event.call<void>("preventDefault");
+ event.call<void>("stopPropagation");
+ }
+ });
+}
+
+TitleBar::~TitleBar()
+{
+ m_element["parentElement"].call<emscripten::val>("removeChild", m_element);
+}
+
+void TitleBar::setTitle(const QString &title)
+{
+ m_label.set("innerText", emscripten::val(title.toStdString()));
+}
+
+void TitleBar::setRestoreVisible(bool visible)
+{
+ m_restore->setVisible(visible);
+}
+
+void TitleBar::setMaximizeVisible(bool visible)
+{
+ m_maximize->setVisible(visible);
+}
+
+void TitleBar::setCloseVisible(bool visible)
+{
+ m_close->setVisible(visible);
+}
+
+void TitleBar::setIcon(std::string_view imageData, std::string_view format)
+{
+ m_icon->setImage(imageData, format);
+}
+
+void TitleBar::setWidth(int width)
+{
+ m_element["style"].set("width", std::to_string(width) + "px");
+}
+
+QRectF TitleBar::geometry() const
+{
+ return QRectF::fromDOMRect(m_element.call<emscripten::val>("getBoundingClientRect"));
+}
+
+bool TitleBar::onPointerDown(const PointerEvent &event)
+{
+ m_element.call<void>("setPointerCapture", event.pointerId);
+ m_capturedPointerId = event.pointerId;
+
+ m_moveStartWindowPosition = m_window->window()->position();
+ m_moveStartPoint = clipPointWithScreen(event.localPoint);
+ m_window->onNonClientEvent(event);
+ return true;
+}
+
+bool TitleBar::onPointerMove(const PointerEvent &event)
+{
+ if (m_capturedPointerId != event.pointerId)
+ return false;
+
+ const QPoint delta = (clipPointWithScreen(event.localPoint) - m_moveStartPoint).toPoint();
+
+ m_window->window()->setPosition(m_moveStartWindowPosition + delta);
+ m_window->onNonClientEvent(event);
+ return true;
+}
+
+bool TitleBar::onPointerUp(const PointerEvent &event)
+{
+ if (m_capturedPointerId != event.pointerId)
+ return false;
+
+ m_element.call<void>("releasePointerCapture", event.pointerId);
+ m_capturedPointerId = -1;
+ m_window->onNonClientEvent(event);
+ return true;
+}
+
+bool TitleBar::onDoubleClick()
+{
+ m_window->onToggleMaximized();
+ return true;
+}
+
+QPointF TitleBar::clipPointWithScreen(const QPointF &pointInTitleBarCoords) const
+{
+ auto containerRect =
+ QRectF::fromDOMRect(m_window->parentNode()->containerElement().call<emscripten::val>(
+ "getBoundingClientRect"));
+ const auto p = dom::mapPoint(m_element, m_window->parentNode()->containerElement(),
+ pointInTitleBarCoords);
+
+ auto result = QPointF(qBound(0., qreal(p.x()), containerRect.width()),
+ qBound(0., qreal(p.y()), containerRect.height()));
+ return m_window->parent() ? result : m_window->platformScreen()->mapFromLocal(result).toPoint();
+}
+
+NonClientArea::NonClientArea(QWasmWindow *window, emscripten::val qtWindowElement)
+ : m_qtWindowElement(qtWindowElement),
+ m_resizer(std::make_unique<Resizer>(window, m_qtWindowElement)),
+ m_titleBar(std::make_unique<TitleBar>(window, m_qtWindowElement))
+{
+ updateResizability();
+}
+
+NonClientArea::~NonClientArea() = default;
+
+void NonClientArea::onClientAreaWidthChange(int width)
+{
+ m_titleBar->setWidth(width);
+}
+
+void NonClientArea::propagateSizeHints()
+{
+ updateResizability();
+}
+
+void NonClientArea::updateResizability()
+{
+ const auto resizeConstraints = m_resizer->getResizeConstraints();
+ const bool nonResizable = resizeConstraints.minShrink.isNull()
+ && resizeConstraints.maxGrow.isNull() && resizeConstraints.maxGrowTop == 0;
+ dom::syncCSSClassWith(m_qtWindowElement, "no-resize", nonResizable);
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/wasm/qwasmwindownonclientarea.h b/src/plugins/platforms/wasm/qwasmwindownonclientarea.h
new file mode 100644
index 0000000000..78c77585a0
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmwindownonclientarea.h
@@ -0,0 +1,227 @@
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef QWASMWINDOWNONCLIENTAREA_H
+#define QWASMWINDOWNONCLIENTAREA_H
+
+#include <QtCore/qrect.h>
+#include <QtCore/qtconfigmacros.h>
+#include <QtCore/qnamespace.h>
+
+#include <emscripten/val.h>
+
+#include <functional>
+#include <memory>
+#include <string_view>
+#include <vector>
+
+QT_BEGIN_NAMESPACE
+
+namespace qstdweb {
+class EventCallback;
+}
+
+struct PointerEvent;
+class QWindow;
+class Resizer;
+class TitleBar;
+class QWasmWindow;
+
+class NonClientArea
+{
+public:
+ NonClientArea(QWasmWindow *window, emscripten::val containerElement);
+ ~NonClientArea();
+
+ void onClientAreaWidthChange(int width);
+ void propagateSizeHints();
+ TitleBar *titleBar() const { return m_titleBar.get(); }
+
+private:
+ void updateResizability();
+
+ emscripten::val m_qtWindowElement;
+ std::unique_ptr<Resizer> m_resizer;
+ std::unique_ptr<TitleBar> m_titleBar;
+};
+
+class WebImageButton
+{
+public:
+ class Callbacks
+ {
+ public:
+ Callbacks();
+ Callbacks(std::function<void()> onInteraction, std::function<void()> onClick);
+ ~Callbacks();
+
+ Callbacks(const Callbacks &) = delete;
+ Callbacks(Callbacks &&);
+ Callbacks &operator=(const Callbacks &) = delete;
+ Callbacks &operator=(Callbacks &&);
+
+ operator bool() const { return !!m_onInteraction; }
+
+ void onInteraction();
+ void onClick();
+
+ private:
+ std::function<void()> m_onInteraction;
+ std::function<void()> m_onClick;
+ };
+
+ WebImageButton();
+ ~WebImageButton();
+
+ void setCallbacks(Callbacks callbacks);
+ void setImage(std::string_view imageData, std::string_view format);
+ void setVisible(bool visible);
+
+ emscripten::val htmlElement() const { return m_containerElement; }
+ emscripten::val imageElement() const { return m_imgElement; }
+
+private:
+ emscripten::val m_containerElement;
+ emscripten::val m_imgElement;
+
+ std::unique_ptr<qstdweb::EventCallback> m_webMouseMoveEventCallback;
+ std::unique_ptr<qstdweb::EventCallback> m_webMouseDownEventCallback;
+ std::unique_ptr<qstdweb::EventCallback> m_webClickEventCallback;
+
+ Callbacks m_callbacks;
+};
+
+struct ResizeConstraints {
+ QPoint minShrink;
+ QPoint maxGrow;
+ int maxGrowTop;
+};
+
+class Resizer
+{
+public:
+ class ResizerElement
+ {
+ public:
+ static constexpr const char *cssClassNameForEdges(Qt::Edges edges)
+ {
+ switch (edges) {
+ case Qt::TopEdge | Qt::LeftEdge:;
+ return "nw";
+ case Qt::TopEdge:
+ return "n";
+ case Qt::TopEdge | Qt::RightEdge:
+ return "ne";
+ case Qt::LeftEdge:
+ return "w";
+ case Qt::RightEdge:
+ return "e";
+ case Qt::BottomEdge | Qt::LeftEdge:
+ return "sw";
+ case Qt::BottomEdge:
+ return "s";
+ case Qt::BottomEdge | Qt::RightEdge:
+ return "se";
+ default:
+ return "";
+ }
+ }
+
+ ResizerElement(emscripten::val parentElement, Qt::Edges edges, Resizer *resizer);
+ ~ResizerElement();
+ ResizerElement(const ResizerElement &other) = delete;
+ ResizerElement(ResizerElement &&other);
+ ResizerElement &operator=(const ResizerElement &other) = delete;
+ ResizerElement &operator=(ResizerElement &&other) = delete;
+
+ bool onPointerDown(const PointerEvent &event);
+ bool onPointerMove(const PointerEvent &event);
+ bool onPointerUp(const PointerEvent &event);
+
+ private:
+ emscripten::val m_element;
+
+ int m_capturedPointerId = -1;
+
+ const Qt::Edges m_edges;
+
+ Resizer *m_resizer;
+
+ std::unique_ptr<qstdweb::EventCallback> m_mouseDownEvent;
+ std::unique_ptr<qstdweb::EventCallback> m_mouseMoveEvent;
+ std::unique_ptr<qstdweb::EventCallback> m_mouseUpEvent;
+ };
+
+ using ClickCallback = std::function<void()>;
+
+ Resizer(QWasmWindow *window, emscripten::val parentElement);
+ ~Resizer();
+
+ ResizeConstraints getResizeConstraints();
+
+private:
+ void onInteraction();
+ void startResize(Qt::Edges resizeEdges, const PointerEvent &event);
+ void continueResize(const PointerEvent &event);
+ void finishResize();
+
+ struct ResizeData
+ {
+ Qt::Edges edges = Qt::Edges::fromInt(0);
+ QPointF originInScreenCoords;
+ QPoint minShrink;
+ QPoint maxGrow;
+ QRect initialBounds;
+ };
+ std::unique_ptr<ResizeData> m_currentResizeData;
+
+ QWasmWindow *m_window;
+ emscripten::val m_windowElement;
+ std::vector<std::unique_ptr<ResizerElement>> m_elements;
+};
+
+class TitleBar
+{
+public:
+ TitleBar(QWasmWindow *window, emscripten::val parentElement);
+ ~TitleBar();
+
+ void setTitle(const QString &title);
+ void setRestoreVisible(bool visible);
+ void setMaximizeVisible(bool visible);
+ void setCloseVisible(bool visible);
+ void setIcon(std::string_view imageData, std::string_view format);
+ void setWidth(int width);
+
+ QRectF geometry() const;
+
+private:
+ bool onPointerDown(const PointerEvent &event);
+ bool onPointerMove(const PointerEvent &event);
+ bool onPointerUp(const PointerEvent &event);
+ bool onDoubleClick();
+
+ QPointF clipPointWithScreen(const QPointF &pointInTitleBarCoords) const;
+
+ QWasmWindow *m_window;
+
+ emscripten::val m_element;
+ emscripten::val m_label;
+
+ std::unique_ptr<WebImageButton> m_close;
+ std::unique_ptr<WebImageButton> m_maximize;
+ std::unique_ptr<WebImageButton> m_restore;
+ std::unique_ptr<WebImageButton> m_icon;
+
+ int m_capturedPointerId = -1;
+ QPointF m_moveStartPoint;
+ QPoint m_moveStartWindowPosition;
+
+ std::unique_ptr<qstdweb::EventCallback> m_mouseDownEvent;
+ std::unique_ptr<qstdweb::EventCallback> m_mouseMoveEvent;
+ std::unique_ptr<qstdweb::EventCallback> m_mouseUpEvent;
+ std::unique_ptr<qstdweb::EventCallback> m_doubleClickEvent;
+};
+
+QT_END_NAMESPACE
+#endif // QWASMWINDOWNONCLIENTAREA_H
diff --git a/src/plugins/platforms/wasm/qwasmwindowstack.cpp b/src/plugins/platforms/wasm/qwasmwindowstack.cpp
new file mode 100644
index 0000000000..d3769c7a1b
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmwindowstack.cpp
@@ -0,0 +1,203 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "qwasmwindowstack.h"
+
+QT_BEGIN_NAMESPACE
+
+QWasmWindowStack::QWasmWindowStack(WindowOrderChangedCallbackType windowOrderChangedCallback)
+ : m_windowOrderChangedCallback(std::move(windowOrderChangedCallback)),
+ m_regularWindowsBegin(m_windowStack.begin()),
+ m_alwaysOnTopWindowsBegin(m_windowStack.begin())
+{
+}
+
+QWasmWindowStack::~QWasmWindowStack() = default;
+
+void QWasmWindowStack::pushWindow(QWasmWindow *window, PositionPreference position)
+{
+ Q_ASSERT(m_windowStack.count(window) == 0);
+
+ if (position == PositionPreference::StayOnTop) {
+ const auto stayOnTopDistance =
+ std::distance(m_windowStack.begin(), m_alwaysOnTopWindowsBegin);
+ const auto regularDistance = std::distance(m_windowStack.begin(), m_regularWindowsBegin);
+ m_windowStack.push_back(window);
+ m_alwaysOnTopWindowsBegin = m_windowStack.begin() + stayOnTopDistance;
+ m_regularWindowsBegin = m_windowStack.begin() + regularDistance;
+ } else if (position == PositionPreference::Regular) {
+ const auto regularDistance = std::distance(m_windowStack.begin(), m_regularWindowsBegin);
+ m_alwaysOnTopWindowsBegin = m_windowStack.insert(m_alwaysOnTopWindowsBegin, window) + 1;
+ m_regularWindowsBegin = m_windowStack.begin() + regularDistance;
+ } else {
+ const auto stayOnTopDistance =
+ std::distance(m_windowStack.begin(), m_alwaysOnTopWindowsBegin);
+ m_regularWindowsBegin = m_windowStack.insert(m_regularWindowsBegin, window) + 1;
+ m_alwaysOnTopWindowsBegin = m_windowStack.begin() + stayOnTopDistance + 1;
+ }
+
+ m_windowOrderChangedCallback();
+}
+
+void QWasmWindowStack::removeWindow(QWasmWindow *window)
+{
+ Q_ASSERT(m_windowStack.count(window) == 1);
+
+ auto it = std::find(m_windowStack.begin(), m_windowStack.end(), window);
+ const auto position = getWindowPositionPreference(it);
+ const auto stayOnTopDistance = std::distance(m_windowStack.begin(), m_alwaysOnTopWindowsBegin);
+ const auto regularDistance = std::distance(m_windowStack.begin(), m_regularWindowsBegin);
+
+ m_windowStack.erase(it);
+
+ m_alwaysOnTopWindowsBegin = m_windowStack.begin() + stayOnTopDistance
+ - (position != PositionPreference::StayOnTop ? 1 : 0);
+ m_regularWindowsBegin = m_windowStack.begin() + regularDistance
+ - (position == PositionPreference::StayOnBottom ? 1 : 0);
+
+ m_windowOrderChangedCallback();
+}
+
+void QWasmWindowStack::raise(QWasmWindow *window)
+{
+ Q_ASSERT(m_windowStack.count(window) == 1);
+
+ if (window == topWindow())
+ return;
+
+ auto it = std::find(m_windowStack.begin(), m_windowStack.end(), window);
+ auto itEnd = ([this, position = getWindowPositionPreference(it)]() {
+ switch (position) {
+ case PositionPreference::StayOnTop:
+ return m_windowStack.end();
+ case PositionPreference::Regular:
+ return m_alwaysOnTopWindowsBegin;
+ case PositionPreference::StayOnBottom:
+ return m_regularWindowsBegin;
+ }
+ })();
+ std::rotate(it, it + 1, itEnd);
+ m_windowOrderChangedCallback();
+}
+
+void QWasmWindowStack::lower(QWasmWindow *window)
+{
+ Q_ASSERT(m_windowStack.count(window) == 1);
+
+ if (window == *m_windowStack.begin())
+ return;
+
+ auto it = std::find(m_windowStack.begin(), m_windowStack.end(), window);
+ auto itBegin = ([this, position = getWindowPositionPreference(it)]() {
+ switch (position) {
+ case PositionPreference::StayOnTop:
+ return m_alwaysOnTopWindowsBegin;
+ case PositionPreference::Regular:
+ return m_regularWindowsBegin;
+ case PositionPreference::StayOnBottom:
+ return m_windowStack.begin();
+ }
+ })();
+
+ std::rotate(itBegin, it, it + 1);
+ m_windowOrderChangedCallback();
+}
+
+void QWasmWindowStack::windowPositionPreferenceChanged(QWasmWindow *window,
+ PositionPreference position)
+{
+ auto it = std::find(m_windowStack.begin(), m_windowStack.end(), window);
+ const auto currentPosition = getWindowPositionPreference(it);
+
+ const auto zones = static_cast<int>(position) - static_cast<int>(currentPosition);
+ Q_ASSERT(zones != 0);
+
+ if (zones < 0) {
+ // Perform right rotation so that the window lands on top of regular windows
+ const auto begin = std::make_reverse_iterator(it + 1);
+ const auto end = position == PositionPreference::Regular
+ ? std::make_reverse_iterator(m_alwaysOnTopWindowsBegin)
+ : std::make_reverse_iterator(m_regularWindowsBegin);
+ std::rotate(begin, begin + 1, end);
+ if (zones == -2) {
+ ++m_alwaysOnTopWindowsBegin;
+ ++m_regularWindowsBegin;
+ } else if (position == PositionPreference::Regular) {
+ ++m_alwaysOnTopWindowsBegin;
+ } else {
+ ++m_regularWindowsBegin;
+ }
+ } else {
+ // Perform left rotation so that the window lands at the bottom of always on top windows
+ const auto begin = it;
+ const auto end = position == PositionPreference::Regular ? m_regularWindowsBegin
+ : m_alwaysOnTopWindowsBegin;
+ std::rotate(begin, begin + 1, end);
+ if (zones == 2) {
+ --m_alwaysOnTopWindowsBegin;
+ --m_regularWindowsBegin;
+ } else if (position == PositionPreference::Regular) {
+ --m_regularWindowsBegin;
+ } else {
+ --m_alwaysOnTopWindowsBegin;
+ }
+ }
+ m_windowOrderChangedCallback();
+}
+
+QWasmWindowStack::iterator QWasmWindowStack::begin()
+{
+ return m_windowStack.rbegin();
+}
+
+QWasmWindowStack::iterator QWasmWindowStack::end()
+{
+ return m_windowStack.rend();
+}
+
+QWasmWindowStack::const_iterator QWasmWindowStack::begin() const
+{
+ return m_windowStack.rbegin();
+}
+
+QWasmWindowStack::const_iterator QWasmWindowStack::end() const
+{
+ return m_windowStack.rend();
+}
+
+QWasmWindowStack::const_reverse_iterator QWasmWindowStack::rbegin() const
+{
+ return m_windowStack.begin();
+}
+
+QWasmWindowStack::const_reverse_iterator QWasmWindowStack::rend() const
+{
+ return m_windowStack.end();
+}
+
+bool QWasmWindowStack::empty() const
+{
+ return m_windowStack.empty();
+}
+
+size_t QWasmWindowStack::size() const
+{
+ return m_windowStack.size();
+}
+
+QWasmWindow *QWasmWindowStack::topWindow() const
+{
+ return m_windowStack.empty() ? nullptr : m_windowStack.last();
+}
+
+QWasmWindowStack::PositionPreference
+QWasmWindowStack::getWindowPositionPreference(StorageType::iterator windowIt) const
+{
+ if (windowIt >= m_alwaysOnTopWindowsBegin)
+ return PositionPreference::StayOnTop;
+ if (windowIt >= m_regularWindowsBegin)
+ return PositionPreference::Regular;
+ return PositionPreference::StayOnBottom;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/wasm/qwasmwindowstack.h b/src/plugins/platforms/wasm/qwasmwindowstack.h
new file mode 100644
index 0000000000..c75001157a
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmwindowstack.h
@@ -0,0 +1,75 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef QWASMWINDOWSTACK_H
+#define QWASMWINDOWSTACK_H
+
+#include <qglobal.h>
+#include <QtCore/qlist.h>
+
+#include <vector>
+
+QT_BEGIN_NAMESPACE
+
+class QWasmWindow;
+
+// Maintains a z-order hierarchy for a set of windows. The first added window is always treated as
+// the 'root', which always stays at the bottom. Other windows are 'regular', which means they are
+// subject to z-order changes via |raise| and |lower|/
+// If the root is ever removed, all of the current and future windows in the stack are treated as
+// regular.
+// Access to the top element is facilitated by |topWindow|.
+// Changes to the top element are signaled via the |topWindowChangedCallback| supplied at
+// construction.
+class Q_AUTOTEST_EXPORT QWasmWindowStack
+{
+public:
+ using WindowOrderChangedCallbackType = std::function<void()>;
+
+ using StorageType = QList<QWasmWindow *>;
+
+ using iterator = StorageType::reverse_iterator;
+ using const_iterator = StorageType::const_reverse_iterator;
+ using const_reverse_iterator = StorageType::const_iterator;
+
+ enum class PositionPreference {
+ StayOnBottom,
+ Regular,
+ StayOnTop,
+ };
+
+ explicit QWasmWindowStack(WindowOrderChangedCallbackType topWindowChangedCallback);
+ ~QWasmWindowStack();
+
+ void pushWindow(QWasmWindow *window, PositionPreference position);
+ void removeWindow(QWasmWindow *window);
+ void raise(QWasmWindow *window);
+ void lower(QWasmWindow *window);
+ void windowPositionPreferenceChanged(QWasmWindow *window, PositionPreference position);
+
+ // Iterates top-to-bottom
+ iterator begin();
+ iterator end();
+ const_iterator begin() const;
+ const_iterator end() const;
+
+ // Iterates bottom-to-top
+ const_reverse_iterator rbegin() const;
+ const_reverse_iterator rend() const;
+
+ bool empty() const;
+ size_t size() const;
+ QWasmWindow *topWindow() const;
+
+private:
+ PositionPreference getWindowPositionPreference(StorageType::iterator windowIt) const;
+
+ WindowOrderChangedCallbackType m_windowOrderChangedCallback;
+ QList<QWasmWindow *> m_windowStack;
+ StorageType::iterator m_regularWindowsBegin;
+ StorageType::iterator m_alwaysOnTopWindowsBegin;
+};
+
+QT_END_NAMESPACE
+
+#endif // QWASMWINDOWSTACK_H
diff --git a/src/plugins/platforms/wasm/qwasmwindowtreenode.cpp b/src/plugins/platforms/wasm/qwasmwindowtreenode.cpp
new file mode 100644
index 0000000000..ea8d8dbcfa
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmwindowtreenode.cpp
@@ -0,0 +1,108 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "qwasmwindowtreenode.h"
+
+#include "qwasmwindow.h"
+
+QWasmWindowTreeNode::QWasmWindowTreeNode()
+ : m_childStack(std::bind(&QWasmWindowTreeNode::onTopWindowChanged, this))
+{
+}
+
+QWasmWindowTreeNode::~QWasmWindowTreeNode() = default;
+
+void QWasmWindowTreeNode::onParentChanged(QWasmWindowTreeNode *previousParent,
+ QWasmWindowTreeNode *currentParent,
+ QWasmWindowStack::PositionPreference positionPreference)
+{
+ auto *window = asWasmWindow();
+ if (previousParent) {
+ previousParent->m_childStack.removeWindow(window);
+ previousParent->onSubtreeChanged(QWasmWindowTreeNodeChangeType::NodeRemoval, previousParent,
+ window);
+ }
+
+ if (currentParent) {
+ currentParent->m_childStack.pushWindow(window, positionPreference);
+ currentParent->onSubtreeChanged(QWasmWindowTreeNodeChangeType::NodeInsertion, currentParent,
+ window);
+ }
+}
+
+QWasmWindow *QWasmWindowTreeNode::asWasmWindow()
+{
+ return nullptr;
+}
+
+void QWasmWindowTreeNode::onSubtreeChanged(QWasmWindowTreeNodeChangeType changeType,
+ QWasmWindowTreeNode *parent, QWasmWindow *child)
+{
+ if (changeType == QWasmWindowTreeNodeChangeType::NodeInsertion && parent == this
+ && m_childStack.topWindow()
+ && m_childStack.topWindow()->window()) {
+
+ const QVariant showWithoutActivating = m_childStack.topWindow()->window()->property("_q_showWithoutActivating");
+ if (!showWithoutActivating.isValid() || !showWithoutActivating.toBool())
+ m_childStack.topWindow()->requestActivateWindow();
+ }
+
+ if (parentNode())
+ parentNode()->onSubtreeChanged(changeType, parent, child);
+}
+
+void QWasmWindowTreeNode::setWindowZOrder(QWasmWindow *window, int z)
+{
+ window->setZOrder(z);
+}
+
+void QWasmWindowTreeNode::onPositionPreferenceChanged(
+ QWasmWindowStack::PositionPreference positionPreference)
+{
+ if (parentNode()) {
+ parentNode()->m_childStack.windowPositionPreferenceChanged(asWasmWindow(),
+ positionPreference);
+ }
+}
+
+void QWasmWindowTreeNode::setAsActiveNode()
+{
+ if (parentNode())
+ parentNode()->setActiveChildNode(asWasmWindow());
+}
+
+void QWasmWindowTreeNode::bringToTop()
+{
+ if (!parentNode())
+ return;
+ parentNode()->m_childStack.raise(asWasmWindow());
+ parentNode()->bringToTop();
+}
+
+void QWasmWindowTreeNode::sendToBottom()
+{
+ if (!parentNode())
+ return;
+ m_childStack.lower(asWasmWindow());
+}
+
+void QWasmWindowTreeNode::onTopWindowChanged()
+{
+ constexpr int zOrderForElementInFrontOfScreen = 3;
+ int z = zOrderForElementInFrontOfScreen;
+ std::for_each(m_childStack.rbegin(), m_childStack.rend(),
+ [this, &z](QWasmWindow *window) { setWindowZOrder(window, z++); });
+}
+
+void QWasmWindowTreeNode::setActiveChildNode(QWasmWindow *activeChild)
+{
+ m_activeChild = activeChild;
+
+ auto it = m_childStack.begin();
+ if (it == m_childStack.end())
+ return;
+ for (; it != m_childStack.end(); ++it)
+ (*it)->onActivationChanged(*it == m_activeChild);
+
+ setAsActiveNode();
+}
diff --git a/src/plugins/platforms/wasm/qwasmwindowtreenode.h b/src/plugins/platforms/wasm/qwasmwindowtreenode.h
new file mode 100644
index 0000000000..344fdb43cb
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmwindowtreenode.h
@@ -0,0 +1,53 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef QWASMWINDOWTREENODE_H
+#define QWASMWINDOWTREENODE_H
+
+#include "qwasmwindowstack.h"
+
+namespace emscripten {
+class val;
+}
+
+class QWasmWindow;
+
+enum class QWasmWindowTreeNodeChangeType {
+ NodeInsertion,
+ NodeRemoval,
+};
+
+class QWasmWindowTreeNode
+{
+public:
+ QWasmWindowTreeNode();
+ virtual ~QWasmWindowTreeNode();
+
+ virtual emscripten::val containerElement() = 0;
+ virtual QWasmWindowTreeNode *parentNode() = 0;
+
+protected:
+ virtual void onParentChanged(QWasmWindowTreeNode *previous, QWasmWindowTreeNode *current,
+ QWasmWindowStack::PositionPreference positionPreference);
+ virtual QWasmWindow *asWasmWindow();
+ virtual void onSubtreeChanged(QWasmWindowTreeNodeChangeType changeType,
+ QWasmWindowTreeNode *parent, QWasmWindow *child);
+ virtual void setWindowZOrder(QWasmWindow *window, int z);
+
+ void onPositionPreferenceChanged(QWasmWindowStack::PositionPreference positionPreference);
+ void setAsActiveNode();
+ void bringToTop();
+ void sendToBottom();
+
+ const QWasmWindowStack &childStack() const { return m_childStack; }
+ QWasmWindow *activeChild() const { return m_activeChild; }
+
+private:
+ void onTopWindowChanged();
+ void setActiveChildNode(QWasmWindow *activeChild);
+
+ QWasmWindowStack m_childStack;
+ QWasmWindow *m_activeChild = nullptr;
+};
+
+#endif // QWASMWINDOWTREENODE_H
diff --git a/src/plugins/platforms/wasm/resources/maximize.svg b/src/plugins/platforms/wasm/resources/maximize.svg
new file mode 100644
index 0000000000..b5fad4f707
--- /dev/null
+++ b/src/plugins/platforms/wasm/resources/maximize.svg
@@ -0,0 +1 @@
+<svg width="1024" height="1024" xmlns="http://www.w3.org/2000/svg" class="svg-icon"><path stroke="null" d="M-.333-.333h1024.666v1024.666H-.333V-.333M127.75 255.833V896.25h768.5V255.833h-768.5z"/></svg> \ No newline at end of file
diff --git a/src/plugins/platforms/wasm/resources/qtlogo.svg b/src/plugins/platforms/wasm/resources/qtlogo.svg
new file mode 100644
index 0000000000..bfe2493f46
--- /dev/null
+++ b/src/plugins/platforms/wasm/resources/qtlogo.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="616" height="452" viewBox="0 0 462 339"><path fill="#41cd52" d="M63.5 0H462v274.79c-21.4 21.47-42.87 42.87-64.39 64.21H0V63.39C21.08 42.18 42.34 21.13 63.5 0Z"/><path d="M122.37 71.33C137.5 61.32 156.21 58.79 174 58.95c16.94.21 34.72 3.18 48.76 13.29 10.2 7.17 16.83 18.24 21.25 29.69 7.15 18.8 9.25 39.1 9.49 59.08.03 20.12-.88 40.68-7.54 59.85-4.46 13.04-12.95 24.62-24.15 32.66 8.06 13.06 16.28 26.02 24.34 39.08-10.13 4.67-20.23 9.37-30.37 14.02-8.63-14.24-17.22-28.51-25.88-42.73-11.71 1.92-23.69 1.77-35.46.47-14.1-1.69-28.47-5.99-39.35-15.48-8.36-7.24-13.61-17.37-17.2-27.67-5.88-17.42-7.46-35.96-7.73-54.24-.14-19.76 1.12-39.83 7.08-58.79 4.61-14.26 12.24-28.49 25.13-36.85ZM294.13 70.69c10.6-.01 21.2-.01 31.8 0 .03 14.02-.01 28.03.02 42.05 13.55.02 27.1 0 40.65.01-.23 9.1-.48 18.2-.74 27.3-13.54.03-27.07-.01-40.61.02.03 22.98-.07 45.96.05 68.94.26 6.29.12 12.93 2.89 18.74 2.02 4.48 7.46 5.63 11.89 5.78 8.35-.03 16.69-.52 25.04-.67.51 8.36 1 16.73 1.48 25.09-16.61 2.79-34.04 6.13-50.54.91-6.95-2.06-13.43-6.67-16.25-13.54-5.05-11.69-5.46-24.7-5.68-37.25-.02-22.67 0-45.33-.01-68-7.39-.02-14.78.01-22.17-.02-.02-9.09-.02-18.19 0-27.29 7.39-.03 14.77.01 22.16-.02.03-14.02-.01-28.03.02-42.05Z" fill="#fff"/><path fill="#41cd52" d="M160.51 87.7c10.29-1.34 21.09-.98 30.83 2.91 7.89 3.12 14.59 9.23 18.13 16.97 5.43 11.73 7.51 24.68 8.56 37.47 1.14 17.02.98 34.2-1.37 51.12-1.65 10.07-4 20.68-10.82 28.62-6.92 7.97-17.59 11.39-27.83 12.19-10.8.79-22.19 0-31.94-5.11-5.69-3.03-10.52-7.78-13.34-13.6-3.42-6.97-5.3-14.58-6.62-22.2-3.98-24.16-4.94-49.16.5-73.18 2.24-9.06 5.5-18.36 12.12-25.19 5.76-5.85 13.78-8.87 21.78-10Z"/></svg> \ No newline at end of file
diff --git a/src/plugins/platforms/wasm/resources/restore.svg b/src/plugins/platforms/wasm/resources/restore.svg
new file mode 100644
index 0000000000..70ee19170b
--- /dev/null
+++ b/src/plugins/platforms/wasm/resources/restore.svg
@@ -0,0 +1 @@
+<svg width="1024" height="1024" xmlns="http://www.w3.org/2000/svg" class="svg-icon"><path stroke="null" d="M449.191 44.905h535.142v528.951H449.191V44.906m66.893 132.237v330.594H917.44V177.143H516.084z"/><path stroke="null" d="M54.906 453.476h535.141v528.952H54.906V453.476m66.892 132.238V916.31h401.357V585.714H121.798z"/></svg> \ No newline at end of file
diff --git a/src/plugins/platforms/wasm/resources/x.svg b/src/plugins/platforms/wasm/resources/x.svg
new file mode 100644
index 0000000000..1d9ba7361a
--- /dev/null
+++ b/src/plugins/platforms/wasm/resources/x.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 460.775 460.775" style="enable-background:new 0 0 460.775 460.775" xml:space="preserve"><path d="M285.08 230.397 456.218 59.27c6.076-6.077 6.076-15.911 0-21.986L423.511 4.565a15.55 15.55 0 0 0-21.985 0l-171.138 171.14L59.25 4.565a15.551 15.551 0 0 0-21.985 0L4.558 37.284c-6.077 6.075-6.077 15.909 0 21.986l171.138 171.128L4.575 401.505c-6.074 6.077-6.074 15.911 0 21.986l32.709 32.719a15.555 15.555 0 0 0 21.986 0l171.117-171.12 171.118 171.12a15.551 15.551 0 0 0 21.985 0l32.709-32.719c6.074-6.075 6.074-15.909 0-21.986L285.08 230.397z"/></svg> \ No newline at end of file
diff --git a/src/plugins/platforms/wasm/wasm.pro b/src/plugins/platforms/wasm/wasm.pro
deleted file mode 100644
index 1aee4a3e58..0000000000
--- a/src/plugins/platforms/wasm/wasm.pro
+++ /dev/null
@@ -1,79 +0,0 @@
-TARGET = qwasm
-CONFIG += static plugin
-QT += \
- core-private gui-private \
- eventdispatcher_support-private fontdatabase_support-private egl_support-private
-
-qtHaveModule(platformcompositor_support-private): QT += platformcompositor_support-private
-
-# Avoid X11 header collision, use generic EGL native types
-DEFINES += QT_EGL_NO_X11
-
-DEFINES += QT_NO_FOREACH
-
-SOURCES = \
- main.cpp \
- qwasmintegration.cpp \
- qwasmwindow.cpp \
- qwasmscreen.cpp \
- qwasmfontdatabase.cpp \
- qwasmeventtranslator.cpp \
- qwasmeventdispatcher.cpp \
- qwasmcompositor.cpp \
- qwasmcursor.cpp \
- qwasmopenglcontext.cpp \
- qwasmtheme.cpp \
- qwasmclipboard.cpp \
- qwasmservices.cpp \
- qwasmoffscreensurface.cpp \
- qwasmstring.cpp
-
-HEADERS = \
- qwasmintegration.h \
- qwasmwindow.h \
- qwasmscreen.h \
- qwasmfontdatabase.h \
- qwasmeventtranslator.h \
- qwasmeventdispatcher.h \
- qwasmcompositor.h \
- qwasmstylepixmaps_p.h \
- qwasmcursor.h \
- qwasmopenglcontext.h \
- qwasmtheme.h \
- qwasmclipboard.h \
- qwasmservices.h \
- qwasmoffscreensurface.h \
- qwasmstring.h
-
-wasmfonts.files = \
- ../../../3rdparty/wasm/Vera.ttf \
- ../../../3rdparty/wasm/DejaVuSans.ttf \
- ../../../3rdparty/wasm/DejaVuSansMono.ttf
-wasmfonts.prefix = /fonts
-wasmfonts.base = ../../../3rdparty/wasm
-RESOURCES += wasmfonts
-
-qtConfig(opengl) {
- QT += opengl
- SOURCES += qwasmbackingstore.cpp
- HEADERS += qwasmbackingstore.h
-}
-CONFIG += egl
-
-OTHER_FILES += \
- wasm.json \
- wasm_shell.html \
- qtloader.js
-
-shell_files.path = $$[QT_INSTALL_PLUGINS]/platforms
-shell_files.files = \
- wasm_shell.html \
- qtloader.js \
- qtlogo.svg
-
-INSTALLS += shell_files
-
-PLUGIN_TYPE = platforms
-PLUGIN_CLASS_NAME = QWasmIntegrationPlugin
-!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = -
-load(qt_plugin)
diff --git a/src/plugins/platforms/wasm/wasm_shell.html b/src/plugins/platforms/wasm/wasm_shell.html
index d4bf632830..702ea1f59d 100644
--- a/src/plugins/platforms/wasm/wasm_shell.html
+++ b/src/plugins/platforms/wasm/wasm_shell.html
@@ -3,15 +3,17 @@
<head>
<meta charset="utf-8">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+
+ <!--Set visual viewport size for mobile devices to the device size,
+ witch results in a scale of 1 and a 1:1 mapping between CSS pixels
+ and Qt device independent pixels. -->
+ <meta name="viewport" content="width=device-width, height=device-height, user-scalable=0"/>
+
<title>@APPNAME@</title>
<style>
- html, body { padding: 0; margin : 0; overflow:hidden; height: 100% }
- /* the canvas *must not* have any border or padding, or mouse coords will be wrong */
- canvas { border: 0px none; background-color: white; height:100%; width:100%; }
- /* The contenteditable property is set to true for the canvas in order to support
- clipboard events. Hide the resulting focus frame and set the cursor back to
- the default cursor. */
- canvas { outline: 0px solid transparent; caret-color: transparent; cursor:default }
+ /* Make the html body cover the entire (visual) viewport with no scroll bars. */
+ html, body { padding: 0; margin: 0; overflow: hidden; height: 100% }
+ #screen { width: 100%; height: 100%; }
</style>
</head>
<body onload="init()">
@@ -23,43 +25,50 @@
<noscript>JavaScript is disabled. Please enable JavaScript to use this application.</noscript>
</center>
</figure>
- <canvas id="qtcanvas" oncontextmenu="event.preventDefault()" contenteditable="true"></canvas>
+ <div id="screen"></div>
+
+ <script type="text/javascript">
+ async function init()
+ {
+ const spinner = document.querySelector('#qtspinner');
+ const screen = document.querySelector('#screen');
+ const status = document.querySelector('#qtstatus');
+
+ const showUi = (ui) => {
+ [spinner, screen].forEach(element => element.style.display = 'none');
+ if (screen === ui)
+ screen.style.position = 'default';
+ ui.style.display = 'block';
+ }
- <script type='text/javascript'>
- function init() {
- var spinner = document.querySelector('#qtspinner');
- var canvas = document.querySelector('#qtcanvas');
- var status = document.querySelector('#qtstatus')
+ try {
+ showUi(spinner);
+ status.innerHTML = 'Loading...';
- var qtLoader = QtLoader({
- canvasElements : [canvas],
- showLoader: function(loaderStatus) {
- spinner.style.display = 'block';
- canvas.style.display = 'none';
- status.innerHTML = loaderStatus + "...";
- },
- showError: function(errorText) {
- status.innerHTML = errorText;
- spinner.style.display = 'block';
- canvas.style.display = 'none';
- },
- showExit: function() {
- status.innerHTML = "Application exit";
- if (qtLoader.exitCode !== undefined)
- status.innerHTML += " with code " + qtLoader.exitCode;
- if (qtLoader.exitText !== undefined)
- status.innerHTML += " (" + qtLoader.exitText + ")";
- spinner.style.display = 'block';
- canvas.style.display = 'none';
- },
- showCanvas: function() {
- spinner.style.display = 'none';
- canvas.style.display = 'block';
- },
- });
- qtLoader.loadEmscriptenModule("@APPNAME@");
- }
+ const instance = await qtLoad({
+ qt: {
+ onLoaded: () => showUi(screen),
+ onExit: exitData =>
+ {
+ status.innerHTML = 'Application exit';
+ status.innerHTML +=
+ exitData.code !== undefined ? ` with code ${exitData.code}` : '';
+ status.innerHTML +=
+ exitData.text !== undefined ? ` (${exitData.text})` : '';
+ showUi(spinner);
+ },
+ entryFunction: window.@APPEXPORTNAME@,
+ containerElements: [screen],
+ @PRELOAD@
+ }
+ });
+ } catch (e) {
+ console.error(e);
+ console.error(e.stack);
+ }
+ }
</script>
+ <script src="@APPNAME@.js"></script>
<script type="text/javascript" src="qtloader.js"></script>
</body>
</html>
diff --git a/src/plugins/platforms/windows/.prev_CMakeLists.txt b/src/plugins/platforms/windows/.prev_CMakeLists.txt
deleted file mode 100644
index 299dda24af..0000000000
--- a/src/plugins/platforms/windows/.prev_CMakeLists.txt
+++ /dev/null
@@ -1,245 +0,0 @@
-# Generated from windows.pro.
-
-#####################################################################
-## QWindowsIntegrationPlugin Plugin:
-#####################################################################
-
-qt_add_plugin(QWindowsIntegrationPlugin
- OUTPUT_NAME qwindows
- TYPE platforms
- SOURCES
- main.cpp
- qtwindowsglobal.h
- qwin10helpers.cpp qwin10helpers.h
- qwindowsbackingstore.cpp qwindowsbackingstore.h
- qwindowscombase.h
- qwindowscontext.cpp qwindowscontext.h
- qwindowscursor.cpp qwindowscursor.h
- qwindowsdialoghelpers.cpp qwindowsdialoghelpers.h
- qwindowsdropdataobject.cpp qwindowsdropdataobject.h
- qwindowsgdiintegration.cpp qwindowsgdiintegration.h
- qwindowsgdinativeinterface.cpp qwindowsgdinativeinterface.h
- qwindowsinputcontext.cpp qwindowsinputcontext.h
- qwindowsintegration.cpp qwindowsintegration.h
- qwindowsinternalmimedata.cpp qwindowsinternalmimedata.h
- qwindowskeymapper.cpp qwindowskeymapper.h
- qwindowsmenu.cpp qwindowsmenu.h
- qwindowsmime.cpp qwindowsmime.h
- qwindowsmousehandler.cpp qwindowsmousehandler.h
- qwindowsnativeinterface.cpp qwindowsnativeinterface.h
- qwindowsole.cpp qwindowsole.h
- qwindowsopengltester.cpp qwindowsopengltester.h
- qwindowspointerhandler.cpp qwindowspointerhandler.h
- qwindowsscreen.cpp qwindowsscreen.h
- qwindowsservices.cpp qwindowsservices.h
- qwindowstheme.cpp qwindowstheme.h
- qwindowsthreadpoolrunner.h
- qwindowswindow.cpp qwindowswindow.h
- DEFINES
- QT_NO_CAST_FROM_ASCII
- QT_NO_FOREACH
- INCLUDE_DIRECTORIES
- ${CMAKE_CURRENT_SOURCE_DIR}
- LIBRARIES
- advapi32
- d3d9
- gdi32
- ole32
- shell32
- user32
- winmm
- PUBLIC_LIBRARIES
- Qt::Core
- Qt::CorePrivate
- Qt::EventDispatcherSupportPrivate
- Qt::FontDatabaseSupportPrivate
- Qt::Gui
- Qt::GuiPrivate
- Qt::ThemeSupportPrivate
- dwmapi
- imm32
- oleaut32
- shlwapi
- winspool
- wtsapi32
-)
-
-# Resources:
-set_source_files_properties("openglblacklists/default.json"
- PROPERTIES QT_RESOURCE_ALIAS "default.json"
-)
-set(openglblacklists_resource_files
- "openglblacklists/default.json"
-)
-
-qt_add_resource(QWindowsIntegrationPlugin "openglblacklists"
- PREFIX
- "/qt-project.org/windows/openglblacklists"
- FILES
- ${openglblacklists_resource_files}
-)
-
-
-#### Keys ignored in scope 1:.:.:windows.pro:<TRUE>:
-# OTHER_FILES = "windows.json"
-
-## Scopes:
-#####################################################################
-
-qt_extend_target(QWindowsIntegrationPlugin CONDITION TARGET Qt::PlatformCompositorSupportPrivate
- PUBLIC_LIBRARIES
- Qt::PlatformCompositorSupportPrivate
-)
-
-qt_extend_target(QWindowsIntegrationPlugin CONDITION QT_FEATURE_accessibility
- SOURCES
- uiautomation/qwindowsuiaaccessibility.cpp uiautomation/qwindowsuiaaccessibility.h
- uiautomation/qwindowsuiabaseprovider.cpp uiautomation/qwindowsuiabaseprovider.h
- uiautomation/qwindowsuiagriditemprovider.cpp uiautomation/qwindowsuiagriditemprovider.h
- uiautomation/qwindowsuiagridprovider.cpp uiautomation/qwindowsuiagridprovider.h
- uiautomation/qwindowsuiainvokeprovider.cpp uiautomation/qwindowsuiainvokeprovider.h
- uiautomation/qwindowsuiamainprovider.cpp uiautomation/qwindowsuiamainprovider.h
- uiautomation/qwindowsuiaprovidercache.cpp uiautomation/qwindowsuiaprovidercache.h
- uiautomation/qwindowsuiarangevalueprovider.cpp uiautomation/qwindowsuiarangevalueprovider.h
- uiautomation/qwindowsuiaselectionitemprovider.cpp uiautomation/qwindowsuiaselectionitemprovider.h
- uiautomation/qwindowsuiaselectionprovider.cpp uiautomation/qwindowsuiaselectionprovider.h
- uiautomation/qwindowsuiatableitemprovider.cpp uiautomation/qwindowsuiatableitemprovider.h
- uiautomation/qwindowsuiatableprovider.cpp uiautomation/qwindowsuiatableprovider.h
- uiautomation/qwindowsuiatextprovider.cpp uiautomation/qwindowsuiatextprovider.h
- uiautomation/qwindowsuiatextrangeprovider.cpp uiautomation/qwindowsuiatextrangeprovider.h
- uiautomation/qwindowsuiatoggleprovider.cpp uiautomation/qwindowsuiatoggleprovider.h
- uiautomation/qwindowsuiautils.cpp uiautomation/qwindowsuiautils.h
- uiautomation/qwindowsuiavalueprovider.cpp uiautomation/qwindowsuiavalueprovider.h
- uiautomation/qwindowsuiawindowprovider.cpp uiautomation/qwindowsuiawindowprovider.h
- PUBLIC_LIBRARIES
- Qt::AccessibilitySupportPrivate
-)
-
-qt_extend_target(QWindowsIntegrationPlugin CONDITION QT_FEATURE_vulkan
- SOURCES
- qwindowsvulkaninstance.cpp qwindowsvulkaninstance.h
- PUBLIC_LIBRARIES
- Qt::VulkanSupportPrivate
-)
-
-qt_extend_target(QWindowsIntegrationPlugin CONDITION QT_FEATURE_directwrite3
- DEFINES
- QT_USE_DIRECTWRITE2
- QT_USE_DIRECTWRITE3
-)
-
-#### Keys ignored in scope 6:.:.:windows.pro:NOT TARGET___equals____ss_QT_DEFAULT_QPA_PLUGIN:
-# PLUGIN_EXTENDS = "-"
-
-qt_extend_target(QWindowsIntegrationPlugin CONDITION QT_FEATURE_opengl AND NOT QT_FEATURE_dynamicgl AND NOT QT_FEATURE_opengles2
- PUBLIC_LIBRARIES
- opengl32
-)
-
-qt_extend_target(QWindowsIntegrationPlugin CONDITION mingw
- PUBLIC_LIBRARIES
- uuid
-)
-
-qt_extend_target(QWindowsIntegrationPlugin CONDITION QT_FEATURE_opengl
- SOURCES
- qwindowsopenglcontext.h
-)
-
-qt_extend_target(QWindowsIntegrationPlugin CONDITION QT_FEATURE_opengles2
- SOURCES
- qwindowseglcontext.cpp qwindowseglcontext.h
-)
-
-qt_extend_target(QWindowsIntegrationPlugin CONDITION QT_FEATURE_opengl AND NOT QT_FEATURE_opengles2
- SOURCES
- qwindowsglcontext.cpp qwindowsglcontext.h
-)
-
-qt_extend_target(QWindowsIntegrationPlugin CONDITION QT_FEATURE_dynamicgl
- SOURCES
- qwindowseglcontext.cpp qwindowseglcontext.h
-)
-
-qt_extend_target(QWindowsIntegrationPlugin CONDITION QT_FEATURE_systemtrayicon
- SOURCES
- qwindowssystemtrayicon.cpp qwindowssystemtrayicon.h
-)
-
-qt_extend_target(QWindowsIntegrationPlugin CONDITION QT_FEATURE_clipboard
- SOURCES
- qwindowsclipboard.cpp qwindowsclipboard.h
-)
-
-qt_extend_target(QWindowsIntegrationPlugin CONDITION QT_FEATURE_clipboard AND QT_FEATURE_draganddrop
- SOURCES
- qwindowsdrag.cpp qwindowsdrag.h
-)
-
-qt_extend_target(QWindowsIntegrationPlugin CONDITION QT_FEATURE_tabletevent
- SOURCES
- qwindowstabletsupport.cpp qwindowstabletsupport.h
- INCLUDE_DIRECTORIES
- ${QT_SOURCE_TREE}/src/3rdparty/wintab
-)
-
-qt_extend_target(QWindowsIntegrationPlugin CONDITION QT_FEATURE_sessionmanager
- SOURCES
- qwindowssessionmanager.cpp qwindowssessionmanager.h
-)
-
-if(QT_FEATURE_imageformat_png)
- # Resources:
- set(cursors_resource_files
- "images/closedhandcursor_32.png"
- "images/closedhandcursor_48.png"
- "images/closedhandcursor_64.png"
- "images/dragcopycursor_32.png"
- "images/dragcopycursor_48.png"
- "images/dragcopycursor_64.png"
- "images/draglinkcursor_32.png"
- "images/draglinkcursor_48.png"
- "images/draglinkcursor_64.png"
- "images/dragmovecursor_32.png"
- "images/dragmovecursor_48.png"
- "images/dragmovecursor_64.png"
- "images/openhandcursor_32.png"
- "images/openhandcursor_48.png"
- "images/openhandcursor_64.png"
- "images/splithcursor_32.png"
- "images/splithcursor_48.png"
- "images/splithcursor_64.png"
- "images/splitvcursor_32.png"
- "images/splitvcursor_48.png"
- "images/splitvcursor_64.png"
- )
-
- qt_add_resource(QWindowsIntegrationPlugin "cursors"
- PREFIX
- "/qt-project.org/windows/cursors"
- FILES
- ${cursors_resource_files}
- )
-endif()
-
-qt_extend_target(QWindowsIntegrationPlugin CONDITION QT_FEATURE_accessibility AND TARGET Qt::WindowsUIAutomationSupportPrivate
- PUBLIC_LIBRARIES
- Qt::WindowsUIAutomationSupportPrivate
-)
-
-qt_extend_target(QWindowsIntegrationPlugin CONDITION QT_FEATURE_accessibility AND mingw
- PUBLIC_LIBRARIES
- uuid
-)
-
-qt_extend_target(QWindowsIntegrationPlugin CONDITION QT_FEATURE_combined_angle_lib
- DEFINES
- LIBEGL_NAME=
- LIBGLESV2_NAME=
-)
-
-qt_extend_target(QWindowsIntegrationPlugin CONDITION NOT QT_FEATURE_combined_angle_lib
- DEFINES
- LIBEGL_NAME=
- LIBGLESV2_NAME=
-)
diff --git a/src/plugins/platforms/windows/CMakeLists.txt b/src/plugins/platforms/windows/CMakeLists.txt
index 81a8c3bfe9..fb73b70c29 100644
--- a/src/plugins/platforms/windows/CMakeLists.txt
+++ b/src/plugins/platforms/windows/CMakeLists.txt
@@ -1,17 +1,19 @@
-# Generated from windows.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## QWindowsIntegrationPlugin Plugin:
#####################################################################
-qt_add_plugin(QWindowsIntegrationPlugin
+qt_internal_add_plugin(QWindowsIntegrationPlugin
OUTPUT_NAME qwindows
- TYPE platforms
- DEFAULT_IF ${QT_QPA_DEFAULT_PLATFORM} MATCHES windows # special case
+ PLUGIN_TYPE platforms
+ DEFAULT_IF ${QT_QPA_DEFAULT_PLATFORM} MATCHES windows
SOURCES
main.cpp
qtwindowsglobal.h
qwin10helpers.cpp qwin10helpers.h
+ qwindowsapplication.cpp qwindowsapplication.h
qwindowsbackingstore.cpp qwindowsbackingstore.h
qwindowscombase.h
qwindowscontext.cpp qwindowscontext.h
@@ -20,12 +22,13 @@ qt_add_plugin(QWindowsIntegrationPlugin
qwindowsdropdataobject.cpp qwindowsdropdataobject.h
qwindowsgdiintegration.cpp qwindowsgdiintegration.h
qwindowsgdinativeinterface.cpp qwindowsgdinativeinterface.h
+ qwindowsiconengine.cpp qwindowsiconengine.h
qwindowsinputcontext.cpp qwindowsinputcontext.h
qwindowsintegration.cpp qwindowsintegration.h
qwindowsinternalmimedata.cpp qwindowsinternalmimedata.h
qwindowskeymapper.cpp qwindowskeymapper.h
qwindowsmenu.cpp qwindowsmenu.h
- qwindowsmime.cpp qwindowsmime.h
+ qwindowsmimeregistry.cpp qwindowsmimeregistry.h
qwindowsmousehandler.cpp qwindowsmousehandler.h
qwindowsnativeinterface.cpp qwindowsnativeinterface.h
qwindowsole.cpp qwindowsole.h
@@ -36,33 +39,35 @@ qt_add_plugin(QWindowsIntegrationPlugin
qwindowstheme.cpp qwindowstheme.h
qwindowsthreadpoolrunner.h
qwindowswindow.cpp qwindowswindow.h
+ NO_UNITY_BUILD_SOURCES
+ qwindowspointerhandler.cpp
DEFINES
QT_NO_CAST_FROM_ASCII
QT_NO_FOREACH
INCLUDE_DIRECTORIES
${CMAKE_CURRENT_SOURCE_DIR}
LIBRARIES
- advapi32
- d3d9
- gdi32
- ole32
- shell32
- user32
- winmm
- PUBLIC_LIBRARIES
Qt::Core
Qt::CorePrivate
- Qt::EventDispatcherSupportPrivate
- Qt::FontDatabaseSupportPrivate
Qt::Gui
Qt::GuiPrivate
- Qt::ThemeSupportPrivate
+ advapi32
dwmapi
+ gdi32
imm32
+ ole32
oleaut32
+ setupapi
+ shell32
shlwapi
+ user32
+ winmm
winspool
wtsapi32
+ shcore
+ comdlg32
+ d3d9
+ runtimeobject
)
# Resources:
@@ -73,118 +78,64 @@ set(openglblacklists_resource_files
"openglblacklists/default.json"
)
-qt_add_resource(QWindowsIntegrationPlugin "openglblacklists"
+qt_internal_add_resource(QWindowsIntegrationPlugin "openglblacklists"
PREFIX
"/qt-project.org/windows/openglblacklists"
FILES
${openglblacklists_resource_files}
)
-
-#### Keys ignored in scope 1:.:.:windows.pro:<TRUE>:
-# OTHER_FILES = "windows.json"
-
## Scopes:
#####################################################################
-qt_extend_target(QWindowsIntegrationPlugin CONDITION TARGET Qt::PlatformCompositorSupportPrivate
- PUBLIC_LIBRARIES
- Qt::PlatformCompositorSupportPrivate
-)
-
-qt_extend_target(QWindowsIntegrationPlugin CONDITION QT_FEATURE_accessibility
- SOURCES
- uiautomation/qwindowsuiaaccessibility.cpp uiautomation/qwindowsuiaaccessibility.h
- uiautomation/qwindowsuiabaseprovider.cpp uiautomation/qwindowsuiabaseprovider.h
- uiautomation/qwindowsuiagriditemprovider.cpp uiautomation/qwindowsuiagriditemprovider.h
- uiautomation/qwindowsuiagridprovider.cpp uiautomation/qwindowsuiagridprovider.h
- uiautomation/qwindowsuiainvokeprovider.cpp uiautomation/qwindowsuiainvokeprovider.h
- uiautomation/qwindowsuiamainprovider.cpp uiautomation/qwindowsuiamainprovider.h
- uiautomation/qwindowsuiaprovidercache.cpp uiautomation/qwindowsuiaprovidercache.h
- uiautomation/qwindowsuiarangevalueprovider.cpp uiautomation/qwindowsuiarangevalueprovider.h
- uiautomation/qwindowsuiaselectionitemprovider.cpp uiautomation/qwindowsuiaselectionitemprovider.h
- uiautomation/qwindowsuiaselectionprovider.cpp uiautomation/qwindowsuiaselectionprovider.h
- uiautomation/qwindowsuiatableitemprovider.cpp uiautomation/qwindowsuiatableitemprovider.h
- uiautomation/qwindowsuiatableprovider.cpp uiautomation/qwindowsuiatableprovider.h
- uiautomation/qwindowsuiatextprovider.cpp uiautomation/qwindowsuiatextprovider.h
- uiautomation/qwindowsuiatextrangeprovider.cpp uiautomation/qwindowsuiatextrangeprovider.h
- uiautomation/qwindowsuiatoggleprovider.cpp uiautomation/qwindowsuiatoggleprovider.h
- uiautomation/qwindowsuiautils.cpp uiautomation/qwindowsuiautils.h
- uiautomation/qwindowsuiavalueprovider.cpp uiautomation/qwindowsuiavalueprovider.h
- uiautomation/qwindowsuiawindowprovider.cpp uiautomation/qwindowsuiawindowprovider.h
- PUBLIC_LIBRARIES
- Qt::AccessibilitySupportPrivate
-)
-
-qt_extend_target(QWindowsIntegrationPlugin CONDITION QT_FEATURE_vulkan
+qt_internal_extend_target(QWindowsIntegrationPlugin CONDITION QT_FEATURE_opengl
SOURCES
- qwindowsvulkaninstance.cpp qwindowsvulkaninstance.h
- PUBLIC_LIBRARIES
- Qt::VulkanSupportPrivate
-)
-
-qt_extend_target(QWindowsIntegrationPlugin CONDITION QT_FEATURE_directwrite3
- DEFINES
- QT_USE_DIRECTWRITE2
- QT_USE_DIRECTWRITE3
+ qwindowsglcontext.cpp qwindowsglcontext.h
+ qwindowsopenglcontext.h
+ LIBRARIES
+ Qt::OpenGLPrivate
)
-#### Keys ignored in scope 6:.:.:windows.pro:NOT TARGET___equals____ss_QT_DEFAULT_QPA_PLUGIN:
-# PLUGIN_EXTENDS = "-"
-
-qt_extend_target(QWindowsIntegrationPlugin CONDITION QT_FEATURE_opengl AND NOT QT_FEATURE_dynamicgl AND NOT QT_FEATURE_opengles2
- PUBLIC_LIBRARIES
+qt_internal_extend_target(QWindowsIntegrationPlugin CONDITION QT_FEATURE_opengl AND NOT QT_FEATURE_dynamicgl
+ LIBRARIES
opengl32
)
-qt_extend_target(QWindowsIntegrationPlugin CONDITION mingw
- PUBLIC_LIBRARIES
+qt_internal_extend_target(QWindowsIntegrationPlugin CONDITION MINGW
+ LIBRARIES
uuid
+ NO_PCH_SOURCES
+ qwindowspointerhandler.cpp
)
-qt_extend_target(QWindowsIntegrationPlugin CONDITION QT_FEATURE_opengl
- SOURCES
- qwindowsopenglcontext.h
-)
-
-qt_extend_target(QWindowsIntegrationPlugin CONDITION QT_FEATURE_opengles2
- SOURCES
- qwindowseglcontext.cpp qwindowseglcontext.h
-)
-
-qt_extend_target(QWindowsIntegrationPlugin CONDITION QT_FEATURE_opengl AND NOT QT_FEATURE_opengles2
- SOURCES
- qwindowsglcontext.cpp qwindowsglcontext.h
-)
-
-qt_extend_target(QWindowsIntegrationPlugin CONDITION QT_FEATURE_dynamicgl
+qt_internal_extend_target(QWindowsIntegrationPlugin CONDITION QT_FEATURE_systemtrayicon
SOURCES
- qwindowseglcontext.cpp qwindowseglcontext.h
+ qwindowssystemtrayicon.cpp qwindowssystemtrayicon.h
)
-qt_extend_target(QWindowsIntegrationPlugin CONDITION QT_FEATURE_systemtrayicon
+qt_internal_extend_target(QWindowsIntegrationPlugin CONDITION QT_FEATURE_vulkan
SOURCES
- qwindowssystemtrayicon.cpp qwindowssystemtrayicon.h
+ qwindowsvulkaninstance.cpp qwindowsvulkaninstance.h
)
-qt_extend_target(QWindowsIntegrationPlugin CONDITION QT_FEATURE_clipboard
+qt_internal_extend_target(QWindowsIntegrationPlugin CONDITION QT_FEATURE_clipboard
SOURCES
qwindowsclipboard.cpp qwindowsclipboard.h
)
-qt_extend_target(QWindowsIntegrationPlugin CONDITION QT_FEATURE_clipboard AND QT_FEATURE_draganddrop
+qt_internal_extend_target(QWindowsIntegrationPlugin CONDITION QT_FEATURE_clipboard AND QT_FEATURE_draganddrop
SOURCES
qwindowsdrag.cpp qwindowsdrag.h
)
-qt_extend_target(QWindowsIntegrationPlugin CONDITION QT_FEATURE_tabletevent
+qt_internal_extend_target(QWindowsIntegrationPlugin CONDITION QT_FEATURE_tabletevent
SOURCES
qwindowstabletsupport.cpp qwindowstabletsupport.h
INCLUDE_DIRECTORIES
- ${QT_SOURCE_TREE}/src/3rdparty/wintab
+ ${QtBase_SOURCE_DIR}/src/3rdparty/wintab
)
-qt_extend_target(QWindowsIntegrationPlugin CONDITION QT_FEATURE_sessionmanager
+qt_internal_extend_target(QWindowsIntegrationPlugin CONDITION QT_FEATURE_sessionmanager
SOURCES
qwindowssessionmanager.cpp qwindowssessionmanager.h
)
@@ -215,7 +166,7 @@ if(QT_FEATURE_imageformat_png)
"images/splitvcursor_64.png"
)
- qt_add_resource(QWindowsIntegrationPlugin "cursors"
+ qt_internal_add_resource(QWindowsIntegrationPlugin "cursors"
PREFIX
"/qt-project.org/windows/cursors"
FILES
@@ -223,17 +174,41 @@ if(QT_FEATURE_imageformat_png)
)
endif()
-qt_extend_target(QWindowsIntegrationPlugin CONDITION QT_FEATURE_accessibility AND TARGET Qt::WindowsUIAutomationSupportPrivate
- PUBLIC_LIBRARIES
- Qt::WindowsUIAutomationSupportPrivate
+qt_internal_extend_target(QWindowsIntegrationPlugin CONDITION QT_FEATURE_accessibility
+ SOURCES
+ uiautomation/qwindowsuiautomation.cpp uiautomation/qwindowsuiautomation.h
+ uiautomation/qwindowsuiaaccessibility.cpp uiautomation/qwindowsuiaaccessibility.h
+ uiautomation/qwindowsuiabaseprovider.cpp uiautomation/qwindowsuiabaseprovider.h
+ uiautomation/qwindowsuiaexpandcollapseprovider.cpp uiautomation/qwindowsuiaexpandcollapseprovider.h
+ uiautomation/qwindowsuiagriditemprovider.cpp uiautomation/qwindowsuiagriditemprovider.h
+ uiautomation/qwindowsuiagridprovider.cpp uiautomation/qwindowsuiagridprovider.h
+ uiautomation/qwindowsuiainvokeprovider.cpp uiautomation/qwindowsuiainvokeprovider.h
+ uiautomation/qwindowsuiamainprovider.cpp uiautomation/qwindowsuiamainprovider.h
+ uiautomation/qwindowsuiaprovidercache.cpp uiautomation/qwindowsuiaprovidercache.h
+ uiautomation/qwindowsuiarangevalueprovider.cpp uiautomation/qwindowsuiarangevalueprovider.h
+ uiautomation/qwindowsuiaselectionitemprovider.cpp uiautomation/qwindowsuiaselectionitemprovider.h
+ uiautomation/qwindowsuiaselectionprovider.cpp uiautomation/qwindowsuiaselectionprovider.h
+ uiautomation/qwindowsuiatableitemprovider.cpp uiautomation/qwindowsuiatableitemprovider.h
+ uiautomation/qwindowsuiatableprovider.cpp uiautomation/qwindowsuiatableprovider.h
+ uiautomation/qwindowsuiatextprovider.cpp uiautomation/qwindowsuiatextprovider.h
+ uiautomation/qwindowsuiatextrangeprovider.cpp uiautomation/qwindowsuiatextrangeprovider.h
+ uiautomation/qwindowsuiatoggleprovider.cpp uiautomation/qwindowsuiatoggleprovider.h
+ uiautomation/qwindowsuiautils.cpp uiautomation/qwindowsuiautils.h
+ uiautomation/qwindowsuiavalueprovider.cpp uiautomation/qwindowsuiavalueprovider.h
+ uiautomation/qwindowsuiawindowprovider.cpp uiautomation/qwindowsuiawindowprovider.h
)
-qt_extend_target(QWindowsIntegrationPlugin CONDITION QT_FEATURE_accessibility AND mingw
- PUBLIC_LIBRARIES
+if(QT_FEATURE_accessibility)
+ find_library(UI_AUTOMATION_LIBRARY uiautomationcore)
+ if(UI_AUTOMATION_LIBRARY)
+ qt_internal_extend_target(QWindowsIntegrationPlugin
+ LIBRARIES
+ ${UI_AUTOMATION_LIBRARY}
+ )
+ endif()
+endif()
+
+qt_internal_extend_target(QWindowsIntegrationPlugin CONDITION MINGW AND QT_FEATURE_accessibility
+ LIBRARIES
uuid
)
-
-# special case:
-# qt_extend_target(QWindowsIntegrationPlugin CONDITION QT_FEATURE_combined_angle_lib ...
-# qt_extend_target(QWindowsIntegrationPlugin CONDITION NOT QT_FEATURE_combined_angle_lib ...
-
diff --git a/src/plugins/platforms/windows/cursors.qrc b/src/plugins/platforms/windows/cursors.qrc
deleted file mode 100644
index fded527aac..0000000000
--- a/src/plugins/platforms/windows/cursors.qrc
+++ /dev/null
@@ -1,25 +0,0 @@
-<RCC>
- <qresource prefix="/qt-project.org/windows/cursors">
- <file>images/closedhandcursor_32.png</file>
- <file>images/closedhandcursor_48.png</file>
- <file>images/closedhandcursor_64.png</file>
- <file>images/dragcopycursor_32.png</file>
- <file>images/dragcopycursor_48.png</file>
- <file>images/dragcopycursor_64.png</file>
- <file>images/draglinkcursor_32.png</file>
- <file>images/draglinkcursor_48.png</file>
- <file>images/draglinkcursor_64.png</file>
- <file>images/dragmovecursor_32.png</file>
- <file>images/dragmovecursor_48.png</file>
- <file>images/dragmovecursor_64.png</file>
- <file>images/openhandcursor_32.png</file>
- <file>images/openhandcursor_48.png</file>
- <file>images/openhandcursor_64.png</file>
- <file>images/splithcursor_32.png</file>
- <file>images/splithcursor_48.png</file>
- <file>images/splithcursor_64.png</file>
- <file>images/splitvcursor_32.png</file>
- <file>images/splitvcursor_48.png</file>
- <file>images/splitvcursor_64.png</file>
- </qresource>
-</RCC>
diff --git a/src/plugins/platforms/windows/main.cpp b/src/plugins/platforms/windows/main.cpp
index 1929f800a4..51c1fb4a45 100644
--- a/src/plugins/platforms/windows/main.cpp
+++ b/src/plugins/platforms/windows/main.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <qpa/qplatformintegrationplugin.h>
@@ -45,11 +9,12 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
/*!
- \group qt-lighthouse-win
- \title Qt Lighthouse plugin for Windows
+ \title Qt platform plugin for Windows
- \brief Class documentation of the Qt Lighthouse plugin for Windows.
+ \brief Class documentation of the Qt platform plugin for Windows.
\section1 Supported Parameters
@@ -78,7 +43,6 @@ QT_BEGIN_NAMESPACE
\class QWindowsIntegrationPlugin
\brief Plugin.
\internal
- \ingroup qt-lighthouse-win
*/
/*!
@@ -86,7 +50,6 @@ QT_BEGIN_NAMESPACE
\brief Namespace for enumerations, etc.
\internal
- \ingroup qt-lighthouse-win
*/
/*!
@@ -97,7 +60,6 @@ QT_BEGIN_NAMESPACE
With flags that should help to structure the code.
\internal
- \ingroup qt-lighthouse-win
*/
class QWindowsIntegrationPlugin : public QPlatformIntegrationPlugin
@@ -105,12 +67,12 @@ class QWindowsIntegrationPlugin : public QPlatformIntegrationPlugin
Q_OBJECT
Q_PLUGIN_METADATA(IID QPlatformIntegrationFactoryInterface_iid FILE "windows.json")
public:
- QPlatformIntegration *create(const QString&, const QStringList&, int &, char **);
+ QPlatformIntegration *create(const QString &, const QStringList &, int &, char **) override;
};
QPlatformIntegration *QWindowsIntegrationPlugin::create(const QString& system, const QStringList& paramList, int &, char **)
{
- if (system.compare(system, QLatin1String("windows"), Qt::CaseInsensitive) == 0)
+ if (system.compare(system, "windows"_L1, Qt::CaseInsensitive) == 0)
return new QWindowsGdiIntegration(paramList);
return nullptr;
}
diff --git a/src/plugins/platforms/windows/openglblacklists.qrc b/src/plugins/platforms/windows/openglblacklists.qrc
deleted file mode 100644
index 9f0c186c21..0000000000
--- a/src/plugins/platforms/windows/openglblacklists.qrc
+++ /dev/null
@@ -1,5 +0,0 @@
-<RCC>
- <qresource prefix="/qt-project.org/windows/openglblacklists">
- <file alias="default.json">openglblacklists/default.json</file>
- </qresource>
-</RCC>
diff --git a/src/plugins/platforms/windows/openglblacklists/default.json b/src/plugins/platforms/windows/openglblacklists/default.json
index e37351f9e0..072acdd115 100644
--- a/src/plugins/platforms/windows/openglblacklists/default.json
+++ b/src/plugins/platforms/windows/openglblacklists/default.json
@@ -93,7 +93,7 @@
},
{
"id": 8,
- "description": "Standard VGA: Insufficent support for OpenGL, D3D9 and D3D11",
+ "description": "Standard VGA: Insufficient support for OpenGL, D3D9 and D3D11",
"vendor_id": "0x0000",
"device_id": ["0x0000"],
"os": {
diff --git a/src/plugins/platforms/windows/qtwindowsglobal.h b/src/plugins/platforms/windows/qtwindowsglobal.h
index 985f13bdc5..96a72600eb 100644
--- a/src/plugins/platforms/windows/qtwindowsglobal.h
+++ b/src/plugins/platforms/windows/qtwindowsglobal.h
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Samuel Gaist <samuel.gaist@edeltech.ch>
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2013 Samuel Gaist <samuel.gaist@edeltech.ch>
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QTWINDOWSGLOBAL_H
#define QTWINDOWSGLOBAL_H
@@ -44,8 +8,16 @@
#include <QtCore/qt_windows.h>
#include <QtCore/qnamespace.h>
-#ifndef WM_DWMCOMPOSITIONCHANGED // MinGW.
-# define WM_DWMCOMPOSITIONCHANGED 0x31E
+#ifndef WM_DWMCOMPOSITIONCHANGED
+# define WM_DWMCOMPOSITIONCHANGED 0x31E
+#endif
+
+#ifndef WM_DWMCOLORIZATIONCOLORCHANGED
+# define WM_DWMCOLORIZATIONCOLORCHANGED 0x0320
+#endif
+
+#ifndef WM_SYSCOLORCHANGE
+# define WM_SYSCOLORCHANGE 0x0015
#endif
#ifndef WM_TOUCH
@@ -60,6 +32,10 @@
# define WM_DPICHANGED 0x02E0
#endif
+#ifndef WM_GETDPISCALEDSIZE
+# define WM_GETDPISCALEDSIZE 0x02E4
+#endif
+
// WM_POINTER support from Windows 8 onwards (WINVER >= 0x0602)
#ifndef WM_POINTERUPDATE
# define WM_NCPOINTERUPDATE 0x0241
@@ -76,12 +52,20 @@
# define WM_POINTERHWHEEL 0x024F
#endif // WM_POINTERUPDATE
+#if !defined(_DPI_AWARENESS_CONTEXTS_)
+# define DPI_AWARENESS_CONTEXT_UNAWARE ((HANDLE)-1)
+# define DPI_AWARENESS_CONTEXT_SYSTEM_AWARE ((HANDLE)-2)
+# define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE ((HANDLE)-3)
+# define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 ((HANDLE)-4)
+# define DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED ((HANDLE)-5)
+#endif
+
QT_BEGIN_NAMESPACE
namespace QtWindows
{
-enum
+enum WindowsEventTypeFlags
{
WindowEventFlag = 0x10000,
MouseEventFlag = 0x20000,
@@ -121,6 +105,9 @@ enum WindowsEventType // Simplify event types
EnterSizeMoveEvent = WindowEventFlag + 22,
ExitSizeMoveEvent = WindowEventFlag + 23,
PointerActivateWindowEvent = WindowEventFlag + 24,
+ DpiScaledSizeEvent = WindowEventFlag + 25,
+ DpiChangedAfterParentEvent = WindowEventFlag + 27,
+ TaskbarButtonCreated = WindowEventFlag + 28,
MouseEvent = MouseEventFlag + 1,
MouseWheelEvent = MouseEventFlag + 2,
CursorEvent = MouseEventFlag + 3,
@@ -132,7 +119,7 @@ enum WindowsEventType // Simplify event types
NonClientPointerEvent = NonClientEventFlag + PointerEventFlag + 4,
KeyEvent = KeyEventFlag + 1,
KeyDownEvent = KeyEventFlag + KeyDownEventFlag + 1,
- KeyboardLayoutChangeEvent = KeyEventFlag + 2,
+ InputLanguageChangeEvent = KeyEventFlag + 2,
InputMethodKeyEvent = InputMethodEventFlag + KeyEventFlag + 1,
InputMethodKeyDownEvent = InputMethodEventFlag + KeyEventFlag + KeyDownEventFlag + 1,
ClipboardEvent = ClipboardEventFlag + 1,
@@ -154,26 +141,37 @@ enum WindowsEventType // Simplify event types
InputMethodRequest = InputMethodEventFlag + 6,
ThemeChanged = ThemingEventFlag + 1,
CompositionSettingsChanged = ThemingEventFlag + 2,
- DisplayChangedEvent = 437,
- SettingChangedEvent = DisplayChangedEvent + 1,
+ SettingChangedEvent = 438,
ScrollEvent = GenericEventFlag + 1,
ContextMenu = 123,
GestureEvent = 124,
UnknownEvent = 542
};
+Q_DECLARE_MIXED_ENUM_OPERATORS(bool, WindowsEventTypeFlags, WindowsEventType);
+Q_DECLARE_MIXED_ENUM_OPERATORS(bool, WindowsEventType, WindowsEventTypeFlags);
-// Matches Process_DPI_Awareness (Windows 8.1 onwards), used for SetProcessDpiAwareness()
-enum ProcessDpiAwareness
+enum class DpiAwareness
{
- ProcessDpiUnaware,
- ProcessSystemDpiAware,
- ProcessPerMonitorDpiAware
+ Invalid = -1,
+ Unaware,
+ System,
+ PerMonitor,
+ PerMonitorVersion2,
+ Unaware_GdiScaled
};
} // namespace QtWindows
inline QtWindows::WindowsEventType windowsEventType(UINT message, WPARAM wParamIn, LPARAM lParamIn)
{
+ static const UINT WM_TASKBAR_BUTTON_CREATED = []{
+ UINT message = RegisterWindowMessage(L"TaskbarButtonCreated");
+ // In case the application is run elevated, allow the
+ // TaskbarButtonCreated message through.
+ ChangeWindowMessageFilter(message, MSGFLT_ADD);
+ return message;
+ }();
+
switch (message) {
case WM_PAINT:
case WM_ERASEBKGND:
@@ -232,7 +230,7 @@ inline QtWindows::WindowsEventType windowsEventType(UINT message, WPARAM wParamI
return QtWindows::InputMethodKeyDownEvent;
#ifdef WM_INPUTLANGCHANGE
case WM_INPUTLANGCHANGE:
- return QtWindows::KeyboardLayoutChangeEvent;
+ return QtWindows::InputLanguageChangeEvent;
#endif // WM_INPUTLANGCHANGE
case WM_TOUCH:
return QtWindows::TouchEvent;
@@ -271,12 +269,9 @@ inline QtWindows::WindowsEventType windowsEventType(UINT message, WPARAM wParamI
// http://msdn.microsoft.com/en-us/library/ms695534(v=vs.85).aspx
case WM_SETTINGCHANGE:
return QtWindows::SettingChangedEvent;
- case WM_DISPLAYCHANGE:
- return QtWindows::DisplayChangedEvent;
case WM_THEMECHANGED:
-#ifdef WM_SYSCOLORCHANGE // Windows 7: Handle color change as theme change (QTBUG-34170).
- case WM_SYSCOLORCHANGE:
-#endif
+ case WM_SYSCOLORCHANGE: // Handle color change as theme change (QTBUG-34170).
+ case WM_DWMCOLORIZATIONCOLORCHANGED:
return QtWindows::ThemeChanged;
case WM_DWMCOMPOSITIONCHANGED:
return QtWindows::CompositionSettingsChanged;
@@ -307,6 +302,10 @@ inline QtWindows::WindowsEventType windowsEventType(UINT message, WPARAM wParamI
return HIWORD(wParamIn) ? QtWindows::AcceleratorCommandEvent : QtWindows::MenuCommandEvent;
case WM_DPICHANGED:
return QtWindows::DpiChangedEvent;
+ case WM_DPICHANGED_AFTERPARENT:
+ return QtWindows::DpiChangedAfterParentEvent;
+ case WM_GETDPISCALEDSIZE:
+ return QtWindows::DpiScaledSizeEvent;
case WM_ENTERSIZEMOVE:
return QtWindows::EnterSizeMoveEvent;
case WM_EXITSIZEMOVE:
@@ -323,9 +322,15 @@ inline QtWindows::WindowsEventType windowsEventType(UINT message, WPARAM wParamI
return QtWindows::NonClientPointerEvent;
if (message >= WM_POINTERUPDATE && message <= WM_POINTERHWHEEL)
return QtWindows::PointerEvent;
+ if (message == WM_TASKBAR_BUTTON_CREATED)
+ return QtWindows::TaskbarButtonCreated;
return QtWindows::UnknownEvent;
}
+#ifndef QT_NO_DEBUG_STREAM
+extern QDebug operator<<(QDebug, QtWindows::DpiAwareness);
+#endif
+
QT_END_NAMESPACE
#endif // QTWINDOWSGLOBAL_H
diff --git a/src/plugins/platforms/windows/qwin10helpers.cpp b/src/plugins/platforms/windows/qwin10helpers.cpp
index 9a7fce9cd5..026e81cb0c 100644
--- a/src/plugins/platforms/windows/qwin10helpers.cpp
+++ b/src/plugins/platforms/windows/qwin10helpers.cpp
@@ -1,52 +1,16 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qwin10helpers.h"
#include <QtCore/qdebug.h>
-#include <QtCore/qoperatingsystemversion.h>
-#include <QtCore/private/qsystemlibrary_p.h>
+#include <winstring.h>
+#include <roapi.h>
#if defined(Q_CC_MINGW) || defined(Q_CC_CLANG)
# define HAS_UI_VIEW_SETTINGS_INTEROP
// Present from MSVC2015 + SDK 10 onwards
-#elif (!defined(Q_CC_MSVC) || _MSC_VER >= 1900) && NTDDI_VERSION >= 0xa000000
+#elif (!defined(Q_CC_MSVC) || _MSC_VER >= 1900) && WINVER >= 0x0A00
# define HAS_UI_VIEW_SETTINGS_INTEROP
# define HAS_UI_VIEW_SETTINGS
#endif
@@ -96,56 +60,23 @@ public:
QT_BEGIN_NAMESPACE
-// Starting from Windows 10
-struct QWindowsComBaseDLL
-{
- bool init();
- bool isValid() const
- {
- return roGetActivationFactory != nullptr && windowsCreateStringReference != nullptr;
- }
-
- typedef HRESULT (WINAPI *RoGetActivationFactory)(HSTRING, REFIID, void **);
- typedef HRESULT (WINAPI *WindowsCreateStringReference)(PCWSTR, UINT32, HSTRING_HEADER *, HSTRING *);
-
- RoGetActivationFactory roGetActivationFactory = nullptr;
- WindowsCreateStringReference windowsCreateStringReference = nullptr;
-};
-
-static QWindowsComBaseDLL baseComDll;
-
-bool QWindowsComBaseDLL::init()
-{
- if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows10 && !isValid()) {
- QSystemLibrary library(QStringLiteral("combase"));
- roGetActivationFactory =
- reinterpret_cast<RoGetActivationFactory>(library.resolve("RoGetActivationFactory"));
- windowsCreateStringReference =
- reinterpret_cast<WindowsCreateStringReference>(library.resolve("WindowsCreateStringReference"));
- }
- return isValid();
-}
-
// Return tablet mode, note: Does not work for GetDesktopWindow().
bool qt_windowsIsTabletMode(HWND hwnd)
{
bool result = false;
- if (!baseComDll.init())
- return false;
-
const wchar_t uiViewSettingsId[] = L"Windows.UI.ViewManagement.UIViewSettings";
HSTRING_HEADER uiViewSettingsIdRefHeader;
HSTRING uiViewSettingsIdHs = nullptr;
const auto uiViewSettingsIdLen = UINT32(sizeof(uiViewSettingsId) / sizeof(uiViewSettingsId[0]) - 1);
- if (FAILED(baseComDll.windowsCreateStringReference(uiViewSettingsId, uiViewSettingsIdLen, &uiViewSettingsIdRefHeader, &uiViewSettingsIdHs)))
+ if (FAILED(WindowsCreateStringReference(uiViewSettingsId, uiViewSettingsIdLen, &uiViewSettingsIdRefHeader, &uiViewSettingsIdHs)))
return false;
IUIViewSettingsInterop *uiViewSettingsInterop = nullptr;
// __uuidof(IUIViewSettingsInterop);
const GUID uiViewSettingsInteropRefId = {0x3694dbf9, 0x8f68, 0x44be,{0x8f, 0xf5, 0x19, 0x5c, 0x98, 0xed, 0xe8, 0xa6}};
- HRESULT hr = baseComDll.roGetActivationFactory(uiViewSettingsIdHs, uiViewSettingsInteropRefId,
+ HRESULT hr = RoGetActivationFactory(uiViewSettingsIdHs, uiViewSettingsInteropRefId,
reinterpret_cast<void **>(&uiViewSettingsInterop));
if (FAILED(hr))
return false;
diff --git a/src/plugins/platforms/windows/qwin10helpers.h b/src/plugins/platforms/windows/qwin10helpers.h
index 4f364dfc59..e601947267 100644
--- a/src/plugins/platforms/windows/qwin10helpers.h
+++ b/src/plugins/platforms/windows/qwin10helpers.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QWIN10HELPERS_H
#define QWIN10HELPERS_H
diff --git a/src/plugins/platforms/windows/qwindowsapplication.cpp b/src/plugins/platforms/windows/qwindowsapplication.cpp
new file mode 100644
index 0000000000..60cbf1f7ba
--- /dev/null
+++ b/src/plugins/platforms/windows/qwindowsapplication.cpp
@@ -0,0 +1,151 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qwindowsapplication.h"
+#include "qwindowsclipboard.h"
+#include "qwindowscontext.h"
+#include "qwindowsmimeregistry.h"
+#include "qwin10helpers.h"
+#include "qwindowsopengltester.h"
+#include "qwindowswindow.h"
+#include "qwindowsintegration.h"
+#include "qwindowstheme.h"
+
+#include <QtCore/qvariant.h>
+#include <QtCore/private/qfunctions_win_p.h>
+
+#include <QtGui/qpalette.h>
+
+QT_BEGIN_NAMESPACE
+
+void QWindowsApplication::setTouchWindowTouchType(QWindowsApplication::TouchWindowTouchTypes type)
+{
+ if (m_touchWindowTouchTypes == type)
+ return;
+ m_touchWindowTouchTypes = type;
+ if (auto ctx = QWindowsContext::instance())
+ ctx->registerTouchWindows();
+}
+
+QWindowsApplication::TouchWindowTouchTypes QWindowsApplication::touchWindowTouchType() const
+{
+ return m_touchWindowTouchTypes;
+}
+
+QWindowsApplication::WindowActivationBehavior QWindowsApplication::windowActivationBehavior() const
+{
+ return m_windowActivationBehavior;
+}
+
+void QWindowsApplication::setWindowActivationBehavior(WindowActivationBehavior behavior)
+{
+ m_windowActivationBehavior = behavior;
+}
+
+void QWindowsApplication::setHasBorderInFullScreenDefault(bool border)
+{
+ QWindowsWindow::setHasBorderInFullScreenDefault(border);
+}
+
+bool QWindowsApplication::isTabletMode() const
+{
+#if QT_CONFIG(clipboard)
+ if (const QWindowsClipboard *clipboard = QWindowsClipboard::instance())
+ return qt_windowsIsTabletMode(clipboard->clipboardViewer());
+#endif
+ return false;
+}
+
+bool QWindowsApplication::isWinTabEnabled() const
+{
+ auto ctx = QWindowsContext::instance();
+ return ctx != nullptr && ctx->tabletSupport() != nullptr;
+}
+
+bool QWindowsApplication::setWinTabEnabled(bool enabled)
+{
+ if (enabled == isWinTabEnabled())
+ return true;
+ auto ctx = QWindowsContext::instance();
+ if (!ctx)
+ return false;
+ return enabled ? ctx->initTablet() : ctx->disposeTablet();
+}
+
+bool QWindowsApplication::isDarkMode() const
+{
+ return QWindowsContext::isDarkMode();
+}
+
+QWindowsApplication::DarkModeHandling QWindowsApplication::darkModeHandling() const
+{
+ return m_darkModeHandling;
+}
+
+void QWindowsApplication::setDarkModeHandling(QWindowsApplication::DarkModeHandling handling)
+{
+ m_darkModeHandling = handling;
+}
+
+void QWindowsApplication::registerMime(QWindowsMimeConverter *mime)
+{
+ if (auto ctx = QWindowsContext::instance())
+ ctx->mimeConverter().registerMime(mime);
+}
+
+void QWindowsApplication::unregisterMime(QWindowsMimeConverter *mime)
+{
+ if (auto ctx = QWindowsContext::instance())
+ ctx->mimeConverter().unregisterMime(mime);
+}
+
+int QWindowsApplication::registerMimeType(const QString &mime)
+{
+ return QWindowsMimeRegistry::registerMimeType(mime);
+}
+
+HWND QWindowsApplication::createMessageWindow(const QString &classNameTemplate,
+ const QString &windowName,
+ QFunctionPointer eventProc) const
+{
+ QWindowsContext *ctx = QWindowsContext::instance();
+ if (!ctx)
+ return nullptr;
+ auto wndProc = eventProc ? reinterpret_cast<WNDPROC>(eventProc) : DefWindowProc;
+ return ctx->createDummyWindow(classNameTemplate,
+ reinterpret_cast<const wchar_t*>(windowName.utf16()),
+ wndProc);
+}
+
+bool QWindowsApplication::asyncExpose() const
+{
+ QWindowsContext *ctx = QWindowsContext::instance();
+ return ctx && ctx->asyncExpose();
+}
+
+void QWindowsApplication::setAsyncExpose(bool value)
+{
+ if (QWindowsContext *ctx = QWindowsContext::instance())
+ ctx->setAsyncExpose(value);
+}
+
+QVariant QWindowsApplication::gpu() const
+{
+ return GpuDescription::detect().toVariant();
+}
+
+QVariant QWindowsApplication::gpuList() const
+{
+ QVariantList result;
+ const auto gpus = GpuDescription::detectAll();
+ for (const auto &gpu : gpus)
+ result.append(gpu.toVariant());
+ return result;
+}
+
+void QWindowsApplication::populateLightSystemPalette(QPalette &result) const
+{
+ result = QWindowsTheme::systemPalette(Qt::ColorScheme::Light);
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/windows/qwindowsapplication.h b/src/plugins/platforms/windows/qwindowsapplication.h
new file mode 100644
index 0000000000..efacd74e18
--- /dev/null
+++ b/src/plugins/platforms/windows/qwindowsapplication.h
@@ -0,0 +1,56 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QWINDOWSAPPLICATION_H
+#define QWINDOWSAPPLICATION_H
+
+#include <QtGui/private/qguiapplication_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QWindowsApplication : public QNativeInterface::Private::QWindowsApplication
+{
+public:
+ void setTouchWindowTouchType(TouchWindowTouchTypes type) override;
+ TouchWindowTouchTypes touchWindowTouchType() const override;
+
+ WindowActivationBehavior windowActivationBehavior() const override;
+ void setWindowActivationBehavior(WindowActivationBehavior behavior) override;
+
+ void setHasBorderInFullScreenDefault(bool border) override;
+
+ bool isTabletMode() const override;
+
+ bool isWinTabEnabled() const override;
+ bool setWinTabEnabled(bool enabled) override;
+
+ bool isDarkMode() const override;
+ DarkModeHandling darkModeHandling() const override;
+ void setDarkModeHandling(DarkModeHandling handling) override;
+
+ void registerMime(QWindowsMimeConverter *mime) override;
+ void unregisterMime(QWindowsMimeConverter *mime) override;
+
+ int registerMimeType(const QString &mime) override;
+
+ HWND createMessageWindow(const QString &classNameTemplate,
+ const QString &windowName,
+ QFunctionPointer eventProc = nullptr) const override;
+
+ bool asyncExpose() const override;
+ void setAsyncExpose(bool value) override;
+
+ QVariant gpu() const override;
+ QVariant gpuList() const override;
+
+ void populateLightSystemPalette(QPalette &palette) const override;
+
+private:
+ WindowActivationBehavior m_windowActivationBehavior = DefaultActivateWindow;
+ TouchWindowTouchTypes m_touchWindowTouchTypes = NormalTouch;
+ DarkModeHandling m_darkModeHandling;
+};
+
+QT_END_NAMESPACE
+
+#endif // QWINDOWSAPPLICATION_H
diff --git a/src/plugins/platforms/windows/qwindowsbackingstore.cpp b/src/plugins/platforms/windows/qwindowsbackingstore.cpp
index bd7bdc55d1..07918f6094 100644
--- a/src/plugins/platforms/windows/qwindowsbackingstore.cpp
+++ b/src/plugins/platforms/windows/qwindowsbackingstore.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qwindowsbackingstore.h"
#include "qwindowswindow.h"
@@ -43,7 +7,7 @@
#include <QtGui/qwindow.h>
#include <QtGui/qpainter.h>
-#include <QtFontDatabaseSupport/private/qwindowsnativeimage_p.h>
+#include <QtGui/private/qwindowsnativeimage_p.h>
#include <private/qhighdpiscaling_p.h>
#include <private/qimage_p.h>
@@ -55,7 +19,6 @@ QT_BEGIN_NAMESPACE
\class QWindowsBackingStore
\brief Backing store for windows.
\internal
- \ingroup qt-lighthouse-win
*/
QWindowsBackingStore::QWindowsBackingStore(QWindow *window) :
@@ -92,9 +55,8 @@ void QWindowsBackingStore::flush(QWindow *window, const QRegion &region,
if ((flags & Qt::FramelessWindowHint) && QWindowsWindow::setWindowLayered(rw->handle(), flags, hasAlpha, rw->opacity()) && hasAlpha) {
// Windows with alpha: Use blend function to update.
QRect r = QHighDpi::toNativePixels(window->frameGeometry(), window);
- QPoint frameOffset(QHighDpi::toNativePixels(QPoint(window->frameMargins().left(), window->frameMargins().top()),
- static_cast<const QWindow *>(nullptr)));
- QRect dirtyRect = br.translated(offset + frameOffset);
+ QMargins frameMargins = rw->frameMargins();
+ QRect dirtyRect = br.translated(offset + QPoint(frameMargins.left(), frameMargins.top()));
SIZE size = {r.width(), r.height()};
POINT ptDst = {r.x(), r.y()};
@@ -155,7 +117,7 @@ void QWindowsBackingStore::resize(const QSize &size, const QRegion &region)
if (QImage::toPixelFormat(format).alphaUsage() == QPixelFormat::UsesAlpha)
m_alphaNeedsFill = true;
else // upgrade but here we know app painting does not rely on alpha hence no need to fill
- format = qt_maybeAlphaVersionWithSameDepth(format);
+ format = qt_maybeDataCompatibleAlphaVersion(format);
QWindowsNativeImage *oldwni = m_image.data();
auto *newwni = new QWindowsNativeImage(size.width(), size.height(), format);
@@ -184,8 +146,8 @@ bool QWindowsBackingStore::scroll(const QRegion &area, int dx, int dy)
return false;
const QPoint offset(dx, dy);
- for (const QRect &rect : area)
- qt_scrollRectInImage(m_image->image(), rect, offset);
+ const QRect rect = area.boundingRect();
+ qt_scrollRectInImage(m_image->image(), rect, offset);
return true;
}
diff --git a/src/plugins/platforms/windows/qwindowsbackingstore.h b/src/plugins/platforms/windows/qwindowsbackingstore.h
index b96c8f0e61..186123b38e 100644
--- a/src/plugins/platforms/windows/qwindowsbackingstore.h
+++ b/src/plugins/platforms/windows/qwindowsbackingstore.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QWINDOWSBACKINGSTORE_H
#define QWINDOWSBACKINGSTORE_H
diff --git a/src/plugins/platforms/windows/qwindowsclipboard.cpp b/src/plugins/platforms/windows/qwindowsclipboard.cpp
index efcb0b6e6e..7a6d41e0b3 100644
--- a/src/plugins/platforms/windows/qwindowsclipboard.cpp
+++ b/src/plugins/platforms/windows/qwindowsclipboard.cpp
@@ -1,46 +1,9 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qwindowsclipboard.h"
#include "qwindowscontext.h"
#include "qwindowsole.h"
-#include "qwindowsmime.h"
#include <QtGui/qguiapplication.h>
#include <QtGui/qclipboard.h>
@@ -53,8 +16,9 @@
#include <QtCore/qthread.h>
#include <QtCore/qvariant.h>
#include <QtCore/qurl.h>
+#include <QtCore/private/qsystemerror_p.h>
-#include <QtEventDispatcherSupport/private/qwindowsguieventdispatcher_p.h>
+#include <QtGui/private/qwindowsguieventdispatcher_p.h>
QT_BEGIN_NAMESPACE
@@ -71,7 +35,6 @@ QT_BEGIN_NAMESPACE
\note The OLE-functions used in this class require OleInitialize().
\internal
- \ingroup qt-lighthouse-win
*/
#ifndef QT_NO_DEBUG_STREAM
@@ -110,7 +73,6 @@ static QDebug operator<<(QDebug d, const QMimeData *mimeData)
\sa QWindowsInternalMimeDataBase, QWindowsClipboard
\internal
- \ingroup qt-lighthouse-win
*/
IDataObject *QWindowsClipboardRetrievalMimeData::retrieveDataObject() const
@@ -193,12 +155,9 @@ void QWindowsClipboard::registerViewer()
createDummyWindow(QStringLiteral("ClipboardView"), L"QtClipboardView",
qClipboardViewerWndProc, WS_OVERLAPPED);
- // Try format listener API (Vista onwards) first.
- if (QWindowsContext::user32dll.addClipboardFormatListener && QWindowsContext::user32dll.removeClipboardFormatListener) {
- m_formatListenerRegistered = QWindowsContext::user32dll.addClipboardFormatListener(m_clipboardViewer);
- if (!m_formatListenerRegistered)
- qErrnoWarning("AddClipboardFormatListener() failed.");
- }
+ m_formatListenerRegistered = AddClipboardFormatListener(m_clipboardViewer);
+ if (!m_formatListenerRegistered)
+ qErrnoWarning("AddClipboardFormatListener() failed.");
if (!m_formatListenerRegistered)
m_nextClipboardViewer = SetClipboardViewer(m_clipboardViewer);
@@ -212,7 +171,7 @@ void QWindowsClipboard::unregisterViewer()
{
if (m_clipboardViewer) {
if (m_formatListenerRegistered) {
- QWindowsContext::user32dll.removeClipboardFormatListener(m_clipboardViewer);
+ RemoveClipboardFormatListener(m_clipboardViewer);
m_formatListenerRegistered = false;
} else {
ChangeClipboardChain(m_clipboardViewer, m_nextClipboardViewer);
@@ -342,7 +301,7 @@ void QWindowsClipboard::setMimeData(QMimeData *mimeData, QClipboard::Mode mode)
mimeData->formats().join(u", ") : QString(QStringLiteral("NULL"));
qErrnoWarning("OleSetClipboard: Failed to set mime data (%s) on clipboard: %s",
qPrintable(mimeDataFormats),
- QWindowsContext::comErrorString(src).constData());
+ qPrintable(QSystemError::windowsComString(src)));
releaseIData();
return;
}
diff --git a/src/plugins/platforms/windows/qwindowsclipboard.h b/src/plugins/platforms/windows/qwindowsclipboard.h
index 24a6bc908d..9713dccf9b 100644
--- a/src/plugins/platforms/windows/qwindowsclipboard.h
+++ b/src/plugins/platforms/windows/qwindowsclipboard.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QWINDOWSCLIPBOARD_H
#define QWINDOWSCLIPBOARD_H
diff --git a/src/plugins/platforms/windows/qwindowscombase.h b/src/plugins/platforms/windows/qwindowscombase.h
index bb4b295395..c54ff7a11f 100644
--- a/src/plugins/platforms/windows/qwindowscombase.h
+++ b/src/plugins/platforms/windows/qwindowscombase.h
@@ -1,45 +1,11 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QWINDOWSCOMBASE_H
#define QWINDOWSCOMBASE_H
+#include <qt_windows.h>
+
#include <QtCore/qglobal.h>
#include <unknwn.h>
@@ -77,38 +43,9 @@ bool qWindowsComQueryUnknownInterfaceMulti(Derived *d, REFIID id, LPVOID *iface)
return false;
}
-// Helper base class to provide IUnknown methods for COM classes (single inheritance)
-template <class ComInterface> class QWindowsComBase : public ComInterface
-{
- Q_DISABLE_COPY_MOVE(QWindowsComBase)
-public:
- explicit QWindowsComBase(ULONG initialRefCount = 1) : m_ref(initialRefCount) {}
- virtual ~QWindowsComBase() = default;
-
- HRESULT STDMETHODCALLTYPE QueryInterface(REFIID id, LPVOID *iface)
- {
- *iface = nullptr;
- return qWindowsComQueryInterface<IUnknown>(this, id, iface) || qWindowsComQueryInterface<ComInterface>(this, id, iface)
- ? S_OK : E_NOINTERFACE;
- }
-
- ULONG STDMETHODCALLTYPE AddRef() { return ++m_ref; }
-
- ULONG STDMETHODCALLTYPE Release()
- {
- if (!--m_ref) {
- delete this;
- return 0;
- }
- return m_ref;
- }
-
-private:
- ULONG m_ref;
-};
-
// Clang does not consider __declspec(nothrow) as nothrow
QT_WARNING_DISABLE_CLANG("-Wmicrosoft-exception-spec")
+QT_WARNING_DISABLE_CLANG("-Wmissing-exception-spec")
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp
index 438a0fbaa4..c85c44d949 100644
--- a/src/plugins/platforms/windows/qwindowscontext.cpp
+++ b/src/plugins/platforms/windows/qwindowscontext.cpp
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Samuel Gaist <samuel.gaist@edeltech.ch>
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2013 Samuel Gaist <samuel.gaist@edeltech.ch>
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qwindowscontext.h"
#include "qwindowsintegration.h"
@@ -47,7 +11,7 @@
#include "qwindowspointerhandler.h"
#include "qtwindowsglobal.h"
#include "qwindowsmenu.h"
-#include "qwindowsmime.h"
+#include "qwindowsmimeregistry.h"
#include "qwindowsinputcontext.h"
#if QT_CONFIG(tabletevent)
# include "qwindowstabletsupport.h"
@@ -70,31 +34,37 @@
#include <qpa/qplatformnativeinterface.h>
#include <QtGui/qguiapplication.h>
#include <QtGui/qopenglcontext.h>
+#include <QtGui/qpointingdevice.h>
#include <QtCore/qset.h>
#include <QtCore/qhash.h>
#include <QtCore/qlibraryinfo.h>
#include <QtCore/qstringlist.h>
#include <QtCore/qdebug.h>
-#include <QtCore/qoperatingsystemversion.h>
#include <QtCore/qsysinfo.h>
#include <QtCore/qscopedpointer.h>
#include <QtCore/quuid.h>
-#include <QtCore/private/qsystemlibrary_p.h>
#include <QtCore/private/qwinregistry_p.h>
+#if QT_CONFIG(cpp_winrt)
+# include <QtCore/private/qfactorycacheregistration_p.h>
+#endif
+#include <QtCore/private/qsystemerror_p.h>
-#include <QtEventDispatcherSupport/private/qwindowsguieventdispatcher_p.h>
+#include <QtGui/private/qwindowsguieventdispatcher_p.h>
+#include <QtGui/private/qwindowsthemecache_p.h>
#include <stdlib.h>
#include <stdio.h>
#include <windowsx.h>
-#include <comdef.h>
#include <dbt.h>
#include <wtsapi32.h>
+#include <shellscalingapi.h>
QT_BEGIN_NAMESPACE
-Q_LOGGING_CATEGORY(lcQpaWindows, "qt.qpa.windows")
+using namespace Qt::StringLiterals;
+
+Q_LOGGING_CATEGORY(lcQpaWindow, "qt.qpa.window")
Q_LOGGING_CATEGORY(lcQpaEvents, "qt.qpa.events")
Q_LOGGING_CATEGORY(lcQpaGl, "qt.qpa.gl")
Q_LOGGING_CATEGORY(lcQpaMime, "qt.qpa.mime")
@@ -105,6 +75,7 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
Q_LOGGING_CATEGORY(lcQpaAccessibility, "qt.qpa.accessibility")
Q_LOGGING_CATEGORY(lcQpaUiAutomation, "qt.qpa.uiautomation")
Q_LOGGING_CATEGORY(lcQpaTrayIcon, "qt.qpa.trayicon")
+Q_LOGGING_CATEGORY(lcQpaScreen, "qt.qpa.screen")
int QWindowsContext::verbose = 0;
@@ -150,98 +121,6 @@ static inline bool sessionManagerInteractionBlocked()
static inline bool sessionManagerInteractionBlocked() { return false; }
#endif
-static inline int windowDpiAwareness(HWND hwnd)
-{
- return QWindowsContext::user32dll.getWindowDpiAwarenessContext && QWindowsContext::user32dll.getAwarenessFromDpiAwarenessContext
- ? QWindowsContext::user32dll.getAwarenessFromDpiAwarenessContext(QWindowsContext::user32dll.getWindowDpiAwarenessContext(hwnd))
- : -1;
-}
-
-// Note: This only works within WM_NCCREATE
-static bool enableNonClientDpiScaling(HWND hwnd)
-{
- bool result = false;
- if (QWindowsContext::user32dll.enableNonClientDpiScaling && windowDpiAwareness(hwnd) == 2) {
- result = QWindowsContext::user32dll.enableNonClientDpiScaling(hwnd) != FALSE;
- if (!result) {
- const DWORD errorCode = GetLastError();
- qErrnoWarning(int(errorCode), "EnableNonClientDpiScaling() failed for HWND %p (%lu)",
- hwnd, errorCode);
- }
- }
- return result;
-}
-
-/*!
- \class QWindowsUser32DLL
- \brief Struct that contains dynamically resolved symbols of User32.dll.
-
- The stub libraries shipped with the MinGW compiler miss some of the
- functions. They need to be retrieved dynamically.
-
- In addition, touch-related functions are available only from Windows onwards.
- These need to resolved dynamically for Q_CC_MSVC as well.
-
- \sa QWindowsShell32DLL
-
- \internal
- \ingroup qt-lighthouse-win
-*/
-
-void QWindowsUser32DLL::init()
-{
- QSystemLibrary library(QStringLiteral("user32"));
- setProcessDPIAware = (SetProcessDPIAware)library.resolve("SetProcessDPIAware");
-
- addClipboardFormatListener = (AddClipboardFormatListener)library.resolve("AddClipboardFormatListener");
- removeClipboardFormatListener = (RemoveClipboardFormatListener)library.resolve("RemoveClipboardFormatListener");
-
- 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");
- }
-
- if (QOperatingSystemVersion::current()
- >= QOperatingSystemVersion(QOperatingSystemVersion::Windows, 10, 0, 14393)) {
- adjustWindowRectExForDpi = (AdjustWindowRectExForDpi)library.resolve("AdjustWindowRectExForDpi");
- enableNonClientDpiScaling = (EnableNonClientDpiScaling)library.resolve("EnableNonClientDpiScaling");
- getWindowDpiAwarenessContext = (GetWindowDpiAwarenessContext)library.resolve("GetWindowDpiAwarenessContext");
- getAwarenessFromDpiAwarenessContext = (GetAwarenessFromDpiAwarenessContext)library.resolve("GetAwarenessFromDpiAwarenessContext");
- systemParametersInfoForDpi = (SystemParametersInfoForDpi)library.resolve("SystemParametersInfoForDpi");
- }
-}
-
-bool QWindowsUser32DLL::supportsPointerApi()
-{
- return enableMouseInPointer && getPointerType && getPointerInfo && getPointerDeviceRects
- && getPointerTouchInfo && getPointerFrameTouchInfo && getPointerFrameTouchInfoHistory
- && getPointerPenInfo && getPointerPenInfoHistory && skipPointerFrameMessages;
-}
-
-void QWindowsShcoreDLL::init()
-{
- if (QOperatingSystemVersion::current() < QOperatingSystemVersion::Windows8_1)
- return;
- QSystemLibrary library(QStringLiteral("SHCore"));
- getProcessDpiAwareness = (GetProcessDpiAwareness)library.resolve("GetProcessDpiAwareness");
- setProcessDpiAwareness = (SetProcessDpiAwareness)library.resolve("SetProcessDpiAwareness");
- getDpiForMonitor = (GetDpiForMonitor)library.resolve("GetDpiForMonitor");
-}
-
-QWindowsUser32DLL QWindowsContext::user32dll;
-QWindowsShcoreDLL QWindowsContext::shcoredll;
-
QWindowsContext *QWindowsContext::m_instance = nullptr;
/*!
@@ -251,23 +130,20 @@ QWindowsContext *QWindowsContext::m_instance = nullptr;
Holds state information formerly stored in \c qapplication_win.cpp.
\internal
- \ingroup qt-lighthouse-win
*/
-typedef QHash<HWND, QWindowsWindow *> HandleBaseWindowHash;
-
struct QWindowsContextPrivate {
QWindowsContextPrivate();
unsigned m_systemInfo = 0;
QSet<QString> m_registeredWindowClassNames;
- HandleBaseWindowHash m_windows;
+ QWindowsContext::HandleBaseWindowHash m_windows;
HDC m_displayContext = nullptr;
int m_defaultDPI = 96;
QWindowsKeyMapper m_keyMapper;
QWindowsMouseHandler m_mouseHandler;
QWindowsPointerHandler m_pointerHandler;
- QWindowsMimeConverter m_mimeConverter;
+ QWindowsMimeRegistry m_mimeConverter;
QWindowsScreenManager m_screenManager;
QSharedPointer<QWindowCreationContext> m_creationContext;
#if QT_CONFIG(tabletevent)
@@ -279,16 +155,15 @@ struct QWindowsContextPrivate {
HPOWERNOTIFY m_powerNotification = nullptr;
HWND m_powerDummyWindow = nullptr;
static bool m_darkMode;
+ static bool m_v2DpiAware;
};
bool QWindowsContextPrivate::m_darkMode = false;
+bool QWindowsContextPrivate::m_v2DpiAware = false;
QWindowsContextPrivate::QWindowsContextPrivate()
: m_oleInitializeResult(OleInitialize(nullptr))
{
- QWindowsContext::user32dll.init();
- QWindowsContext::shcoredll.init();
-
if (m_pointerHandler.touchDevice() || m_mouseHandler.touchDevice())
m_systemInfo |= QWindowsContext::SI_SupportsTouch;
m_displayContext = GetDC(nullptr);
@@ -300,7 +175,7 @@ QWindowsContextPrivate::QWindowsContextPrivate()
m_darkMode = QWindowsTheme::queryDarkMode();
if (FAILED(m_oleInitializeResult)) {
qWarning() << "QWindowsContext: OleInitialize() failed: "
- << QWindowsContext::comErrorString(m_oleInitializeResult);
+ << QSystemError::windowsComString(m_oleInitializeResult);
}
}
@@ -330,8 +205,12 @@ QWindowsContext::~QWindowsContext()
DestroyWindow(d->m_powerDummyWindow);
unregisterWindowClasses();
- if (d->m_oleInitializeResult == S_OK || d->m_oleInitializeResult == S_FALSE)
+ if (d->m_oleInitializeResult == S_OK || d->m_oleInitializeResult == S_FALSE) {
+#ifdef QT_USE_FACTORY_CACHE_REGISTRATION
+ detail::QWinRTFactoryCacheRegistration::clearAllCaches();
+#endif
OleUninitialize();
+ }
d->m_screenManager.clearScreens(); // Order: Potentially calls back to the windows.
if (d->m_displayContext)
@@ -348,33 +227,50 @@ bool QWindowsContext::initTouch(unsigned integrationOptions)
{
if (d->m_systemInfo & QWindowsContext::SI_SupportsTouch)
return true;
-
- QTouchDevice *touchDevice = (d->m_systemInfo & QWindowsContext::SI_SupportsPointer) ?
- d->m_pointerHandler.ensureTouchDevice() : d->m_mouseHandler.ensureTouchDevice();
- if (!touchDevice)
+ const bool usePointerHandler = (d->m_systemInfo & QWindowsContext::SI_SupportsPointer) != 0;
+ auto touchDevice = usePointerHandler ? d->m_pointerHandler.touchDevice() : d->m_mouseHandler.touchDevice();
+ if (touchDevice.isNull()) {
+ const bool mouseEmulation =
+ (integrationOptions & QWindowsIntegration::DontPassOsMouseEventsSynthesizedFromTouch) == 0;
+ touchDevice = QWindowsPointerHandler::createTouchDevice(mouseEmulation);
+ }
+ if (touchDevice.isNull())
return false;
-
- if (!(integrationOptions & QWindowsIntegration::DontPassOsMouseEventsSynthesizedFromTouch))
- touchDevice->setCapabilities(touchDevice->capabilities() | QTouchDevice::MouseEmulation);
-
- QWindowSystemInterface::registerTouchDevice(touchDevice);
+ d->m_pointerHandler.setTouchDevice(touchDevice);
+ d->m_mouseHandler.setTouchDevice(touchDevice);
+ QWindowSystemInterface::registerInputDevice(touchDevice.data());
d->m_systemInfo |= QWindowsContext::SI_SupportsTouch;
// A touch device was plugged while the app is running. Register all windows for touch.
- if (QGuiApplicationPrivate::is_app_running) {
- for (QWindowsWindow *w : qAsConst(d->m_windows))
+ registerTouchWindows();
+
+ return true;
+}
+
+void QWindowsContext::registerTouchWindows()
+{
+ if (QGuiApplicationPrivate::is_app_running
+ && (d->m_systemInfo & QWindowsContext::SI_SupportsTouch) != 0) {
+ for (QWindowsWindow *w : std::as_const(d->m_windows))
w->registerTouchWindow();
}
+}
+bool QWindowsContext::initTablet()
+{
+#if QT_CONFIG(tabletevent)
+ d->m_tabletSupport.reset(QWindowsTabletSupport::create());
return true;
+#else
+ return false;
+#endif
}
-bool QWindowsContext::initTablet(unsigned integrationOptions)
+bool QWindowsContext::disposeTablet()
{
- Q_UNUSED(integrationOptions);
#if QT_CONFIG(tabletevent)
- d->m_tabletSupport.reset(QWindowsTabletSupport::create());
+ d->m_tabletSupport.reset();
return true;
#else
return false;
@@ -386,12 +282,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;
-
d->m_systemInfo |= QWindowsContext::SI_SupportsPointer;
return true;
}
@@ -448,10 +338,9 @@ bool QWindowsContext::initPowerNotificationHandler()
void QWindowsContext::setTabletAbsoluteRange(int a)
{
#if QT_CONFIG(tabletevent)
- if (!d->m_tabletSupport.isNull())
- d->m_tabletSupport->setAbsoluteRange(a);
+ QWindowsTabletSupport::setAbsoluteRange(a);
#else
- Q_UNUSED(a)
+ Q_UNUSED(a);
#endif
}
@@ -460,34 +349,119 @@ void QWindowsContext::setDetectAltGrModifier(bool a)
d->m_keyMapper.setDetectAltGrModifier(a);
}
-int QWindowsContext::processDpiAwareness()
+[[nodiscard]] static inline QtWindows::DpiAwareness
+ dpiAwarenessContextToQtDpiAwareness(DPI_AWARENESS_CONTEXT context)
+{
+ // IsValidDpiAwarenessContext() will handle the NULL pointer case.
+ if (!IsValidDpiAwarenessContext(context))
+ return QtWindows::DpiAwareness::Invalid;
+ if (AreDpiAwarenessContextsEqual(context, DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED))
+ return QtWindows::DpiAwareness::Unaware_GdiScaled;
+ if (AreDpiAwarenessContextsEqual(context, DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2))
+ return QtWindows::DpiAwareness::PerMonitorVersion2;
+ if (AreDpiAwarenessContextsEqual(context, DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE))
+ return QtWindows::DpiAwareness::PerMonitor;
+ if (AreDpiAwarenessContextsEqual(context, DPI_AWARENESS_CONTEXT_SYSTEM_AWARE))
+ return QtWindows::DpiAwareness::System;
+ if (AreDpiAwarenessContextsEqual(context, DPI_AWARENESS_CONTEXT_UNAWARE))
+ return QtWindows::DpiAwareness::Unaware;
+ return QtWindows::DpiAwareness::Invalid;
+}
+
+QtWindows::DpiAwareness QWindowsContext::windowDpiAwareness(HWND hwnd)
+{
+ if (!hwnd)
+ return QtWindows::DpiAwareness::Invalid;
+ const auto context = GetWindowDpiAwarenessContext(hwnd);
+ return dpiAwarenessContextToQtDpiAwareness(context);
+}
+
+QtWindows::DpiAwareness QWindowsContext::processDpiAwareness()
+{
+ // Although we have GetDpiAwarenessContextForProcess(), however,
+ // it's only available on Win10 1903+, which is a little higher
+ // than Qt's minimum supported version (1809), so we can't use it.
+ // Luckily, MS docs said GetThreadDpiAwarenessContext() will also
+ // return the default DPI_AWARENESS_CONTEXT for the process if
+ // SetThreadDpiAwarenessContext() was never called. So we can use
+ // it as an equivalent.
+ const auto context = GetThreadDpiAwarenessContext();
+ return dpiAwarenessContextToQtDpiAwareness(context);
+}
+
+[[nodiscard]] static inline DPI_AWARENESS_CONTEXT
+ qtDpiAwarenessToDpiAwarenessContext(QtWindows::DpiAwareness dpiAwareness)
+{
+ switch (dpiAwareness) {
+ case QtWindows::DpiAwareness::Invalid:
+ return nullptr;
+ case QtWindows::DpiAwareness::Unaware:
+ return DPI_AWARENESS_CONTEXT_UNAWARE;
+ case QtWindows::DpiAwareness::System:
+ return DPI_AWARENESS_CONTEXT_SYSTEM_AWARE;
+ case QtWindows::DpiAwareness::PerMonitor:
+ return DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE;
+ case QtWindows::DpiAwareness::PerMonitorVersion2:
+ return DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2;
+ case QtWindows::DpiAwareness::Unaware_GdiScaled:
+ return DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED;
+ }
+ return nullptr;
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug d, QtWindows::DpiAwareness dpiAwareness)
{
- int result;
- if (QWindowsContext::shcoredll.getProcessDpiAwareness
- && SUCCEEDED(QWindowsContext::shcoredll.getProcessDpiAwareness(nullptr, &result))) {
- return result;
+ const QDebugStateSaver saver(d);
+ QString message = u"QtWindows::DpiAwareness::"_s;
+ switch (dpiAwareness) {
+ case QtWindows::DpiAwareness::Invalid:
+ message += u"Invalid"_s;
+ break;
+ case QtWindows::DpiAwareness::Unaware:
+ message += u"Unaware"_s;
+ break;
+ case QtWindows::DpiAwareness::System:
+ message += u"System"_s;
+ break;
+ case QtWindows::DpiAwareness::PerMonitor:
+ message += u"PerMonitor"_s;
+ break;
+ case QtWindows::DpiAwareness::PerMonitorVersion2:
+ message += u"PerMonitorVersion2"_s;
+ break;
+ case QtWindows::DpiAwareness::Unaware_GdiScaled:
+ message += u"Unaware_GdiScaled"_s;
+ break;
}
- return -1;
+ d.nospace().noquote() << message;
+ return d;
}
+#endif
-void QWindowsContext::setProcessDpiAwareness(QtWindows::ProcessDpiAwareness dpiAwareness)
+bool QWindowsContext::setProcessDpiAwareness(QtWindows::DpiAwareness dpiAwareness)
{
- qCDebug(lcQpaWindows) << __FUNCTION__ << dpiAwareness;
- if (QWindowsContext::shcoredll.isValid()) {
- const HRESULT hr = QWindowsContext::shcoredll.setProcessDpiAwareness(dpiAwareness);
- // E_ACCESSDENIED means set externally (MSVC manifest or external app loading Qt plugin).
- // Silence warning in that case unless debug is enabled.
- if (FAILED(hr) && (hr != E_ACCESSDENIED || lcQpaWindows().isDebugEnabled())) {
- qWarning().noquote().nospace() << "SetProcessDpiAwareness("
- << dpiAwareness << ") failed: " << QWindowsContext::comErrorString(hr)
- << ", using " << QWindowsContext::processDpiAwareness();
- }
- } else {
- if (dpiAwareness != QtWindows::ProcessDpiUnaware && QWindowsContext::user32dll.setProcessDPIAware) {
- if (!QWindowsContext::user32dll.setProcessDPIAware())
- qErrnoWarning("SetProcessDPIAware() failed");
- }
+ qCDebug(lcQpaWindow) << __FUNCTION__ << dpiAwareness;
+ if (processDpiAwareness() == dpiAwareness)
+ return true;
+ const auto context = qtDpiAwarenessToDpiAwarenessContext(dpiAwareness);
+ if (!IsValidDpiAwarenessContext(context)) {
+ qCWarning(lcQpaWindow) << dpiAwareness << "is not supported by current system.";
+ return false;
+ }
+ if (!SetProcessDpiAwarenessContext(context)) {
+ qCWarning(lcQpaWindow).noquote().nospace()
+ << "SetProcessDpiAwarenessContext() failed: "
+ << QSystemError::windowsString()
+ << "\nQt's default DPI awareness context is "
+ << "DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2. If you know what you "
+ << "are doing, you can overwrite this default using qt.conf "
+ << "(https://doc.qt.io/qt-6/highdpi.html#configuring-windows).";
+ return false;
}
+ QWindowsContextPrivate::m_v2DpiAware
+ = processDpiAwareness() == QtWindows::DpiAwareness::PerMonitorVersion2;
+ return true;
}
bool QWindowsContext::isDarkMode()
@@ -510,9 +484,14 @@ bool QWindowsContext::useRTLExtensions() const
return d->m_keyMapper.useRTLExtensions();
}
-QList<int> QWindowsContext::possibleKeys(const QKeyEvent *e) const
+QPlatformKeyMapper *QWindowsContext::keyMapper() const
+{
+ return &d->m_keyMapper;
+}
+
+QWindowsContext::HandleBaseWindowHash &QWindowsContext::windows()
{
- return d->m_keyMapper.possibleKeys(e);
+ return d->m_windows;
}
QSharedPointer<QWindowCreationContext> QWindowsContext::setWindowCreationContext(const QSharedPointer<QWindowCreationContext> &ctx)
@@ -559,6 +538,8 @@ QString QWindowsContext::classNamePrefix()
# define xstr(s) str(s)
# define str(s) #s
str << xstr(QT_NAMESPACE);
+# undef str
+# undef xstr
#endif
}
return result;
@@ -596,30 +577,30 @@ QString QWindowsContext::registerWindowClass(const QWindow *w)
}
// Create a unique name for the flag combination
QString cname = classNamePrefix();
- cname += QLatin1String("QWindow");
+ cname += "QWindow"_L1;
switch (type) {
case Qt::Tool:
- cname += QLatin1String("Tool");
+ cname += "Tool"_L1;
break;
case Qt::ToolTip:
- cname += QLatin1String("ToolTip");
+ cname += "ToolTip"_L1;
break;
case Qt::Popup:
- cname += QLatin1String("Popup");
+ cname += "Popup"_L1;
break;
default:
break;
}
if (style & CS_DROPSHADOW)
- cname += QLatin1String("DropShadow");
+ cname += "DropShadow"_L1;
if (style & CS_SAVEBITS)
- cname += QLatin1String("SaveBits");
+ cname += "SaveBits"_L1;
if (style & CS_OWNDC)
- cname += QLatin1String("OwnDC");
+ cname += "OwnDC"_L1;
if (icon)
- cname += QLatin1String("Icon");
+ cname += "Icon"_L1;
- return registerWindowClass(cname, qWindowsWndProc, style, GetSysColorBrush(COLOR_WINDOW), icon);
+ return registerWindowClass(cname, qWindowsWndProc, style, nullptr, icon);
}
QString QWindowsContext::registerWindowClass(QString cname,
@@ -634,9 +615,10 @@ QString QWindowsContext::registerWindowClass(QString cname,
// has already been registered by another instance of Qt then
// add a UUID. The check needs to be performed for each name
// in case new message windows are added (QTBUG-81347).
+ // Note: GetClassInfo() returns != 0 when a class exists.
const auto appInstance = static_cast<HINSTANCE>(GetModuleHandle(nullptr));
WNDCLASS wcinfo;
- const bool classExists = GetClassInfo(appInstance, reinterpret_cast<LPCWSTR>(cname.utf16()), &wcinfo) == TRUE
+ const bool classExists = GetClassInfo(appInstance, reinterpret_cast<LPCWSTR>(cname.utf16()), &wcinfo) != FALSE
&& wcinfo.lpfnWndProc != proc;
if (classExists)
@@ -677,7 +659,7 @@ QString QWindowsContext::registerWindowClass(QString cname,
qPrintable(cname));
d->m_registeredWindowClassNames.insert(cname);
- qCDebug(lcQpaWindows).nospace() << __FUNCTION__ << ' ' << cname
+ qCDebug(lcQpaWindow).nospace() << __FUNCTION__ << ' ' << cname
<< " style=0x" << Qt::hex << style << Qt::dec
<< " brush=" << brush << " icon=" << icon << " atom=" << atom;
return cname;
@@ -687,7 +669,7 @@ void QWindowsContext::unregisterWindowClasses()
{
const auto appInstance = static_cast<HINSTANCE>(GetModuleHandle(nullptr));
- for (const QString &name : qAsConst(d->m_registeredWindowClassNames)) {
+ for (const QString &name : std::as_const(d->m_registeredWindowClassNames)) {
if (!UnregisterClass(reinterpret_cast<LPCWSTR>(name.utf16()), appInstance) && QWindowsContext::verbose)
qErrnoWarning("UnregisterClass failed for '%s'", qPrintable(name));
}
@@ -699,23 +681,6 @@ int QWindowsContext::screenDepth() const
return GetDeviceCaps(d->m_displayContext, BITSPIXEL);
}
-QString QWindowsContext::windowsErrorMessage(unsigned long errorCode)
-{
- QString rc = QString::fromLatin1("#%1: ").arg(errorCode);
- ushort *lpMsgBuf;
-
- const DWORD len = FormatMessage(
- FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
- nullptr, errorCode, 0, reinterpret_cast<LPTSTR>(&lpMsgBuf), 0, nullptr);
- if (len) {
- rc = QString::fromUtf16(lpMsgBuf, int(len));
- LocalFree(lpMsgBuf);
- } else {
- rc += QString::fromLatin1("<unknown error>");
- }
- return rc;
-}
-
void QWindowsContext::addWindow(HWND hwnd, QWindowsWindow *w)
{
d->m_windows.insert(hwnd, w);
@@ -819,6 +784,8 @@ static inline bool findPlatformWindowHelper(const POINT &screenPoint, unsigned c
if (!(cwexFlags & CWP_SKIPTRANSPARENT)
&& (GetWindowLongPtr(child, GWL_EXSTYLE) & WS_EX_TRANSPARENT)) {
const HWND nonTransparentChild = ChildWindowFromPointEx(*hwnd, point, cwexFlags | CWP_SKIPTRANSPARENT);
+ if (!nonTransparentChild || nonTransparentChild == *hwnd)
+ return false;
if (QWindowsWindow *nonTransparentWindow = context->findPlatformWindow(nonTransparentChild)) {
*result = nonTransparentWindow;
*hwnd = nonTransparentChild;
@@ -876,7 +843,7 @@ bool QWindowsContext::isSessionLocked()
return result;
}
-QWindowsMimeConverter &QWindowsContext::mimeConverter() const
+QWindowsMimeRegistry &QWindowsContext::mimeConverter() const
{
return d->m_mimeConverter;
}
@@ -914,103 +881,18 @@ HWND QWindowsContext::createDummyWindow(const QString &classNameIn,
HWND_MESSAGE, nullptr, static_cast<HINSTANCE>(GetModuleHandle(nullptr)), nullptr);
}
-// Re-engineered from the inline function _com_error::ErrorMessage().
-// We cannot use it directly since it uses swprintf_s(), which is not
-// present in the MSVCRT.DLL found on Windows XP (QTBUG-35617).
-static inline QString errorMessageFromComError(const _com_error &comError)
+void QWindowsContext::forceNcCalcSize(HWND hwnd)
{
- TCHAR *message = nullptr;
- FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
- nullptr, DWORD(comError.Error()), MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),
- message, 0, nullptr);
- if (message) {
- const QString result = QString::fromWCharArray(message).trimmed();
- LocalFree(static_cast<HLOCAL>(message));
- return result;
- }
- if (const WORD wCode = comError.WCode())
- return QString::asprintf("IDispatch error #%u", uint(wCode));
- return QString::asprintf("Unknown error 0x0%x", uint(comError.Error()));
-}
-
-/*!
- \brief Common COM error strings.
-*/
-
-QByteArray QWindowsContext::comErrorString(HRESULT hr)
-{
- QByteArray result = QByteArrayLiteral("COM error 0x")
- + QByteArray::number(quintptr(hr), 16) + ' ';
- switch (hr) {
- case S_OK:
- result += QByteArrayLiteral("S_OK");
- break;
- case S_FALSE:
- result += QByteArrayLiteral("S_FALSE");
- break;
- case E_UNEXPECTED:
- result += QByteArrayLiteral("E_UNEXPECTED");
- break;
- case E_ACCESSDENIED:
- result += QByteArrayLiteral("E_ACCESSDENIED");
- break;
- case CO_E_ALREADYINITIALIZED:
- result += QByteArrayLiteral("CO_E_ALREADYINITIALIZED");
- break;
- case CO_E_NOTINITIALIZED:
- result += QByteArrayLiteral("CO_E_NOTINITIALIZED");
- break;
- case RPC_E_CHANGED_MODE:
- result += QByteArrayLiteral("RPC_E_CHANGED_MODE");
- break;
- case OLE_E_WRONGCOMPOBJ:
- result += QByteArrayLiteral("OLE_E_WRONGCOMPOBJ");
- break;
- case CO_E_NOT_SUPPORTED:
- result += QByteArrayLiteral("CO_E_NOT_SUPPORTED");
- break;
- case E_NOTIMPL:
- result += QByteArrayLiteral("E_NOTIMPL");
- break;
- case E_INVALIDARG:
- result += QByteArrayLiteral("E_INVALIDARG");
- break;
- case E_NOINTERFACE:
- result += QByteArrayLiteral("E_NOINTERFACE");
- break;
- case E_POINTER:
- result += QByteArrayLiteral("E_POINTER");
- break;
- case E_HANDLE:
- result += QByteArrayLiteral("E_HANDLE");
- break;
- case E_ABORT:
- result += QByteArrayLiteral("E_ABORT");
- break;
- case E_FAIL:
- result += QByteArrayLiteral("E_FAIL");
- break;
- case RPC_E_WRONG_THREAD:
- result += QByteArrayLiteral("RPC_E_WRONG_THREAD");
- break;
- case RPC_E_THREAD_NOT_INIT:
- result += QByteArrayLiteral("RPC_E_THREAD_NOT_INIT");
- break;
- default:
- break;
- }
- _com_error error(hr);
- result += QByteArrayLiteral(" (");
- result += errorMessageFromComError(error).toUtf8();
- result += ')';
- return result;
+ // Force WM_NCCALCSIZE to adjust margin
+ SetWindowPos(hwnd, nullptr, 0, 0, 0, 0,
+ SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER);
}
bool QWindowsContext::systemParametersInfo(unsigned action, unsigned param, void *out,
unsigned dpi)
{
- const BOOL result = QWindowsContext::user32dll.systemParametersInfoForDpi != nullptr && dpi != 0
- ? QWindowsContext::user32dll.systemParametersInfoForDpi(action, param, out, 0, dpi)
+ const BOOL result = dpi != 0
+ ? SystemParametersInfoForDpi(action, param, out, 0, dpi)
: SystemParametersInfo(action, param, out, 0);
return result == TRUE;
}
@@ -1051,31 +933,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)
{
- return QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows10
- && window->isTopLevel()
+ // DPI aware V2 processes always have NonClientDpiScaling enabled.
+ if (QWindowsContextPrivate::m_v2DpiAware)
+ return true;
+
+ return window->isTopLevel()
&& !window->property(QWindowsWindow::embeddedNativeParentHandleProperty).isValid()
#if QT_CONFIG(opengl) // /QTBUG-62901, EnableNonClientDpiScaling has problems with GL
&& (window->surfaceType() != QSurface::OpenGLSurface
@@ -1111,6 +975,21 @@ static inline bool isInputMessage(UINT m)
|| (m >= WM_KEYFIRST && m <= WM_KEYLAST);
}
+// Note: This only works within WM_NCCREATE
+static bool enableNonClientDpiScaling(HWND hwnd)
+{
+ bool result = false;
+ if (QWindowsContext::windowDpiAwareness(hwnd) == QtWindows::DpiAwareness::PerMonitor) {
+ result = EnableNonClientDpiScaling(hwnd) != FALSE;
+ if (!result) {
+ const DWORD errorCode = GetLastError();
+ qErrnoWarning(int(errorCode), "EnableNonClientDpiScaling() failed for HWND %p (%lu)",
+ hwnd, errorCode);
+ }
+ }
+ return result;
+}
+
/*!
\brief Main windows procedure registered for windows.
@@ -1127,9 +1006,10 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
MSG msg;
msg.hwnd = hwnd; // re-create MSG structure
- msg.message = message; // time and pt fields ignored
+ msg.message = message;
msg.wParam = wParam;
msg.lParam = lParam;
+ msg.time = GetMessageTime();
msg.pt.x = msg.pt.y = 0;
if (et != QtWindows::CursorEvent && (et & (QtWindows::MouseEventFlag | QtWindows::NonClientEventFlag))) {
msg.pt.x = GET_X_LPARAM(lParam);
@@ -1208,28 +1088,25 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
#else
return false;
#endif
- case QtWindows::DisplayChangedEvent:
- if (QWindowsTheme *t = QWindowsTheme::instance())
- t->displayChanged();
- QWindowsWindow::displayChanged();
- return d->m_screenManager.handleDisplayChange(wParam, lParam);
case QtWindows::SettingChangedEvent: {
QWindowsWindow::settingsChanged();
- const bool darkMode = QWindowsTheme::queryDarkMode();
- if (darkMode != QWindowsContextPrivate::m_darkMode) {
+ // Only refresh the window theme if the user changes the personalize settings.
+ if ((wParam == 0) && (lParam != 0) // lParam sometimes may be NULL.
+ && (wcscmp(reinterpret_cast<LPCWSTR>(lParam), L"ImmersiveColorSet") == 0)) {
+ const bool darkMode = QWindowsTheme::queryDarkMode();
+ const bool darkModeChanged = darkMode != QWindowsContextPrivate::m_darkMode;
QWindowsContextPrivate::m_darkMode = darkMode;
- auto nativeInterface =
- static_cast<QWindowsNativeInterface *>(QWindowsIntegration::instance()->nativeInterface());
- emit nativeInterface->darkModeChanged(darkMode);
- const auto options = QWindowsIntegration::instance()->options();
- if ((options & QWindowsIntegration::DarkModeWindowFrames) != 0) {
- for (QWindowsWindow *w : d->m_windows)
- w->setDarkBorder(QWindowsContextPrivate::m_darkMode);
- }
- if ((options & QWindowsIntegration::DarkModeStyle) != 0) {
+ auto integration = QWindowsIntegration::instance();
+ integration->updateApplicationBadge();
+ if (integration->darkModeHandling().testFlag(QWindowsApplication::DarkModeStyle)) {
QWindowsTheme::instance()->refresh();
- for (QWindowsWindow *w : d->m_windows)
- QWindowSystemInterface::handleThemeChange(w->window());
+ QWindowSystemInterface::handleThemeChange();
+ }
+ if (darkModeChanged) {
+ if (integration->darkModeHandling().testFlag(QWindowsApplication::DarkModeWindowFrames)) {
+ for (QWindowsWindow *w : d->m_windows)
+ w->setDarkBorder(QWindowsContextPrivate::m_darkMode);
+ }
}
}
return d->m_screenManager.handleScreenChanges();
@@ -1247,14 +1124,18 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
d->m_creationContext->applyToMinMaxInfo(reinterpret_cast<MINMAXINFO *>(lParam));
return true;
case QtWindows::ResizeEvent:
- d->m_creationContext->obtainedSize = QSize(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
+ d->m_creationContext->obtainedSize = QSize(LOWORD(lParam), HIWORD(lParam));
return true;
case QtWindows::MoveEvent:
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);
@@ -1286,7 +1167,7 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
if (wParam == DBT_DEVNODES_CHANGED)
initTouch();
break;
- case QtWindows::KeyboardLayoutChangeEvent:
+ case QtWindows::InputLanguageChangeEvent:
if (QWindowsInputContext *wic = windowsInputContext())
wic->handleInputLanguageChanged(wParam, lParam);
Q_FALLTHROUGH();
@@ -1316,7 +1197,7 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
platformWindow->handleMoved();
return true;
case QtWindows::ResizeEvent:
- platformWindow->handleResized(static_cast<int>(wParam));
+ platformWindow->handleResized(static_cast<int>(wParam), lParam);
return true;
case QtWindows::QuerySizeHints:
platformWindow->getSizeHints(reinterpret_cast<MINMAXINFO *>(lParam));
@@ -1326,25 +1207,33 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
case QtWindows::NonClientHitTest:
return platformWindow->handleNonClientHitTest(QPoint(msg.pt.x, msg.pt.y), result);
case QtWindows::GeometryChangingEvent:
- return platformWindow->QWindowsWindow::handleGeometryChanging(&msg);
+ return platformWindow->handleGeometryChanging(&msg);
case QtWindows::ExposeEvent:
- return platformWindow->handleWmPaint(hwnd, message, wParam, lParam);
+ return platformWindow->handleWmPaint(hwnd, message, wParam, lParam, result);
case QtWindows::NonClientMouseEvent:
- if ((d->m_systemInfo & QWindowsContext::SI_SupportsPointer) && platformWindow->frameStrutEventsEnabled())
+ if (!platformWindow->frameStrutEventsEnabled())
+ break;
+ if ((d->m_systemInfo & QWindowsContext::SI_SupportsPointer))
return sessionManagerInteractionBlocked() || d->m_pointerHandler.translateMouseEvent(platformWindow->window(), hwnd, et, msg, result);
else
return sessionManagerInteractionBlocked() || d->m_mouseHandler.translateMouseEvent(platformWindow->window(), hwnd, et, msg, result);
case QtWindows::NonClientPointerEvent:
- if ((d->m_systemInfo & QWindowsContext::SI_SupportsPointer) && platformWindow->frameStrutEventsEnabled())
+ if (!platformWindow->frameStrutEventsEnabled())
+ break;
+ if ((d->m_systemInfo & QWindowsContext::SI_SupportsPointer))
return sessionManagerInteractionBlocked() || d->m_pointerHandler.translatePointerEvent(platformWindow->window(), hwnd, et, msg, result);
break;
case QtWindows::EnterSizeMoveEvent:
platformWindow->setFlag(QWindowsWindow::ResizeMoveActive);
+ if (!IsZoomed(hwnd))
+ platformWindow->updateRestoreGeometry();
return true;
case QtWindows::ExitSizeMoveEvent:
platformWindow->clearFlag(QWindowsWindow::ResizeMoveActive);
platformWindow->checkForScreenChanged();
handleExitSizeMove(platformWindow->window());
+ if (!IsZoomed(hwnd))
+ platformWindow->updateRestoreGeometry();
return true;
case QtWindows::ScrollEvent:
if (!(d->m_systemInfo & QWindowsContext::SI_SupportsPointer))
@@ -1390,6 +1279,7 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
QWindowSystemInterface::handleCloseEvent(platformWindow->window());
return true;
case QtWindows::ThemeChanged: {
+ QWindowsThemeCache::clearThemeCache(platformWindow->handle());
// Switch from Aero to Classic changes margins.
if (QWindowsTheme *theme = QWindowsTheme::instance())
theme->windowsThemeChanged(platformWindow->window());
@@ -1431,26 +1321,15 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
return true;
#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);
- }
- platformWindow->checkForScreenChanged(QWindowsWindow::FromDpiChange);
- return doResize;
- }
+ case QtWindows::DpiScaledSizeEvent:
+ platformWindow->handleDpiScaledSize(wParam, lParam, result);
+ return true;
+ case QtWindows::DpiChangedEvent:
+ platformWindow->handleDpiChanged(hwnd, wParam, lParam);
+ return true;
+ case QtWindows::DpiChangedAfterParentEvent:
+ platformWindow->handleDpiChangedAfterParent(hwnd);
+ return true;
#if QT_CONFIG(sessionmanager)
case QtWindows::QueryEndSessionApplicationEvent: {
QWindowsSessionManager *sessionManager = platformSessionManager();
@@ -1492,6 +1371,11 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
return true;
}
#endif // !defined(QT_NO_SESSIONMANAGER)
+ case QtWindows::TaskbarButtonCreated:
+ // Apply application badge if this is the first time we have a taskbar
+ // button, or after Explorer restart.
+ QWindowsIntegration::instance()->updateApplicationBadge();
+ break;
default:
break;
}
@@ -1534,7 +1418,7 @@ void QWindowsContext::handleFocusEvent(QtWindows::WindowsEventType et,
}
if (nextActiveWindow != d->m_lastActiveWindow) {
d->m_lastActiveWindow = nextActiveWindow;
- QWindowSystemInterface::handleWindowActivated(nextActiveWindow);
+ QWindowSystemInterface::handleFocusWindowChanged(nextActiveWindow, Qt::ActiveWindowFocusReason);
}
}
@@ -1564,7 +1448,7 @@ bool QWindowsContext::handleContextMenuEvent(QWindow *window, const MSG &msg)
}
QWindowSystemInterface::handleContextMenuEvent(window, mouseTriggered, pos, globalPos,
- QWindowsKeyMapper::queryKeyboardModifiers());
+ keyMapper()->queryKeyboardModifiers());
return true;
}
#endif
@@ -1585,7 +1469,7 @@ void QWindowsContext::handleExitSizeMove(QWindow *window)
const Qt::MouseButtons appButtons = QGuiApplication::mouseButtons();
if (currentButtons == appButtons)
return;
- const Qt::KeyboardModifiers keyboardModifiers = QWindowsKeyMapper::queryKeyboardModifiers();
+ const Qt::KeyboardModifiers keyboardModifiers = keyMapper()->queryKeyboardModifiers();
const QPoint globalPos = QWindowsCursor::mousePosition();
const QPlatformWindow *platWin = window->handle();
const QPoint localPos = platWin->mapFromGlobal(globalPos);
@@ -1594,8 +1478,7 @@ void QWindowsContext::handleExitSizeMove(QWindow *window)
for (Qt::MouseButton button : {Qt::LeftButton, Qt::RightButton, Qt::MiddleButton}) {
if (appButtons.testFlag(button) && !currentButtons.testFlag(button)) {
QWindowSystemInterface::handleMouseEvent(window, localPos, globalPos,
- currentButtons, button, type,
- keyboardModifiers);
+ currentButtons, button, type, keyboardModifiers);
}
}
if (d->m_systemInfo & QWindowsContext::SI_SupportsPointer)
@@ -1614,12 +1497,6 @@ void QWindowsContext::setAsyncExpose(bool value)
d->m_asyncExpose = value;
}
-QTouchDevice *QWindowsContext::touchDevice() const
-{
- return (d->m_systemInfo & QWindowsContext::SI_SupportsPointer) ?
- d->m_pointerHandler.touchDevice() : d->m_mouseHandler.touchDevice();
-}
-
DWORD QWindowsContext::readAdvancedExplorerSettings(const wchar_t *subKey, DWORD defaultValue)
{
const auto value =
@@ -1666,7 +1543,6 @@ static inline bool isTopLevel(HWND hwnd)
There is another one for timers, sockets, etc in
QEventDispatcherWin32.
- \ingroup qt-lighthouse-win
*/
extern "C" LRESULT QT_WIN_CALLBACK qWindowsWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
@@ -1696,7 +1572,7 @@ extern "C" LRESULT QT_WIN_CALLBACK qWindowsWndProc(HWND hwnd, UINT message, WPAR
marginsFromRects(ncCalcSizeFrame, rectFromNcCalcSize(message, wParam, lParam, 0));
if (margins.left() >= 0) {
if (platformWindow) {
- qCDebug(lcQpaWindows) << __FUNCTION__ << "WM_NCCALCSIZE for" << hwnd << margins;
+ qCDebug(lcQpaWindow) << __FUNCTION__ << "WM_NCCALCSIZE for" << hwnd << margins;
platformWindow->setFullFrameMargins(margins);
} else {
const QSharedPointer<QWindowCreationContext> ctx = QWindowsContext::instance()->windowCreationContext();
@@ -1715,11 +1591,7 @@ static inline QByteArray nativeEventType() { return QByteArrayLiteral("windows_g
bool QWindowsContext::filterNativeEvent(MSG *msg, LRESULT *result)
{
QAbstractEventDispatcher *dispatcher = QAbstractEventDispatcher::instance();
-#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
qintptr filterResult = 0;
-#else
- long filterResult = 0;
-#endif
if (dispatcher && dispatcher->filterNativeEvent(nativeEventType(), msg, &filterResult)) {
*result = LRESULT(filterResult);
return true;
@@ -1730,11 +1602,7 @@ bool QWindowsContext::filterNativeEvent(MSG *msg, LRESULT *result)
// Send to QWindowSystemInterface
bool QWindowsContext::filterNativeEvent(QWindow *window, MSG *msg, LRESULT *result)
{
-#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
qintptr filterResult = 0;
-#else
- long filterResult = 0;
-#endif
if (QWindowSystemInterface::handleNativeEvent(window, nativeEventType(), msg, &filterResult)) {
*result = LRESULT(filterResult);
return true;
diff --git a/src/plugins/platforms/windows/qwindowscontext.h b/src/plugins/platforms/windows/qwindowscontext.h
index 1831ac6ec0..1089224433 100644
--- a/src/plugins/platforms/windows/qwindowscontext.h
+++ b/src/plugins/platforms/windows/qwindowscontext.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QWINDOWSCONTEXT_H
#define QWINDOWSCONTEXT_H
@@ -51,12 +15,9 @@
#include <shlobj.h>
#include <shlwapi.h>
-struct IBindCtx;
-struct _SHSTOCKICONINFO;
-
QT_BEGIN_NAMESPACE
-Q_DECLARE_LOGGING_CATEGORY(lcQpaWindows)
+Q_DECLARE_LOGGING_CATEGORY(lcQpaWindow)
Q_DECLARE_LOGGING_CATEGORY(lcQpaEvents)
Q_DECLARE_LOGGING_CATEGORY(lcQpaGl)
Q_DECLARE_LOGGING_CATEGORY(lcQpaMime)
@@ -67,96 +28,27 @@ Q_DECLARE_LOGGING_CATEGORY(lcQpaTablet)
Q_DECLARE_LOGGING_CATEGORY(lcQpaAccessibility)
Q_DECLARE_LOGGING_CATEGORY(lcQpaUiAutomation)
Q_DECLARE_LOGGING_CATEGORY(lcQpaTrayIcon)
+Q_DECLARE_LOGGING_CATEGORY(lcQpaScreen)
class QWindow;
class QPlatformScreen;
class QPlatformWindow;
+class QPlatformKeyMapper;
class QWindowsMenuBar;
class QWindowsScreenManager;
class QWindowsTabletSupport;
class QWindowsWindow;
-class QWindowsMimeConverter;
+class QWindowsMimeRegistry;
struct QWindowCreationContext;
struct QWindowsContextPrivate;
class QPoint;
class QKeyEvent;
-class QTouchDevice;
-
-struct QWindowsUser32DLL
-{
- inline void init();
- inline bool supportsPointerApi();
-
- typedef BOOL (WINAPI *EnableMouseInPointer)(BOOL);
- typedef BOOL (WINAPI *GetPointerType)(UINT32, PVOID);
- typedef BOOL (WINAPI *GetPointerInfo)(UINT32, PVOID);
- typedef BOOL (WINAPI *GetPointerDeviceRects)(HANDLE, RECT *, RECT *);
- typedef BOOL (WINAPI *GetPointerTouchInfo)(UINT32, PVOID);
- typedef BOOL (WINAPI *GetPointerFrameTouchInfo)(UINT32, UINT32 *, PVOID);
- typedef BOOL (WINAPI *GetPointerFrameTouchInfoHistory)(UINT32, UINT32 *, UINT32 *, PVOID);
- typedef BOOL (WINAPI *GetPointerPenInfo)(UINT32, PVOID);
- typedef BOOL (WINAPI *GetPointerPenInfoHistory)(UINT32, UINT32 *, PVOID);
- typedef BOOL (WINAPI *SkipPointerFrameMessages)(UINT32);
- typedef BOOL (WINAPI *SetProcessDPIAware)();
- typedef BOOL (WINAPI *AddClipboardFormatListener)(HWND);
- typedef BOOL (WINAPI *RemoveClipboardFormatListener)(HWND);
- typedef BOOL (WINAPI *GetDisplayAutoRotationPreferences)(DWORD *);
- typedef BOOL (WINAPI *SetDisplayAutoRotationPreferences)(DWORD);
- typedef BOOL (WINAPI *AdjustWindowRectExForDpi)(LPRECT,DWORD,BOOL,DWORD,UINT);
- typedef BOOL (WINAPI *EnableNonClientDpiScaling)(HWND);
- typedef int (WINAPI *GetWindowDpiAwarenessContext)(HWND);
- typedef int (WINAPI *GetAwarenessFromDpiAwarenessContext)(int);
- typedef BOOL (WINAPI *SystemParametersInfoForDpi)(UINT, UINT, PVOID, UINT, UINT);
-
- // Windows pointer functions (Windows 8 or later).
- EnableMouseInPointer enableMouseInPointer = nullptr;
- GetPointerType getPointerType = nullptr;
- GetPointerInfo getPointerInfo = nullptr;
- GetPointerDeviceRects getPointerDeviceRects = nullptr;
- GetPointerTouchInfo getPointerTouchInfo = nullptr;
- GetPointerFrameTouchInfo getPointerFrameTouchInfo = nullptr;
- GetPointerFrameTouchInfoHistory getPointerFrameTouchInfoHistory = nullptr;
- GetPointerPenInfo getPointerPenInfo = nullptr;
- GetPointerPenInfoHistory getPointerPenInfoHistory = nullptr;
- SkipPointerFrameMessages skipPointerFrameMessages = nullptr;
-
- // Windows Vista onwards
- SetProcessDPIAware setProcessDPIAware = nullptr;
-
- // Clipboard listeners are present on Windows Vista onwards
- // but missing in MinGW 4.9 stub libs. Can be removed in MinGW 5.
- AddClipboardFormatListener addClipboardFormatListener = nullptr;
- RemoveClipboardFormatListener removeClipboardFormatListener = nullptr;
-
- // Rotation API
- GetDisplayAutoRotationPreferences getDisplayAutoRotationPreferences = nullptr;
- SetDisplayAutoRotationPreferences setDisplayAutoRotationPreferences = nullptr;
-
- AdjustWindowRectExForDpi adjustWindowRectExForDpi = nullptr;
- EnableNonClientDpiScaling enableNonClientDpiScaling = nullptr;
- GetWindowDpiAwarenessContext getWindowDpiAwarenessContext = nullptr;
- GetAwarenessFromDpiAwarenessContext getAwarenessFromDpiAwarenessContext = nullptr;
- SystemParametersInfoForDpi systemParametersInfoForDpi = nullptr;
-};
-
-// Shell scaling library (Windows 8.1 onwards)
-struct QWindowsShcoreDLL {
- void init();
- inline bool isValid() const { return getProcessDpiAwareness && setProcessDpiAwareness && getDpiForMonitor; }
-
- typedef HRESULT (WINAPI *GetProcessDpiAwareness)(HANDLE,int *);
- typedef HRESULT (WINAPI *SetProcessDpiAwareness)(int);
- typedef HRESULT (WINAPI *GetDpiForMonitor)(HMONITOR,int,UINT *,UINT *);
-
- GetProcessDpiAwareness getProcessDpiAwareness = nullptr;
- SetProcessDpiAwareness setProcessDpiAwareness = nullptr;
- GetDpiForMonitor getDpiForMonitor = nullptr;
-};
-
+class QPointingDevice;
class QWindowsContext
{
Q_DISABLE_COPY_MOVE(QWindowsContext)
public:
+ using HandleBaseWindowHash = QHash<HWND, QWindowsWindow *>;
enum SystemInfoFlags
{
@@ -173,8 +65,10 @@ public:
bool initTouch();
bool initTouch(unsigned integrationOptions); // For calls from QWindowsIntegration::QWindowsIntegration() only.
- bool initTablet(unsigned integrationOptions);
+ void registerTouchWindows();
+ bool initTablet();
bool initPointer(unsigned integrationOptions);
+ bool disposeTablet();
bool initPowerNotificationHandler();
@@ -194,8 +88,6 @@ public:
static QWindowsContext *instance();
- static QString windowsErrorMessage(unsigned long errorCode);
-
void addWindow(HWND, QWindowsWindow *w);
void removeWindow(HWND);
@@ -222,9 +114,11 @@ public:
QSharedPointer<QWindowCreationContext> setWindowCreationContext(const QSharedPointer<QWindowCreationContext> &ctx);
QSharedPointer<QWindowCreationContext> windowCreationContext() const;
- void setTabletAbsoluteRange(int a);
- void setProcessDpiAwareness(QtWindows::ProcessDpiAwareness dpiAwareness);
- static int processDpiAwareness();
+ static void setTabletAbsoluteRange(int a);
+
+ static bool setProcessDpiAwareness(QtWindows::DpiAwareness dpiAwareness);
+ static QtWindows::DpiAwareness processDpiAwareness();
+ static QtWindows::DpiAwareness windowDpiAwareness(HWND hwnd);
static bool isDarkMode();
@@ -234,21 +128,21 @@ public:
unsigned systemInfo() const;
bool useRTLExtensions() const;
- QList<int> possibleKeys(const QKeyEvent *e) const;
+ QPlatformKeyMapper *keyMapper() const;
+
+ HandleBaseWindowHash &windows();
static bool isSessionLocked();
- QWindowsMimeConverter &mimeConverter() const;
+ QWindowsMimeRegistry &mimeConverter() const;
QWindowsScreenManager &screenManager();
QWindowsTabletSupport *tabletSupport() const;
- static QWindowsUser32DLL user32dll;
- static QWindowsShcoreDLL shcoredll;
-
- static QByteArray comErrorString(HRESULT hr);
bool asyncExpose() const;
void setAsyncExpose(bool value);
+ static void forceNcCalcSize(HWND hwnd);
+
static bool systemParametersInfo(unsigned action, unsigned param, void *out, unsigned dpi = 0);
static bool systemParametersInfoForScreen(unsigned action, unsigned param, void *out,
const QPlatformScreen *screen = nullptr);
@@ -262,8 +156,6 @@ public:
static DWORD readAdvancedExplorerSettings(const wchar_t *subKey, DWORD defaultValue);
- QTouchDevice *touchDevice() const;
-
static bool filterNativeEvent(MSG *msg, LRESULT *result);
static bool filterNativeEvent(QWindow *window, MSG *msg, LRESULT *result);
diff --git a/src/plugins/platforms/windows/qwindowscursor.cpp b/src/plugins/platforms/windows/qwindowscursor.cpp
index 19de3d5939..b416886120 100644
--- a/src/plugins/platforms/windows/qwindowscursor.cpp
+++ b/src/plugins/platforms/windows/qwindowscursor.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QT_NO_CURSOR
#include "qwindowscursor.h"
@@ -50,6 +14,7 @@
#include <QtGui/qscreen.h>
#include <QtGui/private/qguiapplication_p.h> // getPixmapCursor()
#include <QtGui/private/qhighdpiscaling_p.h>
+#include <QtGui/private/qpixmap_win_p.h>
#include <QtCore/private/qwinregistry_p.h>
#include <QtCore/qdebug.h>
@@ -65,25 +30,23 @@ static bool initResources()
QT_BEGIN_NAMESPACE
-Q_GUI_EXPORT HBITMAP qt_pixmapToWinHBITMAP(const QPixmap &p, int hbitmapFormat = 0);
-Q_GUI_EXPORT HBITMAP qt_createIconMask(const QBitmap &bitmap);
+using namespace Qt::Literals::StringLiterals;
/*!
\class QWindowsCursorCacheKey
\brief Cache key for storing values in a QHash with a QCursor as key.
\internal
- \ingroup qt-lighthouse-win
*/
QWindowsPixmapCursorCacheKey::QWindowsPixmapCursorCacheKey(const QCursor &c)
: bitmapCacheKey(c.pixmap().cacheKey()), maskCacheKey(0)
{
if (!bitmapCacheKey) {
- Q_ASSERT(!c.bitmap(Qt::ReturnByValue).isNull());
- Q_ASSERT(!c.mask(Qt::ReturnByValue).isNull());
- bitmapCacheKey = c.bitmap(Qt::ReturnByValue).cacheKey();
- maskCacheKey = c.mask(Qt::ReturnByValue).cacheKey();
+ Q_ASSERT(!c.bitmap().isNull());
+ Q_ASSERT(!c.mask().isNull());
+ bitmapCacheKey = c.bitmap().cacheKey();
+ maskCacheKey = c.mask().cacheKey();
}
}
@@ -97,14 +60,13 @@ QWindowsPixmapCursorCacheKey::QWindowsPixmapCursorCacheKey(const QCursor &c)
as do the Window manager frames (resize/move handles).
\internal
- \ingroup qt-lighthouse-win
\sa QWindowsWindowCursor
*/
HCURSOR QWindowsCursor::createPixmapCursor(QPixmap pixmap, const QPoint &hotSpot, qreal scaleFactor)
{
HCURSOR cur = nullptr;
- const qreal pixmapScaleFactor = scaleFactor / pixmap.devicePixelRatioF();
+ const qreal pixmapScaleFactor = scaleFactor / pixmap.devicePixelRatio();
if (!qFuzzyCompare(pixmapScaleFactor, 1)) {
pixmap = pixmap.scaled((pixmapScaleFactor * QSizeF(pixmap.size())).toSize(),
Qt::KeepAspectRatio, Qt::SmoothTransformation);
@@ -143,14 +105,16 @@ static HCURSOR createBitmapCursor(const QImage &bbits, const QImage &mbits,
hotSpot.setX(width / 2);
if (hotSpot.y() < 0)
hotSpot.setY(height / 2);
- const int n = qMax(1, width / 8);
- QScopedArrayPointer<uchar> xBits(new uchar[height * n]);
- QScopedArrayPointer<uchar> xMask(new uchar[height * n]);
+ // a ddb is word aligned, QImage depends on bow it was created
+ const auto bplDdb = qMax(1, ((width + 15) >> 4) << 1);
+ const auto bplImg = int(bbits.bytesPerLine());
+ QScopedArrayPointer<uchar> xBits(new uchar[height * bplDdb]);
+ QScopedArrayPointer<uchar> xMask(new uchar[height * bplDdb]);
int x = 0;
for (int i = 0; i < height; ++i) {
const uchar *bits = bbits.constScanLine(i);
const uchar *mask = mbits.constScanLine(i);
- for (int j = 0; j < n; ++j) {
+ for (int j = 0; j < bplImg && j < bplDdb; ++j) {
uchar b = bits[j];
uchar m = mask[j];
if (invb)
@@ -161,6 +125,11 @@ static HCURSOR createBitmapCursor(const QImage &bbits, const QImage &mbits,
xMask[x] = b ^ m;
++x;
}
+ for (int i = bplImg; i < bplDdb; ++i) {
+ xBits[x] = 0;
+ xMask[x] = 0;
+ ++x;
+ }
}
return CreateCursor(GetModuleHandle(nullptr), hotSpot.x(), hotSpot.y(), width, height,
xBits.data(), xMask.data());
@@ -169,17 +138,17 @@ static HCURSOR createBitmapCursor(const QImage &bbits, const QImage &mbits,
// Create a cursor from image and mask of the format QImage::Format_Mono.
static HCURSOR createBitmapCursor(const QCursor &cursor, qreal scaleFactor = 1)
{
- Q_ASSERT(cursor.shape() == Qt::BitmapCursor && !cursor.bitmap(Qt::ReturnByValue).isNull());
- QImage bbits = cursor.bitmap(Qt::ReturnByValue).toImage();
- QImage mbits = cursor.mask(Qt::ReturnByValue).toImage();
- scaleFactor /= bbits.devicePixelRatioF();
+ Q_ASSERT(cursor.shape() == Qt::BitmapCursor && !cursor.bitmap().isNull());
+ QImage bbits = cursor.bitmap().toImage();
+ QImage mbits = cursor.mask().toImage();
+ scaleFactor /= bbits.devicePixelRatio();
if (!qFuzzyCompare(scaleFactor, 1)) {
const QSize scaledSize = (QSizeF(bbits.size()) * scaleFactor).toSize();
bbits = bbits.scaled(scaledSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
mbits = mbits.scaled(scaledSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
}
- bbits = bbits.convertToFormat(QImage::Format_Mono);
- mbits = mbits.convertToFormat(QImage::Format_Mono);
+ bbits = std::move(bbits).convertToFormat(QImage::Format_Mono);
+ mbits = std::move(mbits).convertToFormat(QImage::Format_Mono);
const bool invb = bbits.colorCount() > 1 && qGray(bbits.color(0)) < qGray(bbits.color(1));
const bool invm = mbits.colorCount() > 1 && qGray(mbits.color(0)) < qGray(mbits.color(1));
return createBitmapCursor(bbits, mbits, cursor.hotSpot(), invb, invm);
@@ -476,8 +445,8 @@ QWindowsCursor::PixmapCursor QWindowsCursor::customCursor(Qt::CursorShape cursor
if (!bestFit)
return PixmapCursor();
- const QPixmap rawImage(QStringLiteral(":/qt-project.org/windows/cursors/images/") +
- QString::fromLatin1(bestFit->fileName));
+ const QPixmap rawImage(":/qt-project.org/windows/cursors/images/"_L1 +
+ QLatin1StringView(bestFit->fileName));
return PixmapCursor(rawImage, QPoint(bestFit->hotSpotX, bestFit->hotSpotY));
}
#endif // !QT_NO_IMAGEFORMAT_PNG
@@ -590,7 +559,7 @@ QWindowsCursor::QWindowsCursor(const QPlatformScreen *screen)
: m_screen(screen)
{
static const bool dummy = initResources();
- Q_UNUSED(dummy)
+ Q_UNUSED(dummy);
}
inline CursorHandlePtr QWindowsCursor::cursorHandle(const QCursor &cursor)
@@ -654,6 +623,11 @@ void QWindowsCursor::clearOverrideCursor()
SetCursor(m_overriddenCursor);
m_overriddenCursor = m_overrideCursor = nullptr;
}
+ auto &windows = QWindowsContext::instance()->windows();
+ for (auto it = windows.cbegin(), end = windows.cend(); it != end; ++it) {
+ if (it.value()->screen() == m_screen)
+ it.value()->setFlag(QWindowsWindow::RestoreOverrideCursor);
+ }
}
QPoint QWindowsCursor::mousePosition()
@@ -816,7 +790,6 @@ HCURSOR QWindowsCursor::hCursor(const QCursor &c) const
cursor handle resource.
\internal
- \ingroup qt-lighthouse-win
\sa QWindowsCursor
*/
diff --git a/src/plugins/platforms/windows/qwindowscursor.h b/src/plugins/platforms/windows/qwindowscursor.h
index cf3635bd6b..d5c0388d1d 100644
--- a/src/plugins/platforms/windows/qwindowscursor.h
+++ b/src/plugins/platforms/windows/qwindowscursor.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QWINDOWSCURSOR_H
#define QWINDOWSCURSOR_H
@@ -61,9 +25,9 @@ inline bool operator==(const QWindowsPixmapCursorCacheKey &k1, const QWindowsPix
return k1.bitmapCacheKey == k2.bitmapCacheKey && k1.maskCacheKey == k2.maskCacheKey;
}
-inline uint qHash(const QWindowsPixmapCursorCacheKey &k, uint seed) noexcept
+inline size_t qHash(const QWindowsPixmapCursorCacheKey &k, size_t seed) noexcept
{
- return (uint(k.bitmapCacheKey) + uint(k.maskCacheKey)) ^ seed;
+ return (size_t(k.bitmapCacheKey) + size_t(k.maskCacheKey)) ^ seed;
}
class CursorHandle
diff --git a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp
index b038e19689..0ce0b0e2a7 100644
--- a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp
+++ b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp
@@ -1,49 +1,9 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#define QT_NO_URL_CAST_FROM_STRING 1
-#ifndef _WIN32_WINNT
-#define _WIN32_WINNT 0x0601
-#endif
-
-#include "qwindowscombase.h"
+#include <QtCore/qt_windows.h>
#include "qwindowsdialoghelpers.h"
#include "qwindowscontext.h"
@@ -55,7 +15,9 @@
#include <QtGui/qcolor.h>
#include <QtCore/qdebug.h>
-#include <QtCore/qregularexpression.h>
+#if QT_CONFIG(regularexpression)
+# include <QtCore/qregularexpression.h>
+#endif
#include <QtCore/qtimer.h>
#include <QtCore/qdir.h>
#include <QtCore/qscopedpointer.h>
@@ -68,44 +30,18 @@
#include <QtCore/qmutex.h>
#include <QtCore/quuid.h>
#include <QtCore/qtemporaryfile.h>
-#include <QtCore/private/qsystemlibrary_p.h>
+#include <QtCore/private/qfunctions_win_p.h>
+#include <QtCore/private/qsystemerror_p.h>
+#include <QtCore/private/qcomobject_p.h>
#include <algorithm>
#include <vector>
-#include <QtCore/qt_windows.h>
-
// #define USE_NATIVE_COLOR_DIALOG /* Testing purposes only */
QT_BEGIN_NAMESPACE
-#ifndef QT_NO_DEBUG_STREAM
-/* Output UID (IID, CLSID) as C++ constants.
- * The constants are contained in the Windows SDK libs, but not for MinGW. */
-static inline QString guidToString(const GUID &g)
-{
- QString rc;
- QTextStream str(&rc);
- str.setIntegerBase(16);
- str.setNumberFlags(str.numberFlags() | QTextStream::ShowBase);
- str << '{' << g.Data1 << ", " << g.Data2 << ", " << g.Data3;
- str.setFieldWidth(2);
- str.setFieldAlignment(QTextStream::AlignRight);
- str.setPadChar(u'0');
- str << ",{" << g.Data4[0] << ", " << g.Data4[1] << ", " << g.Data4[2] << ", " << g.Data4[3]
- << ", " << g.Data4[4] << ", " << g.Data4[5] << ", " << g.Data4[6] << ", " << g.Data4[7]
- << "}};";
- return rc;
-}
-
-inline QDebug operator<<(QDebug d, const GUID &g)
-{
- QDebugStateSaver saver(d);
- d.nospace();
- d << guidToString(g);
- return d;
-}
-#endif // !QT_NO_DEBUG_STREAM
+using namespace Qt::StringLiterals;
// Return an allocated wchar_t array from a QString, reserve more memory if desired.
static wchar_t *qStringToWCharArray(const QString &s, size_t reserveSize = 0)
@@ -128,7 +64,6 @@ namespace QWindowsDialogs
remove all those messages (usually 1) and post the last one with a
reset button state.
- \ingroup qt-lighthouse-win
*/
void eatMouseMove()
@@ -141,6 +76,22 @@ void eatMouseMove()
qCDebug(lcQpaDialogs) << __FUNCTION__ << "triggered=" << (msg.message == WM_MOUSEMOVE);
}
+HWND getHWND(IFileDialog *fileDialog)
+{
+ IOleWindow *oleWindow = nullptr;
+ if (FAILED(fileDialog->QueryInterface(IID_IOleWindow, reinterpret_cast<void **>(&oleWindow)))) {
+ qCWarning(lcQpaDialogs, "Native file dialog: unable to query IID_IOleWindow interface.");
+ return HWND(0);
+ }
+
+ HWND result(0);
+ if (FAILED(oleWindow->GetWindow(&result)))
+ qCWarning(lcQpaDialogs, "Native file dialog: unable to get dialog's window.");
+
+ oleWindow->Release();
+ return result;
+}
+
} // namespace QWindowsDialogs
/*!
@@ -149,7 +100,7 @@ void eatMouseMove()
Base classes for native dialogs (using the CLSID-based
dialog interfaces "IFileDialog", etc. available from Windows
- Vista on) that mimick the behaviour of their QDialog
+ Vista on) that mimic the behavior of their QDialog
counterparts as close as possible.
Instances of derived classes are controlled by
@@ -171,7 +122,6 @@ void eatMouseMove()
\sa QWindowsDialogHelperBase
\internal
- \ingroup qt-lighthouse-win
*/
class QWindowsNativeDialogBase : public QObject
@@ -211,24 +161,28 @@ private:
\sa QWindowsDialogThread, QWindowsNativeDialogBase
\internal
- \ingroup qt-lighthouse-win
*/
template <class BaseClass>
+QWindowsDialogHelperBase<BaseClass>::~QWindowsDialogHelperBase()
+{
+ hide();
+ cleanupThread();
+}
+
+template <class BaseClass>
void QWindowsDialogHelperBase<BaseClass>::cleanupThread()
{
- if (m_thread) { // Thread may be running if the dialog failed to close.
- if (m_thread->isRunning())
- m_thread->wait(500);
- if (m_thread->isRunning()) {
- m_thread->terminate();
- m_thread->wait(300);
- if (m_thread->isRunning())
- qCCritical(lcQpaDialogs) <<__FUNCTION__ << "Failed to terminate thread.";
- else
- qCWarning(lcQpaDialogs) << __FUNCTION__ << "Thread terminated.";
- }
- delete m_thread;
+ if (m_thread) {
+ // Thread may be running if the dialog failed to close. Give it a bit
+ // to exit, but let it be a memory leak if that fails. We must not
+ // terminate the thread, it might be stuck in Comdlg32 or an IModalWindow
+ // implementation, and we might end up dead-locking the application if the thread
+ // holds a mutex or critical section.
+ if (m_thread->wait(500))
+ delete m_thread;
+ else
+ qCCritical(lcQpaDialogs) <<__FUNCTION__ << "Thread failed to finish.";
m_thread = nullptr;
}
}
@@ -255,7 +209,7 @@ QWindowsNativeDialogBase *QWindowsDialogHelperBase<BaseClass>::ensureNativeDialo
// Create dialog and apply common settings. Check "executed" flag as well
// since for example IFileDialog::Show() works only once.
if (m_nativeDialog.isNull() || m_nativeDialog->executed())
- m_nativeDialog = QWindowsNativeDialogBasePtr(createNativeDialog());
+ m_nativeDialog = QWindowsNativeDialogBasePtr(createNativeDialog(), &QObject::deleteLater);
return m_nativeDialog.data();
}
@@ -265,7 +219,6 @@ QWindowsNativeDialogBase *QWindowsDialogHelperBase<BaseClass>::ensureNativeDialo
\sa QWindowsDialogHelperBase
\internal
- \ingroup qt-lighthouse-win
*/
class QWindowsDialogThread : public QThread
@@ -275,7 +228,7 @@ public:
explicit QWindowsDialogThread(const QWindowsNativeDialogBasePtr &d, HWND owner)
: m_dialog(d), m_owner(owner) {}
- void run();
+ void run() override;
private:
const QWindowsNativeDialogBasePtr m_dialog;
@@ -285,6 +238,7 @@ private:
void QWindowsDialogThread::run()
{
qCDebug(lcQpaDialogs) << '>' << __FUNCTION__;
+ QComHelper comInit(COINIT_APARTMENTTHREADED);
m_dialog->exec(m_owner);
qCDebug(lcQpaDialogs) << '<' << __FUNCTION__;
}
@@ -341,47 +295,13 @@ void QWindowsDialogHelperBase<BaseClass>::stopTimer()
}
}
-// Find a file dialog window created by IFileDialog by process id, window
-// title and class, which starts with a hash '#'.
-
-struct FindDialogContext
-{
- explicit FindDialogContext(const QString &titleIn)
- : title(qStringToWCharArray(titleIn)), processId(GetCurrentProcessId()), hwnd(nullptr) {}
-
- const QScopedArrayPointer<wchar_t> title;
- const DWORD processId;
- HWND hwnd; // contains the HWND of the window found.
-};
-
-static BOOL QT_WIN_CALLBACK findDialogEnumWindowsProc(HWND hwnd, LPARAM lParam)
-{
- auto *context = reinterpret_cast<FindDialogContext *>(lParam);
- DWORD winPid = 0;
- GetWindowThreadProcessId(hwnd, &winPid);
- if (winPid != context->processId)
- return TRUE;
- wchar_t buf[256];
- if (!RealGetWindowClass(hwnd, buf, sizeof(buf)/sizeof(wchar_t)) || buf[0] != L'#')
- return TRUE;
- if (!GetWindowTextW(hwnd, buf, sizeof(buf)/sizeof(wchar_t)) || wcscmp(buf, context->title.data()) != 0)
- return TRUE;
- context->hwnd = hwnd;
- return FALSE;
-}
-
-static inline HWND findDialogWindow(const QString &title)
-{
- FindDialogContext context(title);
- EnumWindows(findDialogEnumWindowsProc, reinterpret_cast<LPARAM>(&context));
- return context.hwnd;
-}
-
template <class BaseClass>
void QWindowsDialogHelperBase<BaseClass>::hide()
{
- if (m_nativeDialog)
+ if (m_nativeDialog) {
m_nativeDialog->close();
+ m_nativeDialog.clear();
+ }
m_ownerWindow = nullptr;
}
@@ -406,7 +326,6 @@ void QWindowsDialogHelperBase<BaseClass>::exec()
does not reliably work. Provides thread-safe setters (for the non-modal case).
\internal
- \ingroup qt-lighthouse-win
\sa QFileDialogOptions
*/
@@ -500,26 +419,31 @@ inline void QWindowsFileDialogSharedData::fromOptions(const QSharedPointer<QFile
\sa QWindowsNativeFileDialogBase, QWindowsFileDialogHelper
\internal
- \ingroup qt-lighthouse-win
*/
class QWindowsNativeFileDialogBase;
-class QWindowsNativeFileDialogEventHandler : public QWindowsComBase<IFileDialogEvents>
+class QWindowsNativeFileDialogEventHandler : public QComObject<IFileDialogEvents>
{
Q_DISABLE_COPY_MOVE(QWindowsNativeFileDialogEventHandler)
public:
static IFileDialogEvents *create(QWindowsNativeFileDialogBase *nativeFileDialog);
// IFileDialogEvents methods
- IFACEMETHODIMP OnFileOk(IFileDialog *);
- IFACEMETHODIMP OnFolderChange(IFileDialog *) { return S_OK; }
- IFACEMETHODIMP OnFolderChanging(IFileDialog *, IShellItem *);
- IFACEMETHODIMP OnHelp(IFileDialog *) { return S_OK; }
- IFACEMETHODIMP OnSelectionChange(IFileDialog *);
- IFACEMETHODIMP OnShareViolation(IFileDialog *, IShellItem *, FDE_SHAREVIOLATION_RESPONSE *) { return S_OK; }
- IFACEMETHODIMP OnTypeChange(IFileDialog *);
- IFACEMETHODIMP OnOverwrite(IFileDialog *, IShellItem *, FDE_OVERWRITE_RESPONSE *) { return S_OK; }
+ IFACEMETHODIMP OnFileOk(IFileDialog *) override;
+ IFACEMETHODIMP OnFolderChange(IFileDialog *) override { return S_OK; }
+ IFACEMETHODIMP OnFolderChanging(IFileDialog *, IShellItem *) override;
+ IFACEMETHODIMP OnSelectionChange(IFileDialog *) override;
+ IFACEMETHODIMP OnShareViolation(IFileDialog *, IShellItem *,
+ FDE_SHAREVIOLATION_RESPONSE *) override
+ {
+ return S_OK;
+ }
+ IFACEMETHODIMP OnTypeChange(IFileDialog *) override;
+ IFACEMETHODIMP OnOverwrite(IFileDialog *, IShellItem *, FDE_OVERWRITE_RESPONSE *) override
+ {
+ return S_OK;
+ }
QWindowsNativeFileDialogEventHandler(QWindowsNativeFileDialogBase *nativeFileDialog) :
m_nativeFileDialog(nativeFileDialog) {}
@@ -546,7 +470,6 @@ IFileDialogEvents *QWindowsNativeFileDialogEventHandler::create(QWindowsNativeFi
\sa QWindowsNativeFileDialogBase
\internal
- \ingroup qt-lighthouse-win
*/
class QWindowsShellItem
{
@@ -593,8 +516,18 @@ QWindowsShellItem::QWindowsShellItem(IShellItem *item)
: m_item(item)
, m_attributes(0)
{
- if (FAILED(item->GetAttributes(SFGAO_CAPABILITYMASK | SFGAO_DISPLAYATTRMASK | SFGAO_CONTENTSMASK | SFGAO_STORAGECAPMASK, &m_attributes)))
+ SFGAOF mask = (SFGAO_CAPABILITYMASK | SFGAO_CONTENTSMASK | SFGAO_STORAGECAPMASK);
+
+ // Check for attributes which might be expensive to enumerate for subfolders
+ if (FAILED(item->GetAttributes((SFGAO_STREAM | SFGAO_COMPRESSED), &m_attributes))) {
m_attributes = 0;
+ } else {
+ // If the item is compressed or stream, skip expensive subfolder test
+ if (m_attributes & (SFGAO_STREAM | SFGAO_COMPRESSED))
+ mask &= ~SFGAO_HASSUBFOLDER;
+ if (FAILED(item->GetAttributes(mask, &m_attributes)))
+ m_attributes = 0;
+ }
}
QString QWindowsShellItem::path() const
@@ -633,8 +566,8 @@ QUrl QWindowsShellItem::url() const
if (urlV.isValid())
return urlV;
// Last resort: encode the absolute desktop parsing id as data URL
- const QString data = QStringLiteral("data:text/plain;base64,")
- + QLatin1String(desktopAbsoluteParsing().toLatin1().toBase64());
+ const QString data = "data:text/plain;base64,"_L1
+ + QLatin1StringView(desktopAbsoluteParsing().toLatin1().toBase64());
return QUrl(data);
}
@@ -667,14 +600,14 @@ QWindowsShellItem::IShellItems QWindowsShellItem::itemsFromItemArray(IShellItemA
bool QWindowsShellItem::copyData(QIODevice *out, QString *errorMessage)
{
if (!canStream()) {
- *errorMessage = QLatin1String("Item not streamable");
+ *errorMessage = "Item not streamable"_L1;
return false;
}
IStream *istream = nullptr;
HRESULT hr = m_item->BindToHandler(nullptr, BHID_Stream, IID_PPV_ARGS(&istream));
if (FAILED(hr)) {
- *errorMessage = QLatin1String("BindToHandler() failed: ")
- + QLatin1String(QWindowsContext::comErrorString(hr));
+ *errorMessage = "BindToHandler() failed: "_L1
+ + QSystemError::windowsComString(hr);
return false;
}
enum : ULONG { bufSize = 102400 };
@@ -690,8 +623,8 @@ bool QWindowsShellItem::copyData(QIODevice *out, QString *errorMessage)
}
istream->Release();
if (hr != S_OK && hr != S_FALSE) {
- *errorMessage = QLatin1String("Read() failed: ")
- + QLatin1String(QWindowsContext::comErrorString(hr));
+ *errorMessage = "Read() failed: "_L1
+ + QSystemError::windowsComString(hr);
return false;
}
return true;
@@ -789,7 +722,6 @@ QDebug operator<<(QDebug d, IShellItem *i)
\sa QWindowsNativeFileDialogEventHandler, QWindowsFileDialogHelper
\internal
- \ingroup qt-lighthouse-win
*/
class QWindowsNativeFileDialogBase : public QWindowsNativeDialogBase
@@ -1034,9 +966,12 @@ static QList<FilterSpec> filterSpecs(const QStringList &filters,
result.reserve(filters.size());
*totalStringLength = 0;
+#if QT_CONFIG(regularexpression)
const QRegularExpression filterSeparatorRE(QStringLiteral("[;\\s]+"));
const QString separator = QStringLiteral(";");
Q_ASSERT(filterSeparatorRE.isValid());
+#endif
+
// Split filter specification as 'Texts (*.txt[;] *.doc)', '*.txt[;] *.doc'
// into description and filters specification as '*.txt;*.doc'
for (const QString &filterString : filters) {
@@ -1049,7 +984,11 @@ static QList<FilterSpec> filterSpecs(const QStringList &filters,
filterString.mid(openingParenPos + 1, closingParenPos - openingParenPos - 1).trimmed();
if (filterSpec.filter.isEmpty())
filterSpec.filter += u'*';
+#if QT_CONFIG(regularexpression)
filterSpec.filter.replace(filterSeparatorRE, separator);
+#else
+ filterSpec.filter.replace(u' ', u';');
+#endif
filterSpec.description = filterString;
if (hideFilterDetails && openingParenPos != -1) { // Do not show pattern in description
filterSpec.description.truncate(openingParenPos);
@@ -1086,8 +1025,11 @@ void QWindowsNativeFileDialogBase::setNameFilters(const QStringList &filters)
const QString &filter = specs[i].filter;
if (!m_hideFiltersDetails && !filter.startsWith(u"*.")) {
const int pos = description.lastIndexOf(u'(');
- if (pos > 0)
+ if (pos > 0) {
description.truncate(pos);
+ while (!description.isEmpty() && description.back().isSpace())
+ description.chop(1);
+ }
}
// Add to buffer.
comFilterSpec[i].pszName = ptr;
@@ -1259,7 +1201,7 @@ void QWindowsNativeFileDialogBase::close()
m_fileDialog->Close(S_OK);
// IFileDialog::Close() does not work unless invoked from a callback.
// Try to find the window and send it a WM_CLOSE in addition.
- const HWND hwnd = findDialogWindow(m_title);
+ const HWND hwnd = QWindowsDialogs::getHWND(m_fileDialog);
qCDebug(lcQpaDialogs) << __FUNCTION__ << "closing" << hwnd;
if (hwnd && IsWindowVisible(hwnd))
PostMessageW(hwnd, WM_CLOSE, 0, 0);
@@ -1295,7 +1237,6 @@ HRESULT QWindowsNativeFileDialogEventHandler::OnFileOk(IFileDialog *)
Implements single-selection methods.
\internal
- \ingroup qt-lighthouse-win
*/
class QWindowsNativeSaveFileDialog : public QWindowsNativeFileDialogBase
@@ -1372,7 +1313,6 @@ QList<QUrl> QWindowsNativeSaveFileDialog::selectedFiles() const
Implements multi-selection methods.
\internal
- \ingroup qt-lighthouse-win
*/
class QWindowsNativeOpenFileDialog : public QWindowsNativeFileDialogBase
@@ -1397,7 +1337,7 @@ Q_GLOBAL_STATIC(QStringList, temporaryItemCopies)
static void cleanupTemporaryItemCopies()
{
- for (const QString &file : qAsConst(*temporaryItemCopies()))
+ for (const QString &file : std::as_const(*temporaryItemCopies()))
QFile::remove(file);
}
@@ -1419,7 +1359,7 @@ QString tempFilePattern(QString name)
int lastDot = name.lastIndexOf(u'.');
if (lastDot < 0)
lastDot = name.size();
- name.insert(lastDot, QStringLiteral("_XXXXXX"));
+ name.insert(lastDot, "_XXXXXX"_L1);
for (int i = lastDot - 1; i >= 0; --i) {
if (!validFileNameCharacter(name.at(i)))
@@ -1433,14 +1373,14 @@ QString tempFilePattern(QString name)
static QString createTemporaryItemCopy(QWindowsShellItem &qItem, QString *errorMessage)
{
if (!qItem.canStream()) {
- *errorMessage = QLatin1String("Item not streamable");
+ *errorMessage = "Item not streamable"_L1;
return QString();
}
QTemporaryFile targetFile(tempFilePattern(qItem.normalDisplay()));
targetFile.setAutoRemove(false);
if (!targetFile.open()) {
- *errorMessage = QLatin1String("Cannot create temporary file: ")
+ *errorMessage = "Cannot create temporary file: "_L1
+ targetFile.errorString();
return QString();
}
@@ -1545,7 +1485,6 @@ QWindowsNativeFileDialogBase *QWindowsNativeFileDialogBase::create(QFileDialogOp
but only on QQuickWindows, which do not have a fallback.
\internal
- \ingroup qt-lighthouse-win
*/
class QWindowsFileDialogHelper : public QWindowsDialogHelperBase<QPlatformFileDialogHelper>
@@ -1612,7 +1551,7 @@ QWindowsNativeDialogBase *QWindowsFileDialogHelper::createNativeDialog()
if (!info.isDir())
result->selectFile(info.fileName());
} else {
- result->selectFile(url.path()); // TODO url.fileName() once it exists
+ result->selectFile(url.fileName());
}
}
// No need to select initialNameFilter if mode is Dir
@@ -1646,7 +1585,7 @@ void QWindowsFileDialogHelper::selectFile(const QUrl &fileName)
qCDebug(lcQpaDialogs) << __FUNCTION__ << fileName.toString();
if (hasNativeDialog()) // Might be invoked from the QFileDialog constructor.
- nativeFileDialog()->selectFile(fileName.toLocalFile()); // ## should use QUrl::fileName() once it exists
+ nativeFileDialog()->selectFile(fileName.fileName());
}
QList<QUrl> QWindowsFileDialogHelper::selectedFiles() const
@@ -1681,7 +1620,6 @@ QString QWindowsFileDialogHelper::selectedNameFilter() const
\internal
\sa QWindowsXpFileDialogHelper
- \ingroup qt-lighthouse-win
*/
class QWindowsXpNativeFileDialog : public QWindowsNativeDialogBase
@@ -1701,9 +1639,6 @@ public slots:
void close() override {}
private:
- typedef BOOL (APIENTRY *PtrGetOpenFileNameW)(LPOPENFILENAMEW);
- typedef BOOL (APIENTRY *PtrGetSaveFileNameW)(LPOPENFILENAMEW);
-
explicit QWindowsXpNativeFileDialog(const OptionsPtr &options, const QWindowsFileDialogSharedData &data);
void populateOpenFileName(OPENFILENAME *ofn, HWND owner) const;
QList<QUrl> execExistingDir(HWND owner);
@@ -1713,27 +1648,11 @@ private:
QString m_title;
QPlatformDialogHelper::DialogCode m_result;
QWindowsFileDialogSharedData m_data;
-
- static PtrGetOpenFileNameW m_getOpenFileNameW;
- static PtrGetSaveFileNameW m_getSaveFileNameW;
};
-QWindowsXpNativeFileDialog::PtrGetOpenFileNameW QWindowsXpNativeFileDialog::m_getOpenFileNameW = nullptr;
-QWindowsXpNativeFileDialog::PtrGetSaveFileNameW QWindowsXpNativeFileDialog::m_getSaveFileNameW = nullptr;
-
QWindowsXpNativeFileDialog *QWindowsXpNativeFileDialog::create(const OptionsPtr &options, const QWindowsFileDialogSharedData &data)
{
- // GetOpenFileNameW() GetSaveFileName() are resolved
- // dynamically as not to create a dependency on Comdlg32, which
- // is used on XP only.
- if (!m_getOpenFileNameW) {
- QSystemLibrary library(QStringLiteral("Comdlg32"));
- m_getOpenFileNameW = (PtrGetOpenFileNameW)(library.resolve("GetOpenFileNameW"));
- m_getSaveFileNameW = (PtrGetSaveFileNameW)(library.resolve("GetSaveFileNameW"));
- }
- if (m_getOpenFileNameW && m_getSaveFileNameW)
- return new QWindowsXpNativeFileDialog(options, data);
- return nullptr;
+ return new QWindowsXpNativeFileDialog(options, data);
}
QWindowsXpNativeFileDialog::QWindowsXpNativeFileDialog(const OptionsPtr &options,
@@ -1774,14 +1693,6 @@ static int QT_WIN_CALLBACK xpFileDialogGetExistingDirCallbackProc(HWND hwnd, UIN
return dialog->existingDirCallback(hwnd, uMsg, lParam);
}
-/* The correct declaration of the SHGetPathFromIDList symbol is
- * being used in mingw-w64 as of r6215, which is a v3 snapshot. */
-#if defined(Q_CC_MINGW) && (!defined(__MINGW64_VERSION_MAJOR) || __MINGW64_VERSION_MAJOR < 3)
-typedef ITEMIDLIST *qt_LpItemIdList;
-#else
-using qt_LpItemIdList = PIDLIST_ABSOLUTE;
-#endif
-
int QWindowsXpNativeFileDialog::existingDirCallback(HWND hwnd, UINT uMsg, LPARAM lParam)
{
switch (uMsg) {
@@ -1795,7 +1706,7 @@ int QWindowsXpNativeFileDialog::existingDirCallback(HWND hwnd, UINT uMsg, LPARAM
break;
case BFFM_SELCHANGED: {
wchar_t path[MAX_PATH];
- const bool ok = SHGetPathFromIDList(reinterpret_cast<qt_LpItemIdList>(lParam), path)
+ const bool ok = SHGetPathFromIDList(reinterpret_cast<PIDLIST_ABSOLUTE>(lParam), path)
&& path[0];
SendMessage(hwnd, BFFM_ENABLEOK, ok ? 1 : 0, 1);
}
@@ -1817,7 +1728,7 @@ QList<QUrl> QWindowsXpNativeFileDialog::execExistingDir(HWND owner)
bi.lpfn = xpFileDialogGetExistingDirCallbackProc;
bi.lParam = LPARAM(this);
QList<QUrl> selectedFiles;
- if (qt_LpItemIdList pItemIDList = SHBrowseForFolder(&bi)) {
+ if (const auto pItemIDList = SHBrowseForFolder(&bi)) {
wchar_t path[MAX_PATH];
path[0] = 0;
if (SHGetPathFromIDList(pItemIDList, path) && path[0])
@@ -1897,7 +1808,7 @@ QList<QUrl> QWindowsXpNativeFileDialog::execFileNames(HWND owner, int *selectedF
populateOpenFileName(&ofn, owner);
QList<QUrl> result;
const bool isSave = m_options->acceptMode() == QFileDialogOptions::AcceptSave;
- if (isSave ? m_getSaveFileNameW(&ofn) : m_getOpenFileNameW(&ofn)) {
+ if (isSave ? GetSaveFileNameW(&ofn) : GetOpenFileNameW(&ofn)) {
*selectedFilterIndex = ofn.nFilterIndex - 1;
const QString dir = QDir::cleanPath(QString::fromWCharArray(ofn.lpstrFile));
result.push_back(QUrl::fromLocalFile(dir));
@@ -1929,7 +1840,6 @@ QList<QUrl> QWindowsXpNativeFileDialog::execFileNames(HWND owner, int *selectedF
\sa QWindowsXpNativeFileDialog
\internal
- \ingroup qt-lighthouse-win
*/
class QWindowsXpFileDialogHelper : public QWindowsDialogHelperBase<QPlatformFileDialogHelper>
@@ -2006,7 +1916,6 @@ QString QWindowsXpFileDialogHelper::selectedNameFilter() const
\sa QWindowsColorDialogHelper
\sa #define USE_NATIVE_COLOR_DIALOG
\internal
- \ingroup qt-lighthouse-win
*/
using SharedPointerColor = QSharedPointer<QColor>;
@@ -2041,8 +1950,6 @@ QWindowsNativeColorDialog::QWindowsNativeColorDialog(const SharedPointerColor &c
void QWindowsNativeColorDialog::doExec(HWND owner)
{
- typedef BOOL (WINAPI *ChooseColorWType)(LPCHOOSECOLORW);
-
CHOOSECOLOR chooseColor;
ZeroMemory(&chooseColor, sizeof(chooseColor));
chooseColor.lStructSize = sizeof(chooseColor);
@@ -2055,18 +1962,9 @@ void QWindowsNativeColorDialog::doExec(HWND owner)
m_customColors[c] = qColorToCOLORREF(QColor(qCustomColors[c]));
chooseColor.rgbResult = qColorToCOLORREF(*m_color);
chooseColor.Flags = CC_FULLOPEN | CC_RGBINIT;
- static ChooseColorWType chooseColorW = 0;
- if (!chooseColorW) {
- QSystemLibrary library(QStringLiteral("Comdlg32"));
- chooseColorW = (ChooseColorWType)library.resolve("ChooseColorW");
- }
- if (chooseColorW) {
- m_code = chooseColorW(&chooseColor) ?
- QPlatformDialogHelper::Accepted : QPlatformDialogHelper::Rejected;
- QWindowsDialogs::eatMouseMove();
- } else {
- m_code = QPlatformDialogHelper::Rejected;
- }
+ m_code = ChooseColorW(&chooseColor) ?
+ QPlatformDialogHelper::Accepted : QPlatformDialogHelper::Rejected;
+ QWindowsDialogs::eatMouseMove();
if (m_code == QPlatformDialogHelper::Accepted) {
*m_color = COLORREFToQColor(chooseColor.rgbResult);
for (int c= 0; c < customColorCount; ++c)
@@ -2086,7 +1984,6 @@ void QWindowsNativeColorDialog::doExec(HWND owner)
\sa #define USE_NATIVE_COLOR_DIALOG
\sa QWindowsNativeColorDialog
\internal
- \ingroup qt-lighthouse-win
*/
class QWindowsColorDialogHelper : public QWindowsDialogHelperBase<QPlatformColorDialogHelper>
diff --git a/src/plugins/platforms/windows/qwindowsdialoghelpers.h b/src/plugins/platforms/windows/qwindowsdialoghelpers.h
index 8686749011..64f40bc3a9 100644
--- a/src/plugins/platforms/windows/qwindowsdialoghelpers.h
+++ b/src/plugins/platforms/windows/qwindowsdialoghelpers.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QWINDOWSDIALOGHELPER_H
#define QWINDOWSDIALOGHELPER_H
@@ -67,7 +31,7 @@ class QWindowsDialogHelperBase : public BaseClass
Q_DISABLE_COPY_MOVE(QWindowsDialogHelperBase)
public:
using QWindowsNativeDialogBasePtr = QSharedPointer<QWindowsNativeDialogBase>;
- ~QWindowsDialogHelperBase() { cleanupThread(); }
+ ~QWindowsDialogHelperBase();
void exec() override;
bool show(Qt::WindowFlags windowFlags,
@@ -80,7 +44,7 @@ public:
protected:
QWindowsDialogHelperBase() = default;
QWindowsNativeDialogBase *nativeDialog() const;
- inline bool hasNativeDialog() const { return m_nativeDialog; }
+ inline bool hasNativeDialog() const { return !m_nativeDialog.isNull(); }
void timerEvent(QTimerEvent *) override;
private:
diff --git a/src/plugins/platforms/windows/qwindowsdrag.cpp b/src/plugins/platforms/windows/qwindowsdrag.cpp
index 3e4c93d47a..c6f55c3509 100644
--- a/src/plugins/platforms/windows/qwindowsdrag.cpp
+++ b/src/plugins/platforms/windows/qwindowsdrag.cpp
@@ -1,42 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+#include <QtCore/qt_windows.h>
#include "qwindowsdrag.h"
#include "qwindowscontext.h"
#include "qwindowsscreen.h"
@@ -45,7 +10,6 @@
#endif
#include "qwindowsintegration.h"
#include "qwindowsdropdataobject.h"
-#include <QtCore/qt_windows.h>
#include "qwindowswindow.h"
#include "qwindowsmousehandler.h"
#include "qwindowscursor.h"
@@ -64,6 +28,8 @@
#include <QtCore/qdebug.h>
#include <QtCore/qbuffer.h>
#include <QtCore/qpoint.h>
+#include <QtCore/qpointer.h>
+#include <QtCore/private/qcomobject_p.h>
#include <shlobj.h>
@@ -75,7 +41,6 @@ QT_BEGIN_NAMESPACE
\sa QWindowsOleDropSource
\internal
- \ingroup qt-lighthouse-win
*/
class QWindowsDragCursorWindow : public QRasterWindow
@@ -135,7 +100,6 @@ void QWindowsDragCursorWindow::setPixmap(const QPixmap &p)
\sa QWindowsDrag
\internal
- \ingroup qt-lighthouse-win
*/
IDataObject *QWindowsDropMimeData::retrieveDataObject() const
@@ -192,20 +156,6 @@ static inline Qt::KeyboardModifiers toQtKeyboardModifiers(DWORD keyState)
return modifiers;
}
-static inline Qt::MouseButtons toQtMouseButtons(DWORD keyState)
-{
- Qt::MouseButtons buttons = Qt::NoButton;
-
- if (keyState & MK_LBUTTON)
- buttons |= Qt::LeftButton;
- if (keyState & MK_RBUTTON)
- buttons |= Qt::RightButton;
- if (keyState & MK_MBUTTON)
- buttons |= Qt::MidButton;
-
- return buttons;
-}
-
static Qt::KeyboardModifiers lastModifiers = Qt::NoModifier;
static Qt::MouseButtons lastButtons = Qt::NoButton;
@@ -217,10 +167,9 @@ static Qt::MouseButtons lastButtons = Qt::NoButton;
\sa QWindowsDrag
\internal
- \ingroup qt-lighthouse-win
*/
-class QWindowsOleDropSource : public QWindowsComBase<IDropSource>
+class QWindowsOleDropSource : public QComObject<IDropSource>
{
public:
enum Mode {
@@ -234,8 +183,8 @@ public:
void createCursors();
// IDropSource methods
- STDMETHOD(QueryContinueDrag)(BOOL fEscapePressed, DWORD grfKeyState);
- STDMETHOD(GiveFeedback)(DWORD dwEffect);
+ STDMETHOD(QueryContinueDrag)(BOOL fEscapePressed, DWORD grfKeyState) override;
+ STDMETHOD(GiveFeedback)(DWORD dwEffect) override;
private:
struct CursorEntry {
@@ -389,7 +338,10 @@ void QWindowsOleDropSource::createCursors()
QT_ENSURE_STACK_ALIGNED_FOR_SSE STDMETHODIMP
QWindowsOleDropSource::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState)
{
- Qt::MouseButtons buttons = toQtMouseButtons(grfKeyState);
+ // In some rare cases, when a mouse button is released but the mouse is static,
+ // grfKeyState will not be updated with these released buttons until the mouse
+ // is moved. So we use the async key state given by queryMouseButtons() instead.
+ Qt::MouseButtons buttons = QWindowsMouseHandler::queryMouseButtons();
SCODE result = S_OK;
if (fEscapePressed || QWindowsDrag::isCanceled()) {
@@ -398,7 +350,7 @@ QWindowsOleDropSource::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState)
} else {
if (buttons && !m_currentButtons) {
m_currentButtons = buttons;
- } else if (!(m_currentButtons & buttons)) { // Button changed: Complete Drop operation.
+ } else if (m_currentButtons != buttons) { // Button changed: Complete Drop operation.
result = DRAGDROP_S_DROP;
}
}
@@ -434,7 +386,7 @@ QWindowsOleDropSource::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState)
}
/*!
- \brief Give feedback: Change cursor accoding to action.
+ \brief Give feedback: Change cursor according to action.
*/
QT_ENSURE_STACK_ALIGNED_FOR_SSE STDMETHODIMP
@@ -485,7 +437,6 @@ QWindowsOleDropSource::GiveFeedback(DWORD dwEffect)
\sa QWindowsDrag
\internal
- \ingroup qt-lighthouse-win
*/
QWindowsOleDropTarget::QWindowsOleDropTarget(QWindow *w) : m_window(w)
@@ -509,7 +460,7 @@ void QWindowsOleDropTarget::handleDrag(QWindow *window, DWORD grfKeyState,
const Qt::DropActions actions = translateToQDragDropActions(*pdwEffect);
lastModifiers = toQtKeyboardModifiers(grfKeyState);
- lastButtons = toQtMouseButtons(grfKeyState);
+ lastButtons = QWindowsMouseHandler::queryMouseButtons();
const QPlatformDragQtResponse response =
QWindowSystemInterface::handleDrag(window, windowsDrag->dropData(),
@@ -577,7 +528,8 @@ QWindowsOleDropTarget::DragLeave()
qCDebug(lcQpaMime) << __FUNCTION__ << ' ' << m_window;
- lastModifiers = QWindowsKeyMapper::queryKeyboardModifiers();
+ const auto *keyMapper = QWindowsContext::instance()->keyMapper();
+ lastModifiers = keyMapper->queryKeyboardModifiers();
lastButtons = QWindowsMouseHandler::queryMouseButtons();
QWindowSystemInterface::handleDrag(m_window, nullptr, QPoint(), Qt::IgnoreAction,
@@ -607,7 +559,7 @@ QWindowsOleDropTarget::Drop(LPDATAOBJECT pDataObj, DWORD grfKeyState,
QWindowsDrag *windowsDrag = QWindowsDrag::instance();
lastModifiers = toQtKeyboardModifiers(grfKeyState);
- lastButtons = toQtMouseButtons(grfKeyState);
+ lastButtons = QWindowsMouseHandler::queryMouseButtons();
const QPlatformDropQtResponse response =
QWindowSystemInterface::handleDrop(m_window, windowsDrag->dropData(),
@@ -659,11 +611,9 @@ QWindowsOleDropTarget::Drop(LPDATAOBJECT pDataObj, DWORD grfKeyState,
\class QWindowsDrag
\brief Windows drag implementation.
\internal
- \ingroup qt-lighthouse-win
*/
bool QWindowsDrag::m_canceled = false;
-bool QWindowsDrag::m_dragging = false;
QWindowsDrag::QWindowsDrag() = default;
@@ -696,6 +646,86 @@ IDropTargetHelper* QWindowsDrag::dropHelper() {
return m_cachedDropTargetHelper;
}
+// Workaround for DoDragDrop() not working with touch/pen input, causing DnD to hang until the mouse is moved.
+// We process pointer messages for touch/pen and generate mouse input through SendInput() to trigger DoDragDrop()
+static HRESULT startDoDragDrop(LPDATAOBJECT pDataObj, LPDROPSOURCE pDropSource, DWORD dwOKEffects, LPDWORD pdwEffect)
+{
+ QWindow *underMouse = QWindowsContext::instance()->windowUnderMouse();
+ const bool hasMouseCapture = underMouse && static_cast<QWindowsWindow *>(underMouse->handle())->hasMouseCapture();
+ const HWND hwnd = hasMouseCapture ? reinterpret_cast<HWND>(underMouse->winId()) : ::GetFocus();
+ bool starting = false;
+
+ for (;;) {
+ MSG msg{};
+ if (::GetMessage(&msg, hwnd, 0, 0) > 0) {
+
+ if (msg.message == WM_MOUSEMOVE) {
+
+ // Only consider the first simulated event, or actual mouse messages.
+ if (!starting && (msg.wParam & (MK_LBUTTON | MK_MBUTTON | MK_RBUTTON | MK_XBUTTON1 | MK_XBUTTON2)) == 0)
+ return E_FAIL;
+
+ return ::DoDragDrop(pDataObj, pDropSource, dwOKEffects, pdwEffect);
+ }
+
+ if (msg.message == WM_POINTERUPDATE) {
+
+ const quint32 pointerId = GET_POINTERID_WPARAM(msg.wParam);
+
+ POINTER_INFO pointerInfo{};
+ if (!GetPointerInfo(pointerId, &pointerInfo))
+ return E_FAIL;
+
+ if (pointerInfo.pointerFlags & POINTER_FLAG_PRIMARY) {
+
+ DWORD flags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_VIRTUALDESK | MOUSEEVENTF_MOVE;
+ if (IS_POINTER_FIRSTBUTTON_WPARAM(msg.wParam))
+ flags |= MOUSEEVENTF_LEFTDOWN;
+ if (IS_POINTER_SECONDBUTTON_WPARAM(msg.wParam))
+ flags |= MOUSEEVENTF_RIGHTDOWN;
+ if (IS_POINTER_THIRDBUTTON_WPARAM(msg.wParam))
+ flags |= MOUSEEVENTF_MIDDLEDOWN;
+
+ if (!starting) {
+ POINT pt{};
+ if (::GetCursorPos(&pt)) {
+
+ // Send mouse input that can generate a WM_MOUSEMOVE message.
+ if ((flags & MOUSEEVENTF_LEFTDOWN || flags & MOUSEEVENTF_RIGHTDOWN || flags & MOUSEEVENTF_MIDDLEDOWN)
+ && (pt.x != pointerInfo.ptPixelLocation.x || pt.y != pointerInfo.ptPixelLocation.y)) {
+
+ const int origin_x = ::GetSystemMetrics(SM_XVIRTUALSCREEN);
+ const int origin_y = ::GetSystemMetrics(SM_YVIRTUALSCREEN);
+ const int virt_w = ::GetSystemMetrics(SM_CXVIRTUALSCREEN);
+ const int virt_h = ::GetSystemMetrics(SM_CYVIRTUALSCREEN);
+ const int virt_x = pointerInfo.ptPixelLocation.x - origin_x;
+ const int virt_y = pointerInfo.ptPixelLocation.y - origin_y;
+
+ INPUT input{};
+ input.type = INPUT_MOUSE;
+ input.mi.dx = static_cast<DWORD>(virt_x * (65535.0 / virt_w));
+ input.mi.dy = static_cast<DWORD>(virt_y * (65535.0 / virt_h));
+ input.mi.dwFlags = flags;
+
+ ::SendInput(1, &input, sizeof(input));
+ starting = true;
+ }
+ }
+ }
+ }
+ } else {
+ // Handle other messages.
+ qWindowsWndProc(msg.hwnd, msg.message, msg.wParam, msg.lParam);
+
+ if (msg.message == WM_POINTERLEAVE)
+ return E_FAIL;
+ }
+ } else {
+ return E_FAIL;
+ }
+ }
+}
+
Qt::DropAction QWindowsDrag::drag(QDrag *drag)
{
// TODO: Accessibility handling?
@@ -711,10 +741,7 @@ Qt::DropAction QWindowsDrag::drag(QDrag *drag)
const DWORD allowedEffects = translateToWinDragEffects(possibleActions);
qCDebug(lcQpaMime) << '>' << __FUNCTION__ << "possible Actions=0x"
<< Qt::hex << int(possibleActions) << "effects=0x" << allowedEffects << Qt::dec;
- // Indicate message handlers we are in DoDragDrop() event loop.
- QWindowsDrag::m_dragging = true;
- const HRESULT r = DoDragDrop(dropDataObject, windowDropSource, allowedEffects, &resultEffect);
- QWindowsDrag::m_dragging = false;
+ const HRESULT r = startDoDragDrop(dropDataObject, windowDropSource, allowedEffects, &resultEffect);
const DWORD reportedPerformedEffect = dropDataObject->reportedPerformedEffect();
if (r == DRAGDROP_S_DROP) {
if (reportedPerformedEffect == DROPEFFECT_MOVE && resultEffect != DROPEFFECT_MOVE) {
diff --git a/src/plugins/platforms/windows/qwindowsdrag.h b/src/plugins/platforms/windows/qwindowsdrag.h
index 5f30c59882..a2d0e54044 100644
--- a/src/plugins/platforms/windows/qwindowsdrag.h
+++ b/src/plugins/platforms/windows/qwindowsdrag.h
@@ -1,51 +1,15 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QWINDOWSDRAG_H
#define QWINDOWSDRAG_H
-#include "qwindowscombase.h"
#include "qwindowsinternalmimedata.h"
#include <qpa/qplatformdrag.h>
#include <QtGui/qpixmap.h>
#include <QtGui/qdrag.h>
+#include <QtCore/private/qcomobject_p.h>
struct IDropTargetHelper;
@@ -59,17 +23,19 @@ public:
IDataObject *retrieveDataObject() const override;
};
-class QWindowsOleDropTarget : public QWindowsComBase<IDropTarget>
+class QWindowsOleDropTarget : public QComObject<IDropTarget>
{
public:
explicit QWindowsOleDropTarget(QWindow *w);
~QWindowsOleDropTarget() override;
// IDropTarget methods
- STDMETHOD(DragEnter)(LPDATAOBJECT pDataObj, DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect);
- STDMETHOD(DragOver)(DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect);
- STDMETHOD(DragLeave)();
- STDMETHOD(Drop)(LPDATAOBJECT pDataObj, DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect);
+ STDMETHOD(DragEnter)
+ (LPDATAOBJECT pDataObj, DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect) override;
+ STDMETHOD(DragOver)(DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect) override;
+ STDMETHOD(DragLeave)() override;
+ STDMETHOD(Drop)
+ (LPDATAOBJECT pDataObj, DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect) override;
private:
void handleDrag(QWindow *window, DWORD grfKeyState, const QPoint &, LPDWORD pdwEffect);
@@ -92,7 +58,6 @@ public:
static QWindowsDrag *instance();
void cancelDrag() override { QWindowsDrag::m_canceled = true; }
static bool isCanceled() { return QWindowsDrag::m_canceled; }
- static bool isDragging() { return QWindowsDrag::m_dragging; }
IDataObject *dropDataObject() const { return m_dropDataObject; }
void setDropDataObject(IDataObject *dataObject) { m_dropDataObject = dataObject; }
@@ -103,7 +68,6 @@ public:
private:
static bool m_canceled;
- static bool m_dragging;
QWindowsDropMimeData m_dropData;
IDataObject *m_dropDataObject = nullptr;
diff --git a/src/plugins/platforms/windows/qwindowsdropdataobject.cpp b/src/plugins/platforms/windows/qwindowsdropdataobject.cpp
index c9dd1c7c17..629291640f 100644
--- a/src/plugins/platforms/windows/qwindowsdropdataobject.cpp
+++ b/src/plugins/platforms/windows/qwindowsdropdataobject.cpp
@@ -1,50 +1,16 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qwindowsdropdataobject.h"
#include <QtCore/qurl.h>
#include <QtCore/qmimedata.h>
-#include "qwindowsmime.h"
+#include "qwindowsmimeregistry.h"
QT_BEGIN_NAMESPACE
+using namespace Qt::Literals::StringLiterals;
+
/*!
\class QWindowsDropDataObject
\brief QWindowsOleDataObject subclass specialized for handling Drag&Drop.
@@ -54,7 +20,6 @@ QT_BEGIN_NAMESPACE
(instead of creating local hyperlinks).
\internal
- \ingroup qt-lighthouse-win
*/
QWindowsDropDataObject::QWindowsDropDataObject(QMimeData *mimeData) :
@@ -90,11 +55,11 @@ bool QWindowsDropDataObject::shouldIgnore(LPFORMATETC pformatetc) const
QMimeData *dropData = mimeData();
if (dropData && dropData->formats().size() == 1 && dropData->hasUrls()) {
- QString formatName = QWindowsMimeConverter::clipboardFormatName(pformatetc->cfFormat);
+ QString formatName = QWindowsMimeRegistry::clipboardFormatName(pformatetc->cfFormat);
if (pformatetc->cfFormat == CF_UNICODETEXT
|| pformatetc->cfFormat == CF_TEXT
- || formatName == QStringLiteral("UniformResourceLocator")
- || formatName == QStringLiteral("UniformResourceLocatorW")) {
+ || formatName == "UniformResourceLocator"_L1
+ || formatName == "UniformResourceLocatorW"_L1) {
const auto urls = dropData->urls();
return std::all_of(urls.cbegin(), urls.cend(), [] (const QUrl &u) { return u.isLocalFile(); });
}
diff --git a/src/plugins/platforms/windows/qwindowsdropdataobject.h b/src/plugins/platforms/windows/qwindowsdropdataobject.h
index 16ba7b036a..b74a3dbc7e 100644
--- a/src/plugins/platforms/windows/qwindowsdropdataobject.h
+++ b/src/plugins/platforms/windows/qwindowsdropdataobject.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QWINDOWSDROPDATAOBJECT_H
#define QWINDOWSDROPDATAOBJECT_H
@@ -51,8 +15,8 @@ public:
~QWindowsDropDataObject() override;
// overridden IDataObject methods
- STDMETHOD(GetData)(LPFORMATETC pformatetcIn, LPSTGMEDIUM pmedium);
- STDMETHOD(QueryGetData)(LPFORMATETC pformatetc);
+ STDMETHOD(GetData)(LPFORMATETC pformatetcIn, LPSTGMEDIUM pmedium) override;
+ STDMETHOD(QueryGetData)(LPFORMATETC pformatetc) override;
private:
bool shouldIgnore(LPFORMATETC pformatetc) const;
diff --git a/src/plugins/platforms/windows/qwindowseglcontext.cpp b/src/plugins/platforms/windows/qwindowseglcontext.cpp
deleted file mode 100644
index 76baa93d98..0000000000
--- a/src/plugins/platforms/windows/qwindowseglcontext.cpp
+++ /dev/null
@@ -1,920 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 "qwindowseglcontext.h"
-#include "qwindowscontext.h"
-#include "qwindowswindow.h"
-
-#include <QtCore/qdebug.h>
-#include <QtGui/qopenglcontext.h>
-
-#if defined(QT_OPENGL_ES_2_ANGLE) || defined(QT_OPENGL_DYNAMIC)
-# include <EGL/eglext.h>
-#endif
-
-QT_BEGIN_NAMESPACE
-
-/*!
- \class QWindowsEGLStaticContext
- \brief Static data for QWindowsEGLContext.
-
- Keeps the display. The class is shared via QSharedPointer in the windows, the
- contexts and in QWindowsIntegration. The display will be closed if the last instance
- is deleted.
-
- No EGL or OpenGL functions are called directly. Instead, they are resolved
- dynamically. This works even if the plugin links directly to libegl/libglesv2 so
- there is no need to differentiate between dynamic or Angle-only builds in here.
-
- \internal
- \ingroup qt-lighthouse-win
-*/
-
-QWindowsLibEGL QWindowsEGLStaticContext::libEGL;
-QWindowsLibGLESv2 QWindowsEGLStaticContext::libGLESv2;
-
-#if !defined(QT_STATIC) || defined(QT_OPENGL_DYNAMIC)
-
-#ifdef Q_CC_MINGW
-static void *resolveFunc(HMODULE lib, const char *name)
-{
- QString baseNameStr = QString::fromLatin1(name);
- QString nameStr;
- void *proc = 0;
-
- // Play nice with 32-bit mingw: Try func first, then func@0, func@4,
- // func@8, func@12, ..., func@64. The def file does not provide any aliases
- // in libEGL and libGLESv2 in these builds which results in exporting
- // function names like eglInitialize@12. This cannot be fixed without
- // breaking binary compatibility. So be flexible here instead.
-
- int argSize = -1;
- while (!proc && argSize <= 64) {
- nameStr = baseNameStr;
- if (argSize >= 0)
- nameStr += u'@' + QString::number(argSize);
- argSize = argSize < 0 ? 0 : argSize + 4;
- proc = (void *) ::GetProcAddress(lib, nameStr.toLatin1().constData());
- }
- return proc;
-}
-#else
-static inline void *resolveFunc(HMODULE lib, const char *name)
-{
- return ::GetProcAddress(lib, name);
-}
-#endif // Q_CC_MINGW
-
-void *QWindowsLibEGL::resolve(const char *name)
-{
- return m_lib ? resolveFunc(m_lib, name) : nullptr;
-}
-
-#endif // !QT_STATIC
-
-#if !defined(QT_STATIC) || defined(QT_OPENGL_DYNAMIC)
-# define RESOLVE(signature, name) signature(resolve( #name ));
-#else
-# define RESOLVE(signature, name) signature(&::name);
-#endif
-
-bool QWindowsLibEGL::init()
-{
- const char dllName[] = QT_STRINGIFY(LIBEGL_NAME)
-#if defined(QT_DEBUG)
- "d"
-#endif
- "";
-
- qCDebug(lcQpaGl) << "Qt: Using EGL from" << dllName;
-
-#if !defined(QT_STATIC) || defined(QT_OPENGL_DYNAMIC)
- m_lib = ::LoadLibraryW((const wchar_t *) QString::fromLatin1(dllName).utf16());
- if (!m_lib) {
- qErrnoWarning(::GetLastError(), "Failed to load %s", dllName);
- return false;
- }
-#endif
-
- eglGetError = RESOLVE((EGLint (EGLAPIENTRY *)(void)), eglGetError);
- eglGetDisplay = RESOLVE((EGLDisplay (EGLAPIENTRY *)(EGLNativeDisplayType)), eglGetDisplay);
- eglInitialize = RESOLVE((EGLBoolean (EGLAPIENTRY *)(EGLDisplay, EGLint *, EGLint *)), eglInitialize);
- eglTerminate = RESOLVE((EGLBoolean (EGLAPIENTRY *)(EGLDisplay)), eglTerminate);
- eglChooseConfig = RESOLVE((EGLBoolean (EGLAPIENTRY *)(EGLDisplay, const EGLint *, EGLConfig *, EGLint, EGLint *)), eglChooseConfig);
- eglGetConfigAttrib = RESOLVE((EGLBoolean (EGLAPIENTRY *)(EGLDisplay, EGLConfig, EGLint, EGLint *)), eglGetConfigAttrib);
- eglCreateWindowSurface = RESOLVE((EGLSurface (EGLAPIENTRY *)(EGLDisplay, EGLConfig, EGLNativeWindowType, const EGLint *)), eglCreateWindowSurface);
- eglCreatePbufferSurface = RESOLVE((EGLSurface (EGLAPIENTRY *)(EGLDisplay , EGLConfig, const EGLint *)), eglCreatePbufferSurface);
- eglDestroySurface = RESOLVE((EGLBoolean (EGLAPIENTRY *)(EGLDisplay , EGLSurface )), eglDestroySurface);
- eglBindAPI = RESOLVE((EGLBoolean (EGLAPIENTRY * )(EGLenum )), eglBindAPI);
- eglSwapInterval = RESOLVE((EGLBoolean (EGLAPIENTRY *)(EGLDisplay , EGLint )), eglSwapInterval);
- eglCreateContext = RESOLVE((EGLContext (EGLAPIENTRY *)(EGLDisplay , EGLConfig , EGLContext , const EGLint *)), eglCreateContext);
- eglDestroyContext = RESOLVE((EGLBoolean (EGLAPIENTRY *)(EGLDisplay, EGLContext)), eglDestroyContext);
- eglMakeCurrent = RESOLVE((EGLBoolean (EGLAPIENTRY *)(EGLDisplay , EGLSurface , EGLSurface , EGLContext )), eglMakeCurrent);
- eglGetCurrentContext = RESOLVE((EGLContext (EGLAPIENTRY *)(void)), eglGetCurrentContext);
- eglGetCurrentSurface = RESOLVE((EGLSurface (EGLAPIENTRY *)(EGLint )), eglGetCurrentSurface);
- eglGetCurrentDisplay = RESOLVE((EGLDisplay (EGLAPIENTRY *)(void)), eglGetCurrentDisplay);
- eglSwapBuffers = RESOLVE((EGLBoolean (EGLAPIENTRY *)(EGLDisplay , EGLSurface)), eglSwapBuffers);
- eglGetProcAddress = RESOLVE((QFunctionPointer (EGLAPIENTRY * )(const char *)), eglGetProcAddress);
-
- if (!eglGetError || !eglGetDisplay || !eglInitialize || !eglGetProcAddress)
- return false;
-
- eglGetPlatformDisplayEXT = nullptr;
-#ifdef EGL_ANGLE_platform_angle
- eglGetPlatformDisplayEXT = reinterpret_cast<EGLDisplay (EGLAPIENTRY *)(EGLenum, void *, const EGLint *)>(eglGetProcAddress("eglGetPlatformDisplayEXT"));
-#endif
-
- return true;
-}
-
-#if !defined(QT_STATIC) || defined(QT_OPENGL_DYNAMIC)
-void *QWindowsLibGLESv2::resolve(const char *name)
-{
- return m_lib ? resolveFunc(m_lib, name) : nullptr;
-}
-#endif // !QT_STATIC
-
-bool QWindowsLibGLESv2::init()
-{
-
- const char dllName[] = QT_STRINGIFY(LIBGLESV2_NAME)
-#if defined(QT_DEBUG)
- "d"
-#endif
- "";
-
- qCDebug(lcQpaGl) << "Qt: Using OpenGL ES 2.0 from" << dllName;
-#if !defined(QT_STATIC) || defined(QT_OPENGL_DYNAMIC)
- m_lib = ::LoadLibraryW(reinterpret_cast<LPCWSTR>(QString::fromLatin1(dllName).utf16()));
- if (!m_lib) {
- qErrnoWarning(int(GetLastError()), "Failed to load %s", dllName);
- return false;
- }
-#endif // !QT_STATIC
-
- void (APIENTRY * glBindTexture)(GLenum target, GLuint texture) = RESOLVE((void (APIENTRY *)(GLenum , GLuint )), glBindTexture);
- GLuint (APIENTRY * glCreateShader)(GLenum type) = RESOLVE((GLuint (APIENTRY *)(GLenum )), glCreateShader);
- void (APIENTRY * glClearDepthf)(GLclampf depth) = RESOLVE((void (APIENTRY *)(GLclampf )), glClearDepthf);
- glGetString = RESOLVE((const GLubyte * (APIENTRY *)(GLenum )), glGetString);
-
- return glBindTexture && glCreateShader && glClearDepthf;
-}
-
-QWindowsEGLStaticContext::QWindowsEGLStaticContext(EGLDisplay display)
- : m_display(display)
-{
-}
-
-bool QWindowsEGLStaticContext::initializeAngle(QWindowsOpenGLTester::Renderers preferredType, HDC dc,
- EGLDisplay *display, EGLint *major, EGLint *minor)
-{
-#ifdef EGL_ANGLE_platform_angle
- if (libEGL.eglGetPlatformDisplayEXT
- && (preferredType & QWindowsOpenGLTester::AngleBackendMask)) {
- const EGLint anglePlatformAttributes[][5] = {
- { EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, EGL_NONE },
- { EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE, EGL_NONE },
- { EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE,
- EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE, EGL_NONE }
- };
- const EGLint *attributes = nullptr;
- if (preferredType & QWindowsOpenGLTester::AngleRendererD3d11)
- attributes = anglePlatformAttributes[0];
- else if (preferredType & QWindowsOpenGLTester::AngleRendererD3d9)
- attributes = anglePlatformAttributes[1];
- else if (preferredType & QWindowsOpenGLTester::AngleRendererD3d11Warp)
- attributes = anglePlatformAttributes[2];
- if (attributes) {
- *display = libEGL.eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, dc, attributes);
- if (!libEGL.eglInitialize(*display, major, minor)) {
- libEGL.eglTerminate(*display);
- *display = EGL_NO_DISPLAY;
- *major = *minor = 0;
- return false;
- }
- }
- }
-#else // EGL_ANGLE_platform_angle
- Q_UNUSED(preferredType);
- Q_UNUSED(dc);
- Q_UNUSED(display);
- Q_UNUSED(major);
- Q_UNUSED(minor);
-#endif
- return true;
-}
-
-QWindowsEGLStaticContext *QWindowsEGLStaticContext::create(QWindowsOpenGLTester::Renderers preferredType)
-{
- const HDC dc = QWindowsContext::instance()->displayContext();
- if (!dc){
- qWarning("%s: No Display", __FUNCTION__);
- return nullptr;
- }
-
- if (!libEGL.init()) {
- qWarning("%s: Failed to load and resolve libEGL functions", __FUNCTION__);
- return nullptr;
- }
- if (!libGLESv2.init()) {
- qWarning("%s: Failed to load and resolve libGLESv2 functions", __FUNCTION__);
- return nullptr;
- }
-
- EGLDisplay display = EGL_NO_DISPLAY;
- EGLint major = 0;
- EGLint minor = 0;
-
- if (!initializeAngle(preferredType, dc, &display, &major, &minor)
- && (preferredType & QWindowsOpenGLTester::AngleRendererD3d11)) {
- preferredType &= ~QWindowsOpenGLTester::AngleRendererD3d11;
- initializeAngle(preferredType, dc, &display, &major, &minor);
- }
-
- if (display == EGL_NO_DISPLAY)
- display = libEGL.eglGetDisplay(dc);
- if (!display) {
- qWarning("%s: Could not obtain EGL display", __FUNCTION__);
- return nullptr;
- }
-
- if (!major && !libEGL.eglInitialize(display, &major, &minor)) {
- int err = libEGL.eglGetError();
- qWarning("%s: Could not initialize EGL display: error 0x%x", __FUNCTION__, err);
- if (err == 0x3001)
- qWarning("%s: When using ANGLE, check if d3dcompiler_4x.dll is available", __FUNCTION__);
- return nullptr;
- }
-
- qCDebug(lcQpaGl) << __FUNCTION__ << "Created EGL display" << display << 'v' <<major << '.' << minor;
- return new QWindowsEGLStaticContext(display);
-}
-
-QWindowsEGLStaticContext::~QWindowsEGLStaticContext()
-{
- qCDebug(lcQpaGl) << __FUNCTION__ << "Releasing EGL display " << m_display;
- libEGL.eglTerminate(m_display);
-}
-
-QWindowsOpenGLContext *QWindowsEGLStaticContext::createContext(QOpenGLContext *context)
-{
- return new QWindowsEGLContext(this, context->format(), context->shareHandle());
-}
-
-void *QWindowsEGLStaticContext::createWindowSurface(void *nativeWindow, void *nativeConfig, int *err)
-{
- *err = 0;
- EGLSurface surface = libEGL.eglCreateWindowSurface(m_display, nativeConfig,
- static_cast<EGLNativeWindowType>(nativeWindow), nullptr);
- if (surface == EGL_NO_SURFACE) {
- *err = libEGL.eglGetError();
- qWarning("%s: Could not create the EGL window surface: 0x%x", __FUNCTION__, *err);
- }
-
- return surface;
-}
-
-void QWindowsEGLStaticContext::destroyWindowSurface(void *nativeSurface)
-{
- libEGL.eglDestroySurface(m_display, nativeSurface);
-}
-
-QSurfaceFormat QWindowsEGLStaticContext::formatFromConfig(EGLDisplay display, EGLConfig config,
- const QSurfaceFormat &referenceFormat)
-{
- QSurfaceFormat format;
- EGLint redSize = 0;
- EGLint greenSize = 0;
- EGLint blueSize = 0;
- EGLint alphaSize = 0;
- EGLint depthSize = 0;
- EGLint stencilSize = 0;
- EGLint sampleCount = 0;
-
- libEGL.eglGetConfigAttrib(display, config, EGL_RED_SIZE, &redSize);
- libEGL.eglGetConfigAttrib(display, config, EGL_GREEN_SIZE, &greenSize);
- libEGL.eglGetConfigAttrib(display, config, EGL_BLUE_SIZE, &blueSize);
- libEGL.eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &alphaSize);
- libEGL.eglGetConfigAttrib(display, config, EGL_DEPTH_SIZE, &depthSize);
- libEGL.eglGetConfigAttrib(display, config, EGL_STENCIL_SIZE, &stencilSize);
- libEGL.eglGetConfigAttrib(display, config, EGL_SAMPLES, &sampleCount);
-
- format.setRenderableType(QSurfaceFormat::OpenGLES);
- format.setVersion(referenceFormat.majorVersion(), referenceFormat.minorVersion());
- format.setProfile(referenceFormat.profile());
- format.setOptions(referenceFormat.options());
-
- format.setRedBufferSize(redSize);
- format.setGreenBufferSize(greenSize);
- format.setBlueBufferSize(blueSize);
- format.setAlphaBufferSize(alphaSize);
- format.setDepthBufferSize(depthSize);
- format.setStencilBufferSize(stencilSize);
- format.setSamples(sampleCount);
- format.setStereo(false);
- format.setSwapInterval(referenceFormat.swapInterval());
-
- // Clear the EGL error state because some of the above may
- // have errored out because the attribute is not applicable
- // to the surface type. Such errors don't matter.
- libEGL.eglGetError();
-
- return format;
-}
-
-/*!
- \class QWindowsEGLContext
- \brief Open EGL context.
-
- \section1 Using QWindowsEGLContext for Desktop with ANGLE
- \section2 Build Instructions
- \list
- \o Install the Direct X SDK
- \o Checkout and build ANGLE (SVN repository) as explained here:
- \l{https://chromium.googlesource.com/angle/angle/+/master/README.md}
- When building for 64bit, de-activate the "WarnAsError" option
- in every project file (as otherwise integer conversion
- warnings will break the build).
- \o Run configure.exe with the options "-opengl es2".
- \o Build qtbase and test some examples.
- \endlist
-
- \internal
- \ingroup qt-lighthouse-win
-*/
-
-QWindowsEGLContext::QWindowsEGLContext(QWindowsEGLStaticContext *staticContext,
- const QSurfaceFormat &format,
- QPlatformOpenGLContext *share)
- : m_staticContext(staticContext)
- , m_eglDisplay(staticContext->display())
-{
- if (!m_staticContext)
- return;
-
- m_eglConfig = chooseConfig(format);
- m_format = m_staticContext->formatFromConfig(m_eglDisplay, m_eglConfig, format);
- m_shareContext = share ? static_cast<QWindowsEGLContext *>(share)->m_eglContext : nullptr;
-
- QVector<EGLint> contextAttrs;
- const int major = m_format.majorVersion();
- const int minor = m_format.minorVersion();
- if (major > 3 || (major == 3 && minor > 0))
- qWarning("QWindowsEGLContext: ANGLE only partially supports OpenGL ES > 3.0");
- contextAttrs.append(EGL_CONTEXT_MAJOR_VERSION);
- contextAttrs.append(major);
- contextAttrs.append(EGL_CONTEXT_MINOR_VERSION);
- contextAttrs.append(minor);
- contextAttrs.append(EGL_NONE);
-
- QWindowsEGLStaticContext::libEGL.eglBindAPI(m_api);
- m_eglContext = QWindowsEGLStaticContext::libEGL.eglCreateContext(m_eglDisplay, m_eglConfig, m_shareContext, contextAttrs.constData());
- if (m_eglContext == EGL_NO_CONTEXT && m_shareContext != EGL_NO_CONTEXT) {
- m_shareContext = nullptr;
- m_eglContext = QWindowsEGLStaticContext::libEGL.eglCreateContext(m_eglDisplay, m_eglConfig, nullptr, contextAttrs.constData());
- }
-
- if (m_eglContext == EGL_NO_CONTEXT) {
- int err = QWindowsEGLStaticContext::libEGL.eglGetError();
- qWarning("QWindowsEGLContext: Failed to create context, eglError: %x, this: %p", err, this);
- // ANGLE gives bad alloc when it fails to reset a previously lost D3D device.
- // A common cause for this is disabling the graphics adapter used by the app.
- if (err == EGL_BAD_ALLOC)
- qWarning("QWindowsEGLContext: Graphics device lost. (Did the adapter get disabled?)");
- return;
- }
-
- // Make the context current to ensure the GL version query works. This needs a surface too.
- const EGLint pbufferAttributes[] = {
- EGL_WIDTH, 1,
- EGL_HEIGHT, 1,
- EGL_LARGEST_PBUFFER, EGL_FALSE,
- EGL_NONE
- };
- EGLSurface pbuffer = QWindowsEGLStaticContext::libEGL.eglCreatePbufferSurface(m_eglDisplay, m_eglConfig, pbufferAttributes);
- if (pbuffer == EGL_NO_SURFACE)
- return;
-
- EGLDisplay prevDisplay = QWindowsEGLStaticContext::libEGL.eglGetCurrentDisplay();
- if (prevDisplay == EGL_NO_DISPLAY) // when no context is current
- prevDisplay = m_eglDisplay;
- EGLContext prevContext = QWindowsEGLStaticContext::libEGL.eglGetCurrentContext();
- EGLSurface prevSurfaceDraw = QWindowsEGLStaticContext::libEGL.eglGetCurrentSurface(EGL_DRAW);
- EGLSurface prevSurfaceRead = QWindowsEGLStaticContext::libEGL.eglGetCurrentSurface(EGL_READ);
-
- if (QWindowsEGLStaticContext::libEGL.eglMakeCurrent(m_eglDisplay, pbuffer, pbuffer, m_eglContext)) {
- const GLubyte *s = QWindowsEGLStaticContext::libGLESv2.glGetString(GL_VERSION);
- if (s) {
- QByteArray version = QByteArray(reinterpret_cast<const char *>(s));
- int major, minor;
- if (QPlatformOpenGLContext::parseOpenGLVersion(version, major, minor)) {
- m_format.setMajorVersion(major);
- m_format.setMinorVersion(minor);
- }
- }
- m_format.setProfile(QSurfaceFormat::NoProfile);
- m_format.setOptions(QSurfaceFormat::FormatOptions());
- QWindowsEGLStaticContext::libEGL.eglMakeCurrent(prevDisplay, prevSurfaceDraw, prevSurfaceRead, prevContext);
- }
- QWindowsEGLStaticContext::libEGL.eglDestroySurface(m_eglDisplay, pbuffer);
-}
-
-QWindowsEGLContext::~QWindowsEGLContext()
-{
- if (m_eglContext != EGL_NO_CONTEXT) {
- QWindowsEGLStaticContext::libEGL.eglDestroyContext(m_eglDisplay, m_eglContext);
- m_eglContext = EGL_NO_CONTEXT;
- }
-}
-
-bool QWindowsEGLContext::makeCurrent(QPlatformSurface *surface)
-{
- Q_ASSERT(surface->surface()->supportsOpenGL());
-
- QWindowsEGLStaticContext::libEGL.eglBindAPI(m_api);
-
- auto *window = static_cast<QWindowsWindow *>(surface);
- window->aboutToMakeCurrent();
- int err = 0;
- auto eglSurface = static_cast<EGLSurface>(window->surface(m_eglConfig, &err));
- if (eglSurface == EGL_NO_SURFACE) {
- if (err == EGL_CONTEXT_LOST) {
- m_eglContext = EGL_NO_CONTEXT;
- qCDebug(lcQpaGl) << "Got EGL context lost in createWindowSurface() for context" << this;
- } else if (err == EGL_BAD_ACCESS) {
- // With ANGLE this means no (D3D) device and can happen when disabling/changing graphics adapters.
- qCDebug(lcQpaGl) << "Bad access (missing device?) in createWindowSurface() for context" << this;
- // Simulate context loss as the context is useless.
- QWindowsEGLStaticContext::libEGL.eglDestroyContext(m_eglDisplay, m_eglContext);
- m_eglContext = EGL_NO_CONTEXT;
- }
- return false;
- }
-
- // shortcut: on some GPUs, eglMakeCurrent is not a cheap operation
- if (QWindowsEGLStaticContext::libEGL.eglGetCurrentContext() == m_eglContext &&
- QWindowsEGLStaticContext::libEGL.eglGetCurrentDisplay() == m_eglDisplay &&
- QWindowsEGLStaticContext::libEGL.eglGetCurrentSurface(EGL_READ) == eglSurface &&
- QWindowsEGLStaticContext::libEGL.eglGetCurrentSurface(EGL_DRAW) == eglSurface) {
- return true;
- }
-
- const bool ok = QWindowsEGLStaticContext::libEGL.eglMakeCurrent(m_eglDisplay, eglSurface, eglSurface, m_eglContext);
- if (ok) {
- const int requestedSwapInterval = surface->format().swapInterval();
- if (requestedSwapInterval >= 0 && m_swapInterval != requestedSwapInterval) {
- m_swapInterval = requestedSwapInterval;
- QWindowsEGLStaticContext::libEGL.eglSwapInterval(m_staticContext->display(), m_swapInterval);
- }
- } else {
- err = QWindowsEGLStaticContext::libEGL.eglGetError();
- // EGL_CONTEXT_LOST (loss of the D3D device) is not necessarily fatal.
- // Qt Quick is able to recover for example.
- if (err == EGL_CONTEXT_LOST) {
- m_eglContext = EGL_NO_CONTEXT;
- qCDebug(lcQpaGl) << "Got EGL context lost in makeCurrent() for context" << this;
- // Drop the surface. Will recreate on the next makeCurrent.
- window->invalidateSurface();
- } else {
- qWarning("%s: Failed to make surface current. eglError: %x, this: %p", __FUNCTION__, err, this);
- }
- }
-
- return ok;
-}
-
-void QWindowsEGLContext::doneCurrent()
-{
- QWindowsEGLStaticContext::libEGL.eglBindAPI(m_api);
- bool ok = QWindowsEGLStaticContext::libEGL.eglMakeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
- if (!ok)
- qWarning("%s: Failed to make no context/surface current. eglError: %d, this: %p", __FUNCTION__,
- QWindowsEGLStaticContext::libEGL.eglGetError(), this);
-}
-
-void QWindowsEGLContext::swapBuffers(QPlatformSurface *surface)
-{
- QWindowsEGLStaticContext::libEGL.eglBindAPI(m_api);
- auto *window = static_cast<QWindowsWindow *>(surface);
- int err = 0;
- auto eglSurface = static_cast<EGLSurface>(window->surface(m_eglConfig, &err));
- if (eglSurface == EGL_NO_SURFACE) {
- if (err == EGL_CONTEXT_LOST) {
- m_eglContext = EGL_NO_CONTEXT;
- qCDebug(lcQpaGl) << "Got EGL context lost in createWindowSurface() for context" << this;
- }
- return;
- }
-
- bool ok = QWindowsEGLStaticContext::libEGL.eglSwapBuffers(m_eglDisplay, eglSurface);
- if (!ok) {
- err = QWindowsEGLStaticContext::libEGL.eglGetError();
- if (err == EGL_CONTEXT_LOST) {
- m_eglContext = EGL_NO_CONTEXT;
- qCDebug(lcQpaGl) << "Got EGL context lost in eglSwapBuffers()";
- } else {
- qWarning("%s: Failed to swap buffers. eglError: %d, this: %p", __FUNCTION__, err, this);
- }
- }
-}
-
-QFunctionPointer QWindowsEGLContext::getProcAddress(const char *procName)
-{
- QWindowsEGLStaticContext::libEGL.eglBindAPI(m_api);
-
- QFunctionPointer procAddress = nullptr;
-
- // Special logic for ANGLE extensions for blitFramebuffer and
- // renderbufferStorageMultisample. In version 2 contexts the extensions
- // must be used instead of the suffixless, version 3.0 functions.
- if (m_format.majorVersion() < 3) {
- if (!strcmp(procName, "glBlitFramebuffer") || !strcmp(procName, "glRenderbufferStorageMultisample")) {
- char extName[32 + 5 + 1];
- strcpy(extName, procName);
- strcat(extName, "ANGLE");
- procAddress = reinterpret_cast<QFunctionPointer>(QWindowsEGLStaticContext::libEGL.eglGetProcAddress(extName));
- }
- }
-
- if (!procAddress)
- procAddress = reinterpret_cast<QFunctionPointer>(QWindowsEGLStaticContext::libEGL.eglGetProcAddress(procName));
-
- // We support AllGLFunctionsQueryable, which means this function must be able to
- // return a function pointer for standard GLES2 functions too. These are not
- // guaranteed to be queryable via eglGetProcAddress().
- if (!procAddress) {
-#if defined(QT_STATIC) && !defined(QT_OPENGL_DYNAMIC)
- static struct StdFunc {
- const char *name;
- void *func;
- } standardFuncs[] = {
- { "glBindTexture", (void *) ::glBindTexture },
- { "glBlendFunc", (void *) ::glBlendFunc },
- { "glClear", (void *) ::glClear },
- { "glClearColor", (void *) ::glClearColor },
- { "glClearStencil", (void *) ::glClearStencil },
- { "glColorMask", (void *) ::glColorMask },
- { "glCopyTexImage2D", (void *) ::glCopyTexImage2D },
- { "glCopyTexSubImage2D", (void *) ::glCopyTexSubImage2D },
- { "glCullFace", (void *) ::glCullFace },
- { "glDeleteTextures", (void *) ::glDeleteTextures },
- { "glDepthFunc", (void *) ::glDepthFunc },
- { "glDepthMask", (void *) ::glDepthMask },
- { "glDisable", (void *) ::glDisable },
- { "glDrawArrays", (void *) ::glDrawArrays },
- { "glDrawElements", (void *) ::glDrawElements },
- { "glEnable", (void *) ::glEnable },
- { "glFinish", (void *) ::glFinish },
- { "glFlush", (void *) ::glFlush },
- { "glFrontFace", (void *) ::glFrontFace },
- { "glGenTextures", (void *) ::glGenTextures },
- { "glGetBooleanv", (void *) ::glGetBooleanv },
- { "glGetError", (void *) ::glGetError },
- { "glGetFloatv", (void *) ::glGetFloatv },
- { "glGetIntegerv", (void *) ::glGetIntegerv },
- { "glGetString", (void *) ::glGetString },
- { "glGetTexParameterfv", (void *) ::glGetTexParameterfv },
- { "glGetTexParameteriv", (void *) ::glGetTexParameteriv },
- { "glHint", (void *) ::glHint },
- { "glIsEnabled", (void *) ::glIsEnabled },
- { "glIsTexture", (void *) ::glIsTexture },
- { "glLineWidth", (void *) ::glLineWidth },
- { "glPixelStorei", (void *) ::glPixelStorei },
- { "glPolygonOffset", (void *) ::glPolygonOffset },
- { "glReadPixels", (void *) ::glReadPixels },
- { "glScissor", (void *) ::glScissor },
- { "glStencilFunc", (void *) ::glStencilFunc },
- { "glStencilMask", (void *) ::glStencilMask },
- { "glStencilOp", (void *) ::glStencilOp },
- { "glTexImage2D", (void *) ::glTexImage2D },
- { "glTexParameterf", (void *) ::glTexParameterf },
- { "glTexParameterfv", (void *) ::glTexParameterfv },
- { "glTexParameteri", (void *) ::glTexParameteri },
- { "glTexParameteriv", (void *) ::glTexParameteriv },
- { "glTexSubImage2D", (void *) ::glTexSubImage2D },
- { "glViewport", (void *) ::glViewport },
-
- { "glActiveTexture", (void *) ::glActiveTexture },
- { "glAttachShader", (void *) ::glAttachShader },
- { "glBindAttribLocation", (void *) ::glBindAttribLocation },
- { "glBindBuffer", (void *) ::glBindBuffer },
- { "glBindFramebuffer", (void *) ::glBindFramebuffer },
- { "glBindRenderbuffer", (void *) ::glBindRenderbuffer },
- { "glBlendColor", (void *) ::glBlendColor },
- { "glBlendEquation", (void *) ::glBlendEquation },
- { "glBlendEquationSeparate", (void *) ::glBlendEquationSeparate },
- { "glBlendFuncSeparate", (void *) ::glBlendFuncSeparate },
- { "glBufferData", (void *) ::glBufferData },
- { "glBufferSubData", (void *) ::glBufferSubData },
- { "glCheckFramebufferStatus", (void *) ::glCheckFramebufferStatus },
- { "glCompileShader", (void *) ::glCompileShader },
- { "glCompressedTexImage2D", (void *) ::glCompressedTexImage2D },
- { "glCompressedTexSubImage2D", (void *) ::glCompressedTexSubImage2D },
- { "glCreateProgram", (void *) ::glCreateProgram },
- { "glCreateShader", (void *) ::glCreateShader },
- { "glDeleteBuffers", (void *) ::glDeleteBuffers },
- { "glDeleteFramebuffers", (void *) ::glDeleteFramebuffers },
- { "glDeleteProgram", (void *) ::glDeleteProgram },
- { "glDeleteRenderbuffers", (void *) ::glDeleteRenderbuffers },
- { "glDeleteShader", (void *) ::glDeleteShader },
- { "glDetachShader", (void *) ::glDetachShader },
- { "glDisableVertexAttribArray", (void *) ::glDisableVertexAttribArray },
- { "glEnableVertexAttribArray", (void *) ::glEnableVertexAttribArray },
- { "glFramebufferRenderbuffer", (void *) ::glFramebufferRenderbuffer },
- { "glFramebufferTexture2D", (void *) ::glFramebufferTexture2D },
- { "glGenBuffers", (void *) ::glGenBuffers },
- { "glGenerateMipmap", (void *) ::glGenerateMipmap },
- { "glGenFramebuffers", (void *) ::glGenFramebuffers },
- { "glGenRenderbuffers", (void *) ::glGenRenderbuffers },
- { "glGetActiveAttrib", (void *) ::glGetActiveAttrib },
- { "glGetActiveUniform", (void *) ::glGetActiveUniform },
- { "glGetAttachedShaders", (void *) ::glGetAttachedShaders },
- { "glGetAttribLocation", (void *) ::glGetAttribLocation },
- { "glGetBufferParameteriv", (void *) ::glGetBufferParameteriv },
- { "glGetFramebufferAttachmentParameteriv", (void *) ::glGetFramebufferAttachmentParameteriv },
- { "glGetProgramiv", (void *) ::glGetProgramiv },
- { "glGetProgramInfoLog", (void *) ::glGetProgramInfoLog },
- { "glGetRenderbufferParameteriv", (void *) ::glGetRenderbufferParameteriv },
- { "glGetShaderiv", (void *) ::glGetShaderiv },
- { "glGetShaderInfoLog", (void *) ::glGetShaderInfoLog },
- { "glGetShaderPrecisionFormat", (void *) ::glGetShaderPrecisionFormat },
- { "glGetShaderSource", (void *) ::glGetShaderSource },
- { "glGetUniformfv", (void *) ::glGetUniformfv },
- { "glGetUniformiv", (void *) ::glGetUniformiv },
- { "glGetUniformLocation", (void *) ::glGetUniformLocation },
- { "glGetVertexAttribfv", (void *) ::glGetVertexAttribfv },
- { "glGetVertexAttribiv", (void *) ::glGetVertexAttribiv },
- { "glGetVertexAttribPointerv", (void *) ::glGetVertexAttribPointerv },
- { "glIsBuffer", (void *) ::glIsBuffer },
- { "glIsFramebuffer", (void *) ::glIsFramebuffer },
- { "glIsProgram", (void *) ::glIsProgram },
- { "glIsRenderbuffer", (void *) ::glIsRenderbuffer },
- { "glIsShader", (void *) ::glIsShader },
- { "glLinkProgram", (void *) ::glLinkProgram },
- { "glReleaseShaderCompiler", (void *) ::glReleaseShaderCompiler },
- { "glRenderbufferStorage", (void *) ::glRenderbufferStorage },
- { "glSampleCoverage", (void *) ::glSampleCoverage },
- { "glShaderBinary", (void *) ::glShaderBinary },
- { "glShaderSource", (void *) ::glShaderSource },
- { "glStencilFuncSeparate", (void *) ::glStencilFuncSeparate },
- { "glStencilMaskSeparate", (void *) ::glStencilMaskSeparate },
- { "glStencilOpSeparate", (void *) ::glStencilOpSeparate },
- { "glUniform1f", (void *) ::glUniform1f },
- { "glUniform1fv", (void *) ::glUniform1fv },
- { "glUniform1i", (void *) ::glUniform1i },
- { "glUniform1iv", (void *) ::glUniform1iv },
- { "glUniform2f", (void *) ::glUniform2f },
- { "glUniform2fv", (void *) ::glUniform2fv },
- { "glUniform2i", (void *) ::glUniform2i },
- { "glUniform2iv", (void *) ::glUniform2iv },
- { "glUniform3f", (void *) ::glUniform3f },
- { "glUniform3fv", (void *) ::glUniform3fv },
- { "glUniform3i", (void *) ::glUniform3i },
- { "glUniform3iv", (void *) ::glUniform3iv },
- { "glUniform4f", (void *) ::glUniform4f },
- { "glUniform4fv", (void *) ::glUniform4fv },
- { "glUniform4i", (void *) ::glUniform4i },
- { "glUniform4iv", (void *) ::glUniform4iv },
- { "glUniformMatrix2fv", (void *) ::glUniformMatrix2fv },
- { "glUniformMatrix3fv", (void *) ::glUniformMatrix3fv },
- { "glUniformMatrix4fv", (void *) ::glUniformMatrix4fv },
- { "glUseProgram", (void *) ::glUseProgram },
- { "glValidateProgram", (void *) ::glValidateProgram },
- { "glVertexAttrib1f", (void *) ::glVertexAttrib1f },
- { "glVertexAttrib1fv", (void *) ::glVertexAttrib1fv },
- { "glVertexAttrib2f", (void *) ::glVertexAttrib2f },
- { "glVertexAttrib2fv", (void *) ::glVertexAttrib2fv },
- { "glVertexAttrib3f", (void *) ::glVertexAttrib3f },
- { "glVertexAttrib3fv", (void *) ::glVertexAttrib3fv },
- { "glVertexAttrib4f", (void *) ::glVertexAttrib4f },
- { "glVertexAttrib4fv", (void *) ::glVertexAttrib4fv },
- { "glVertexAttribPointer", (void *) ::glVertexAttribPointer },
-
- { "glClearDepthf", (void *) ::glClearDepthf },
- { "glDepthRangef", (void *) ::glDepthRangef }
- };
- for (size_t i = 0; i < sizeof(standardFuncs) / sizeof(StdFunc); ++i)
- if (!qstrcmp(procName, standardFuncs[i].name))
- return reinterpret_cast<QFunctionPointer>(standardFuncs[i].func);
-#else
- procAddress = reinterpret_cast<QFunctionPointer>(QWindowsEGLStaticContext::libGLESv2.resolve(procName));
-#endif
-}
-
- if (QWindowsContext::verbose > 1)
- qCDebug(lcQpaGl) << __FUNCTION__ << procName << QWindowsEGLStaticContext::libEGL.eglGetCurrentContext() << "returns" << procAddress;
-
- return procAddress;
-}
-
-static QVector<EGLint> createConfigAttributesFromFormat(const QSurfaceFormat &format)
-{
- int redSize = format.redBufferSize();
- int greenSize = format.greenBufferSize();
- int blueSize = format.blueBufferSize();
- int alphaSize = format.alphaBufferSize();
- int depthSize = format.depthBufferSize();
- int stencilSize = format.stencilBufferSize();
- int sampleCount = format.samples();
-
- QVector<EGLint> configAttributes;
- configAttributes.reserve(16);
-
- configAttributes.append(EGL_RED_SIZE);
- configAttributes.append(redSize > 0 ? redSize : 0);
-
- configAttributes.append(EGL_GREEN_SIZE);
- configAttributes.append(greenSize > 0 ? greenSize : 0);
-
- configAttributes.append(EGL_BLUE_SIZE);
- configAttributes.append(blueSize > 0 ? blueSize : 0);
-
- configAttributes.append(EGL_ALPHA_SIZE);
- configAttributes.append(alphaSize > 0 ? alphaSize : 0);
-
- configAttributes.append(EGL_DEPTH_SIZE);
- configAttributes.append(depthSize > 0 ? depthSize : 0);
-
- configAttributes.append(EGL_STENCIL_SIZE);
- configAttributes.append(stencilSize > 0 ? stencilSize : 0);
-
- configAttributes.append(EGL_SAMPLES);
- configAttributes.append(sampleCount > 0 ? sampleCount : 0);
-
- configAttributes.append(EGL_SAMPLE_BUFFERS);
- configAttributes.append(sampleCount > 0);
-
- return configAttributes;
-}
-
-static bool reduceConfigAttributes(QVector<EGLint> *configAttributes)
-{
- int i = -1;
-
- i = configAttributes->indexOf(EGL_SWAP_BEHAVIOR);
- if (i >= 0) {
- configAttributes->remove(i,2);
- }
-
- i = configAttributes->indexOf(EGL_BUFFER_SIZE);
- if (i >= 0) {
- if (configAttributes->at(i+1) == 16) {
- configAttributes->remove(i,2);
- return true;
- }
- }
-
- i = configAttributes->indexOf(EGL_SAMPLES);
- if (i >= 0) {
- EGLint value = configAttributes->value(i+1, 0);
- if (value > 1)
- configAttributes->replace(i+1, qMin(EGLint(16), value / 2));
- else
- configAttributes->remove(i, 2);
- return true;
- }
-
- i = configAttributes->indexOf(EGL_SAMPLE_BUFFERS);
- if (i >= 0) {
- configAttributes->remove(i,2);
- return true;
- }
-
- i = configAttributes->indexOf(EGL_ALPHA_SIZE);
- if (i >= 0) {
- configAttributes->remove(i,2);
-#if defined(EGL_BIND_TO_TEXTURE_RGBA) && defined(EGL_BIND_TO_TEXTURE_RGB)
- i = configAttributes->indexOf(EGL_BIND_TO_TEXTURE_RGBA);
- if (i >= 0) {
- configAttributes->replace(i,EGL_BIND_TO_TEXTURE_RGB);
- configAttributes->replace(i+1,true);
-
- }
-#endif
- return true;
- }
-
- i = configAttributes->indexOf(EGL_STENCIL_SIZE);
- if (i >= 0) {
- if (configAttributes->at(i + 1) > 1)
- configAttributes->replace(i + 1, 1);
- else
- configAttributes->remove(i, 2);
- return true;
- }
-
- i = configAttributes->indexOf(EGL_DEPTH_SIZE);
- if (i >= 0) {
- if (configAttributes->at(i + 1) > 1)
- configAttributes->replace(i + 1, 1);
- else
- configAttributes->remove(i, 2);
- return true;
- }
-#ifdef EGL_BIND_TO_TEXTURE_RGB
- i = configAttributes->indexOf(EGL_BIND_TO_TEXTURE_RGB);
- if (i >= 0) {
- configAttributes->remove(i,2);
- return true;
- }
-#endif
-
- return false;
-}
-
-EGLConfig QWindowsEGLContext::chooseConfig(const QSurfaceFormat &format)
-{
- QVector<EGLint> configureAttributes = createConfigAttributesFromFormat(format);
- configureAttributes.append(EGL_SURFACE_TYPE);
- configureAttributes.append(EGL_WINDOW_BIT);
- configureAttributes.append(EGL_RENDERABLE_TYPE);
- configureAttributes.append(EGL_OPENGL_ES2_BIT);
- configureAttributes.append(EGL_NONE);
-
- EGLDisplay display = m_staticContext->display();
- EGLConfig cfg = nullptr;
- do {
- // Get the number of matching configurations for this set of properties.
- EGLint matching = 0;
- if (!QWindowsEGLStaticContext::libEGL.eglChooseConfig(display, configureAttributes.constData(), nullptr, 0, &matching) || !matching)
- continue;
-
- // Fetch all of the matching configurations and find the
- // first that matches the pixel format we wanted.
- int i = configureAttributes.indexOf(EGL_RED_SIZE);
- int confAttrRed = configureAttributes.at(i+1);
- i = configureAttributes.indexOf(EGL_GREEN_SIZE);
- int confAttrGreen = configureAttributes.at(i+1);
- i = configureAttributes.indexOf(EGL_BLUE_SIZE);
- int confAttrBlue = configureAttributes.at(i+1);
- i = configureAttributes.indexOf(EGL_ALPHA_SIZE);
- int confAttrAlpha = i == -1 ? 0 : configureAttributes.at(i+1);
-
- QVector<EGLConfig> configs(matching);
- QWindowsEGLStaticContext::libEGL.eglChooseConfig(display, configureAttributes.constData(), configs.data(), configs.size(), &matching);
- if (!cfg && matching > 0)
- cfg = configs.constFirst();
-
- EGLint red = 0;
- EGLint green = 0;
- EGLint blue = 0;
- EGLint alpha = 0;
- for (const EGLConfig &config : configs) {
- if (confAttrRed)
- QWindowsEGLStaticContext::libEGL.eglGetConfigAttrib(display, config, EGL_RED_SIZE, &red);
- if (confAttrGreen)
- QWindowsEGLStaticContext::libEGL.eglGetConfigAttrib(display, config, EGL_GREEN_SIZE, &green);
- if (confAttrBlue)
- QWindowsEGLStaticContext::libEGL.eglGetConfigAttrib(display, config, EGL_BLUE_SIZE, &blue);
- if (confAttrAlpha)
- QWindowsEGLStaticContext::libEGL.eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &alpha);
-
- if (red == confAttrRed && green == confAttrGreen
- && blue == confAttrBlue && alpha == confAttrAlpha)
- return config;
- }
- } while (reduceConfigAttributes(&configureAttributes));
-
- if (!cfg)
- qWarning("Cannot find EGLConfig, returning null config");
-
- return cfg;
-}
-
-QT_END_NAMESPACE
diff --git a/src/plugins/platforms/windows/qwindowseglcontext.h b/src/plugins/platforms/windows/qwindowseglcontext.h
deleted file mode 100644
index d96e266159..0000000000
--- a/src/plugins/platforms/windows/qwindowseglcontext.h
+++ /dev/null
@@ -1,176 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 QWINDOWSEGLCONTEXT_H
-#define QWINDOWSEGLCONTEXT_H
-
-#include "qwindowsopenglcontext.h"
-#include "qwindowsopengltester.h"
-#include <EGL/egl.h>
-
-QT_BEGIN_NAMESPACE
-
-struct QWindowsLibEGL
-{
- bool init();
-
- EGLint (EGLAPIENTRY * eglGetError)(void);
- EGLDisplay (EGLAPIENTRY * eglGetDisplay)(EGLNativeDisplayType display_id);
- EGLBoolean (EGLAPIENTRY * eglInitialize)(EGLDisplay dpy, EGLint *major, EGLint *minor);
- EGLBoolean (EGLAPIENTRY * eglTerminate)(EGLDisplay dpy);
- EGLBoolean (EGLAPIENTRY * eglChooseConfig)(EGLDisplay dpy, const EGLint *attrib_list,
- EGLConfig *configs, EGLint config_size,
- EGLint *num_config);
- EGLBoolean (EGLAPIENTRY * eglGetConfigAttrib)(EGLDisplay dpy, EGLConfig config,
- EGLint attribute, EGLint *value);
- EGLSurface (EGLAPIENTRY * eglCreateWindowSurface)(EGLDisplay dpy, EGLConfig config,
- EGLNativeWindowType win,
- const EGLint *attrib_list);
- EGLSurface (EGLAPIENTRY * eglCreatePbufferSurface)(EGLDisplay dpy, EGLConfig config,
- const EGLint *attrib_list);
- EGLBoolean (EGLAPIENTRY * eglDestroySurface)(EGLDisplay dpy, EGLSurface surface);
- EGLBoolean (EGLAPIENTRY * eglBindAPI)(EGLenum api);
- EGLBoolean (EGLAPIENTRY * eglSwapInterval)(EGLDisplay dpy, EGLint interval);
- EGLContext (EGLAPIENTRY * eglCreateContext)(EGLDisplay dpy, EGLConfig config,
- EGLContext share_context,
- const EGLint *attrib_list);
- EGLBoolean (EGLAPIENTRY * eglDestroyContext)(EGLDisplay dpy, EGLContext ctx);
- EGLBoolean (EGLAPIENTRY * eglMakeCurrent)(EGLDisplay dpy, EGLSurface draw,
- EGLSurface read, EGLContext ctx);
- EGLContext (EGLAPIENTRY * eglGetCurrentContext)(void);
- EGLSurface (EGLAPIENTRY * eglGetCurrentSurface)(EGLint readdraw);
- EGLDisplay (EGLAPIENTRY * eglGetCurrentDisplay)(void);
- EGLBoolean (EGLAPIENTRY * eglSwapBuffers)(EGLDisplay dpy, EGLSurface surface);
- QFunctionPointer (EGLAPIENTRY *eglGetProcAddress)(const char *procname);
-
- EGLDisplay (EGLAPIENTRY * eglGetPlatformDisplayEXT)(EGLenum platform, void *native_display, const EGLint *attrib_list);
-
-private:
-#if !defined(QT_STATIC) || defined(QT_OPENGL_DYNAMIC)
- void *resolve(const char *name);
- HMODULE m_lib;
-#endif
-};
-
-struct QWindowsLibGLESv2
-{
- bool init();
-
-#if !defined(QT_STATIC) || defined(QT_OPENGL_DYNAMIC)
- void *moduleHandle() const { return m_lib; }
-#else
- void *moduleHandle() const { return nullptr; }
-#endif
-
- const GLubyte * (APIENTRY * glGetString)(GLenum name);
-
-#if !defined(QT_STATIC) || defined(QT_OPENGL_DYNAMIC)
- void *resolve(const char *name);
-private:
- HMODULE m_lib;
-#endif
-};
-
-class QWindowsEGLStaticContext : public QWindowsStaticOpenGLContext
-{
- Q_DISABLE_COPY_MOVE(QWindowsEGLStaticContext)
-
-public:
- static QWindowsEGLStaticContext *create(QWindowsOpenGLTester::Renderers preferredType);
- ~QWindowsEGLStaticContext() override;
-
- EGLDisplay display() const { return m_display; }
-
- QWindowsOpenGLContext *createContext(QOpenGLContext *context) override;
- void *moduleHandle() const override { return libGLESv2.moduleHandle(); }
- QOpenGLContext::OpenGLModuleType moduleType() const override { return QOpenGLContext::LibGLES; }
-
- void *createWindowSurface(void *nativeWindow, void *nativeConfig, int *err) override;
- void destroyWindowSurface(void *nativeSurface) override;
-
- QSurfaceFormat formatFromConfig(EGLDisplay display, EGLConfig config, const QSurfaceFormat &referenceFormat);
-
- static QWindowsLibEGL libEGL;
- static QWindowsLibGLESv2 libGLESv2;
-
-private:
- explicit QWindowsEGLStaticContext(EGLDisplay display);
- static bool initializeAngle(QWindowsOpenGLTester::Renderers preferredType, HDC dc,
- EGLDisplay *display, EGLint *major, EGLint *minor);
-
- const EGLDisplay m_display;
-};
-
-class QWindowsEGLContext : public QWindowsOpenGLContext
-{
-public:
- QWindowsEGLContext(QWindowsEGLStaticContext *staticContext,
- const QSurfaceFormat &format,
- QPlatformOpenGLContext *share);
- ~QWindowsEGLContext() override;
-
- bool makeCurrent(QPlatformSurface *surface) override;
- void doneCurrent() override;
- void swapBuffers(QPlatformSurface *surface) override;
- QFunctionPointer getProcAddress(const char *procName) override;
-
- QSurfaceFormat format() const override { return m_format; }
- bool isSharing() const override { return m_shareContext != EGL_NO_CONTEXT; }
- bool isValid() const override { return m_eglContext != EGL_NO_CONTEXT; }
-
- void *nativeContext() const override { return m_eglContext; }
- void *nativeDisplay() const override { return m_eglDisplay; }
- void *nativeConfig() const override { return m_eglConfig; }
-
-private:
- EGLConfig chooseConfig(const QSurfaceFormat &format);
-
- QWindowsEGLStaticContext *m_staticContext;
- EGLContext m_eglContext;
- EGLContext m_shareContext;
- EGLDisplay m_eglDisplay;
- EGLConfig m_eglConfig;
- QSurfaceFormat m_format;
- EGLenum m_api = EGL_OPENGL_ES_API;
- int m_swapInterval = -1;
-};
-
-QT_END_NAMESPACE
-
-#endif // QWINDOWSEGLCONTEXT_H
diff --git a/src/plugins/platforms/windows/qwindowsgdiintegration.cpp b/src/plugins/platforms/windows/qwindowsgdiintegration.cpp
index 7e9595321a..14fd03fc1f 100644
--- a/src/plugins/platforms/windows/qwindowsgdiintegration.cpp
+++ b/src/plugins/platforms/windows/qwindowsgdiintegration.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qwindowsgdiintegration.h"
#include "qwindowscontext.h"
@@ -45,10 +9,6 @@
#include <QtCore/qdebug.h>
#include <QtGui/private/qpixmap_raster_p.h>
-#if QT_CONFIG(opengl)
-#include <QtPlatformCompositorSupport/qpa/qplatformbackingstoreopenglsupport.h>
-#endif
-
QT_BEGIN_NAMESPACE
class QWindowsGdiIntegrationPrivate
@@ -77,11 +37,7 @@ QPlatformPixmap *QWindowsGdiIntegration::createPlatformPixmap(QPlatformPixmap::P
QPlatformBackingStore *QWindowsGdiIntegration::createPlatformBackingStore(QWindow *window) const
{
- auto *backingStore = new QWindowsBackingStore(window);
-#ifndef QT_NO_OPENGL
- backingStore->setOpenGLSupport(new QPlatformBackingStoreOpenGLSupport(backingStore));
-#endif
- return backingStore;
+ return new QWindowsBackingStore(window);
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/windows/qwindowsgdiintegration.h b/src/plugins/platforms/windows/qwindowsgdiintegration.h
index 74ce3ffd49..fbb6b7460d 100644
--- a/src/plugins/platforms/windows/qwindowsgdiintegration.h
+++ b/src/plugins/platforms/windows/qwindowsgdiintegration.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QWINDOWSGDIINTEGRATION_H
#define QWINDOWSGDIINTEGRATION_H
diff --git a/src/plugins/platforms/windows/qwindowsgdinativeinterface.cpp b/src/plugins/platforms/windows/qwindowsgdinativeinterface.cpp
index f2418b0e60..78325c88d1 100644
--- a/src/plugins/platforms/windows/qwindowsgdinativeinterface.cpp
+++ b/src/plugins/platforms/windows/qwindowsgdinativeinterface.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qwindowsgdinativeinterface.h"
#include "qwindowsbackingstore.h"
diff --git a/src/plugins/platforms/windows/qwindowsgdinativeinterface.h b/src/plugins/platforms/windows/qwindowsgdinativeinterface.h
index c86d3cbb47..7ef1244db3 100644
--- a/src/plugins/platforms/windows/qwindowsgdinativeinterface.h
+++ b/src/plugins/platforms/windows/qwindowsgdinativeinterface.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QWINDOWSGDINATIVEINTERFACE_H
#define QWINDOWSGDINATIVEINTERFACE_H
diff --git a/src/plugins/platforms/windows/qwindowsglcontext.cpp b/src/plugins/platforms/windows/qwindowsglcontext.cpp
index 7431f52e8a..5ca52c2c19 100644
--- a/src/plugins/platforms/windows/qwindowsglcontext.cpp
+++ b/src/plugins/platforms/windows/qwindowsglcontext.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qwindowsglcontext.h"
#include "qwindowscontext.h"
@@ -44,10 +8,10 @@
#include <QtCore/qdebug.h>
#include <QtCore/qsysinfo.h>
+#include <QtGui/qcolorspace.h>
#include <QtGui/qguiapplication.h>
#include <qpa/qplatformnativeinterface.h>
-#include <QtPlatformHeaders/qwglnativecontext.h>
-
+#include <private/qsystemlibrary_p.h>
#include <algorithm>
#include <wingdi.h>
@@ -162,19 +126,25 @@ QFunctionPointer QWindowsOpengl32DLL::resolve(const char *name)
bool QWindowsOpengl32DLL::init(bool softwareRendering)
{
- const QByteArray opengl32 = QByteArrayLiteral("opengl32.dll");
- const QByteArray swopengl = QByteArrayLiteral("opengl32sw.dll");
+ const QByteArray opengl32 = QByteArrayLiteral("opengl32");
+ const QByteArray swopengl = QByteArrayLiteral("opengl32sw");
+ bool useSystemLib = false;
QByteArray openglDll = qgetenv("QT_OPENGL_DLL");
- if (openglDll.isEmpty())
+ if (openglDll.isEmpty()) {
openglDll = softwareRendering ? swopengl : opengl32;
+ useSystemLib = !softwareRendering;
+ }
openglDll = openglDll.toLower();
m_nonOpengl32 = openglDll != opengl32;
qCDebug(lcQpaGl) << "Qt: Using WGL and OpenGL from" << openglDll;
- m_lib = ::LoadLibraryA(openglDll.constData());
+ if (useSystemLib)
+ m_lib = QSystemLibrary::load((wchar_t*)(QString::fromLatin1(openglDll).utf16()));
+ else
+ m_lib = LoadLibraryA(openglDll.constData());
if (!m_lib) {
qErrnoWarning(::GetLastError(), "Failed to load %s", openglDll.constData());
return false;
@@ -184,7 +154,7 @@ bool QWindowsOpengl32DLL::init(bool softwareRendering)
// Load opengl32.dll always. GDI functions like ChoosePixelFormat do
// GetModuleHandle for opengl32.dll and behave differently (and call back into
// opengl32) when the module is present. This is fine for dummy contexts and windows.
- ::LoadLibraryA("opengl32.dll");
+ QSystemLibrary::load(L"opengl32");
}
wglCreateContext = reinterpret_cast<HGLRC (WINAPI *)(HDC)>(resolve("wglCreateContext"));
@@ -225,6 +195,11 @@ QWindowsOpenGLContext *QOpenGLStaticContext::createContext(QOpenGLContext *conte
return new QWindowsGLContext(this, context);
}
+QWindowsOpenGLContext *QOpenGLStaticContext::createContext(HGLRC context, HWND window)
+{
+ return new QWindowsGLContext(this, context, window);
+}
+
template <class MaskType, class FlagType> inline bool testFlag(MaskType mask, FlagType flag)
{
return (mask & MaskType(flag)) != 0;
@@ -569,11 +544,14 @@ static int choosePixelFormat(HDC hdc,
iAttributes[i++] = WGL_NUMBER_OVERLAYS_ARB;
iAttributes[i++] = 1;
}
+ // must be the one before the last one
const int samples = format.samples();
const bool sampleBuffersRequested = samples > 1
&& testFlag(staticContext.extensions, QOpenGLStaticContext::SampleBuffers);
+ int sampleBuffersKeyPosition = 0;
int samplesValuePosition = 0;
if (sampleBuffersRequested) {
+ sampleBuffersKeyPosition = i;
iAttributes[i++] = WGL_SAMPLE_BUFFERS_ARB;
iAttributes[i++] = TRUE;
iAttributes[i++] = WGL_SAMPLES_ARB;
@@ -584,10 +562,10 @@ static int choosePixelFormat(HDC hdc,
iAttributes[i++] = FALSE;
}
// must be the last
- bool srgbRequested = format.colorSpace() == QSurfaceFormat::sRGBColorSpace;
- int srgbValuePosition = 0;
+ bool srgbRequested = format.colorSpace() == QColorSpace::SRgb;
+ int srgbCapableKeyPosition = 0;
if (srgbRequested) {
- srgbValuePosition = i;
+ srgbCapableKeyPosition = i;
iAttributes[i++] = WGL_FRAMEBUFFER_SRGB_CAPABLE_EXT;
iAttributes[i++] = TRUE;
}
@@ -601,8 +579,9 @@ static int choosePixelFormat(HDC hdc,
&& numFormats >= 1;
if (valid || (!sampleBuffersRequested && !srgbRequested))
break;
+ // NB reductions must be done in reverse order (disable the last first, then move on to the one before that, etc.)
if (srgbRequested) {
- iAttributes[srgbValuePosition] = 0;
+ iAttributes[srgbCapableKeyPosition] = 0;
srgbRequested = false;
} else if (sampleBuffersRequested) {
if (iAttributes[samplesValuePosition] > 1) {
@@ -610,11 +589,8 @@ static int choosePixelFormat(HDC hdc,
} else if (iAttributes[samplesValuePosition] == 1) {
// Fallback in case it is unable to initialize with any
// samples to avoid falling back to the GDI path
- // NB: The sample attributes needs to be at the end for this
- // to work correctly
- iAttributes[samplesValuePosition - 1] = FALSE;
+ iAttributes[sampleBuffersKeyPosition] = 0;
iAttributes[samplesValuePosition] = 0;
- iAttributes[samplesValuePosition + 1] = 0;
} else {
break;
}
@@ -706,10 +682,10 @@ static QSurfaceFormat
if (hasSampleBuffers) {
result.setSamples(iValues[13]);
if (hasSrgbSupport && iValues[14])
- result.setColorSpace(QSurfaceFormat::sRGBColorSpace);
+ result.setColorSpace(QColorSpace::SRgb);
} else {
if (hasSrgbSupport && iValues[12])
- result.setColorSpace(QSurfaceFormat::sRGBColorSpace);
+ result.setColorSpace(QColorSpace::SRgb);
}
if (additionalIn) {
if (iValues[7])
@@ -858,7 +834,6 @@ static inline QOpenGLContextData createDummyWindowOpenGLContextData()
context and to apply to a QSurfaceFormat.
\internal
- \ingroup qt-lighthouse-win
*/
QWindowsOpenGLContextFormat QWindowsOpenGLContextFormat::current()
@@ -913,7 +888,6 @@ void QWindowsOpenGLContextFormat::apply(QSurfaceFormat *format) const
is a current GL context.
\internal
- \ingroup qt-lighthouse-win
*/
class QOpenGLTemporaryContext
@@ -946,7 +920,6 @@ QOpenGLTemporaryContext::~QOpenGLTemporaryContext()
/*!
\class QWindowsOpenGLAdditionalFormat
\brief Additional format information that is not in QSurfaceFormat
- \ingroup qt-lighthouse-win
*/
/*!
@@ -964,7 +937,6 @@ QOpenGLTemporaryContext::~QOpenGLTemporaryContext()
\sa QWindowsGLContext
\internal
- \ingroup qt-lighthouse-win
*/
#define SAMPLE_BUFFER_EXTENSION "GL_ARB_multisample"
@@ -1051,66 +1023,15 @@ QOpenGLStaticContext *QOpenGLStaticContext::create(bool softwareRendering)
QOpenGLContextData and are released in doneCurrent().
\internal
- \ingroup qt-lighthouse-win
*/
QWindowsGLContext::QWindowsGLContext(QOpenGLStaticContext *staticContext,
QOpenGLContext *context) :
- m_staticContext(staticContext),
- m_context(context),
- m_renderingContext(nullptr),
- m_pixelFormat(0),
- m_extensionsUsed(false),
- m_swapInterval(-1),
- m_ownsContext(true),
- m_getGraphicsResetStatus(nullptr),
- m_lost(false)
+ m_staticContext(staticContext)
{
if (!m_staticContext) // Something went very wrong. Stop here, isValid() will return false.
return;
- QVariant nativeHandle = context->nativeHandle();
- if (!nativeHandle.isNull()) {
- // Adopt and existing context.
- if (!nativeHandle.canConvert<QWGLNativeContext>()) {
- qWarning("QWindowsGLContext: Requires a QWGLNativeContext");
- return;
- }
- auto handle = nativeHandle.value<QWGLNativeContext>();
- HGLRC wglcontext = handle.context();
- HWND wnd = handle.window();
- if (!wglcontext || !wnd) {
- qWarning("QWindowsGLContext: No context and window given");
- return;
- }
-
- HDC dc = GetDC(wnd);
- // A window with an associated pixel format is mandatory.
- // When no SetPixelFormat() call has been made, the following will fail.
- m_pixelFormat = GetPixelFormat(dc);
- bool ok = m_pixelFormat != 0;
- if (!ok)
- qWarning("QWindowsGLContext: Failed to get pixel format");
- ok = DescribePixelFormat(dc, m_pixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &m_obtainedPixelFormatDescriptor);
- if (!ok) {
- qWarning("QWindowsGLContext: Failed to describe pixel format");
- } else {
- QWindowsOpenGLAdditionalFormat obtainedAdditional;
- m_obtainedFormat = GDI::qSurfaceFormatFromPixelFormat(m_obtainedPixelFormatDescriptor, &obtainedAdditional);
- m_renderingContext = wglcontext;
- ok = updateObtainedParams(dc);
- }
-
- ReleaseDC(wnd, dc);
-
- if (ok)
- m_ownsContext = false;
- else
- m_renderingContext = nullptr;
-
- return;
- }
-
QSurfaceFormat format = context->format();
if (format.renderableType() == QSurfaceFormat::DefaultRenderableType)
format.setRenderableType(QSurfaceFormat::OpenGL);
@@ -1212,11 +1133,6 @@ QWindowsGLContext::QWindowsGLContext(QOpenGLStaticContext *staticContext,
} while (false);
- // Make the HGLRC retrievable via QOpenGLContext::nativeHandle().
- // Do not provide the window since it is the dummy one and it is about to disappear.
- if (m_renderingContext)
- context->setNativeHandle(QVariant::fromValue<QWGLNativeContext>(QWGLNativeContext(m_renderingContext, nullptr)));
-
if (hdc)
ReleaseDC(dummyWindow, hdc);
if (dummyWindow)
@@ -1230,6 +1146,37 @@ QWindowsGLContext::QWindowsGLContext(QOpenGLStaticContext *staticContext,
<< "\n HGLRC=" << m_renderingContext;
}
+QWindowsGLContext::QWindowsGLContext(QOpenGLStaticContext *staticContext, HGLRC wglcontext, HWND wnd)
+ : m_staticContext(staticContext)
+{
+ if (!m_staticContext) // Something went very wrong. Stop here, isValid() will return false.
+ return;
+
+ HDC dc = GetDC(wnd);
+ // A window with an associated pixel format is mandatory.
+ // When no SetPixelFormat() call has been made, the following will fail.
+ m_pixelFormat = GetPixelFormat(dc);
+ bool ok = m_pixelFormat != 0;
+ if (!ok)
+ qWarning("QWindowsGLContext: Failed to get pixel format");
+ ok = DescribePixelFormat(dc, m_pixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &m_obtainedPixelFormatDescriptor);
+ if (!ok) {
+ qWarning("QWindowsGLContext: Failed to describe pixel format");
+ } else {
+ QWindowsOpenGLAdditionalFormat obtainedAdditional;
+ m_obtainedFormat = GDI::qSurfaceFormatFromPixelFormat(m_obtainedPixelFormatDescriptor, &obtainedAdditional);
+ m_renderingContext = wglcontext;
+ ok = updateObtainedParams(dc);
+ }
+
+ ReleaseDC(wnd, dc);
+
+ if (ok)
+ m_ownsContext = false;
+ else
+ m_renderingContext = nullptr;
+}
+
QWindowsGLContext::~QWindowsGLContext()
{
if (m_renderingContext && m_ownsContext)
@@ -1315,17 +1262,19 @@ bool QWindowsGLContext::makeCurrent(QPlatformSurface *surface)
// Do we already have a DC entry for that window?
auto *window = static_cast<QWindowsWindow *>(surface);
- window->aboutToMakeCurrent();
const HWND hwnd = window->handle();
if (const QOpenGLContextData *contextData = findByHWND(m_windowContexts, hwnd)) {
// Repeated calls to wglMakeCurrent when vsync is enabled in the driver will
// often result in 100% cpuload. This check is cheap and avoids the problem.
- // This is reproducable on NVidia cards and Intel onboard chips.
+ // This is reproducible on NVidia cards and Intel onboard chips.
if (QOpenGLStaticContext::opengl32.wglGetCurrentContext() == contextData->renderingContext
&& QOpenGLStaticContext::opengl32.wglGetCurrentDC() == contextData->hdc) {
return true;
}
- return QOpenGLStaticContext::opengl32.wglMakeCurrent(contextData->hdc, contextData->renderingContext);
+ const bool success = QOpenGLStaticContext::opengl32.wglMakeCurrent(contextData->hdc, contextData->renderingContext);
+ if (!success)
+ qErrnoWarning("%s: wglMakeCurrent() failed for existing context data", __FUNCTION__);
+ return success;
}
// Create a new entry.
const QOpenGLContextData newContext(m_renderingContext, hwnd, GetDC(hwnd));
@@ -1353,6 +1302,8 @@ bool QWindowsGLContext::makeCurrent(QPlatformSurface *surface)
qCDebug(lcQpaGl) << "makeCurrent(): context loss detected" << this;
// Drop the surface. Will recreate on the next makeCurrent.
window->invalidateSurface();
+ } else {
+ qErrnoWarning("%s: wglMakeCurrent() failed", __FUNCTION__);
}
}
diff --git a/src/plugins/platforms/windows/qwindowsglcontext.h b/src/plugins/platforms/windows/qwindowsglcontext.h
index 8794368fe4..bf71959853 100644
--- a/src/plugins/platforms/windows/qwindowsglcontext.h
+++ b/src/plugins/platforms/windows/qwindowsglcontext.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QWINDOWSGLCONTEXT_H
#define QWINDOWSGLCONTEXT_H
@@ -174,6 +138,7 @@ public:
static QByteArray getGlString(unsigned int which);
QWindowsOpenGLContext *createContext(QOpenGLContext *context) override;
+ QWindowsOpenGLContext *createContext(HGLRC context, HWND window) override;
void *moduleHandle() const override { return opengl32.moduleHandle(); }
QOpenGLContext::OpenGLModuleType moduleType() const override
{ return QOpenGLContext::LibGL; }
@@ -199,12 +164,14 @@ public:
static QWindowsOpengl32DLL opengl32;
};
-class QWindowsGLContext : public QWindowsOpenGLContext
+class QWindowsGLContext : public QWindowsOpenGLContext, public QNativeInterface::QWGLContext
{
public:
explicit QWindowsGLContext(QOpenGLStaticContext *staticContext, QOpenGLContext *context);
+ explicit QWindowsGLContext(QOpenGLStaticContext *staticContext, HGLRC context, HWND window);
+
~QWindowsGLContext() override;
- bool isSharing() const override { return m_context->shareHandle(); }
+ bool isSharing() const override { return context()->shareHandle(); }
bool isValid() const override { return m_renderingContext && !m_lost; }
QSurfaceFormat format() const override { return m_obtainedFormat; }
@@ -219,7 +186,7 @@ public:
HGLRC renderingContext() const { return m_renderingContext; }
- void *nativeContext() const override { return m_renderingContext; }
+ HGLRC nativeContext() const override { return m_renderingContext; }
private:
typedef GLenum (APIENTRY *GlGetGraphicsResetStatusArbType)();
@@ -227,18 +194,17 @@ private:
inline void releaseDCs();
bool updateObtainedParams(HDC hdc, int *obtainedSwapInterval = nullptr);
- QOpenGLStaticContext *m_staticContext;
- QOpenGLContext *m_context;
+ QOpenGLStaticContext *m_staticContext = nullptr;
QSurfaceFormat m_obtainedFormat;
- HGLRC m_renderingContext;
+ HGLRC m_renderingContext = nullptr;
std::vector<QOpenGLContextData> m_windowContexts;
PIXELFORMATDESCRIPTOR m_obtainedPixelFormatDescriptor;
- int m_pixelFormat;
- bool m_extensionsUsed;
- int m_swapInterval;
- bool m_ownsContext;
- GlGetGraphicsResetStatusArbType m_getGraphicsResetStatus;
- bool m_lost;
+ int m_pixelFormat = 0;
+ bool m_extensionsUsed = false;
+ int m_swapInterval = -1;
+ bool m_ownsContext = true;
+ GlGetGraphicsResetStatusArbType m_getGraphicsResetStatus = nullptr;
+ bool m_lost = false;
};
#endif
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/windows/qwindowsiconengine.cpp b/src/plugins/platforms/windows/qwindowsiconengine.cpp
new file mode 100644
index 0000000000..5e5ca22ec1
--- /dev/null
+++ b/src/plugins/platforms/windows/qwindowsiconengine.cpp
@@ -0,0 +1,394 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qwindowsiconengine.h"
+
+#include <QtCore/qoperatingsystemversion.h>
+#include <QtGui/qguiapplication.h>
+#include <QtGui/qpainter.h>
+#include <QtGui/qpalette.h>
+
+QT_BEGIN_NAMESPACE
+
+using namespace Qt::StringLiterals;
+
+QString QWindowsIconEngine::glyphs() const
+{
+ if (!QFontInfo(m_iconFont).exactMatch())
+ return {};
+
+ static constexpr std::pair<QLatin1StringView, QStringView> glyphMap[] = {
+ {"address-book-new"_L1, u"\ue780"},
+ {"application-exit"_L1, u"\ue8bb"},
+ {"appointment-new"_L1, u"\ue878"},
+ {"call-start"_L1, u"\uf715"},
+ {"call-stop"_L1, u"\uf405"},
+ {"contact-new"_L1, u"\ue8fa"},
+ {"document-new"_L1, u"\ue8a5"},
+ {"document-open"_L1, u"\ue8e5"},
+ {"document-open-recent"_L1, u"\ue823"},
+ {"document-page-setup"_L1, u"\ue7c3"},
+ {"document-print"_L1, u"\ue749"},
+ {"document-print-preview"_L1, u"\ue956"},
+ {"document-properties"_L1, u"\ue90f"},
+ {"document-revert"_L1, u"\ue7a7"}, // ?
+ {"document-save"_L1, u"\ue74e"}, // or e78c?
+ {"document-save-as"_L1, u"\ue792"},
+ {"document-send"_L1, u"\ue724"},
+ {"edit-clear"_L1, u"\ue894"},
+ {"edit-copy"_L1, u"\ue8c8"},
+ {"edit-cut"_L1, u"\ue8c6"},
+ {"edit-delete"_L1, u"\ue74d"},
+ {"edit-find"_L1, u"\ue721"},
+ //{"edit-find-replace"_L1, u"\u"},
+ {"edit-paste"_L1, u"\ue77f"},
+ {"edit-redo"_L1, u"\ue7a6"},
+ {"edit-select-all"_L1, u"\ue8b3"},
+ {"edit-undo"_L1, u"\ue7a7"},
+ {"folder-new"_L1, u"\ue8f4"},
+ //{"format-indent-less"_L1, u"\u"},
+ //{"format-indent-more"_L1, u"\u"},
+ {"format-justify-center"_L1, u"\ue8e3"},
+ //{"format-justify-fill"_L1, u"\ue235"},
+ {"format-justify-left"_L1, u"\ue8e4"},
+ {"format-justify-right"_L1, u"\ue8e2"},
+ //{"format-text-direction-ltr"_L1, u"\ue247"},
+ //{"format-text-direction-rtl"_L1, u"\ue248"},
+ {"format-text-bold"_L1, u"\ue8dd"},
+ {"format-text-italic"_L1, u"\ue8db"},
+ {"format-text-underline"_L1, u"\ue8dc"},
+ {"format-text-strikethrough"_L1, u"\uede0"},
+ //{"go-bottom"_L1,u"\ue258"},
+ {"go-down"_L1,u"\ue74b"},
+ //{"go-first"_L1, u"\ue5dc"},
+ {"go-home"_L1, u"\ue80f"},
+ // {"go-jump"_L1, u"\uf719"},
+ //{"go-last"_L1, u"\ue5dd"},
+ {"go-next"_L1, u"\ue893"},
+ {"go-previous"_L1, u"\ue892"},
+ //{"go-top"_L1, u"\ue25a"},
+ {"go-up"_L1, u"\ue74a"},
+ {"help-about"_L1, u"\ue946"},
+ //{"help-contents"_L1, u"\ue8de"},
+ {"help-faq"_L1, u"\ue897"},
+ {"insert-image"_L1, u"\ue946"},
+ {"insert-link"_L1, u"\ue71b"},
+ //{"insert-object"_L1, u"\u"},
+ //{"insert-text"_L1, u"\uf827"},
+ {"list-add"_L1, u"\ue710"},
+ {"list-remove"_L1, u"\ue738"},
+ {"mail-forward"_L1, u"\ue89c"},
+ //{"mail-mark-important"_L1, u"\ue937"},
+ //{"mail-mark-junk"_L1, u"\u"},
+ //{"mail-mark-notjunk"_L1, u"\u"},
+ {"mail-mark-read"_L1, u"\ue8c3"},
+ //{"mail-mark-unread"_L1, u"\ue9bc"},
+ {"mail-message-new"_L1, u"\ue70f"},
+ {"mail-reply-all"_L1, u"\ue8c2"},
+ {"mail-reply-sender"_L1, u"\ue8ca"},
+ {"mail-send"_L1, u"\ue724"},
+ //{"mail-send-receive"_L1, u"\u"},
+ {"media-eject"_L1, u"\uf847"},
+ {"media-playback-pause"_L1, u"\ue769"},
+ {"media-playback-start"_L1, u"\ue768"},
+ {"media-playback-stop"_L1, u"\ue71a"},
+ {"media-record"_L1, u"\ue7c8"},
+ {"media-seek-backward"_L1, u"\ueb9e"},
+ {"media-seek-forward"_L1, u"\ueb9d"},
+ {"media-skip-backward"_L1, u"\ue892"},
+ {"media-skip-forward"_L1, u"\ue893"},
+ //{"object-flip-horizontal"_L1, u"\u"},
+ //{"object-flip-vertical"_L1, u"\u"},
+ {"object-rotate-left"_L1, u"\ue80c"},
+ {"object-rotate-right"_L1, u"\ue80d"},
+ //{"process-stop"_L1, u"\ue5c9"},
+ {"system-lock-screen"_L1, u"\uee3f"},
+ {"system-log-out"_L1, u"\uf3b1"},
+ //{"system-run"_L1, u"\u"},
+ {"system-search"_L1, u"\ue721"},
+ {"system-reboot"_L1, u"\ue777"}, // unsure?
+ {"system-shutdown"_L1, u"\ue7e8"},
+ {"tools-check-spelling"_L1, u"\uf87b"},
+ {"view-fullscreen"_L1, u"\ue740"},
+ {"view-refresh"_L1, u"\ue72c"},
+ {"view-restore"_L1, u"\ue777"},
+ //{"view-sort-ascending"_L1, u"\ue25a"},
+ //{"view-sort-descending"_L1, u"\ue258"},
+ {"window-close"_L1, u"\ue8bb"},
+ {"window-new"_L1, u"\ue78b"},
+ {"zoom-fit-best"_L1, u"\ue9a6"},
+ {"zoom-in"_L1, u"\ue8a3"},
+ //{"zoom-original"_L1, u"\u"},
+ {"zoom-out"_L1, u"\ue71f"},
+
+ {"process-working"_L1, u"\ue9f3"},
+
+ {"accessories-calculator"_L1, u"\ue8ef"},
+ {"accessories-character-map"_L1, u"\uf2b7"},
+ {"accessories-dictionary"_L1, u"\ue82d"},
+ //{"accessories-text-editor"_L1, u"\ue262"},
+ {"help-browser"_L1, u"\ue897"},
+ {"multimedia-volume-control"_L1, u"\ue767"},
+ {"preferences-desktop-accessibility"_L1, u"\ue776"},
+ {"preferences-desktop-font"_L1, u"\ue8d2"},
+ {"preferences-desktop-keyboard"_L1, u"\ue765"},
+ {"preferences-desktop-locale"_L1, u"\uf2b7"},
+ //{"preferences-desktop-multimedia"_L1, u"\uea75"},
+ {"preferences-desktop-screensaver"_L1, u"\uf182"},
+ //{"preferences-desktop-theme"_L1, u"\uf560"},
+ //{"preferences-desktop-wallpaper"_L1, u"\ue1bc"},
+ {"system-file-manager"_L1, u"\uec50"},
+ //{"system-software-install"_L1, u"\ueb71"},
+ {"system-software-update"_L1, u"\uecc5"},
+ {"utilities-system-monitor"_L1, u"\ue7f4"},
+ //{"utilities-terminal"_L1, u"\ueb8e"},
+
+ //{"applications-accessories"_L1, u"\u"},
+ {"applications-development"_L1, u"\uec7a"},
+ //{"applications-engineering"_L1, u"\uea3d"},
+ {"applications-games"_L1, u"\ue7fc"},
+ //{"applications-graphics"_L1, u"\u"},
+ {"applications-internet"_L1, u"\ue774"},
+ {"applications-multimedia"_L1, u"\uea69"},
+ //{"applications-office"_L1, u"\u"},
+ //{"applications-other"_L1, u"\u"},
+ //{"applications-science"_L1, u"\uea4b"},
+ {"applications-system"_L1, u"\ue770"},
+ //{"applications-utilities"_L1, u"\u"},
+ //{"preferences-desktop"_L1, u"\ueb97"},
+ //{"preferences-desktop-peripherals"_L1, u"\u"},
+ //{"preferences-desktop-personal"_L1, u"\uf835"},
+ //{"preferences-other"_L1, u"\u"},
+ //{"preferences-system"_L1, u"\ue8b8"},
+ //{"preferences-system-network"_L1, u"\ue894"},
+ {"system-help"_L1, u"\ue946"},
+
+ {"audio-card"_L1, u"\ue8d6"},
+ {"audio-input-microphone"_L1, u"\ue720"},
+ {"battery"_L1, u"\ue83f"},
+ {"camera-photo"_L1, u"\ue722"},
+ {"camera-video"_L1, u"\ue714"},
+ {"camera-web"_L1, u"\ue8b8"},
+ {"computer"_L1, u"\ue7f8"}, // or e7fb?
+ {"drive-harddisk"_L1, u"\ueda2"},
+ {"drive-optical"_L1, u"\ue958"},
+ //{"drive-removable-media"_L1, u"\u"},
+ //{"input-gaming"_L1, u"\u"},
+ {"input-keyboard"_L1, u"\ue92e"},
+ {"input-mouse"_L1, u"\ue962"},
+ {"input-tablet"_L1, u"\ue70a"},
+ {"media-flash"_L1, u"\ue88e"},
+ //{"media-floppy"_L1, u"\u"},
+ {"media-optical"_L1, u"\ue958"},
+ {"media-tape"_L1, u"\ue96a"},
+ //{"modem"_L1, u"\u"},
+ //{"multimedia-player"_L1, u"\u"},
+ {"network-wired"_L1, u"\ue968"},
+ {"network-wireless"_L1, u"\ue701"},
+ //{"pda"_L1, u"\u"},
+ {"phone"_L1, u"\ue717"},
+ {"printer"_L1, u"\ue749"},
+ {"scanner"_L1, u"\ue8fe"},
+ //{"video-display"_L1, u"\uf06a"},
+
+ {"emblem-default"_L1, u"\uf56d"},
+ {"emblem-documents"_L1, u"\ue8a5"},
+ {"emblem-downloads"_L1, u"\ue896"},
+ {"emblem-favorite"_L1, u"\ue734"},
+ {"emblem-important"_L1, u"\ue8c9"},
+ {"emblem-mail"_L1, u"\ue715"},
+ {"emblem-photos"_L1, u"\ue91b"},
+ //{"emblem-readonly"_L1, u"\u"},
+ {"emblem-shared"_L1, u"\ue902"},
+ {"emblem-symbolic-link"_L1, u"\ue71b"},
+ {"emblem-synchronized"_L1, u"\uedab"},
+ {"emblem-system"_L1, u"\ue770"},
+ //{"emblem-unreadable"_L1, u"\u"},
+
+ {"folder"_L1, u"\ue8b7"},
+ //{"folder-remote"_L1, u"\u"},
+ //{"network-server"_L1, u"\ue875"},
+ //{"network-workgroup"_L1, u"\ue1a0"},
+ {"start-here"_L1, u"\ue8fc"}, // unsure
+ {"user-bookmarks"_L1, u"\ue8a4"},
+ //{"user-desktop"_L1, u"\ue30a"},
+ {"user-home"_L1, u"\ue80f"},
+ {"user-trash"_L1, u"\ue74d"},
+
+ //{"appointment-missed"_L1, u"\ue615"},
+ //{"appointment-soon"_L1, u"\uf540"},
+ {"audio-volume-high"_L1, u"\ue995"},
+ {"audio-volume-low"_L1, u"\ue993"},
+ {"audio-volume-medium"_L1, u"\ue994"},
+ {"audio-volume-muted"_L1, u"\ue992"},
+ //{"battery-caution"_L1, u"\ue19c"},
+ {"battery-low"_L1, u"\ue851"}, // ?
+ {"dialog-error"_L1, u"\ue783"},
+ {"dialog-information"_L1, u"\ue946"},
+ //{"dialog-password"_L1, u"\uf042"},
+ {"dialog-question"_L1, u"\uf142"}, // unsure
+ {"dialog-warning"_L1, u"\ue7ba"},
+ //{"folder-drag-accept"_L1, @u"\ue9a3"},
+ {"folder-open"_L1, u"\ue838"},
+ //{"folder-visiting"_L1, u"\ue8a7"},
+ //{"image-loading"_L1, u"\ue41a"},
+ //{"image-missing"_L1, u"\ue3ad"},
+ {"mail-attachment"_L1, u"\ue723"},
+ //{"mail-unread"_L1, u"\uf18a"},
+ //{"mail-read"_L1, u"\uf18c"},
+ {"mail-replied"_L1, u"\ue8ca"},
+ //{"mail-signed"_L1, u"\u"},
+ //{"mail-signed-verified"_L1, u"\u"},
+ {"media-playlist-repeat"_L1, u"\ue8ee"},
+ {"media-playlist-shuffle"_L1, u"\ue8b1"},
+ //{"network-error"_L1, u"\uead9"},
+ //{"network-idle"_L1, u"\ue51f"},
+ {"network-offline"_L1, u"\uf384"},
+ //{"network-receive"_L1, u"\ue2c0"},
+ //{"network-transmit"_L1, u"\ue2c3"},
+ //{"network-transmit-receive"_L1, u"\uca18"},
+ //{"printer-error"_L1, u"\uf7a0"},
+ //{"printer-printing"_L1, u"\uf7a1"},
+ //{"security-high"_L1, u"\ue32a"},
+ //{"security-medium"_L1, u"\ue9e0"},
+ //{"security-low"_L1, u"\uf012"},
+ //{"software-update-available"_L1, u"\ue923"},
+ //{"software-update-urgent"_L1, u"\uf05a"},
+ {"sync-error"_L1, u"\uea6a"},
+ {"sync-synchronizing"_L1, u"\ue895"},
+ //{"task-due"_L1, u"\u"},
+ //{"task-past-due"_L1, u"\u"},
+ {"user-available"_L1, u"\ue8cf"},
+ //{"user-away"_L1, u"\ue510"},
+ //{"user-idle"_L1, u"\u"},
+ //{"user-offline"_L1, u"\uf7b3"},
+ //{"user-trash-full"_L1, u"\ue872"}, //delete
+ //{"user-trash-full"_L1, u"\ue92b"}, //delete_forever
+ {"weather-clear"_L1, u"\ue706"},
+ //{"weather-clear-night"_L1, u"\uf159"},
+ //{"weather-few-clouds"_L1, u"\uf172"},
+ //{"weather-few-clouds-night"_L1, u"\uf174"},
+ //{"weather-fog"_L1, u"\ue818"},
+ {"weather-overcast"_L1, u"\ue753"},
+ //{"weather-severe-alert"_L1, u"\ue002"}, //warning
+ //{"weather-showers"_L1, u"\uf176"},
+ //{"weather-showers-scattered"_L1, u"\u"},
+ //{"weather-snow"_L1, u"\ue80f"}, //snowing
+ //{"weather-storm"_L1, u"\uf070"},
+ };
+
+ const auto it = std::find_if(std::begin(glyphMap), std::end(glyphMap), [this](const auto &c){
+ return c.first == m_iconName;
+ });
+
+ return it != std::end(glyphMap) ? it->second.toString()
+ : (m_iconName.length() == 1 ? m_iconName : QString());
+}
+
+namespace {
+auto iconFontFamily()
+{
+ static const bool isWindows11 = QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows11;
+ return isWindows11 ? u"Segoe Fluent Icons"_s
+ : u"Segoe MDL2 Assets"_s;
+}
+}
+
+QWindowsIconEngine::QWindowsIconEngine(const QString &iconName)
+ : m_iconName(iconName), m_iconFont(iconFontFamily())
+ , m_glyphs(glyphs())
+{
+}
+
+QWindowsIconEngine::~QWindowsIconEngine()
+{}
+
+QIconEngine *QWindowsIconEngine::clone() const
+{
+ return new QWindowsIconEngine(m_iconName);
+}
+
+QString QWindowsIconEngine::key() const
+{
+ return u"QWindowsIconEngine"_s;
+}
+
+QString QWindowsIconEngine::iconName()
+{
+ return m_iconName;
+}
+
+bool QWindowsIconEngine::isNull()
+{
+ if (m_glyphs.isEmpty())
+ return true;
+
+ const QChar c0 = m_glyphs.at(0);
+ const QFontMetrics fontMetrics(m_iconFont);
+ if (c0.category() == QChar::Other_Surrogate && m_glyphs.size() > 1)
+ return !fontMetrics.inFontUcs4(QChar::surrogateToUcs4(c0, m_glyphs.at(1)));
+ return !fontMetrics.inFont(c0);
+}
+
+QList<QSize> QWindowsIconEngine::availableSizes(QIcon::Mode, QIcon::State)
+{
+ return {{16, 16}, {24, 24}, {48, 48}, {128, 128}};
+}
+
+QSize QWindowsIconEngine::actualSize(const QSize &size, QIcon::Mode mode, QIcon::State state)
+{
+ return QIconEngine::actualSize(size, mode, state);
+}
+
+QPixmap QWindowsIconEngine::pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state)
+{
+ return scaledPixmap(size, mode, state, 1.0);
+}
+
+QPixmap QWindowsIconEngine::scaledPixmap(const QSize &size, QIcon::Mode mode, QIcon::State state, qreal scale)
+{
+ const quint64 cacheKey = calculateCacheKey(mode, state);
+ if (cacheKey != m_cacheKey || m_pixmap.size() != size || m_pixmap.devicePixelRatio() != scale) {
+ m_pixmap = QPixmap(size * scale);
+ m_pixmap.fill(Qt::transparent);
+ m_pixmap.setDevicePixelRatio(scale);
+
+ QPainter painter(&m_pixmap);
+ paint(&painter, QRect(QPoint(), size), mode, state);
+
+ m_cacheKey = cacheKey;
+ }
+
+ return m_pixmap;
+}
+
+void QWindowsIconEngine::paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state)
+{
+ Q_UNUSED(state);
+
+ painter->save();
+ QFont renderFont(m_iconFont);
+ renderFont.setPixelSize(rect.height());
+ painter->setFont(renderFont);
+
+ QPalette palette;
+ switch (mode) {
+ case QIcon::Active:
+ painter->setPen(palette.color(QPalette::Active, QPalette::Text));
+ break;
+ case QIcon::Normal:
+ painter->setPen(palette.color(QPalette::Active, QPalette::Text));
+ break;
+ case QIcon::Disabled:
+ painter->setPen(palette.color(QPalette::Disabled, QPalette::Text));
+ break;
+ case QIcon::Selected:
+ painter->setPen(palette.color(QPalette::Active, QPalette::HighlightedText));
+ break;
+ }
+
+ painter->drawText(rect, Qt::AlignCenter, m_glyphs);
+ painter->restore();
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/windows/qwindowsiconengine.h b/src/plugins/platforms/windows/qwindowsiconengine.h
new file mode 100644
index 0000000000..3c6cbddb8b
--- /dev/null
+++ b/src/plugins/platforms/windows/qwindowsiconengine.h
@@ -0,0 +1,47 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QWINDOWSICONENGINE_H
+#define QWINDOWSICONENGINE_H
+
+#include <QtCore/qt_windows.h>
+
+#include <QtGui/qfont.h>
+#include <QtGui/qiconengine.h>
+
+QT_BEGIN_NAMESPACE
+
+class QWindowsIconEngine : public QIconEngine
+{
+public:
+ QWindowsIconEngine(const QString &iconName);
+ ~QWindowsIconEngine();
+ QIconEngine *clone() const override;
+ QString key() const override;
+ QString iconName() override;
+ bool isNull() override;
+
+ QList<QSize> availableSizes(QIcon::Mode, QIcon::State) override;
+ QSize actualSize(const QSize &size, QIcon::Mode mode, QIcon::State state) override;
+ QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) override;
+ QPixmap scaledPixmap(const QSize &size, QIcon::Mode mode, QIcon::State state, qreal scale) override;
+ void paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state) override;
+
+private:
+ static constexpr quint64 calculateCacheKey(QIcon::Mode mode, QIcon::State state)
+ {
+ return (quint64(mode) << 32) | state;
+ }
+
+ QString glyphs() const;
+
+ const QString m_iconName;
+ const QFont m_iconFont;
+ const QString m_glyphs;
+ mutable QPixmap m_pixmap;
+ mutable quint64 m_cacheKey = {};
+};
+
+QT_END_NAMESPACE
+
+#endif // QWINDOWSICONENGINE_H
diff --git a/src/plugins/platforms/windows/qwindowsinputcontext.cpp b/src/plugins/platforms/windows/qwindowsinputcontext.cpp
index f1f5d3a96e..0281025b5b 100644
--- a/src/plugins/platforms/windows/qwindowsinputcontext.cpp
+++ b/src/plugins/platforms/windows/qwindowsinputcontext.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qwindowsinputcontext.h"
#include "qwindowscontext.h"
@@ -47,7 +11,6 @@
#include <QtCore/qobject.h>
#include <QtCore/qrect.h>
#include <QtCore/qtextboundaryfinder.h>
-#include <QtCore/qoperatingsystemversion.h>
#include <QtGui/qevent.h>
#include <QtGui/qtextformat.h>
@@ -160,7 +123,6 @@ Q_CORE_EXPORT QLocale qt_localeFromLCID(LCID id); // from qlocale_win.cpp
needs to be checked (mouse grab might interfere with candidate window).
\internal
- \ingroup qt-lighthouse-win
*/
@@ -199,7 +161,6 @@ bool QWindowsInputContext::hasCapability(Capability capability) const
void QWindowsInputContext::reset()
{
- QPlatformInputContext::reset();
if (!m_compositionContext.hwnd)
return;
qCDebug(lcQpaInputMethods) << __FUNCTION__;
@@ -276,25 +237,9 @@ void QWindowsInputContext::showInputPanel()
if (!m_caretCreated && m_transparentBitmap)
m_caretCreated = CreateCaret(platformWindow->handle(), m_transparentBitmap, 0, 0);
- // For some reason, the on-screen keyboard is only triggered on the Surface
- // with Windows 10 if the Windows IME is (re)enabled _after_ the caret is shown.
if (m_caretCreated) {
cursorRectChanged();
- // We only call ShowCaret() on Windows 10 after 1703 as in earlier versions
- // the caret would actually be visible (QTBUG-74492) and the workaround for
- // the Surface seems unnecessary there anyway. But leave it hidden for IME.
- // Only trigger the native OSK if the Qt OSK is not in use.
- static bool imModuleEmpty = qEnvironmentVariableIsEmpty("QT_IM_MODULE");
- bool nativeVKDisabled = QCoreApplication::testAttribute(Qt::AA_MSWindowsDisableVirtualKeyboard);
- if ((imModuleEmpty && !nativeVKDisabled)
- && QOperatingSystemVersion::current()
- >= QOperatingSystemVersion(QOperatingSystemVersion::Windows, 10, 0, 16299)) {
- ShowCaret(platformWindow->handle());
- } else {
- HideCaret(platformWindow->handle());
- }
- setWindowsImeEnabled(platformWindow, false);
- setWindowsImeEnabled(platformWindow, true);
+ ShowCaret(platformWindow->handle());
}
}
@@ -339,7 +284,6 @@ void QWindowsInputContext::update(Qt::InputMethodQueries queries)
{
if (queries & Qt::ImEnabled)
updateEnabled();
- QPlatformInputContext::update(queries);
}
void QWindowsInputContext::cursorRectChanged()
@@ -732,7 +676,7 @@ int QWindowsInputContext::reconvertString(RECONVERTSTRING *reconv)
reconv->dwTargetStrOffset = reconv->dwCompStrOffset;
auto *pastReconv = reinterpret_cast<ushort *>(reconv + 1);
std::copy(surroundingText.utf16(), surroundingText.utf16() + surroundingText.size(),
- QT_MAKE_UNCHECKED_ARRAY_ITERATOR(pastReconv));
+ pastReconv);
return memSize;
}
diff --git a/src/plugins/platforms/windows/qwindowsinputcontext.h b/src/plugins/platforms/windows/qwindowsinputcontext.h
index 857706bcb9..e7eafb9ea5 100644
--- a/src/plugins/platforms/windows/qwindowsinputcontext.h
+++ b/src/plugins/platforms/windows/qwindowsinputcontext.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QWINDOWSINPUTCONTEXT_H
#define QWINDOWSINPUTCONTEXT_H
diff --git a/src/plugins/platforms/windows/qwindowsintegration.cpp b/src/plugins/platforms/windows/qwindowsintegration.cpp
index 77340387d8..6415c9ac50 100644
--- a/src/plugins/platforms/windows/qwindowsintegration.cpp
+++ b/src/plugins/platforms/windows/qwindowsintegration.cpp
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2013 Samuel Gaist <samuel.gaist@edeltech.ch>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2013 Samuel Gaist <samuel.gaist@edeltech.ch>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qwindowsintegration.h"
#include "qwindowswindow.h"
@@ -48,12 +12,14 @@
#include "qwindowsscreen.h"
#include "qwindowstheme.h"
#include "qwindowsservices.h"
-#ifdef QT_USE_DIRECTWRITE3
-#include <QtFontDatabaseSupport/private/qwindowsdirectwritefontdatabase_p.h>
+#include <QtGui/private/qtgui-config_p.h>
+#if QT_CONFIG(directwrite3)
+#include <QtGui/private/qwindowsdirectwritefontdatabase_p.h>
#endif
#ifndef QT_NO_FREETYPE
-# include <QtFontDatabaseSupport/private/qwindowsfontdatabase_ft_p.h>
+# include <QtGui/private/qwindowsfontdatabase_ft_p.h>
#endif
+#include <QtGui/private/qwindowsfontdatabase_p.h>
#if QT_CONFIG(clipboard)
# include "qwindowsclipboard.h"
# if QT_CONFIG(draganddrop)
@@ -71,28 +37,40 @@
#if QT_CONFIG(sessionmanager)
# include "qwindowssessionmanager.h"
#endif
-#include <QtGui/qtouchdevice.h>
+#include <QtGui/qpointingdevice.h>
#include <QtGui/private/qguiapplication_p.h>
#include <QtGui/private/qhighdpiscaling_p.h>
#include <QtGui/qpa/qplatforminputcontextfactory_p.h>
#include <QtGui/qpa/qplatformcursor.h>
-#include <QtEventDispatcherSupport/private/qwindowsguieventdispatcher_p.h>
+#include <QtGui/private/qwindowsguieventdispatcher_p.h>
#include <QtCore/qdebug.h>
#include <QtCore/qvariant.h>
+#include <QtCore/qoperatingsystemversion.h>
+#include <QtCore/private/qfunctions_win_p.h>
+
+#include <wrl.h>
+
#include <limits.h>
-#if defined(QT_OPENGL_ES_2) || defined(QT_OPENGL_DYNAMIC)
-# include "qwindowseglcontext.h"
-#endif
-#if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_2)
+#if !defined(QT_NO_OPENGL)
# include "qwindowsglcontext.h"
#endif
#include "qwindowsopengltester.h"
+#if QT_CONFIG(cpp_winrt)
+# include <QtCore/private/qt_winrtbase_p.h>
+# include <winrt/Windows.UI.Notifications.h>
+# include <winrt/Windows.Data.Xml.Dom.h>
+# include <winrt/Windows.Foundation.h>
+# include <winrt/Windows.UI.ViewManagement.h>
+#endif
+
+#include <memory>
+
static inline void initOpenGlBlacklistResources()
{
Q_INIT_RESOURCE(openglblacklists);
@@ -100,46 +78,16 @@ static inline void initOpenGlBlacklistResources()
QT_BEGIN_NAMESPACE
-/*!
- \class QWindowsIntegration
- \brief QPlatformIntegration implementation for Windows.
- \internal
-
- \section1 Programming Considerations
-
- The platform plugin should run on Desktop Windows from Windows XP onwards
- and Windows Embedded.
-
- It should compile with:
- \list
- \li Microsoft Visual Studio 2013 or later (using the Microsoft Windows SDK,
- (\c Q_CC_MSVC).
- \li Stock \l{http://mingw.org/}{MinGW} (\c Q_CC_MINGW).
- This version ships with headers that are missing a lot of WinAPI.
- \li MinGW distributions using GCC 4.7 or higher and a recent MinGW-w64 runtime API,
- such as \l{http://tdm-gcc.tdragon.net/}{TDM-GCC}, or
- \l{http://mingwbuilds.sourceforge.net/}{MinGW-builds}
- (\c Q_CC_MINGW and \c __MINGW64_VERSION_MAJOR indicating the version).
- MinGW-w64 provides more complete headers (compared to stock MinGW from mingw.org),
- including a considerable part of the Windows SDK.
- \endlist
-
- When using a function from the WinAPI, the minimum supported Windows version
- and Windows Embedded support should be checked. If the function is not supported
- on Windows XP or is not present in the MinGW-headers, it should be dynamically
- resolved. For this purpose, QWindowsContext has static structs like
- QWindowsUser32DLL and QWindowsShell32DLL. All function pointers should go to
- these structs to avoid lookups in several places.
-
- \ingroup qt-lighthouse-win
-*/
+using namespace Qt::StringLiterals;
struct QWindowsIntegrationPrivate
{
Q_DISABLE_COPY_MOVE(QWindowsIntegrationPrivate)
- explicit QWindowsIntegrationPrivate(const QStringList &paramList);
+ explicit QWindowsIntegrationPrivate() = default;
~QWindowsIntegrationPrivate();
+ void parseOptions(QWindowsIntegration *q, const QStringList &paramList);
+
unsigned m_options = 0;
QWindowsContext m_context;
QPlatformFontDatabase *m_fontDatabase = nullptr;
@@ -161,17 +109,17 @@ struct QWindowsIntegrationPrivate
};
template <typename IntType>
-bool parseIntOption(const QString &parameter,const QLatin1String &option,
+bool parseIntOption(const QString &parameter,const QLatin1StringView &option,
IntType minimumValue, IntType maximumValue, IntType *target)
{
const int valueLength = parameter.size() - option.size() - 1;
if (valueLength < 1 || !parameter.startsWith(option) || parameter.at(option.size()) != u'=')
return false;
bool ok;
- const QStringRef valueRef = parameter.rightRef(valueLength);
+ const auto valueRef = QStringView{parameter}.right(valueLength);
const int value = valueRef.toInt(&ok);
if (ok) {
- if (value >= minimumValue && value <= maximumValue)
+ if (value >= int(minimumValue) && value <= int(maximumValue))
*target = static_cast<IntType>(value);
else {
qWarning() << "Value" << value << "for option" << option << "out of range"
@@ -183,15 +131,19 @@ bool parseIntOption(const QString &parameter,const QLatin1String &option,
return true;
}
+using DarkModeHandlingFlag = QNativeInterface::Private::QWindowsApplication::DarkModeHandlingFlag;
+using DarkModeHandling = QNativeInterface::Private::QWindowsApplication::DarkModeHandling;
+
static inline unsigned parseOptions(const QStringList &paramList,
int *tabletAbsoluteRange,
- QtWindows::ProcessDpiAwareness *dpiAwareness)
+ QtWindows::DpiAwareness *dpiAwareness,
+ DarkModeHandling *darkModeHandling)
{
unsigned options = 0;
for (const QString &param : paramList) {
if (param.startsWith(u"fontengine=")) {
- if (param.endsWith(u"directwrite")) {
- options |= QWindowsIntegration::FontDatabaseDirectWrite;
+ if (param.endsWith(u"gdi")) {
+ options |= QWindowsIntegration::FontDatabaseGDI;
} else if (param.endsWith(u"freetype")) {
options |= QWindowsIntegration::FontDatabaseFreeType;
} else if (param.endsWith(u"native")) {
@@ -213,9 +165,10 @@ static inline unsigned parseOptions(const QStringList &paramList,
options |= QWindowsIntegration::DontUseColorFonts;
} else if (param == u"nomousefromtouch") {
options |= QWindowsIntegration::DontPassOsMouseEventsSynthesizedFromTouch;
- } else if (parseIntOption(param, QLatin1String("verbose"), 0, INT_MAX, &QWindowsContext::verbose)
- || parseIntOption(param, QLatin1String("tabletabsoluterange"), 0, INT_MAX, tabletAbsoluteRange)
- || parseIntOption(param, QLatin1String("dpiawareness"), QtWindows::ProcessDpiUnaware, QtWindows::ProcessPerMonitorDpiAware, dpiAwareness)) {
+ } else if (parseIntOption(param, "verbose"_L1, 0, INT_MAX, &QWindowsContext::verbose)
+ || parseIntOption(param, "tabletabsoluterange"_L1, 0, INT_MAX, tabletAbsoluteRange)
+ || parseIntOption(param, "dpiawareness"_L1, QtWindows::DpiAwareness::Invalid,
+ QtWindows::DpiAwareness::PerMonitorVersion2, dpiAwareness)) {
} else if (param == u"menus=native") {
options |= QWindowsIntegration::AlwaysUseNativeMenus;
} else if (param == u"menus=none") {
@@ -224,10 +177,14 @@ static inline unsigned parseOptions(const QStringList &paramList,
options |= QWindowsIntegration::DontUseWMPointer;
} else if (param == u"reverse") {
options |= QWindowsIntegration::RtlEnabled;
+ } else if (param == u"darkmode=0") {
+ *darkModeHandling = {};
} else if (param == u"darkmode=1") {
- options |= QWindowsIntegration::DarkModeWindowFrames;
+ darkModeHandling->setFlag(DarkModeHandlingFlag::DarkModeWindowFrames);
+ darkModeHandling->setFlag(DarkModeHandlingFlag::DarkModeStyle, false);
} else if (param == u"darkmode=2") {
- options |= QWindowsIntegration::DarkModeWindowFrames | QWindowsIntegration::DarkModeStyle;
+ darkModeHandling->setFlag(DarkModeHandlingFlag::DarkModeWindowFrames);
+ darkModeHandling->setFlag(DarkModeHandlingFlag::DarkModeStyle);
} else {
qWarning() << "Unknown option" << param;
}
@@ -235,31 +192,33 @@ static inline unsigned parseOptions(const QStringList &paramList,
return options;
}
-QWindowsIntegrationPrivate::QWindowsIntegrationPrivate(const QStringList &paramList)
+void QWindowsIntegrationPrivate::parseOptions(QWindowsIntegration *q, const QStringList &paramList)
{
initOpenGlBlacklistResources();
static bool dpiAwarenessSet = false;
+ // Default to per-monitor-v2 awareness (if available)
+ QtWindows::DpiAwareness dpiAwareness = QtWindows::DpiAwareness::PerMonitorVersion2;
+
int tabletAbsoluteRange = -1;
- // Default to per-monitor awareness to avoid being scaled when monitors with different DPI
- // are connected to Windows 8.1
- QtWindows::ProcessDpiAwareness dpiAwareness = QtWindows::ProcessPerMonitorDpiAware;
- m_options = parseOptions(paramList, &tabletAbsoluteRange, &dpiAwareness);
+ DarkModeHandling darkModeHandling = DarkModeHandlingFlag::DarkModeWindowFrames
+ | DarkModeHandlingFlag::DarkModeStyle;
+ m_options = ::parseOptions(paramList, &tabletAbsoluteRange, &dpiAwareness, &darkModeHandling);
+ q->setDarkModeHandling(darkModeHandling);
QWindowsFontDatabase::setFontOptions(m_options);
+ if (tabletAbsoluteRange >= 0)
+ QWindowsContext::setTabletAbsoluteRange(tabletAbsoluteRange);
- if (m_context.initPointer(m_options)) {
+ if (m_context.initPointer(m_options))
QCoreApplication::setAttribute(Qt::AA_CompressHighFrequencyEvents);
- } else {
- m_context.initTablet(m_options);
- if (tabletAbsoluteRange >= 0)
- m_context.setTabletAbsoluteRange(tabletAbsoluteRange);
- }
+ else
+ m_context.initTablet();
+ QWindowSystemInterfacePrivate::TabletEvent::setPlatformSynthesizesMouse(false);
if (!dpiAwarenessSet) { // Set only once in case of repeated instantiations of QGuiApplication.
if (!QCoreApplication::testAttribute(Qt::AA_PluginApplication)) {
m_context.setProcessDpiAwareness(dpiAwareness);
- qCDebug(lcQpaWindows)
- << __FUNCTION__ << "DpiAwareness=" << dpiAwareness
+ qCDebug(lcQpaWindow) << "DpiAwareness=" << dpiAwareness
<< "effective process DPI awareness=" << QWindowsContext::processDpiAwareness();
}
dpiAwarenessSet = true;
@@ -279,13 +238,14 @@ QWindowsIntegrationPrivate::~QWindowsIntegrationPrivate()
QWindowsIntegration *QWindowsIntegration::m_instance = nullptr;
QWindowsIntegration::QWindowsIntegration(const QStringList &paramList) :
- d(new QWindowsIntegrationPrivate(paramList))
+ d(new QWindowsIntegrationPrivate)
{
m_instance = this;
+ d->parseOptions(this, paramList);
#if QT_CONFIG(clipboard)
d->m_clipboard.registerViewer();
#endif
- d->m_context.screenManager().handleScreenChanges();
+ d->m_context.screenManager().initialize();
d->m_context.setDetectAltGrModifier((d->m_options & DetectAltGrModifier) != 0);
}
@@ -296,9 +256,9 @@ QWindowsIntegration::~QWindowsIntegration()
void QWindowsIntegration::initialize()
{
- QString icStr = QPlatformInputContextFactory::requested();
- icStr.isNull() ? d->m_inputContext.reset(new QWindowsInputContext)
- : d->m_inputContext.reset(QPlatformInputContextFactory::create(icStr));
+ auto icStrs = QPlatformInputContextFactory::requested();
+ icStrs.isEmpty() ? d->m_inputContext.reset(new QWindowsInputContext)
+ : d->m_inputContext.reset(QPlatformInputContextFactory::create(icStrs));
}
bool QWindowsIntegration::hasCapability(QPlatformIntegration::Capability cap) const
@@ -326,6 +286,8 @@ bool QWindowsIntegration::hasCapability(QPlatformIntegration::Capability cap) co
return true;
case SwitchableWidgetComposition:
return false; // QTBUG-68329 QTBUG-53515 QTBUG-54734
+ case BackingStoreStaticContents:
+ return true;
default:
return QPlatformIntegration::hasCapability(cap);
}
@@ -336,23 +298,27 @@ QPlatformWindow *QWindowsIntegration::createPlatformWindow(QWindow *window) cons
{
if (window->type() == Qt::Desktop) {
auto *result = new QWindowsDesktopWindow(window);
- qCDebug(lcQpaWindows) << "Desktop window:" << window
+ qCDebug(lcQpaWindow) << "Desktop window:" << window
<< Qt::showbase << Qt::hex << result->winId() << Qt::noshowbase << Qt::dec << result->geometry();
return result;
}
QWindowsWindowData requested;
requested.flags = window->flags();
- requested.geometry = QHighDpi::toNativePixels(window->geometry(), window);
- // Apply custom margins (see QWindowsWindow::setCustomMargins())).
- const QVariant customMarginsV = window->property("_q_windowsCustomMargins");
- if (customMarginsV.isValid())
- requested.customMargins = qvariant_cast<QMargins>(customMarginsV);
+ requested.geometry = window->isTopLevel()
+ ? QHighDpi::toNativePixels(window->geometry(), window)
+ : QHighDpi::toNativeLocalPosition(window->geometry(), window);
+ if (!(requested.flags & Qt::FramelessWindowHint)) {
+ // Apply custom margins (see QWindowsWindow::setCustomMargins())).
+ const QVariant customMarginsV = window->property("_q_windowsCustomMargins");
+ if (customMarginsV.isValid())
+ requested.customMargins = qvariant_cast<QMargins>(customMarginsV);
+ }
QWindowsWindowData obtained =
QWindowsWindowData::create(window, requested,
QWindowsWindow::formatWindowTitle(window->title()));
- qCDebug(lcQpaWindows).nospace()
+ qCDebug(lcQpaWindow).nospace()
<< __FUNCTION__ << ' ' << window
<< "\n Requested: " << requested.geometry << " frame incl.="
<< QWindowsGeometryHint::positionIncludesFrame(window)
@@ -389,7 +355,7 @@ QPlatformWindow *QWindowsIntegration::createForeignWindow(QWindow *window, WId n
screen = pScreen->screen();
if (screen && screen != window->screen())
window->setScreen(screen);
- qCDebug(lcQpaWindows) << "Foreign window:" << window << Qt::showbase << Qt::hex
+ qCDebug(lcQpaWindow) << "Foreign window:" << window << Qt::showbase << Qt::hex
<< result->winId() << Qt::noshowbase << Qt::dec << obtainedGeometry << screen;
return result;
}
@@ -417,13 +383,6 @@ QWindowsStaticOpenGLContext *QWindowsStaticOpenGLContext::doCreate()
}
qCWarning(lcQpaGl, "System OpenGL failed. Falling back to Software OpenGL.");
return QOpenGLStaticContext::create(true);
- // If ANGLE is requested, use it, don't try anything else.
- case QWindowsOpenGLTester::AngleRendererD3d9:
- case QWindowsOpenGLTester::AngleRendererD3d11:
- case QWindowsOpenGLTester::AngleRendererD3d11Warp:
- return QWindowsEGLStaticContext::create(requestedRenderer);
- case QWindowsOpenGLTester::Gles:
- return QWindowsEGLStaticContext::create(requestedRenderer);
case QWindowsOpenGLTester::SoftwareRasterizer:
if (QWindowsStaticOpenGLContext *swCtx = QOpenGLStaticContext::create(true))
return swCtx;
@@ -449,17 +408,8 @@ QWindowsStaticOpenGLContext *QWindowsStaticOpenGLContext::doCreate()
return glCtx;
}
}
- if (QWindowsOpenGLTester::Renderers glesRenderers = supportedRenderers & QWindowsOpenGLTester::GlesMask) {
- if (QWindowsEGLStaticContext *eglCtx = QWindowsEGLStaticContext::create(glesRenderers))
- return eglCtx;
- }
return QOpenGLStaticContext::create(true);
-#elif defined(QT_OPENGL_ES_2)
- QWindowsOpenGLTester::Renderers glesRenderers = QWindowsOpenGLTester::requestedGlesRenderer();
- if (glesRenderers == QWindowsOpenGLTester::InvalidRenderer)
- glesRenderers = QWindowsOpenGLTester::supportedRenderers(QWindowsOpenGLTester::AngleRendererD3d11);
- return QWindowsEGLStaticContext::create(glesRenderers);
-#elif !defined(QT_NO_OPENGL)
+#else
return QOpenGLStaticContext::create();
#endif
}
@@ -473,18 +423,16 @@ QPlatformOpenGLContext *QWindowsIntegration::createPlatformOpenGLContext(QOpenGL
{
qCDebug(lcQpaGl) << __FUNCTION__ << context->format();
if (QWindowsStaticOpenGLContext *staticOpenGLContext = QWindowsIntegration::staticOpenGLContext()) {
- QScopedPointer<QWindowsOpenGLContext> result(staticOpenGLContext->createContext(context));
+ std::unique_ptr<QWindowsOpenGLContext> result(staticOpenGLContext->createContext(context));
if (result->isValid())
- return result.take();
+ return result.release();
}
return nullptr;
}
QOpenGLContext::OpenGLModuleType QWindowsIntegration::openGLModuleType()
{
-#if defined(QT_OPENGL_ES_2)
- return QOpenGLContext::LibGLES;
-#elif !defined(QT_OPENGL_DYNAMIC)
+#if !defined(QT_OPENGL_DYNAMIC)
return QOpenGLContext::LibGL;
#else
if (const QWindowsStaticOpenGLContext *staticOpenGLContext = QWindowsIntegration::staticOpenGLContext())
@@ -493,6 +441,33 @@ QOpenGLContext::OpenGLModuleType QWindowsIntegration::openGLModuleType()
#endif
}
+HMODULE QWindowsIntegration::openGLModuleHandle() const
+{
+ if (QWindowsStaticOpenGLContext *staticOpenGLContext = QWindowsIntegration::staticOpenGLContext())
+ return static_cast<HMODULE>(staticOpenGLContext->moduleHandle());
+
+ return nullptr;
+}
+
+QOpenGLContext *QWindowsIntegration::createOpenGLContext(HGLRC ctx, HWND window, QOpenGLContext *shareContext) const
+{
+ if (!ctx || !window)
+ return nullptr;
+
+ if (QWindowsStaticOpenGLContext *staticOpenGLContext = QWindowsIntegration::staticOpenGLContext()) {
+ std::unique_ptr<QWindowsOpenGLContext> result(staticOpenGLContext->createContext(ctx, window));
+ if (result->isValid()) {
+ auto *context = new QOpenGLContext;
+ context->setShareContext(shareContext);
+ auto *contextPrivate = QOpenGLContextPrivate::get(context);
+ contextPrivate->adopt(result.release());
+ return context;
+ }
+ }
+
+ return nullptr;
+}
+
QWindowsStaticOpenGLContext *QWindowsIntegration::staticOpenGLContext()
{
QWindowsIntegration *integration = QWindowsIntegration::instance();
@@ -509,17 +484,17 @@ QWindowsStaticOpenGLContext *QWindowsIntegration::staticOpenGLContext()
QPlatformFontDatabase *QWindowsIntegration::fontDatabase() const
{
if (!d->m_fontDatabase) {
-#ifdef QT_USE_DIRECTWRITE3
- if (d->m_options & QWindowsIntegration::FontDatabaseDirectWrite)
- d->m_fontDatabase = new QWindowsDirectWriteFontDatabase;
- else
-#endif
#ifndef QT_NO_FREETYPE
if (d->m_options & QWindowsIntegration::FontDatabaseFreeType)
d->m_fontDatabase = new QWindowsFontDatabaseFT;
else
#endif // QT_NO_FREETYPE
- d->m_fontDatabase = new QWindowsFontDatabase();
+#if QT_CONFIG(directwrite3)
+ if (!(d->m_options & (QWindowsIntegration::FontDatabaseGDI | QWindowsIntegration::DontUseDirectWriteFonts)))
+ d->m_fontDatabase = new QWindowsDirectWriteFontDatabase;
+ else
+#endif
+ d->m_fontDatabase = new QWindowsFontDatabase;
}
return d->m_fontDatabase;
}
@@ -567,14 +542,9 @@ QVariant QWindowsIntegration::styleHint(QPlatformIntegration::StyleHint hint) co
return QPlatformIntegration::styleHint(hint);
}
-Qt::KeyboardModifiers QWindowsIntegration::queryKeyboardModifiers() const
+QPlatformKeyMapper *QWindowsIntegration::keyMapper() const
{
- return QWindowsKeyMapper::queryKeyboardModifiers();
-}
-
-QList<int> QWindowsIntegration::possibleKeys(const QKeyEvent *e) const
-{
- return d->m_context.possibleKeys(e);
+ return d->m_context.keyMapper();
}
#if QT_CONFIG(clipboard)
@@ -621,12 +591,12 @@ QAbstractEventDispatcher * QWindowsIntegration::createEventDispatcher() const
QStringList QWindowsIntegration::themeNames() const
{
- return QStringList(QLatin1String(QWindowsTheme::name));
+ return QStringList(QLatin1StringView(QWindowsTheme::name));
}
QPlatformTheme *QWindowsIntegration::createPlatformTheme(const QString &name) const
{
- if (name == QLatin1String(QWindowsTheme::name))
+ if (name == QLatin1StringView(QWindowsTheme::name))
return new QWindowsTheme;
return QPlatformIntegration::createPlatformTheme(name);
}
@@ -641,6 +611,156 @@ void QWindowsIntegration::beep() const
MessageBeep(MB_OK); // For QApplication
}
+void QWindowsIntegration::setApplicationBadge(qint64 number)
+{
+ // Clamp to positive numbers, as the Windows API doesn't support negative numbers
+ number = qMax(0, number);
+
+ // Persist, so we can re-apply it on setting changes and Explorer restart
+ m_applicationBadgeNumber = number;
+
+ static const bool isWindows11 = QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows11;
+
+#if QT_CONFIG(cpp_winrt)
+ // We prefer the native BadgeUpdater API, that allows us to set a number directly,
+ // but it requires that the application has a package identity, and also doesn't
+ // seem to work in all cases on < Windows 11.
+ if (isWindows11 && qt_win_hasPackageIdentity()) {
+ using namespace winrt::Windows::UI::Notifications;
+ auto badgeXml = BadgeUpdateManager::GetTemplateContent(BadgeTemplateType::BadgeNumber);
+ badgeXml.SelectSingleNode(L"//badge/@value").NodeValue(winrt::box_value(winrt::to_hstring(number)));
+ BadgeUpdateManager::CreateBadgeUpdaterForApplication().Update(BadgeNotification(badgeXml));
+ return;
+ }
+#endif
+
+ // Fallback for non-packaged apps, Windows 10, or Qt builds without WinRT/C++ support
+
+ if (!number) {
+ // Clear badge
+ setApplicationBadge(QImage());
+ return;
+ }
+
+ const bool isDarkMode = QWindowsContext::isDarkMode();
+
+ QColor badgeColor;
+ QColor textColor;
+
+#if QT_CONFIG(cpp_winrt)
+ if (isWindows11) {
+ // Match colors used by BadgeUpdater
+ static const auto fromUIColor = [](winrt::Windows::UI::Color &&color) {
+ return QColor(color.R, color.G, color.B, color.A);
+ };
+ using namespace winrt::Windows::UI::ViewManagement;
+ const auto settings = UISettings();
+ badgeColor = fromUIColor(settings.GetColorValue(isDarkMode ?
+ UIColorType::AccentLight2 : UIColorType::Accent));
+ textColor = fromUIColor(settings.GetColorValue(UIColorType::Background));
+ }
+#endif
+
+ if (!badgeColor.isValid()) {
+ // Fall back to basic badge colors, based on Windows 10 look
+ badgeColor = isDarkMode ? Qt::black : QColor(220, 220, 220);
+ badgeColor.setAlphaF(0.5f);
+ textColor = isDarkMode ? Qt::white : Qt::black;
+ }
+
+ const auto devicePixelRatio = qApp->devicePixelRatio();
+
+ static const QSize iconBaseSize(16, 16);
+ QImage image(iconBaseSize * devicePixelRatio,
+ QImage::Format_ARGB32_Premultiplied);
+ image.fill(Qt::transparent);
+
+ QPainter painter(&image);
+
+ QRect badgeRect = image.rect();
+ QPen badgeBorderPen = Qt::NoPen;
+ if (!isWindows11) {
+ QColor badgeBorderColor = textColor;
+ badgeBorderColor.setAlphaF(0.5f);
+ badgeBorderPen = badgeBorderColor;
+ badgeRect.adjust(1, 1, -1, -1);
+ }
+ painter.setBrush(badgeColor);
+ painter.setPen(badgeBorderPen);
+ painter.setRenderHint(QPainter::Antialiasing);
+ painter.drawEllipse(badgeRect);
+
+ auto pixelSize = qCeil(10.5 * devicePixelRatio);
+ // Unlike the BadgeUpdater API we're limited by a square
+ // badge, so adjust the font size when above two digits.
+ const bool textOverflow = number > 99;
+ if (textOverflow)
+ pixelSize *= 0.8;
+
+ QFont font = painter.font();
+ font.setPixelSize(pixelSize);
+ font.setWeight(isWindows11 ? QFont::Medium : QFont::DemiBold);
+ painter.setFont(font);
+
+ painter.setRenderHint(QPainter::TextAntialiasing, devicePixelRatio > 1);
+ painter.setPen(textColor);
+
+ auto text = textOverflow ? u"99+"_s : QString::number(number);
+ painter.translate(textOverflow ? 1 : 0, textOverflow ? 0 : -1);
+ painter.drawText(image.rect(), Qt::AlignCenter, text);
+
+ painter.end();
+
+ setApplicationBadge(image);
+}
+
+void QWindowsIntegration::setApplicationBadge(const QImage &image)
+{
+ QComHelper comHelper;
+
+ using Microsoft::WRL::ComPtr;
+
+ ComPtr<ITaskbarList3> taskbarList;
+ CoCreateInstance(CLSID_TaskbarList, nullptr,
+ CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&taskbarList));
+ if (!taskbarList) {
+ // There may not be any windows with a task bar button yet,
+ // in which case we'll apply the badge once a window with
+ // a button has been created.
+ return;
+ }
+
+ const auto hIcon = image.toHICON();
+
+ // Apply the icon to all top level windows, since the badge is
+ // set on an application level. If one of the windows go away
+ // the other windows will take over in showing the badge.
+ const auto topLevelWindows = QGuiApplication::topLevelWindows();
+ for (auto *topLevelWindow : topLevelWindows) {
+ if (!topLevelWindow->handle())
+ continue;
+ auto hwnd = reinterpret_cast<HWND>(topLevelWindow->winId());
+ taskbarList->SetOverlayIcon(hwnd, hIcon, L"");
+ }
+
+ DestroyIcon(hIcon);
+
+ // FIXME: Update icon when the application scale factor changes.
+ // Doing so in response to screen DPI changes is too soon, as the
+ // task bar is not yet ready for an updated icon, and will just
+ // result in a blurred icon even if our icon is high-DPI.
+}
+
+void QWindowsIntegration::updateApplicationBadge()
+{
+ // The system color settings have changed, or we are reacting
+ // to a task bar button being created for the fist time or after
+ // Explorer had crashed and re-started. In any case, re-apply the
+ // badge so that everything is up to date.
+ if (m_applicationBadgeNumber)
+ setApplicationBadge(m_applicationBadgeNumber);
+}
+
#if QT_CONFIG(vulkan)
QPlatformVulkanInstance *QWindowsIntegration::createPlatformVulkanInstance(QVulkanInstance *instance) const
{
diff --git a/src/plugins/platforms/windows/qwindowsintegration.h b/src/plugins/platforms/windows/qwindowsintegration.h
index 165472ad40..c271207741 100644
--- a/src/plugins/platforms/windows/qwindowsintegration.h
+++ b/src/plugins/platforms/windows/qwindowsintegration.h
@@ -1,49 +1,19 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Samuel Gaist <samuel.gaist@edeltech.ch>
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2013 Samuel Gaist <samuel.gaist@edeltech.ch>
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QWINDOWSINTEGRATION_H
#define QWINDOWSINTEGRATION_H
+#include "qwindowsapplication.h"
+
#include <qpa/qplatformintegration.h>
#include <QtCore/qscopedpointer.h>
-#include <QtFontDatabaseSupport/private/qwindowsfontdatabase_p.h>
+#include <QtGui/private/qwindowsfontdatabase_p.h>
+#ifndef QT_NO_OPENGL
+#include <QtGui/private/qopenglcontext_p.h>
+#endif
+#include <qpa/qplatformopenglcontext.h>
QT_BEGIN_NAMESPACE
@@ -53,6 +23,10 @@ class QWindowsWindow;
class QWindowsStaticOpenGLContext;
class QWindowsIntegration : public QPlatformIntegration
+#ifndef QT_NO_OPENGL
+ , public QNativeInterface::Private::QWindowsGLIntegration
+#endif
+ , public QWindowsApplication
{
Q_DISABLE_COPY_MOVE(QWindowsIntegration)
public:
@@ -71,9 +45,7 @@ public:
DontUseWMPointer = 0x400,
DetectAltGrModifier = 0x800,
RtlEnabled = 0x1000,
- DarkModeWindowFrames = 0x2000,
- DarkModeStyle = 0x4000,
- FontDatabaseDirectWrite = 0x8000
+ FontDatabaseGDI = 0x2000
};
explicit QWindowsIntegration(const QStringList &paramList);
@@ -87,6 +59,10 @@ public:
QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const override;
QOpenGLContext::OpenGLModuleType openGLModuleType() override;
static QWindowsStaticOpenGLContext *staticOpenGLContext();
+
+ HMODULE openGLModuleHandle() const override;
+ QOpenGLContext *createOpenGLContext(HGLRC context, HWND window,
+ QOpenGLContext *shareContext) const override;
#endif
QAbstractEventDispatcher *createEventDispatcher() const override;
void initialize() override;
@@ -106,8 +82,7 @@ public:
QPlatformServices *services() const override;
QVariant styleHint(StyleHint hint) const override;
- Qt::KeyboardModifiers queryKeyboardModifiers() const override;
- QList<int> possibleKeys(const QKeyEvent *e) const override;
+ QPlatformKeyMapper *keyMapper() const override;
static QWindowsIntegration *instance() { return m_instance; }
@@ -115,6 +90,10 @@ public:
void beep() const override;
+ void setApplicationBadge(qint64 number) override;
+ void setApplicationBadge(const QImage &image);
+ void updateApplicationBadge();
+
#if QT_CONFIG(sessionmanager)
QPlatformSessionManager *createPlatformSessionManager(const QString &id, const QString &key) const override;
#endif
@@ -130,6 +109,8 @@ private:
QScopedPointer<QWindowsIntegrationPrivate> d;
static QWindowsIntegration *m_instance;
+
+ qint64 m_applicationBadgeNumber = 0;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/windows/qwindowsinternalmimedata.cpp b/src/plugins/platforms/windows/qwindowsinternalmimedata.cpp
index 44b7523fa6..0542473a4b 100644
--- a/src/plugins/platforms/windows/qwindowsinternalmimedata.cpp
+++ b/src/plugins/platforms/windows/qwindowsinternalmimedata.cpp
@@ -1,46 +1,12 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qwindowsinternalmimedata.h"
#include "qwindowscontext.h"
-#include "qwindowsmime.h"
+#include "qwindowsmimeregistry.h"
#include <QtCore/qdebug.h>
+#include <QtCore/qvariant.h>
+
/*!
\class QWindowsInternalMimeDataBase
\brief Base for implementations of QInternalMimeData using a IDataObject COM object.
@@ -56,11 +22,10 @@
The base class introduces new virtuals to obtain and release
the instances IDataObject from the clipboard or Drag and Drop and
- does conversion using QWindowsMime classes.
+ does conversion using QWindowsMimeConverter classes.
- \sa QInternalMimeData, QWindowsMime, QWindowsMimeConverter
+ \sa QInternalMimeData, QWindowsMimeConverter, QWindowsMimeRegistry
\internal
- \ingroup qt-lighthouse-win
*/
bool QWindowsInternalMimeData::hasFormat_sys(const QString &mime) const
@@ -69,7 +34,7 @@ bool QWindowsInternalMimeData::hasFormat_sys(const QString &mime) const
if (!pDataObj)
return false;
- const QWindowsMimeConverter &mc = QWindowsContext::instance()->mimeConverter();
+ const QWindowsMimeRegistry &mc = QWindowsContext::instance()->mimeConverter();
const bool has = mc.converterToMime(mime, pDataObj) != nullptr;
releaseDataObject(pDataObj);
qCDebug(lcQpaMime) << __FUNCTION__ << mime << has;
@@ -82,29 +47,28 @@ QStringList QWindowsInternalMimeData::formats_sys() const
if (!pDataObj)
return QStringList();
- const QWindowsMimeConverter &mc = QWindowsContext::instance()->mimeConverter();
+ const QWindowsMimeRegistry &mc = QWindowsContext::instance()->mimeConverter();
const QStringList fmts = mc.allMimesForFormats(pDataObj);
releaseDataObject(pDataObj);
qCDebug(lcQpaMime) << __FUNCTION__ << fmts;
return fmts;
}
-QVariant QWindowsInternalMimeData::retrieveData_sys(const QString &mimeType,
- QVariant::Type type) const
+QVariant QWindowsInternalMimeData::retrieveData_sys(const QString &mimeType, QMetaType type) const
{
IDataObject *pDataObj = retrieveDataObject();
if (!pDataObj)
return QVariant();
QVariant result;
- const QWindowsMimeConverter &mc = QWindowsContext::instance()->mimeConverter();
- if (const QWindowsMime *converter = mc.converterToMime(mimeType, pDataObj))
+ const QWindowsMimeRegistry &mc = QWindowsContext::instance()->mimeConverter();
+ if (auto converter = mc.converterToMime(mimeType, pDataObj))
result = converter->convertToMime(mimeType, pDataObj, type);
releaseDataObject(pDataObj);
if (QWindowsContext::verbose) {
- qCDebug(lcQpaMime) <<__FUNCTION__ << ' ' << mimeType << ' ' << type
- << " returns " << result.type()
- << (result.type() != QVariant::ByteArray ? result.toString() : QStringLiteral("<data>"));
+ qCDebug(lcQpaMime) <<__FUNCTION__ << ' ' << mimeType << ' ' << type.name()
+ << " returns " << result.metaType().name()
+ << (result.metaType().id() != QMetaType::QByteArray ? result.toString() : QStringLiteral("<data>"));
}
return result;
}
diff --git a/src/plugins/platforms/windows/qwindowsinternalmimedata.h b/src/plugins/platforms/windows/qwindowsinternalmimedata.h
index dbc1ea3922..64d4ceabdf 100644
--- a/src/plugins/platforms/windows/qwindowsinternalmimedata.h
+++ b/src/plugins/platforms/windows/qwindowsinternalmimedata.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QWINDOWSINTERNALMIME_H
#define QWINDOWSINTERNALMIME_H
@@ -54,7 +18,7 @@ class QWindowsInternalMimeData : public QInternalMimeData {
public:
bool hasFormat_sys(const QString &mimetype) const override;
QStringList formats_sys() const override;
- QVariant retrieveData_sys(const QString &mimetype, QVariant::Type preferredType) const override;
+ QVariant retrieveData_sys(const QString &mimetype, QMetaType preferredType) const override;
protected:
virtual IDataObject *retrieveDataObject() const = 0;
diff --git a/src/plugins/platforms/windows/qwindowskeymapper.cpp b/src/plugins/platforms/windows/qwindowskeymapper.cpp
index e3edf7e81e..ba76cda40b 100644
--- a/src/plugins/platforms/windows/qwindowskeymapper.cpp
+++ b/src/plugins/platforms/windows/qwindowskeymapper.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qwindowskeymapper.h"
#include "qwindowscontext.h"
@@ -49,8 +13,9 @@
#include <private/qguiapplication_p.h>
#include <private/qhighdpiscaling_p.h>
#include <QtGui/qevent.h>
-#include <QtEventDispatcherSupport/private/qwindowsguieventdispatcher_p.h>
+#include <QtGui/private/qwindowsguieventdispatcher_p.h>
#include <QtCore/private/qdebug_p.h>
+#include <QtCore/private/qtools_p.h>
#if defined(WM_APPCOMMAND)
# ifndef FAPPCOMMAND_MOUSE
@@ -88,7 +53,6 @@ QT_BEGIN_NAMESPACE
\class QWindowsKeyMapper
\brief Translates Windows keys to QWindowSystemInterface events.
\internal
- \ingroup qt-lighthouse-win
In addition, handles some special keys to display system menus, etc.
The code originates from \c qkeymapper_win.cpp.
@@ -124,9 +88,17 @@ QWindowsKeyMapper::~QWindowsKeyMapper()= default;
#define VK_OEM_3 0xC0
#endif
-// We not only need the scancode itself but also the extended bit of key messages. Thus we need
-// the additional bit when masking the scancode.
-enum { scancodeBitmask = 0x1ff };
+// Get scancode from the given message
+static constexpr quint32 getScancode(const MSG &msg)
+{
+ const auto keyFlags = HIWORD(msg.lParam);
+ quint32 scancode = LOBYTE(keyFlags);
+ // if extended-key flag is on, the scan code consists of a sequence of two bytes,
+ // where the first byte has a value of 0xe0.
+ if ((keyFlags & KF_EXTENDED) != 0)
+ scancode |= 0xE000;
+ return scancode;
+}
// Key recorder ------------------------------------------------------------------------[ start ] --
struct KeyRecord {
@@ -390,7 +362,8 @@ static const uint KeyTbl[] = { // Keyboard mapping table
Qt::Key_MediaNext, // 176 0xB0 VK_MEDIA_NEXT_TRACK | Next Track key
Qt::Key_MediaPrevious, //177 0xB1 VK_MEDIA_PREV_TRACK | Previous Track key
Qt::Key_MediaStop, // 178 0xB2 VK_MEDIA_STOP | Stop Media key
- Qt::Key_MediaPlay, // 179 0xB3 VK_MEDIA_PLAY_PAUSE | Play/Pause Media key
+ Qt::Key_MediaTogglePlayPause,
+ // 179 0xB3 VK_MEDIA_PLAY_PAUSE | Play/Pause Media key
Qt::Key_LaunchMail, // 180 0xB4 VK_LAUNCH_MAIL | Start Mail key
Qt::Key_LaunchMedia,// 181 0xB5 VK_LAUNCH_MEDIA_SELECT Select Media key
Qt::Key_Launch0, // 182 0xB6 VK_LAUNCH_APP1 | Start Application 1 key
@@ -541,7 +514,7 @@ static const Qt::KeyboardModifiers ModsTbl[] = {
Qt::NoModifier, // Fall-back to raw Key_*
};
static const size_t NumMods = sizeof ModsTbl / sizeof *ModsTbl;
-Q_STATIC_ASSERT((NumMods == KeyboardLayoutItem::NumQtKeys));
+static_assert((NumMods == KeyboardLayoutItem::NumQtKeys));
#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug d, const KeyboardLayoutItem &k)
@@ -567,33 +540,6 @@ QDebug operator<<(QDebug d, const KeyboardLayoutItem &k)
d << ')';
return d;
}
-
-// Helpers to format a list of int as Qt key sequence
-class formatKeys
-{
-public:
- explicit formatKeys(const QList<int> &keys) : m_keys(keys) {}
-
-private:
- friend QDebug operator<<(QDebug d, const formatKeys &keys);
- const QList<int> &m_keys;
-};
-
-QDebug operator<<(QDebug d, const formatKeys &k)
-{
- QDebugStateSaver saver(d);
- d.nospace();
- d << '(';
- for (int i =0, size = k.m_keys.size(); i < size; ++i) {
- if (i)
- d << ", ";
- d << QKeySequence(k.m_keys.at(i));
- }
- d << ')';
- return d;
-}
-#else // !QT_NO_DEBUG_STREAM
-static int formatKeys(const QList<int> &) { return 0; }
#endif // QT_NO_DEBUG_STREAM
/**
@@ -635,8 +581,7 @@ static inline quint32 toKeyOrUnicode(quint32 vk, quint32 scancode, unsigned char
static inline int asciiToKeycode(char a, int state)
{
- if (a >= 'a' && a <= 'z')
- a = toupper(a);
+ a = QtMiscUtils::toAsciiUpper(a);
if ((state & Qt::ControlModifier) != 0) {
if (a >= 0 && a <= 31) // Ctrl+@..Ctrl+A..CTRL+Z..Ctrl+_
a += '@'; // to @..A..Z.._
@@ -692,7 +637,7 @@ void QWindowsKeyMapper::updateKeyMap(const MSG &msg)
{
unsigned char kbdBuffer[256]; // Will hold the complete keyboard state
GetKeyboardState(kbdBuffer);
- const quint32 scancode = (msg.lParam >> 16) & scancodeBitmask;
+ const quint32 scancode = getScancode(msg);
updatePossibleKeyCodes(kbdBuffer, scancode, quint32(msg.wParam));
}
@@ -785,6 +730,27 @@ static inline QString messageKeyText(const MSG &msg)
return ch.isNull() ? QString() : QString(ch);
}
+[[nodiscard]] static inline int getTitleBarHeight(const HWND hwnd)
+{
+ const UINT dpi = GetDpiForWindow(hwnd);
+ const int captionHeight = GetSystemMetricsForDpi(SM_CYCAPTION, dpi);
+ if (IsZoomed(hwnd))
+ return captionHeight;
+ // The frame height should also be taken into account if the window
+ // is not maximized.
+ const int frameHeight = GetSystemMetricsForDpi(SM_CYSIZEFRAME, dpi)
+ + GetSystemMetricsForDpi(SM_CXPADDEDBORDER, dpi);
+ return captionHeight + frameHeight;
+}
+
+[[nodiscard]] static inline bool isSystemMenuOffsetNeeded(const Qt::WindowFlags flags)
+{
+ static constexpr const Qt::WindowFlags titleBarHints =
+ Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint | Qt::WindowContextHelpButtonHint;
+ return (flags & Qt::WindowSystemMenuHint) && (flags & Qt::WindowTitleHint) && !(flags & titleBarHints)
+ && (flags & (Qt::FramelessWindowHint | Qt::CustomizeWindowHint));
+}
+
static void showSystemMenu(QWindow* w)
{
QWindow *topLevel = QWindowsWindow::topLevelOf(w);
@@ -793,41 +759,49 @@ static void showSystemMenu(QWindow* w)
if (!menu)
return; // no menu for this window
-#define enabled (MF_BYCOMMAND | MF_ENABLED)
-#define disabled (MF_BYCOMMAND | MF_GRAYED)
+#define enabled (MF_BYCOMMAND | MFS_ENABLED)
+#define disabled (MF_BYCOMMAND | MFS_GRAYED)
- EnableMenuItem(menu, SC_MINIMIZE, (topLevel->flags() & Qt::WindowMinimizeButtonHint)?enabled:disabled);
- bool maximized = IsZoomed(topLevelHwnd);
+ EnableMenuItem(menu, SC_MINIMIZE, (topLevel->flags() & Qt::WindowMinimizeButtonHint) ? enabled : disabled);
+ const bool maximized = IsZoomed(topLevelHwnd);
- EnableMenuItem(menu, SC_MAXIMIZE, ! (topLevel->flags() & Qt::WindowMaximizeButtonHint) || maximized?disabled:enabled);
- EnableMenuItem(menu, SC_RESTORE, maximized?enabled:disabled);
+ EnableMenuItem(menu, SC_MAXIMIZE, !(topLevel->flags() & Qt::WindowMaximizeButtonHint) || maximized ? disabled : enabled);
// We should _not_ check with the setFixedSize(x,y) case here, since Windows is not able to check
// this and our menu here would be out-of-sync with the menu produced by mouse-click on the
// System Menu, or right-click on the title bar.
- EnableMenuItem(menu, SC_SIZE, (topLevel->flags() & Qt::MSWindowsFixedSizeDialogHint) || maximized?disabled:enabled);
- EnableMenuItem(menu, SC_MOVE, maximized?disabled:enabled);
+ EnableMenuItem(menu, SC_SIZE, (topLevel->flags() & Qt::MSWindowsFixedSizeDialogHint) || maximized ? disabled : enabled);
+ EnableMenuItem(menu, SC_MOVE, maximized ? disabled : enabled);
EnableMenuItem(menu, SC_CLOSE, enabled);
+ EnableMenuItem(menu, SC_RESTORE, maximized ? enabled : disabled);
+
+ // Highlight the first entry in the menu, this is what native Win32 applications usually do.
+ HiliteMenuItem(topLevelHwnd, menu, SC_RESTORE, MF_BYCOMMAND | MFS_HILITE);
+
// Set bold on close menu item
- MENUITEMINFO closeItem;
- closeItem.cbSize = sizeof(MENUITEMINFO);
- closeItem.fMask = MIIM_STATE;
- closeItem.fState = MFS_DEFAULT;
- SetMenuItemInfo(menu, SC_CLOSE, FALSE, &closeItem);
+ SetMenuDefaultItem(menu, SC_CLOSE, FALSE);
#undef enabled
#undef disabled
+
const QPoint pos = QHighDpi::toNativePixels(topLevel->geometry().topLeft(), topLevel);
+ const int titleBarOffset = isSystemMenuOffsetNeeded(topLevel->flags()) ? getTitleBarHeight(topLevelHwnd) : 0;
const int ret = TrackPopupMenuEx(menu,
- TPM_LEFTALIGN | TPM_TOPALIGN | TPM_NONOTIFY | TPM_RETURNCMD,
- pos.x(), pos.y(),
+ TPM_LEFTALIGN | TPM_TOPALIGN | TPM_NONOTIFY | TPM_RETURNCMD,
+ pos.x(), pos.y() + titleBarOffset,
topLevelHwnd,
nullptr);
+
+ // Remove the highlight of the restore menu item, otherwise when the user right-clicks
+ // on the title bar, the popuped system menu will also highlight the restore item, which
+ // is not appropriate, it should only be highlighted if the menu is brought up by keyboard.
+ HiliteMenuItem(topLevelHwnd, menu, SC_RESTORE, MF_BYCOMMAND | MFS_UNHILITE);
+
if (ret)
qWindowsWndProc(topLevelHwnd, WM_SYSCOMMAND, WPARAM(ret), 0);
}
-static inline void sendExtendedPressRelease(QWindow *w, int k,
+static inline void sendExtendedPressRelease(QWindow *w, unsigned long timestamp, int k,
Qt::KeyboardModifiers mods,
quint32 nativeScanCode,
quint32 nativeVirtualKey,
@@ -836,8 +810,8 @@ static inline void sendExtendedPressRelease(QWindow *w, int k,
bool autorep = false,
ushort count = 1)
{
- QWindowSystemInterface::handleExtendedKeyEvent(w, QEvent::KeyPress, k, mods, nativeScanCode, nativeVirtualKey, nativeModifiers, text, autorep, count);
- QWindowSystemInterface::handleExtendedKeyEvent(w, QEvent::KeyRelease, k, mods, nativeScanCode, nativeVirtualKey, nativeModifiers, text, autorep, count);
+ QWindowSystemInterface::handleExtendedKeyEvent(w, timestamp, QEvent::KeyPress, k, mods, nativeScanCode, nativeVirtualKey, nativeModifiers, text, autorep, count);
+ QWindowSystemInterface::handleExtendedKeyEvent(w, timestamp, QEvent::KeyRelease, k, mods, nativeScanCode, nativeVirtualKey, nativeModifiers, text, autorep, count);
}
/*!
@@ -904,11 +878,11 @@ bool QWindowsKeyMapper::translateMultimediaKeyEventInternal(QWindow *window, con
const int qtKey = int(CmdTbl[cmd]);
if (!skipPressRelease)
- sendExtendedPressRelease(receiver, qtKey, Qt::KeyboardModifier(state), 0, 0, 0);
+ sendExtendedPressRelease(receiver, msg.time, qtKey, Qt::KeyboardModifier(state), 0, 0, 0);
// QTBUG-43343: Make sure to return false if Qt does not handle the key, otherwise,
// the keys are not passed to the active media player.
# if QT_CONFIG(shortcut)
- const QKeySequence sequence(Qt::Modifier(state) + qtKey);
+ const QKeySequence sequence(Qt::Modifier(state) | Qt::Key(qtKey));
return QGuiApplicationPrivate::instance()->shortcutMap.hasShortcutForKeySequence(sequence);
# else
return false;
@@ -949,7 +923,7 @@ bool QWindowsKeyMapper::translateKeyEventInternal(QWindow *window, MSG msg,
m_seenAltGr = true;
const UINT msgType = msg.message;
- const quint32 scancode = (msg.lParam >> 16) & scancodeBitmask;
+ const quint32 scancode = getScancode(msg);
auto vk_key = quint32(msg.wParam);
quint32 nModifiers = 0;
@@ -984,7 +958,7 @@ bool QWindowsKeyMapper::translateKeyEventInternal(QWindow *window, MSG msg,
// A multi-character key or a Input method character
// not found by our look-ahead
if (msgType == WM_CHAR || msgType == WM_IME_CHAR) {
- sendExtendedPressRelease(receiver, 0, Qt::KeyboardModifier(state), scancode, vk_key, nModifiers, messageKeyText(msg), false);
+ sendExtendedPressRelease(receiver, msg.time, 0, Qt::KeyboardModifier(state), scancode, 0, nModifiers, messageKeyText(msg), false);
return true;
}
@@ -1019,14 +993,14 @@ bool QWindowsKeyMapper::translateKeyEventInternal(QWindow *window, MSG msg,
if (dirStatus == VK_LSHIFT
&& ((msg.wParam == VK_SHIFT && GetKeyState(VK_LCONTROL))
|| (msg.wParam == VK_CONTROL && GetKeyState(VK_LSHIFT)))) {
- sendExtendedPressRelease(receiver, Qt::Key_Direction_L, {},
+ sendExtendedPressRelease(receiver, msg.time, Qt::Key_Direction_L, {},
scancode, vk_key, nModifiers, QString(), false);
result = true;
dirStatus = 0;
} else if (dirStatus == VK_RSHIFT
&& ( (msg.wParam == VK_SHIFT && GetKeyState(VK_RCONTROL))
|| (msg.wParam == VK_CONTROL && GetKeyState(VK_RSHIFT)))) {
- sendExtendedPressRelease(receiver, Qt::Key_Direction_R, {},
+ sendExtendedPressRelease(receiver, msg.time, Qt::Key_Direction_R, {},
scancode, vk_key, nModifiers, QString(), false);
result = true;
dirStatus = 0;
@@ -1220,7 +1194,6 @@ bool QWindowsKeyMapper::translateKeyEventInternal(QWindow *window, MSG msg,
switch (code) {
case Qt::Key_Escape:
case Qt::Key_Tab:
- case Qt::Key_Enter:
case Qt::Key_F4:
return false; // Send the event on to Windows
case Qt::Key_Space:
@@ -1240,9 +1213,9 @@ bool QWindowsKeyMapper::translateKeyEventInternal(QWindow *window, MSG msg,
// so, we have an auto-repeating key
if (rec) {
if (code < Qt::Key_Shift || code > Qt::Key_ScrollLock) {
- QWindowSystemInterface::handleExtendedKeyEvent(receiver, QEvent::KeyRelease, code,
+ QWindowSystemInterface::handleExtendedKeyEvent(receiver, msg.time, QEvent::KeyRelease, code,
Qt::KeyboardModifier(state), scancode, quint32(msg.wParam), nModifiers, rec->text, true);
- QWindowSystemInterface::handleExtendedKeyEvent(receiver, QEvent::KeyPress, code,
+ QWindowSystemInterface::handleExtendedKeyEvent(receiver, msg.time, QEvent::KeyPress, code,
Qt::KeyboardModifier(state), scancode, quint32(msg.wParam), nModifiers, rec->text, true);
result = true;
}
@@ -1256,7 +1229,7 @@ bool QWindowsKeyMapper::translateKeyEventInternal(QWindow *window, MSG msg,
#ifndef QT_NO_SHORTCUT
// Is Qt interested in the context menu key?
if (modifiers == Qt::SHIFT && code == Qt::Key_F10
- && !QGuiApplicationPrivate::instance()->shortcutMap.hasShortcutForKeySequence(QKeySequence(Qt::SHIFT + Qt::Key_F10))) {
+ && !QGuiApplicationPrivate::instance()->shortcutMap.hasShortcutForKeySequence(QKeySequence(Qt::SHIFT | Qt::Key_F10))) {
return false;
}
#endif // !QT_NO_SHORTCUT
@@ -1268,7 +1241,7 @@ bool QWindowsKeyMapper::translateKeyEventInternal(QWindow *window, MSG msg,
if (msg.wParam == VK_PACKET)
code = asciiToKeycode(char(uch.cell()), state);
- QWindowSystemInterface::handleExtendedKeyEvent(receiver, QEvent::KeyPress, code,
+ QWindowSystemInterface::handleExtendedKeyEvent(receiver, msg.time, QEvent::KeyPress, code,
modifiers, scancode, quint32(msg.wParam), nModifiers, text, false);
result =true;
bool store = true;
@@ -1310,10 +1283,10 @@ bool QWindowsKeyMapper::translateKeyEventInternal(QWindow *window, MSG msg,
if ((msg.lParam & 0x40000000) == 0 &&
Qt::KeyboardModifier(state) == Qt::NoModifier &&
((code == Qt::Key_F18) || (code == Qt::Key_F19) || (code == Qt::Key_F20))) {
- QWindowSystemInterface::handleExtendedKeyEvent(receiver, QEvent::KeyPress, code,
+ QWindowSystemInterface::handleExtendedKeyEvent(receiver, msg.time, QEvent::KeyPress, code,
Qt::MetaModifier, scancode,
quint32(msg.wParam), MetaLeft);
- QWindowSystemInterface::handleExtendedKeyEvent(receiver, QEvent::KeyRelease, code,
+ QWindowSystemInterface::handleExtendedKeyEvent(receiver, msg.time, QEvent::KeyRelease, code,
Qt::NoModifier, scancode,
quint32(msg.wParam), 0);
result = true;
@@ -1325,7 +1298,7 @@ bool QWindowsKeyMapper::translateKeyEventInternal(QWindow *window, MSG msg,
// Map SHIFT + Tab to SHIFT + BackTab, QShortcutMap knows about this translation
if (code == Qt::Key_Tab && (state & Qt::ShiftModifier) == Qt::ShiftModifier)
code = Qt::Key_Backtab;
- QWindowSystemInterface::handleExtendedKeyEvent(receiver, QEvent::KeyRelease, code,
+ QWindowSystemInterface::handleExtendedKeyEvent(receiver, msg.time, QEvent::KeyRelease, code,
Qt::KeyboardModifier(state), scancode, quint32(msg.wParam),
nModifiers,
(rec ? rec->text : QString()), false);
@@ -1347,7 +1320,7 @@ bool QWindowsKeyMapper::translateKeyEventInternal(QWindow *window, MSG msg,
return result;
}
-Qt::KeyboardModifiers QWindowsKeyMapper::queryKeyboardModifiers()
+Qt::KeyboardModifiers QWindowsKeyMapper::queryKeyboardModifiers() const
{
Qt::KeyboardModifiers modifiers = Qt::NoModifier;
if (GetKeyState(VK_SHIFT) < 0)
@@ -1361,9 +1334,9 @@ Qt::KeyboardModifiers QWindowsKeyMapper::queryKeyboardModifiers()
return modifiers;
}
-QList<int> QWindowsKeyMapper::possibleKeys(const QKeyEvent *e) const
+QList<QKeyCombination> QWindowsKeyMapper::possibleKeyCombinations(const QKeyEvent *e) const
{
- QList<int> result;
+ QList<QKeyCombination> result;
const quint32 nativeVirtualKey = e->nativeVirtualKey();
@@ -1377,31 +1350,34 @@ QList<int> QWindowsKeyMapper::possibleKeys(const QKeyEvent *e) const
quint32 baseKey = kbItem.qtKey[0];
Qt::KeyboardModifiers keyMods = e->modifiers();
if (baseKey == Qt::Key_Return && (e->nativeModifiers() & ExtendedKey)) {
- result << int(Qt::Key_Enter + keyMods);
+ result << (Qt::Key_Enter | keyMods);
return result;
}
- result << int(baseKey + keyMods); // The base key is _always_ valid, of course
+
+ // The base key is _always_ valid, of course
+ result << QKeyCombination::fromCombined(int(baseKey) + int(keyMods));
for (size_t i = 1; i < NumMods; ++i) {
Qt::KeyboardModifiers neededMods = ModsTbl[i];
quint32 key = kbItem.qtKey[i];
if (key && key != baseKey && ((keyMods & neededMods) == neededMods)) {
const Qt::KeyboardModifiers missingMods = keyMods & ~neededMods;
- const int matchedKey = int(key) + missingMods;
- const auto it =
- std::find_if(result.begin(), result.end(),
- [key] (int k) { return (k & ~Qt::KeyboardModifierMask) == key; });
+ const auto matchedKey = QKeyCombination::fromCombined(int(key) + int(missingMods));
+ const auto it = std::find_if(result.begin(), result.end(),
+ [key](auto keyCombination) {
+ return keyCombination.key() == key;
+ });
// QTBUG-67200: Use the match with the least modifiers (prefer
// Shift+9 over Alt + Shift + 9) resulting in more missing modifiers.
if (it == result.end())
result << matchedKey;
- else if (missingMods > (*it & Qt::KeyboardModifierMask))
+ else if (missingMods > it->keyboardModifiers())
*it = matchedKey;
}
}
qCDebug(lcQpaEvents) << __FUNCTION__ << e << "nativeVirtualKey="
<< Qt::showbase << Qt::hex << e->nativeVirtualKey() << Qt::dec << Qt::noshowbase
- << e->modifiers() << kbItem << "\n returns" << formatKeys(result);
+ << e->modifiers() << kbItem << "\n returns" << result;
return result;
}
diff --git a/src/plugins/platforms/windows/qwindowskeymapper.h b/src/plugins/platforms/windows/qwindowskeymapper.h
index b1ada1d373..72b2536ad7 100644
--- a/src/plugins/platforms/windows/qwindowskeymapper.h
+++ b/src/plugins/platforms/windows/qwindowskeymapper.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QWINDOWSKEYMAPPER_H
#define QWINDOWSKEYMAPPER_H
@@ -44,6 +8,8 @@
#include <QtCore/qlocale.h>
+#include <qpa/qplatformkeymapper.h>
+
QT_BEGIN_NAMESPACE
class QKeyEvent;
@@ -69,7 +35,7 @@ struct KeyboardLayoutItem {
quint32 qtKey[NumQtKeys]; // Can by any Qt::Key_<foo>, or unicode character
};
-class QWindowsKeyMapper
+class QWindowsKeyMapper : public QPlatformKeyMapper
{
Q_DISABLE_COPY_MOVE(QWindowsKeyMapper)
public:
@@ -89,8 +55,8 @@ public:
QWindow *keyGrabber() const { return m_keyGrabber; }
void setKeyGrabber(QWindow *w) { m_keyGrabber = w; }
- static Qt::KeyboardModifiers queryKeyboardModifiers();
- QList<int> possibleKeys(const QKeyEvent *e) const;
+ Qt::KeyboardModifiers queryKeyboardModifiers() const override;
+ QList<QKeyCombination> possibleKeyCombinations(const QKeyEvent *e) const override;
private:
bool translateKeyEventInternal(QWindow *receiver, MSG msg, bool grab, LRESULT *lResult);
diff --git a/src/plugins/platforms/windows/qwindowsmenu.cpp b/src/plugins/platforms/windows/qwindowsmenu.cpp
index 7c3e87eec1..79deeeaea2 100644
--- a/src/plugins/platforms/windows/qwindowsmenu.cpp
+++ b/src/plugins/platforms/windows/qwindowsmenu.cpp
@@ -1,47 +1,12 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qwindowsmenu.h"
#include "qwindowscontext.h"
#include "qwindowswindow.h"
#include <QtGui/qwindow.h>
+#include <QtGui/private/qpixmap_win_p.h>
#include <QtCore/qdebug.h>
#include <QtCore/qvariant.h>
#include <QtCore/qmetaobject.h>
@@ -56,7 +21,7 @@ QT_BEGIN_NAMESPACE
\brief Windows native menu bar
\list
- \li \l{https://msdn.microsoft.com/de-de/library/windows/desktop/ms647553(v=vs.85).aspx#_win32_Menu_Creation_Functions},
+ \li \l{https://docs.microsoft.com/en-us/windows/win32/menurc/about-menus},
\e{About Menus}
\endlist
@@ -65,15 +30,14 @@ QT_BEGIN_NAMESPACE
Qt Widgets, either the containers or the items might be deleted first.
\internal
- \ingroup qt-lighthouse-win
*/
static uint nextId = 1;
-// Find a QPlatformMenu[Item]* in a vector of QWindowsMenu[Item], where
-// QVector::indexOf() cannot be used since it wants a QWindowsMenu[Item]*
+// Find a QPlatformMenu[Item]* in a list of QWindowsMenu[Item], where
+// QList::indexOf() cannot be used since it wants a QWindowsMenu[Item]*
template <class Derived, class Needle>
-static int indexOf(const QVector<Derived *> &v, const Needle *needle)
+static int indexOf(const QList<Derived *> &v, const Needle *needle)
{
for (int i = 0, size = v.size(); i < size; ++i) {
if (v.at(i) == needle)
@@ -82,9 +46,9 @@ static int indexOf(const QVector<Derived *> &v, const Needle *needle)
return -1;
}
-// Helper for inserting a QPlatformMenu[Item]* into a vector of QWindowsMenu[Item].
+// Helper for inserting a QPlatformMenu[Item]* into a list of QWindowsMenu[Item].
template <class Derived, class Base>
-static int insertBefore(QVector<Derived *> *v, Base *newItemIn, const Base *before = nullptr)
+static int insertBefore(QList<Derived *> *v, Base *newItemIn, const Base *before = nullptr)
{
int index = before ? indexOf(*v, before) : -1;
if (index != -1) {
@@ -176,7 +140,7 @@ static QWindowsMenu *findMenuByHandle(const Menu *menu, HMENU hMenu)
}
template <class MenuType>
-static int findNextVisibleEntry(const QVector<MenuType *> &entries, int pos)
+static int findNextVisibleEntry(const QList<MenuType *> &entries, int pos)
{
for (int i = pos, size = entries.size(); i < size; ++i) {
if (entries.at(i)->isVisible())
@@ -266,8 +230,6 @@ void QWindowsMenuItem::setIcon(const QIcon &icon)
updateBitmap();
}
-Q_GUI_EXPORT HBITMAP qt_pixmapToWinHBITMAP(const QPixmap &p, int hbitmapFormat = 0);
-
void QWindowsMenuItem::updateBitmap()
{
freeBitmap();
@@ -794,20 +756,13 @@ QWindowsMenuBar *QWindowsMenuBar::menuBarOf(const QWindow *notYetCreatedWindow)
? qobject_cast<QWindowsMenuBar *>(menuBarV.value<QObject *>()) : nullptr;
}
-static inline void forceNcCalcSize(HWND hwnd)
-{
- // Force WM_NCCALCSIZE to adjust margin: Does not appear to work?
- SetWindowPos(hwnd, nullptr, 0, 0, 0, 0,
- SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER);
-}
-
void QWindowsMenuBar::install(QWindowsWindow *window)
{
const HWND hwnd = window->handle();
const BOOL result = SetMenu(hwnd, m_hMenuBar);
if (result) {
window->setMenuBar(this);
- forceNcCalcSize(hwnd);
+ QWindowsContext::forceNcCalcSize(hwnd);
}
}
@@ -817,7 +772,7 @@ void QWindowsMenuBar::removeFromWindow()
const HWND hwnd = window->handle();
SetMenu(hwnd, nullptr);
window->setMenuBar(nullptr);
- forceNcCalcSize(hwnd);
+ QWindowsContext::forceNcCalcSize(hwnd);
}
}
@@ -870,7 +825,7 @@ void QWindowsMenuBar::redraw() const
#ifndef QT_NO_DEBUG_STREAM
template <class M> /* Menu[Item] */
-static void formatTextSequence(QDebug &d, const QVector<M *> &v)
+static void formatTextSequence(QDebug &d, const QList<M *> &v)
{
if (const int size = v.size()) {
d << '[' << size << "](";
diff --git a/src/plugins/platforms/windows/qwindowsmenu.h b/src/plugins/platforms/windows/qwindowsmenu.h
index aa36846ec0..6f66180d82 100644
--- a/src/plugins/platforms/windows/qwindowsmenu.h
+++ b/src/plugins/platforms/windows/qwindowsmenu.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QWINDOWSMENU_H
#define QWINDOWSMENU_H
@@ -44,8 +8,7 @@
#include <qpa/qplatformmenu.h>
-#include <QtCore/qvector.h>
-#include <QtCore/qpair.h>
+#include <QtCore/qlist.h>
QT_BEGIN_NAMESPACE
@@ -120,7 +83,7 @@ class QWindowsMenu : public QPlatformMenu
{
Q_OBJECT
public:
- using MenuItems = QVector<QWindowsMenuItem *>;
+ using MenuItems = QList<QWindowsMenuItem *>;
QWindowsMenu();
~QWindowsMenu();
@@ -196,7 +159,7 @@ class QWindowsMenuBar : public QPlatformMenuBar
{
Q_OBJECT
public:
- using Menus = QVector<QWindowsMenu *>;
+ using Menus = QList<QWindowsMenu *>;
QWindowsMenuBar();
~QWindowsMenuBar() override;
diff --git a/src/plugins/platforms/windows/qwindowsmime.h b/src/plugins/platforms/windows/qwindowsmime.h
deleted file mode 100644
index f8708f1259..0000000000
--- a/src/plugins/platforms/windows/qwindowsmime.h
+++ /dev/null
@@ -1,108 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 QWINDOWSMIME_H
-#define QWINDOWSMIME_H
-
-#include <QtCore/qt_windows.h>
-
-#include <QtCore/qvector.h>
-#include <QtCore/qvariant.h>
-
-QT_BEGIN_NAMESPACE
-
-class QDebug;
-class QMimeData;
-
-class QWindowsMime
-{
- Q_DISABLE_COPY_MOVE(QWindowsMime)
-public:
- QWindowsMime();
- virtual ~QWindowsMime();
-
- // for converting from Qt
- virtual bool canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const = 0;
- virtual bool convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const = 0;
- virtual QVector<FORMATETC> formatsForMime(const QString &mimeType, const QMimeData *mimeData) const = 0;
-
- // for converting to Qt
- virtual bool canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const = 0;
- virtual QVariant convertToMime(const QString &mimeType, IDataObject *pDataObj, QVariant::Type preferredType) const = 0;
- virtual QString mimeForFormat(const FORMATETC &formatetc) const = 0;
-
- static int registerMimeType(const QString &mime);
-};
-
-class QWindowsMimeConverter
-{
- Q_DISABLE_COPY_MOVE(QWindowsMimeConverter)
-public:
- QWindowsMimeConverter();
- ~QWindowsMimeConverter();
-
- QWindowsMime *converterToMime(const QString &mimeType, IDataObject *pDataObj) const;
- QStringList allMimesForFormats(IDataObject *pDataObj) const;
- QWindowsMime *converterFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const;
- QVector<FORMATETC> allFormatsForMime(const QMimeData *mimeData) const;
-
- // Convenience.
- QVariant convertToMime(const QStringList &mimeTypes, IDataObject *pDataObj, QVariant::Type preferredType,
- QString *format = nullptr) const;
-
- void registerMime(QWindowsMime *mime);
- void unregisterMime(QWindowsMime *mime) { m_mimes.removeOne(mime); }
-
- static QString clipboardFormatName(int cf);
-
-private:
- void ensureInitialized() const;
-
- mutable QVector<QWindowsMime *> m_mimes;
- mutable int m_internalMimeCount = 0;
-};
-
-#ifndef QT_NO_DEBUG_STREAM
-QDebug operator<<(QDebug, const FORMATETC &);
-QDebug operator<<(QDebug d, IDataObject *);
-#endif
-
-QT_END_NAMESPACE
-
-#endif // QWINDOWSMIME_H
diff --git a/src/plugins/platforms/windows/qwindowsmime.cpp b/src/plugins/platforms/windows/qwindowsmimeregistry.cpp
index fe9e1fe31f..8d147e8fa0 100644
--- a/src/plugins/platforms/windows/qwindowsmime.cpp
+++ b/src/plugins/platforms/windows/qwindowsmimeregistry.cpp
@@ -1,48 +1,11 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 "qwindowsmime.h"
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qwindowsmimeregistry.h"
#include "qwindowscontext.h"
#include <QtGui/private/qinternalmimedata_p.h>
#include <QtCore/qbytearraymatcher.h>
-#include <QtCore/qtextcodec.h>
#include <QtCore/qmap.h>
#include <QtCore/qurl.h>
#include <QtCore/qdir.h>
@@ -56,6 +19,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
/* The MSVC compilers allows multi-byte characters, that has the behavior of
* that each character gets shifted into position. 0x73524742 below is for MSVC
* equivalent to doing 'sRGB', but this does of course not work
@@ -97,7 +62,6 @@ struct BMP_BITMAPV5HEADER {
DWORD bV5ProfileSize;
DWORD bV5Reserved;
};
-static const int BMP_BITFIELDS = 3;
static const char dibFormatC[] = "dib";
@@ -115,16 +79,15 @@ static inline QByteArray msgConversionError(const char *func, const char *format
return msg;
}
-static inline QImage readDib(QByteArray data)
+static inline bool readDib(QBuffer &buffer, QImage &img)
{
- QBuffer buffer(&data);
- buffer.open(QIODevice::ReadOnly);
QImageReader reader(&buffer, dibFormatC);
if (!reader.canRead()) {
- qWarning("%s", msgConversionError(__FUNCTION__, dibFormatC).constData());
- return QImage();
+ qWarning("%s", msgConversionError(__FUNCTION__, dibFormatC).constData());
+ return false;
}
- return reader.read();
+ img = reader.read();
+ return true;
}
static QByteArray writeDib(const QImage &img)
@@ -149,7 +112,10 @@ static bool qt_write_dibv5(QDataStream &s, QImage image)
return false;
//depth will be always 32
- int bpl_bmp = image.width()*4;
+ qsizetype bpl_bmp = qsizetype(image.width()) * 4;
+ qsizetype size = bpl_bmp * image.height();
+ if (qsizetype(DWORD(size)) != size)
+ return false;
BMP_BITMAPV5HEADER bi;
ZeroMemory(&bi, sizeof(bi));
@@ -175,8 +141,20 @@ static bool qt_write_dibv5(QDataStream &s, QImage image)
if (s.status() != QDataStream::Ok)
return false;
+ d->write(reinterpret_cast<const char *>(&bi.bV5RedMask), sizeof(bi.bV5RedMask));
+ if (s.status() != QDataStream::Ok)
+ return false;
+
+ d->write(reinterpret_cast<const char *>(&bi.bV5GreenMask), sizeof(bi.bV5GreenMask));
+ if (s.status() != QDataStream::Ok)
+ return false;
+
+ d->write(reinterpret_cast<const char *>(&bi.bV5BlueMask), sizeof(bi.bV5BlueMask));
+ if (s.status() != QDataStream::Ok)
+ return false;
+
if (image.format() != QImage::Format_ARGB32)
- image = image.convertToFormat(QImage::Format_ARGB32);
+ image = std::move(image).convertToFormat(QImage::Format_ARGB32);
auto *buf = new uchar[bpl_bmp];
@@ -211,94 +189,6 @@ static bool qt_write_dibv5(QDataStream &s, QImage image)
return true;
}
-static int calc_shift(int mask)
-{
- int result = 0;
- while (!(mask & 1)) {
- result++;
- mask >>= 1;
- }
- return result;
-}
-
-//Supports only 32 bit DIBV5
-static bool qt_read_dibv5(QDataStream &s, QImage &image)
-{
- BMP_BITMAPV5HEADER bi;
- QIODevice* d = s.device();
- if (d->atEnd())
- return false;
-
- d->read(reinterpret_cast<char *>(&bi), sizeof(bi)); // read BITMAPV5HEADER header
- if (s.status() != QDataStream::Ok)
- return false;
-
- const int nbits = bi.bV5BitCount;
- if (nbits != 32 || bi.bV5Planes != 1 || bi.bV5Compression != BMP_BITFIELDS)
- return false; //Unsupported DIBV5 format
-
- const int w = bi.bV5Width;
- int h = bi.bV5Height;
- const int red_mask = int(bi.bV5RedMask);
- const int green_mask = int(bi.bV5GreenMask);
- const int blue_mask = int(bi.bV5BlueMask);
- const int alpha_mask = int(bi.bV5AlphaMask);
-
- const QImage::Format format = QImage::Format_ARGB32;
-
- if (bi.bV5Height < 0)
- h = -h; // support images with negative height
- if (image.size() != QSize(w, h) || image.format() != format) {
- image = QImage(w, h, format);
- if (image.isNull()) // could not create image
- return false;
- }
- image.setDotsPerMeterX(bi.bV5XPelsPerMeter);
- image.setDotsPerMeterY(bi.bV5YPelsPerMeter);
-
- const int red_shift = calc_shift(red_mask);
- const int green_shift = calc_shift(green_mask);
- const int blue_shift = calc_shift(blue_mask);
- const int alpha_shift = alpha_mask ? calc_shift(alpha_mask) : 0u;
-
- const int bpl = image.bytesPerLine();
- uchar *data = image.bits();
-
- auto *buf24 = new uchar[bpl];
- const int bpl24 = ((w * nbits + 31) / 32) * 4;
-
- while (--h >= 0) {
- QRgb *p = reinterpret_cast<QRgb *>(data + h * bpl);
- QRgb *end = p + w;
- if (d->read(reinterpret_cast<char *>(buf24), bpl24) != bpl24)
- break;
- const uchar *b = buf24;
- while (p < end) {
- const int c = *b | (*(b + 1)) << 8 | (*(b + 2)) << 16 | (*(b + 3)) << 24;
- *p++ = qRgba(((c & red_mask) >> red_shift) ,
- ((c & green_mask) >> green_shift),
- ((c & blue_mask) >> blue_shift),
- ((c & alpha_mask) >> alpha_shift));
- b += 4;
- }
- }
- delete[] buf24;
-
- if (bi.bV5Height < 0) {
- // Flip the image
- auto *buf = new uchar[bpl];
- h = -bi.bV5Height;
- for (int y = 0; y < h/2; ++y) {
- memcpy(buf, data + y * bpl, size_t(bpl));
- memcpy(data + y*bpl, data + (h - y -1) * bpl, size_t(bpl));
- memcpy(data + (h - y -1 ) * bpl, buf, size_t(bpl));
- }
- delete [] buf;
- }
-
- return true;
-}
-
// helpers for using global memory
static int getCf(const FORMATETC &formatetc)
@@ -410,7 +300,7 @@ QDebug operator<<(QDebug d, const FORMATETC &tc)
d << "CF_ENHMETAFILE";
break;
default:
- d << QWindowsMimeConverter::clipboardFormatName(tc.cfFormat);
+ d << QWindowsMimeRegistry::clipboardFormatName(tc.cfFormat);
break;
}
d << ", dwAspect=" << tc.dwAspect << ", lindex=" << tc.lindex
@@ -443,145 +333,21 @@ QDebug operator<<(QDebug d, IDataObject *dataObj)
}
#endif // !QT_NO_DEBUG_STREAM
-/*!
- \class QWindowsMime
- \brief The QWindowsMime class maps open-standard MIME to Window Clipboard formats.
- \internal
- \ingroup qt-lighthouse-win
-
- Qt's drag-and-drop and clipboard facilities use the MIME standard.
- On X11, this maps trivially to the Xdnd protocol, but on Windows
- although some applications use MIME types to describe clipboard
- formats, others use arbitrary non-standardized naming conventions,
- or unnamed built-in formats of Windows.
-
- By instantiating subclasses of QWindowsMime that provide conversions
- between Windows Clipboard and MIME formats, you can convert
- proprietary clipboard formats to MIME formats.
-
- Qt has predefined support for the following Windows Clipboard formats:
-
- \table
- \header \li Windows Format \li Equivalent MIME type
- \row \li \c CF_UNICODETEXT \li \c text/plain
- \row \li \c CF_TEXT \li \c text/plain
- \row \li \c CF_DIB \li \c{image/xyz}, where \c xyz is
- a \l{QImageWriter::supportedImageFormats()}{Qt image format}
- \row \li \c CF_HDROP \li \c text/uri-list
- \row \li \c CF_INETURL \li \c text/uri-list
- \row \li \c CF_HTML \li \c text/html
- \endtable
-
- An example use of this class would be to map the Windows Metafile
- clipboard format (\c CF_METAFILEPICT) to and from the MIME type
- \c{image/x-wmf}. This conversion might simply be adding or removing
- a header, or even just passing on the data. See \l{Drag and Drop}
- for more information on choosing and definition MIME types.
-
- You can check if a MIME type is convertible using canConvertFromMime() and
- can perform conversions with convertToMime() and convertFromMime().
-
- \sa QWindowsMimeConverter
-*/
-
-/*!
-Constructs a new conversion object, adding it to the globally accessed
-list of available converters.
-*/
-QWindowsMime::QWindowsMime() = default;
-
-/*!
-Destroys a conversion object, removing it from the global
-list of available converters.
-*/
-QWindowsMime::~QWindowsMime() = default;
-
-/*!
- Registers the MIME type \a mime, and returns an ID number
- identifying the format on Windows.
-*/
-int QWindowsMime::registerMimeType(const QString &mime)
-{
- const UINT f = RegisterClipboardFormat(reinterpret_cast<const wchar_t *> (mime.utf16()));
- if (!f)
- qErrnoWarning("QWindowsMime::registerMimeType: Failed to register clipboard format");
-
- return int(f);
-}
-
-/*!
-\fn bool QWindowsMime::canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const
-
- Returns \c true if the converter can convert from the \a mimeData to
- the format specified in \a formatetc.
-
- All subclasses must reimplement this pure virtual function.
-*/
-
-/*!
- \fn bool QWindowsMime::canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const
-
- Returns \c true if the converter can convert to the \a mimeType from
- the available formats in \a pDataObj.
-
- All subclasses must reimplement this pure virtual function.
-*/
-
-/*!
-\fn QString QWindowsMime::mimeForFormat(const FORMATETC &formatetc) const
-
- Returns the mime type that will be created form the format specified
- in \a formatetc, or an empty string if this converter does not support
- \a formatetc.
-
- All subclasses must reimplement this pure virtual function.
-*/
-
-/*!
-\fn QVector<FORMATETC> QWindowsMime::formatsForMime(const QString &mimeType, const QMimeData *mimeData) const
-
- Returns a QVector of FORMATETC structures representing the different windows clipboard
- formats that can be provided for the \a mimeType from the \a mimeData.
-
- All subclasses must reimplement this pure virtual function.
-*/
-
-/*!
- \fn QVariant QWindowsMime::convertToMime(const QString &mimeType, IDataObject *pDataObj,
- QVariant::Type preferredType) const
-
- Returns a QVariant containing the converted data for \a mimeType from \a pDataObj.
- If possible the QVariant should be of the \a preferredType to avoid needless conversions.
-
- All subclasses must reimplement this pure virtual function.
-*/
-
-/*!
-\fn bool QWindowsMime::convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const
-
- Convert the \a mimeData to the format specified in \a formatetc.
- The converted data should then be placed in \a pmedium structure.
-
- Return true if the conversion was successful.
-
- All subclasses must reimplement this pure virtual function.
-*/
-
-class QWindowsMimeText : public QWindowsMime
+class QWindowsMimeText : public QWindowsMimeConverter
{
public:
bool canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const override;
- QVariant convertToMime(const QString &mime, LPDATAOBJECT pDataObj, QVariant::Type preferredType) const override;
+ QVariant convertToMime(const QString &mime, LPDATAOBJECT pDataObj, QMetaType preferredType) const override;
QString mimeForFormat(const FORMATETC &formatetc) const override;
bool canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const override;
bool convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM *pmedium) const override;
- QVector<FORMATETC> formatsForMime(const QString &mimeType, const QMimeData *mimeData) const override;
+ QList<FORMATETC> formatsForMime(const QString &mimeType, const QMimeData *mimeData) const override;
};
bool QWindowsMimeText::canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const
{
int cf = getCf(formatetc);
- return (cf == CF_UNICODETEXT || cf == CF_TEXT) && mimeData->hasText();
+ return (cf == CF_UNICODETEXT || (cf == CF_TEXT && GetACP() != CP_UTF8)) && mimeData->hasText();
}
/*
@@ -672,22 +438,23 @@ QString QWindowsMimeText::mimeForFormat(const FORMATETC &formatetc) const
{
int cf = getCf(formatetc);
if (cf == CF_UNICODETEXT || cf == CF_TEXT)
- return QStringLiteral("text/plain");
+ return u"text/plain"_s;
return QString();
}
-QVector<FORMATETC> QWindowsMimeText::formatsForMime(const QString &mimeType, const QMimeData *mimeData) const
+QList<FORMATETC> QWindowsMimeText::formatsForMime(const QString &mimeType, const QMimeData *mimeData) const
{
- QVector<FORMATETC> formatics;
+ QList<FORMATETC> formatics;
if (mimeType.startsWith(u"text/plain") && mimeData->hasText()) {
formatics += setCf(CF_UNICODETEXT);
- formatics += setCf(CF_TEXT);
+ if (GetACP() != CP_UTF8)
+ formatics += setCf(CF_TEXT);
}
return formatics;
}
-QVariant QWindowsMimeText::convertToMime(const QString &mime, LPDATAOBJECT pDataObj, QVariant::Type preferredType) const
+QVariant QWindowsMimeText::convertToMime(const QString &mime, LPDATAOBJECT pDataObj, QMetaType preferredType) const
{
QVariant ret;
@@ -696,12 +463,12 @@ QVariant QWindowsMimeText::convertToMime(const QString &mime, LPDATAOBJECT pData
QByteArray data = getData(CF_UNICODETEXT, pDataObj);
if (!data.isEmpty()) {
str = QString::fromWCharArray(reinterpret_cast<const wchar_t *>(data.constData()));
- str.replace(QLatin1String("\r\n"), QLatin1String("\n"));
+ str.replace("\r\n"_L1, "\n"_L1);
} else {
data = getData(CF_TEXT, pDataObj);
if (!data.isEmpty()) {
const char* d = data.data();
- const unsigned s = qstrlen(d);
+ const unsigned s = unsigned(qstrlen(d));
QByteArray r(data.size()+1, '\0');
char* o = r.data();
int j=0;
@@ -714,7 +481,7 @@ QVariant QWindowsMimeText::convertToMime(const QString &mime, LPDATAOBJECT pData
str = QString::fromLocal8Bit(r);
}
}
- if (preferredType == QVariant::String)
+ if (preferredType.id() == QMetaType::QString)
ret = str;
else
ret = std::move(str).toUtf8();
@@ -723,16 +490,16 @@ QVariant QWindowsMimeText::convertToMime(const QString &mime, LPDATAOBJECT pData
return ret;
}
-class QWindowsMimeURI : public QWindowsMime
+class QWindowsMimeURI : public QWindowsMimeConverter
{
public:
QWindowsMimeURI();
bool canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const override;
- QVariant convertToMime(const QString &mime, LPDATAOBJECT pDataObj, QVariant::Type preferredType) const override;
+ QVariant convertToMime(const QString &mime, LPDATAOBJECT pDataObj, QMetaType preferredType) const override;
QString mimeForFormat(const FORMATETC &formatetc) const override;
bool canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const override;
bool convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM *pmedium) const override;
- QVector<FORMATETC> formatsForMime(const QString &mimeType, const QMimeData *mimeData) const override;
+ QList<FORMATETC> formatsForMime(const QString &mimeType, const QMimeData *mimeData) const override;
private:
int CF_INETURL_W; // wide char version
int CF_INETURL;
@@ -740,8 +507,8 @@ private:
QWindowsMimeURI::QWindowsMimeURI()
{
- CF_INETURL_W = QWindowsMime::registerMimeType(QStringLiteral("UniformResourceLocatorW"));
- CF_INETURL = QWindowsMime::registerMimeType(QStringLiteral("UniformResourceLocator"));
+ CF_INETURL_W = registerMimeType(u"UniformResourceLocatorW"_s);
+ CF_INETURL = registerMimeType(u"UniformResourceLocator"_s);
}
bool QWindowsMimeURI::canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const
@@ -762,7 +529,7 @@ bool QWindowsMimeURI::convertFromMime(const FORMATETC &formatetc, const QMimeDat
if (getCf(formatetc) == CF_HDROP) {
const auto &urls = mimeData->urls();
QStringList fileNames;
- int size = sizeof(DROPFILES)+2;
+ size_t size = sizeof(DROPFILES) + 2;
for (const QUrl &url : urls) {
const QString fn = QDir::toNativeSeparators(url.toLocalFile());
if (!fn.isEmpty()) {
@@ -771,7 +538,7 @@ bool QWindowsMimeURI::convertFromMime(const FORMATETC &formatetc, const QMimeDat
}
}
- QByteArray result(size, '\0');
+ QByteArray result(int(size), '\0');
auto* d = reinterpret_cast<DROPFILES *>(result.data());
d->pFiles = sizeof(DROPFILES);
GetCursorPos(&d->pt); // try
@@ -782,7 +549,7 @@ bool QWindowsMimeURI::convertFromMime(const FORMATETC &formatetc, const QMimeDat
auto *f = reinterpret_cast<wchar_t *>(files);
for (int i=0; i<fileNames.size(); i++) {
const auto l = size_t(fileNames.at(i).length());
- memcpy(f, fileNames.at(i).utf16(), l * sizeof(ushort));
+ memcpy(f, fileNames.at(i).data(), l * sizeof(ushort));
f += l;
*f++ = 0;
}
@@ -794,8 +561,8 @@ bool QWindowsMimeURI::convertFromMime(const FORMATETC &formatetc, const QMimeDat
const auto urls = mimeData->urls();
QByteArray result;
if (!urls.isEmpty()) {
- QString url = urls.at(0).toString();
- result = QByteArray(reinterpret_cast<const char *>(url.utf16()),
+ const QString url = urls.at(0).toString();
+ result = QByteArray(reinterpret_cast<const char *>(url.data()),
url.length() * int(sizeof(ushort)));
}
result.append('\0');
@@ -824,13 +591,13 @@ QString QWindowsMimeURI::mimeForFormat(const FORMATETC &formatetc) const
{
QString format;
if (getCf(formatetc) == CF_HDROP || getCf(formatetc) == CF_INETURL_W || getCf(formatetc) == CF_INETURL)
- format = QStringLiteral("text/uri-list");
+ format = u"text/uri-list"_s;
return format;
}
-QVector<FORMATETC> QWindowsMimeURI::formatsForMime(const QString &mimeType, const QMimeData *mimeData) const
+QList<FORMATETC> QWindowsMimeURI::formatsForMime(const QString &mimeType, const QMimeData *mimeData) const
{
- QVector<FORMATETC> formatics;
+ QList<FORMATETC> formatics;
if (mimeType == u"text/uri-list") {
if (canConvertFromMime(setCf(CF_HDROP), mimeData))
formatics += setCf(CF_HDROP);
@@ -842,7 +609,7 @@ QVector<FORMATETC> QWindowsMimeURI::formatsForMime(const QString &mimeType, cons
return formatics;
}
-QVariant QWindowsMimeURI::convertToMime(const QString &mimeType, LPDATAOBJECT pDataObj, QVariant::Type preferredType) const
+QVariant QWindowsMimeURI::convertToMime(const QString &mimeType, LPDATAOBJECT pDataObj, QMetaType preferredType) const
{
if (mimeType == u"text/uri-list") {
if (canGetData(CF_HDROP, pDataObj)) {
@@ -870,7 +637,7 @@ QVariant QWindowsMimeURI::convertToMime(const QString &mimeType, LPDATAOBJECT pD
}
}
- if (preferredType == QVariant::Url && urls.size() == 1)
+ if (preferredType.id() == QMetaType::QUrl && urls.size() == 1)
return urls.at(0);
if (!urls.isEmpty())
return urls;
@@ -889,7 +656,7 @@ QVariant QWindowsMimeURI::convertToMime(const QString &mimeType, LPDATAOBJECT pD
return QVariant();
}
-class QWindowsMimeHtml : public QWindowsMime
+class QWindowsMimeHtml : public QWindowsMimeConverter
{
public:
QWindowsMimeHtml();
@@ -897,11 +664,11 @@ public:
// for converting from Qt
bool canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const override;
bool convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const override;
- QVector<FORMATETC> formatsForMime(const QString &mimeType, const QMimeData *mimeData) const override;
+ QList<FORMATETC> formatsForMime(const QString &mimeType, const QMimeData *mimeData) const override;
// for converting to Qt
bool canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const override;
- QVariant convertToMime(const QString &mime, IDataObject *pDataObj, QVariant::Type preferredType) const override;
+ QVariant convertToMime(const QString &mime, IDataObject *pDataObj, QMetaType preferredType) const override;
QString mimeForFormat(const FORMATETC &formatetc) const override;
private:
@@ -910,12 +677,12 @@ private:
QWindowsMimeHtml::QWindowsMimeHtml()
{
- CF_HTML = QWindowsMime::registerMimeType(QStringLiteral("HTML Format"));
+ CF_HTML = registerMimeType(u"HTML Format"_s);
}
-QVector<FORMATETC> QWindowsMimeHtml::formatsForMime(const QString &mimeType, const QMimeData *mimeData) const
+QList<FORMATETC> QWindowsMimeHtml::formatsForMime(const QString &mimeType, const QMimeData *mimeData) const
{
- QVector<FORMATETC> formatetcs;
+ QList<FORMATETC> formatetcs;
if (mimeType == u"text/html" && (!mimeData->html().isEmpty()))
formatetcs += setCf(CF_HTML);
return formatetcs;
@@ -924,7 +691,7 @@ QVector<FORMATETC> QWindowsMimeHtml::formatsForMime(const QString &mimeType, con
QString QWindowsMimeHtml::mimeForFormat(const FORMATETC &formatetc) const
{
if (getCf(formatetc) == CF_HTML)
- return QStringLiteral("text/html");
+ return u"text/html"_s;
return QString();
}
@@ -951,14 +718,14 @@ in bytes). Charset used is mostly utf8, but can be different, ie. we have to loo
...html...
*/
-QVariant QWindowsMimeHtml::convertToMime(const QString &mime, IDataObject *pDataObj, QVariant::Type preferredType) const
+QVariant QWindowsMimeHtml::convertToMime(const QString &mime, IDataObject *pDataObj, QMetaType preferredType) const
{
Q_UNUSED(preferredType);
QVariant result;
if (canConvertToMime(mime, pDataObj)) {
QByteArray html = getData(CF_HTML, pDataObj);
- static Q_RELAXED_CONSTEXPR auto startMatcher = qMakeStaticByteArrayMatcher("StartHTML:");
- static Q_RELAXED_CONSTEXPR auto endMatcher = qMakeStaticByteArrayMatcher("EndHTML:");
+ static constexpr auto startMatcher = qMakeStaticByteArrayMatcher("StartHTML:");
+ static constexpr auto endMatcher = qMakeStaticByteArrayMatcher("EndHTML:");
qCDebug(lcQpaMime) << __FUNCTION__ << "raw:" << html;
int start = startMatcher.indexIn(html);
int end = endMatcher.indexIn(html);
@@ -1001,8 +768,8 @@ bool QWindowsMimeHtml::convertFromMime(const FORMATETC &formatetc, const QMimeDa
"StartFragment:0000000000\r\n" // 56-81
"EndFragment:0000000000\r\n\r\n"; // 82-107
- static Q_RELAXED_CONSTEXPR auto startFragmentMatcher = qMakeStaticByteArrayMatcher("<!--StartFragment-->");
- static Q_RELAXED_CONSTEXPR auto endFragmentMatcher = qMakeStaticByteArrayMatcher("<!--EndFragment-->");
+ static constexpr auto startFragmentMatcher = qMakeStaticByteArrayMatcher("<!--StartFragment-->");
+ static constexpr auto endFragmentMatcher = qMakeStaticByteArrayMatcher("<!--EndFragment-->");
if (startFragmentMatcher.indexIn(data) == -1)
result += "<!--StartFragment-->";
@@ -1027,18 +794,18 @@ bool QWindowsMimeHtml::convertFromMime(const FORMATETC &formatetc, const QMimeDa
#ifndef QT_NO_IMAGEFORMAT_BMP
-class QWindowsMimeImage : public QWindowsMime
+class QWindowsMimeImage : public QWindowsMimeConverter
{
public:
QWindowsMimeImage();
// for converting from Qt
bool canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const override;
bool convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const override;
- QVector<FORMATETC> formatsForMime(const QString &mimeType, const QMimeData *mimeData) const override;
+ QList<FORMATETC> formatsForMime(const QString &mimeType, const QMimeData *mimeData) const override;
// for converting to Qt
bool canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const override;
- QVariant convertToMime(const QString &mime, IDataObject *pDataObj, QVariant::Type preferredType) const override;
+ QVariant convertToMime(const QString &mime, IDataObject *pDataObj, QMetaType preferredType) const override;
QString mimeForFormat(const FORMATETC &formatetc) const override;
private:
bool hasOriginalDIBV5(IDataObject *pDataObj) const;
@@ -1050,9 +817,9 @@ QWindowsMimeImage::QWindowsMimeImage()
CF_PNG = RegisterClipboardFormat(L"PNG");
}
-QVector<FORMATETC> QWindowsMimeImage::formatsForMime(const QString &mimeType, const QMimeData *mimeData) const
+QList<FORMATETC> QWindowsMimeImage::formatsForMime(const QString &mimeType, const QMimeData *mimeData) const
{
- QVector<FORMATETC> formatetcs;
+ QList<FORMATETC> formatetcs;
if (mimeData->hasImage() && mimeType == u"application/x-qt-image") {
//add DIBV5 if image has alpha channel. Do not add CF_PNG here as it will confuse MS Office (QTBUG47656).
auto image = qvariant_cast<QImage>(mimeData->imageData());
@@ -1069,7 +836,7 @@ QString QWindowsMimeImage::mimeForFormat(const FORMATETC &formatetc) const
{
int cf = getCf(formatetc);
if (cf == CF_DIB || cf == CF_DIBV5 || cf == int(CF_PNG))
- return QStringLiteral("application/x-qt-image");
+ return u"application/x-qt-image"_s;
return QString();
}
@@ -1103,7 +870,7 @@ bool QWindowsMimeImage::convertFromMime(const FORMATETC &formatetc, const QMimeD
QByteArray ba;
if (cf == CF_DIB) {
if (img.format() > QImage::Format_ARGB32)
- img = img.convertToFormat(QImage::Format_RGB32);
+ img = std::move(img).convertToFormat(QImage::Format_RGB32);
const QByteArray ba = writeDib(img);
if (!ba.isEmpty())
return setData(ba, pmedium);
@@ -1116,7 +883,7 @@ bool QWindowsMimeImage::convertFromMime(const FORMATETC &formatetc, const QMimeD
} else {
QDataStream s(&ba, QIODevice::WriteOnly);
s.setByteOrder(QDataStream::LittleEndian);// Intel byte order ####
- if (qt_write_dibv5(s, img))
+ if (qt_write_dibv5(s, std::move(img)))
return setData(ba, pmedium);
}
}
@@ -1136,7 +903,7 @@ bool QWindowsMimeImage::hasOriginalDIBV5(IDataObject *pDataObj) const
if (fc.cfFormat == CF_DIB)
break;
if (fc.cfFormat == CF_DIBV5) {
- isSynthesized = false;
+ isSynthesized = false;
break;
}
}
@@ -1145,25 +912,28 @@ bool QWindowsMimeImage::hasOriginalDIBV5(IDataObject *pDataObj) const
return !isSynthesized;
}
-QVariant QWindowsMimeImage::convertToMime(const QString &mimeType, IDataObject *pDataObj, QVariant::Type preferredType) const
+QVariant QWindowsMimeImage::convertToMime(const QString &mimeType, IDataObject *pDataObj, QMetaType preferredType) const
{
Q_UNUSED(preferredType);
QVariant result;
if (mimeType != u"application/x-qt-image")
return result;
- //Try to convert from a format which has more data
- //DIBV5, use only if its is not synthesized
- if (canGetData(CF_DIBV5, pDataObj) && hasOriginalDIBV5(pDataObj)) {
+ // Try to convert from DIBV5 as it is the most widespread format that supports transparency,
+ // but avoid synthesizing it, as that typically loses transparency, e.g. from Office
+ const bool canGetDibV5 = canGetData(CF_DIBV5, pDataObj);
+ const bool hasOrigDibV5 = canGetDibV5 ? hasOriginalDIBV5(pDataObj) : false;
+ qCDebug(lcQpaMime) << "canGetDibV5:" << canGetDibV5 << "hasOrigDibV5:" << hasOrigDibV5;
+ if (hasOrigDibV5) {
+ qCDebug(lcQpaMime) << "Decoding DIBV5";
QImage img;
QByteArray data = getData(CF_DIBV5, pDataObj);
- QDataStream s(&data, QIODevice::ReadOnly);
- s.setByteOrder(QDataStream::LittleEndian);
- if (qt_read_dibv5(s, img)) { // #### supports only 32bit DIBV5
+ QBuffer buffer(&data);
+ if (readDib(buffer, img))
return img;
- }
}
//PNG, MS Office place this (undocumented)
if (canGetData(CF_PNG, pDataObj)) {
+ qCDebug(lcQpaMime) << "Decoding PNG";
QImage img;
QByteArray data = getData(CF_PNG, pDataObj);
if (img.loadFromData(data, "PNG")) {
@@ -1172,8 +942,11 @@ QVariant QWindowsMimeImage::convertToMime(const QString &mimeType, IDataObject *
}
//Fallback to DIB
if (canGetData(CF_DIB, pDataObj)) {
- const QImage img = readDib(getData(CF_DIB, pDataObj));
- if (!img.isNull())
+ qCDebug(lcQpaMime) << "Decoding DIB";
+ QImage img;
+ QByteArray data = getData(CF_DIBV5, pDataObj);
+ QBuffer buffer(&data);
+ if (readDib(buffer, img))
return img;
}
// Failed
@@ -1181,7 +954,7 @@ QVariant QWindowsMimeImage::convertToMime(const QString &mimeType, IDataObject *
}
#endif
-class QBuiltInMimes : public QWindowsMime
+class QBuiltInMimes : public QWindowsMimeConverter
{
public:
QBuiltInMimes();
@@ -1189,11 +962,11 @@ public:
// for converting from Qt
bool canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const override;
bool convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const override;
- QVector<FORMATETC> formatsForMime(const QString &mimeType, const QMimeData *mimeData) const override;
+ QList<FORMATETC> formatsForMime(const QString &mimeType, const QMimeData *mimeData) const override;
// for converting to Qt
bool canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const override;
- QVariant convertToMime(const QString &mime, IDataObject *pDataObj, QVariant::Type preferredType) const override;
+ QVariant convertToMime(const QString &mime, IDataObject *pDataObj, QMetaType preferredType) const override;
QString mimeForFormat(const FORMATETC &formatetc) const override;
private:
@@ -1202,10 +975,10 @@ private:
};
QBuiltInMimes::QBuiltInMimes()
-: QWindowsMime()
+: QWindowsMimeConverter()
{
- outFormats.insert(QWindowsMime::registerMimeType(QStringLiteral("application/x-color")), QStringLiteral("application/x-color"));
- inFormats.insert(QWindowsMime::registerMimeType(QStringLiteral("application/x-color")), QStringLiteral("application/x-color"));
+ outFormats.insert(registerMimeType(u"application/x-color"_s), u"application/x-color"_s);
+ inFormats.insert(registerMimeType(u"application/x-color"_s), u"application/x-color"_s);
}
bool QBuiltInMimes::canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const
@@ -1263,9 +1036,9 @@ bool QBuiltInMimes::convertFromMime(const FORMATETC &formatetc, const QMimeData
return false;
}
-QVector<FORMATETC> QBuiltInMimes::formatsForMime(const QString &mimeType, const QMimeData *mimeData) const
+QList<FORMATETC> QBuiltInMimes::formatsForMime(const QString &mimeType, const QMimeData *mimeData) const
{
- QVector<FORMATETC> formatetcs;
+ QList<FORMATETC> formatetcs;
const auto mit = std::find(outFormats.cbegin(), outFormats.cend(), mimeType);
if (mit != outFormats.cend() && mimeData->formats().contains(mimeType))
formatetcs += setCf(mit.key());
@@ -1278,14 +1051,14 @@ bool QBuiltInMimes::canConvertToMime(const QString &mimeType, IDataObject *pData
return mit != inFormats.cend() && canGetData(mit.key(), pDataObj);
}
-QVariant QBuiltInMimes::convertToMime(const QString &mimeType, IDataObject *pDataObj, QVariant::Type preferredType) const
+QVariant QBuiltInMimes::convertToMime(const QString &mimeType, IDataObject *pDataObj, QMetaType preferredType) const
{
QVariant val;
if (canConvertToMime(mimeType, pDataObj)) {
QByteArray data = getData(inFormats.key(mimeType), pDataObj);
if (!data.isEmpty()) {
qCDebug(lcQpaMime) << __FUNCTION__;
- if (mimeType == u"text/html" && preferredType == QVariant::String) {
+ if (mimeType == u"text/html" && preferredType == QMetaType(QMetaType::QString)) {
// text/html is in wide chars on windows (compatible with Mozilla)
val = QString::fromWCharArray(reinterpret_cast<const wchar_t *>(data.constData()));
} else {
@@ -1302,7 +1075,7 @@ QString QBuiltInMimes::mimeForFormat(const FORMATETC &formatetc) const
}
-class QLastResortMimes : public QWindowsMime
+class QLastResortMimes : public QWindowsMimeConverter
{
public:
@@ -1310,11 +1083,11 @@ public:
// for converting from Qt
bool canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const override;
bool convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const override;
- QVector<FORMATETC> formatsForMime(const QString &mimeType, const QMimeData *mimeData) const override;
+ QList<FORMATETC> formatsForMime(const QString &mimeType, const QMimeData *mimeData) const override;
// for converting to Qt
bool canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const override;
- QVariant convertToMime(const QString &mime, IDataObject *pDataObj, QVariant::Type preferredType) const override;
+ QVariant convertToMime(const QString &mime, IDataObject *pDataObj, QMetaType preferredType) const override;
QString mimeForFormat(const FORMATETC &formatetc) const override;
private:
@@ -1330,25 +1103,25 @@ QLastResortMimes::QLastResortMimes()
{
//MIME Media-Types
if (ianaTypes.isEmpty()) {
- ianaTypes.append(QStringLiteral("application/"));
- ianaTypes.append(QStringLiteral("audio/"));
- ianaTypes.append(QStringLiteral("example/"));
- ianaTypes.append(QStringLiteral("image/"));
- ianaTypes.append(QStringLiteral("message/"));
- ianaTypes.append(QStringLiteral("model/"));
- ianaTypes.append(QStringLiteral("multipart/"));
- ianaTypes.append(QStringLiteral("text/"));
- ianaTypes.append(QStringLiteral("video/"));
+ ianaTypes.append(u"application/"_s);
+ ianaTypes.append(u"audio/"_s);
+ ianaTypes.append(u"example/"_s);
+ ianaTypes.append(u"image/"_s);
+ ianaTypes.append(u"message/"_s);
+ ianaTypes.append(u"model/"_s);
+ ianaTypes.append(u"multipart/"_s);
+ ianaTypes.append(u"text/"_s);
+ ianaTypes.append(u"video/"_s);
}
//Types handled by other classes
if (excludeList.isEmpty()) {
- excludeList.append(QStringLiteral("HTML Format"));
- excludeList.append(QStringLiteral("UniformResourceLocator"));
- excludeList.append(QStringLiteral("text/html"));
- excludeList.append(QStringLiteral("text/plain"));
- excludeList.append(QStringLiteral("text/uri-list"));
- excludeList.append(QStringLiteral("application/x-qt-image"));
- excludeList.append(QStringLiteral("application/x-color"));
+ excludeList.append(u"HTML Format"_s);
+ excludeList.append(u"UniformResourceLocator"_s);
+ excludeList.append(u"text/html"_s);
+ excludeList.append(u"text/plain"_s);
+ excludeList.append(u"text/uri-list"_s);
+ excludeList.append(u"application/x-qt-image"_s);
+ excludeList.append(u"application/x-color"_s);
}
}
@@ -1380,13 +1153,13 @@ bool QLastResortMimes::convertFromMime(const FORMATETC &formatetc, const QMimeDa
#endif // QT_CONFIG(draganddrop)
}
-QVector<FORMATETC> QLastResortMimes::formatsForMime(const QString &mimeType, const QMimeData * /*mimeData*/) const
+QList<FORMATETC> QLastResortMimes::formatsForMime(const QString &mimeType, const QMimeData * /*mimeData*/) const
{
- QVector<FORMATETC> formatetcs;
+ QList<FORMATETC> formatetcs;
auto mit = std::find(formats.begin(), formats.end(), mimeType);
// register any other available formats
if (mit == formats.end() && !excludeList.contains(mimeType, Qt::CaseInsensitive))
- mit = formats.insert(QWindowsMime::registerMimeType(mimeType), mimeType);
+ mit = formats.insert(registerMimeType(mimeType), mimeType);
if (mit != formats.end())
formatetcs += setCf(mit.key());
@@ -1398,7 +1171,7 @@ static const char x_qt_windows_mime[] = "application/x-qt-windows-mime;value=\""
static bool isCustomMimeType(const QString &mimeType)
{
- return mimeType.startsWith(QLatin1String(x_qt_windows_mime), Qt::CaseInsensitive);
+ return mimeType.startsWith(QLatin1StringView(x_qt_windows_mime), Qt::CaseInsensitive);
}
static QString customMimeType(const QString &mimeType, int *lindex = nullptr)
@@ -1412,7 +1185,7 @@ static QString customMimeType(const QString &mimeType, int *lindex = nullptr)
const int endPos = mimeType.indexOf(u';', beginPos + 1);
const int indexStartPos = beginPos + 7;
if (lindex)
- *lindex = mimeType.midRef(indexStartPos, endPos == -1 ? endPos : endPos - indexStartPos).toInt();
+ *lindex = QStringView{mimeType}.mid(indexStartPos, endPos == -1 ? endPos : endPos - indexStartPos).toInt();
} else {
if (lindex)
*lindex = -1;
@@ -1430,11 +1203,11 @@ bool QLastResortMimes::canConvertToMime(const QString &mimeType, IDataObject *pD
}
// if it is not in there then register it and see if we can get it
const auto mit = std::find(formats.cbegin(), formats.cend(), mimeType);
- const int cf = mit != formats.cend() ? mit.key() : QWindowsMime::registerMimeType(mimeType);
+ const int cf = mit != formats.cend() ? mit.key() : registerMimeType(mimeType);
return canGetData(cf, pDataObj);
}
-QVariant QLastResortMimes::convertToMime(const QString &mimeType, IDataObject *pDataObj, QVariant::Type preferredType) const
+QVariant QLastResortMimes::convertToMime(const QString &mimeType, IDataObject *pDataObj, QMetaType preferredType) const
{
Q_UNUSED(preferredType);
QVariant val;
@@ -1447,7 +1220,7 @@ QVariant QLastResortMimes::convertToMime(const QString &mimeType, IDataObject *p
data = getData(int(cf), pDataObj, lindex);
} else {
const auto mit = std::find(formats.cbegin(), formats.cend(), mimeType);
- const int cf = mit != formats.cend() ? mit.key() : QWindowsMime::registerMimeType(mimeType);
+ const int cf = mit != formats.cend() ? mit.key() : registerMimeType(mimeType);
data = getData(cf, pDataObj);
}
if (!data.isEmpty())
@@ -1462,12 +1235,12 @@ QString QLastResortMimes::mimeForFormat(const FORMATETC &formatetc) const
if (!format.isEmpty())
return format;
- const QString clipFormat = QWindowsMimeConverter::clipboardFormatName(getCf(formatetc));
+ const QString clipFormat = QWindowsMimeRegistry::clipboardFormatName(getCf(formatetc));
if (!clipFormat.isEmpty()) {
#if QT_CONFIG(draganddrop)
if (QInternalMimeData::canReadData(clipFormat))
format = clipFormat;
- else if((formatetc.cfFormat >= 0xC000)){
+ else if ((formatetc.cfFormat >= 0xC000)){
//create the mime as custom. not registered.
if (!excludeList.contains(clipFormat, Qt::CaseInsensitive)) {
//check if this is a mime type
@@ -1480,7 +1253,7 @@ QString QLastResortMimes::mimeForFormat(const FORMATETC &formatetc) const
}
}
if (!ianaType)
- format = QLatin1String(x_qt_windows_mime) + clipFormat + u'"';
+ format = QLatin1StringView(x_qt_windows_mime) + clipFormat + u'"';
else
format = clipFormat;
}
@@ -1492,21 +1265,20 @@ QString QLastResortMimes::mimeForFormat(const FORMATETC &formatetc) const
}
/*!
- \class QWindowsMimeConverter
- \brief Manages the list of QWindowsMime instances.
+ \class QWindowsMimeRegistry
+ \brief Manages the list of QWindowsMimeConverter instances.
\internal
- \ingroup qt-lighthouse-win
- \sa QWindowsMime
+ \sa QWindowsMimeConverter
*/
-QWindowsMimeConverter::QWindowsMimeConverter() = default;
+QWindowsMimeRegistry::QWindowsMimeRegistry() = default;
-QWindowsMimeConverter::~QWindowsMimeConverter()
+QWindowsMimeRegistry::~QWindowsMimeRegistry()
{
qDeleteAll(m_mimes.begin(), m_mimes.begin() + m_internalMimeCount);
}
-QWindowsMime * QWindowsMimeConverter::converterToMime(const QString &mimeType, IDataObject *pDataObj) const
+QWindowsMimeRegistry::QWindowsMimeConverter *QWindowsMimeRegistry::converterToMime(const QString &mimeType, IDataObject *pDataObj) const
{
ensureInitialized();
for (int i = m_mimes.size()-1; i >= 0; --i) {
@@ -1516,9 +1288,9 @@ QWindowsMime * QWindowsMimeConverter::converterToMime(const QString &mimeType, I
return nullptr;
}
-QStringList QWindowsMimeConverter::allMimesForFormats(IDataObject *pDataObj) const
+QStringList QWindowsMimeRegistry::allMimesForFormats(IDataObject *pDataObj) const
{
- qCDebug(lcQpaMime) << "QWindowsMime::allMimesForFormats()";
+ qCDebug(lcQpaMime) << "QWindowsMimeConverter::allMimesForFormats()";
ensureInitialized();
QStringList formats;
LPENUMFORMATETC FAR fmtenum;
@@ -1545,7 +1317,7 @@ QStringList QWindowsMimeConverter::allMimesForFormats(IDataObject *pDataObj) con
return formats;
}
-QWindowsMime * QWindowsMimeConverter::converterFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const
+QWindowsMimeRegistry::QWindowsMimeConverter *QWindowsMimeRegistry::converterFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const
{
ensureInitialized();
qCDebug(lcQpaMime) << __FUNCTION__ << formatetc;
@@ -1556,10 +1328,10 @@ QWindowsMime * QWindowsMimeConverter::converterFromMime(const FORMATETC &formate
return nullptr;
}
-QVector<FORMATETC> QWindowsMimeConverter::allFormatsForMime(const QMimeData *mimeData) const
+QList<FORMATETC> QWindowsMimeRegistry::allFormatsForMime(const QMimeData *mimeData) const
{
ensureInitialized();
- QVector<FORMATETC> formatics;
+ QList<FORMATETC> formatics;
#if !QT_CONFIG(draganddrop)
Q_UNUSED(mimeData);
#else
@@ -1573,34 +1345,37 @@ QVector<FORMATETC> QWindowsMimeConverter::allFormatsForMime(const QMimeData *mim
return formatics;
}
-void QWindowsMimeConverter::ensureInitialized() const
+void QWindowsMimeRegistry::ensureInitialized() const
{
- if (m_mimes.isEmpty()) {
- m_mimes
+ if (m_internalMimeCount == 0) {
+ m_internalMimeCount = -1; // prevent reentrancy when types register themselves
#ifndef QT_NO_IMAGEFORMAT_BMP
- << new QWindowsMimeImage
+ (void)new QWindowsMimeImage;
#endif //QT_NO_IMAGEFORMAT_BMP
- << new QLastResortMimes
- << new QWindowsMimeText << new QWindowsMimeURI
- << new QWindowsMimeHtml << new QBuiltInMimes;
+ (void)new QLastResortMimes;
+ (void)new QWindowsMimeText;
+ (void)new QWindowsMimeURI;
+ (void)new QWindowsMimeHtml;
+ (void)new QBuiltInMimes;
m_internalMimeCount = m_mimes.size();
+ Q_ASSERT(m_internalMimeCount > 0);
}
}
-QString QWindowsMimeConverter::clipboardFormatName(int cf)
+QString QWindowsMimeRegistry::clipboardFormatName(int cf)
{
wchar_t buf[256] = {0};
return GetClipboardFormatName(UINT(cf), buf, 255)
? QString::fromWCharArray(buf) : QString();
}
-QVariant QWindowsMimeConverter::convertToMime(const QStringList &mimeTypes,
+QVariant QWindowsMimeRegistry::convertToMime(const QStringList &mimeTypes,
IDataObject *pDataObj,
- QVariant::Type preferredType,
+ QMetaType preferredType,
QString *formatIn /* = 0 */) const
{
for (const QString &format : mimeTypes) {
- if (const QWindowsMime *converter = converterToMime(format, pDataObj)) {
+ if (const QWindowsMimeConverter *converter = converterToMime(format, pDataObj)) {
if (converter->canConvertToMime(format, pDataObj)) {
const QVariant dataV = converter->convertToMime(format, pDataObj, preferredType);
if (dataV.isValid()) {
@@ -1613,14 +1388,33 @@ QVariant QWindowsMimeConverter::convertToMime(const QStringList &mimeTypes,
}
}
}
- qCDebug(lcQpaMime) << __FUNCTION__ << "fails" << mimeTypes << pDataObj << preferredType;
+ qCDebug(lcQpaMime) << __FUNCTION__ << "fails" << mimeTypes << pDataObj << preferredType.id();
return QVariant();
}
-void QWindowsMimeConverter::registerMime(QWindowsMime *mime)
+void QWindowsMimeRegistry::registerMime(QWindowsMimeConverter *mime)
{
ensureInitialized();
m_mimes.append(mime);
}
+/*!
+ Registers the MIME type \a mime, and returns an ID number
+ identifying the format on Windows.
+
+ A mime type \c {application/x-qt-windows-mime;value="WindowsType"} will be
+ registered as the clipboard format for \c WindowsType.
+*/
+int QWindowsMimeRegistry::registerMimeType(const QString &mime)
+{
+ const QString mimeType = isCustomMimeType(mime) ? customMimeType(mime) : mime;
+ const UINT f = RegisterClipboardFormat(reinterpret_cast<const wchar_t *> (mimeType.utf16()));
+ if (!f) {
+ qErrnoWarning("QWindowsMimeRegistry::registerMimeType: Failed to register clipboard format "
+ "for %s", qPrintable(mime));
+ }
+
+ return int(f);
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/windows/qwindowsmimeregistry.h b/src/plugins/platforms/windows/qwindowsmimeregistry.h
new file mode 100644
index 0000000000..a0f4b4c60a
--- /dev/null
+++ b/src/plugins/platforms/windows/qwindowsmimeregistry.h
@@ -0,0 +1,58 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QWINDOWSMIMEREGISTRY_H
+#define QWINDOWSMIMEREGISTRY_H
+
+
+#include <QtCore/qt_windows.h>
+
+#include <QtGui/qwindowsmimeconverter.h>
+#include <QtCore/qlist.h>
+#include <QtCore/qvariant.h>
+
+QT_BEGIN_NAMESPACE
+
+class QDebug;
+class QMimeData;
+
+class QWindowsMimeRegistry
+{
+ Q_DISABLE_COPY_MOVE(QWindowsMimeRegistry)
+public:
+ using QWindowsMimeConverter = QWindowsMimeConverter;
+
+ QWindowsMimeRegistry();
+ ~QWindowsMimeRegistry();
+
+ QWindowsMimeConverter *converterToMime(const QString &mimeType, IDataObject *pDataObj) const;
+ QStringList allMimesForFormats(IDataObject *pDataObj) const;
+ QWindowsMimeConverter *converterFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const;
+ QList<FORMATETC> allFormatsForMime(const QMimeData *mimeData) const;
+
+ // Convenience.
+ QVariant convertToMime(const QStringList &mimeTypes, IDataObject *pDataObj, QMetaType preferredType,
+ QString *format = nullptr) const;
+
+ void registerMime(QWindowsMimeConverter *mime);
+ void unregisterMime(QWindowsMimeConverter *mime) { m_mimes.removeOne(mime); }
+
+ static int registerMimeType(const QString &mime);
+
+ static QString clipboardFormatName(int cf);
+
+private:
+ void ensureInitialized() const;
+
+ mutable QList<QWindowsMimeConverter *> m_mimes;
+ mutable int m_internalMimeCount = 0;
+};
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug, const FORMATETC &);
+QDebug operator<<(QDebug d, IDataObject *);
+#endif
+
+QT_END_NAMESPACE
+
+#endif // QWINDOWSMIMEREGISTRY_H
diff --git a/src/plugins/platforms/windows/qwindowsmousehandler.cpp b/src/plugins/platforms/windows/qwindowsmousehandler.cpp
index b776efc942..9af9fba408 100644
--- a/src/plugins/platforms/windows/qwindowsmousehandler.cpp
+++ b/src/plugins/platforms/windows/qwindowsmousehandler.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qwindowsmousehandler.h"
#include "qwindowskeymapper.h"
@@ -47,12 +11,13 @@
#include <qpa/qwindowsysteminterface.h>
#include <QtGui/qguiapplication.h>
#include <QtGui/qscreen.h>
-#include <QtGui/qtouchdevice.h>
+#include <QtGui/qpointingdevice.h>
#include <QtGui/qwindow.h>
#include <QtGui/qcursor.h>
#include <QtCore/qdebug.h>
-#include <QtCore/qscopedpointer.h>
+
+#include <memory>
#include <windowsx.h>
@@ -117,27 +82,6 @@ static inline void compressMouseMove(MSG *msg)
}
}
-static inline QTouchDevice *createTouchDevice()
-{
- const int digitizers = GetSystemMetrics(SM_DIGITIZER);
- if (!(digitizers & (NID_INTEGRATED_TOUCH | NID_EXTERNAL_TOUCH)))
- return nullptr;
- const int tabletPc = GetSystemMetrics(SM_TABLETPC);
- const int maxTouchPoints = GetSystemMetrics(SM_MAXIMUMTOUCHES);
- qCDebug(lcQpaEvents) << "Digitizers:" << Qt::hex << Qt::showbase << (digitizers & ~NID_READY)
- << "Ready:" << (digitizers & NID_READY) << Qt::dec << Qt::noshowbase
- << "Tablet PC:" << tabletPc << "Max touch points:" << maxTouchPoints;
- auto *result = new QTouchDevice;
- result->setType(digitizers & NID_INTEGRATED_TOUCH
- ? QTouchDevice::TouchScreen : QTouchDevice::TouchPad);
- QTouchDevice::Capabilities capabilities = QTouchDevice::Position | QTouchDevice::Area | QTouchDevice::NormalizedPosition;
- if (result->type() == QTouchDevice::TouchPad)
- capabilities |= QTouchDevice::MouseEmulation;
- result->setCapabilities(capabilities);
- result->setMaximumTouchPoints(maxTouchPoints);
- return result;
-}
-
/*!
\class QWindowsMouseHandler
\brief Windows mouse handler
@@ -145,16 +89,16 @@ static inline QTouchDevice *createTouchDevice()
Dispatches mouse and touch events. Separate for code cleanliness.
\internal
- \ingroup qt-lighthouse-win
*/
QWindowsMouseHandler::QWindowsMouseHandler() = default;
-QTouchDevice *QWindowsMouseHandler::ensureTouchDevice()
+const QPointingDevice *QWindowsMouseHandler::primaryMouse()
{
- if (!m_touchDevice)
- m_touchDevice = createTouchDevice();
- return m_touchDevice;
+ static QPointer<const QPointingDevice> result;
+ if (!result)
+ result = QPointingDevice::primaryPointingDevice();
+ return result;
}
void QWindowsMouseHandler::clearEvents()
@@ -172,7 +116,7 @@ Qt::MouseButtons QWindowsMouseHandler::queryMouseButtons()
if (GetAsyncKeyState(VK_RBUTTON) < 0)
result |= mouseSwapped ? Qt::LeftButton : Qt::RightButton;
if (GetAsyncKeyState(VK_MBUTTON) < 0)
- result |= Qt::MidButton;
+ result |= Qt::MiddleButton;
if (GetAsyncKeyState(VK_XBUTTON1) < 0)
result |= Qt::XButton1;
if (GetAsyncKeyState(VK_XBUTTON2) < 0)
@@ -180,7 +124,7 @@ Qt::MouseButtons QWindowsMouseHandler::queryMouseButtons()
return result;
}
-static QPoint lastMouseMovePos;
+Q_CONSTINIT static QPoint lastMouseMovePos;
namespace {
struct MouseEvent {
@@ -216,11 +160,11 @@ static inline MouseEvent eventFromMsg(const MSG &msg)
case WM_LBUTTONDBLCLK: // Qt QPA does not handle double clicks, send as press
return {QEvent::MouseButtonPress, Qt::LeftButton};
case WM_MBUTTONDOWN:
- return {QEvent::MouseButtonPress, Qt::MidButton};
+ return {QEvent::MouseButtonPress, Qt::MiddleButton};
case WM_MBUTTONUP:
- return {QEvent::MouseButtonRelease, Qt::MidButton};
+ return {QEvent::MouseButtonRelease, Qt::MiddleButton};
case WM_MBUTTONDBLCLK:
- return {QEvent::MouseButtonPress, Qt::MidButton};
+ return {QEvent::MouseButtonPress, Qt::MiddleButton};
case WM_RBUTTONDOWN:
return {QEvent::MouseButtonPress, Qt::RightButton};
case WM_RBUTTONUP:
@@ -242,11 +186,11 @@ static inline MouseEvent eventFromMsg(const MSG &msg)
case WM_NCLBUTTONDBLCLK:
return {QEvent::NonClientAreaMouseButtonPress, Qt::LeftButton};
case WM_NCMBUTTONDOWN:
- return {QEvent::NonClientAreaMouseButtonPress, Qt::MidButton};
+ return {QEvent::NonClientAreaMouseButtonPress, Qt::MiddleButton};
case WM_NCMBUTTONUP:
- return {QEvent::NonClientAreaMouseButtonRelease, Qt::MidButton};
+ return {QEvent::NonClientAreaMouseButtonRelease, Qt::MiddleButton};
case WM_NCMBUTTONDBLCLK:
- return {QEvent::NonClientAreaMouseButtonPress, Qt::MidButton};
+ return {QEvent::NonClientAreaMouseButtonPress, Qt::MiddleButton};
case WM_NCRBUTTONDOWN:
return {QEvent::NonClientAreaMouseButtonPress, Qt::RightButton};
case WM_NCRBUTTONUP:
@@ -281,8 +225,13 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd,
globalPosition = winEventPosition;
clientPosition = QWindowsGeometryHint::mapFromGlobal(hwnd, globalPosition);
} else {
- clientPosition = winEventPosition;
globalPosition = QWindowsGeometryHint::mapToGlobal(hwnd, winEventPosition);
+ auto targetHwnd = hwnd;
+ if (auto *pw = window->handle())
+ targetHwnd = HWND(pw->winId());
+ clientPosition = targetHwnd == hwnd
+ ? winEventPosition
+ : QWindowsGeometryHint::mapFromGlobal(targetHwnd, globalPosition);
}
// Windows sends a mouse move with no buttons pressed to signal "Enter"
@@ -299,6 +248,8 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd,
Qt::MouseEventSource source = Qt::MouseEventNotSynthesized;
+ const QPointingDevice *device = primaryMouse();
+
// Check for events synthesized from touch. Lower byte is touch index, 0 means pen.
static const bool passSynthesizedMouseEvents =
!(QWindowsIntegration::instance()->options() & QWindowsIntegration::DontPassOsMouseEventsSynthesizedFromTouch);
@@ -310,12 +261,15 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd,
if ((extraInfo & signatureMask) == miWpSignature) {
if (extraInfo & 0x80) { // Bit 7 indicates touch event, else tablet pen.
source = Qt::MouseEventSynthesizedBySystem;
+ if (!m_touchDevice.isNull())
+ device = m_touchDevice.data();
if (!passSynthesizedMouseEvents)
return false;
}
}
- const Qt::KeyboardModifiers keyModifiers = QWindowsKeyMapper::queryKeyboardModifiers();
+ const auto *keyMapper = QWindowsContext::instance()->keyMapper();
+ const Qt::KeyboardModifiers keyModifiers = keyMapper->queryKeyboardModifiers();
const MouseEvent mouseEvent = eventFromMsg(msg);
Qt::MouseButtons buttons;
@@ -333,19 +287,16 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd,
if (m_lastEventType == QEvent::NonClientAreaMouseButtonPress
&& (mouseEvent.type == QEvent::NonClientAreaMouseMove || mouseEvent.type == QEvent::MouseMove)
&& (m_lastEventButton & buttons) == 0) {
- if (mouseEvent.type == QEvent::NonClientAreaMouseMove) {
- QWindowSystemInterface::handleFrameStrutMouseEvent(window, clientPosition, globalPosition, buttons, m_lastEventButton,
- QEvent::NonClientAreaMouseButtonRelease, keyModifiers, source);
- } else {
- QWindowSystemInterface::handleMouseEvent(window, clientPosition, globalPosition, buttons, m_lastEventButton,
- QEvent::MouseButtonRelease, keyModifiers, source);
- }
+ auto releaseType = mouseEvent.type == QEvent::NonClientAreaMouseMove ?
+ QEvent::NonClientAreaMouseButtonRelease : QEvent::MouseButtonRelease;
+ QWindowSystemInterface::handleMouseEvent(window, msg.time, device, clientPosition, globalPosition, buttons, m_lastEventButton,
+ releaseType, keyModifiers, source);
}
m_lastEventType = mouseEvent.type;
m_lastEventButton = mouseEvent.button;
if (mouseEvent.type >= QEvent::NonClientAreaMouseMove && mouseEvent.type <= QEvent::NonClientAreaMouseButtonDblClick) {
- QWindowSystemInterface::handleFrameStrutMouseEvent(window, clientPosition,
+ QWindowSystemInterface::handleMouseEvent(window, msg.time, device, clientPosition,
globalPosition, buttons,
mouseEvent.button, mouseEvent.type,
keyModifiers, source);
@@ -372,7 +323,7 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd,
auto *platformWindow = static_cast<QWindowsWindow *>(window->handle());
- // If the window was recently resized via mouse doubleclick on the frame or title bar,
+ // If the window was recently resized via mouse double-click on the frame or title bar,
// we don't get WM_LBUTTONDOWN or WM_LBUTTONDBLCLK for the second click,
// but we will get at least one WM_MOUSEMOVE with left button down and the WM_LBUTTONUP,
// which will result undesired mouse press and release events.
@@ -495,7 +446,7 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd,
}
if (!discardEvent && mouseEvent.type != QEvent::None) {
- QWindowSystemInterface::handleMouseEvent(window, winEventPosition, globalPosition, buttons,
+ QWindowSystemInterface::handleMouseEvent(window, msg.time, device, clientPosition, globalPosition, buttons,
mouseEvent.button, mouseEvent.type,
keyModifiers, source);
}
@@ -519,7 +470,7 @@ static bool isValidWheelReceiver(QWindow *candidate)
return false;
}
-static void redirectWheelEvent(QWindow *window, const QPoint &globalPos, int delta,
+static void redirectWheelEvent(QWindow *window, unsigned long timestamp, const QPoint &globalPos, int delta,
Qt::Orientation orientation, Qt::KeyboardModifiers mods)
{
// Redirect wheel event to one of the following, in order of preference:
@@ -540,6 +491,7 @@ static void redirectWheelEvent(QWindow *window, const QPoint &globalPos, int del
if (handleEvent) {
const QPoint point = (orientation == Qt::Vertical) ? QPoint(0, delta) : QPoint(delta, 0);
QWindowSystemInterface::handleWheelEvent(receiver,
+ timestamp,
QWindowsGeometryHint::mapFromGlobal(receiver, globalPos),
globalPos, QPoint(), point, mods);
}
@@ -568,7 +520,7 @@ bool QWindowsMouseHandler::translateMouseWheelEvent(QWindow *window, HWND,
delta = -delta;
const QPoint globalPos(GET_X_LPARAM(msg.lParam), GET_Y_LPARAM(msg.lParam));
- redirectWheelEvent(window, globalPos, delta, orientation, mods);
+ redirectWheelEvent(window, msg.time, globalPos, delta, orientation, mods);
return true;
}
@@ -599,7 +551,7 @@ bool QWindowsMouseHandler::translateScrollEvent(QWindow *window, HWND,
return false;
}
- redirectWheelEvent(window, QCursor::pos(), delta, Qt::Horizontal, Qt::NoModifier);
+ redirectWheelEvent(window, msg.time, QCursor::pos(), delta, Qt::Horizontal, Qt::NoModifier);
return true;
}
@@ -625,15 +577,14 @@ bool QWindowsMouseHandler::translateTouchEvent(QWindow *window, HWND,
const QRect screenGeometry = screen->geometry();
const int winTouchPointCount = int(msg.wParam);
- QScopedArrayPointer<TOUCHINPUT> winTouchInputs(new TOUCHINPUT[winTouchPointCount]);
- memset(winTouchInputs.data(), 0, sizeof(TOUCHINPUT) * size_t(winTouchPointCount));
+ const auto winTouchInputs = std::make_unique<TOUCHINPUT[]>(winTouchPointCount);
QTouchPointList touchPoints;
touchPoints.reserve(winTouchPointCount);
- Qt::TouchPointStates allStates;
+ QEventPoint::States allStates;
GetTouchInputInfo(reinterpret_cast<HTOUCHINPUT>(msg.lParam),
- UINT(msg.wParam), winTouchInputs.data(), sizeof(TOUCHINPUT));
+ UINT(msg.wParam), winTouchInputs.get(), sizeof(TOUCHINPUT));
for (int i = 0; i < winTouchPointCount; ++i) {
const TOUCHINPUT &winTouchInput = winTouchInputs[i];
int id = m_touchInputIDToTouchPointID.value(winTouchInput.dwID, -1);
@@ -657,15 +608,15 @@ bool QWindowsMouseHandler::translateTouchEvent(QWindow *window, HWND,
touchPoint.normalPosition = normalPosition;
if (winTouchInput.dwFlags & TOUCHEVENTF_DOWN) {
- touchPoint.state = Qt::TouchPointPressed;
+ touchPoint.state = QEventPoint::State::Pressed;
m_lastTouchPositions.insert(id, touchPoint.normalPosition);
} else if (winTouchInput.dwFlags & TOUCHEVENTF_UP) {
- touchPoint.state = Qt::TouchPointReleased;
+ touchPoint.state = QEventPoint::State::Released;
m_lastTouchPositions.remove(id);
} else {
touchPoint.state = (stationaryTouchPoint
- ? Qt::TouchPointStationary
- : Qt::TouchPointMoved);
+ ? QEventPoint::State::Stationary
+ : QEventPoint::State::Updated);
m_lastTouchPositions.insert(id, touchPoint.normalPosition);
}
@@ -677,13 +628,15 @@ bool QWindowsMouseHandler::translateTouchEvent(QWindow *window, HWND,
CloseTouchInputHandle(reinterpret_cast<HTOUCHINPUT>(msg.lParam));
// all touch points released, forget the ids we've seen, they may not be reused
- if (allStates == Qt::TouchPointReleased)
+ if (allStates == QEventPoint::State::Released)
m_touchInputIDToTouchPointID.clear();
+ const auto *keyMapper = QWindowsContext::instance()->keyMapper();
QWindowSystemInterface::handleTouchEvent(window,
- m_touchDevice,
+ msg.time,
+ m_touchDevice.data(),
touchPoints,
- QWindowsKeyMapper::queryKeyboardModifiers());
+ keyMapper->queryKeyboardModifiers());
return true;
}
@@ -691,9 +644,9 @@ bool QWindowsMouseHandler::translateGestureEvent(QWindow *window, HWND hwnd,
QtWindows::WindowsEventType,
MSG msg, LRESULT *)
{
- Q_UNUSED(window)
- Q_UNUSED(hwnd)
- Q_UNUSED(msg)
+ Q_UNUSED(window);
+ Q_UNUSED(hwnd);
+ Q_UNUSED(msg);
return false;
}
diff --git a/src/plugins/platforms/windows/qwindowsmousehandler.h b/src/plugins/platforms/windows/qwindowsmousehandler.h
index 1d3d1f4761..7fde349f58 100644
--- a/src/plugins/platforms/windows/qwindowsmousehandler.h
+++ b/src/plugins/platforms/windows/qwindowsmousehandler.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QWINDOWSMOUSEHANDLER_H
#define QWINDOWSMOUSEHANDLER_H
@@ -45,21 +9,24 @@
#include <QtCore/qpointer.h>
#include <QtCore/qhash.h>
+#include <QtCore/qsharedpointer.h>
#include <QtGui/qevent.h>
QT_BEGIN_NAMESPACE
class QWindow;
-class QTouchDevice;
+class QPointingDevice;
class QWindowsMouseHandler
{
Q_DISABLE_COPY_MOVE(QWindowsMouseHandler)
public:
+ using QPointingDevicePtr = QSharedPointer<QPointingDevice>;
+
QWindowsMouseHandler();
- QTouchDevice *touchDevice() const { return m_touchDevice; }
- QTouchDevice *ensureTouchDevice();
+ const QPointingDevicePtr &touchDevice() const { return m_touchDevice; }
+ void setTouchDevice(const QPointingDevicePtr &d) { m_touchDevice = d; }
bool translateMouseEvent(QWindow *widget, HWND hwnd,
QtWindows::WindowsEventType t, MSG msg,
@@ -82,6 +49,8 @@ public:
void clearWindowUnderMouse() { m_windowUnderMouse = nullptr; }
void clearEvents();
+ static const QPointingDevice *primaryMouse();
+
private:
inline bool translateMouseWheelEvent(QWindow *window, HWND hwnd,
MSG msg, LRESULT *result);
@@ -90,7 +59,7 @@ private:
QPointer<QWindow> m_trackedWindow;
QHash<DWORD, int> m_touchInputIDToTouchPointID;
QHash<int, QPointF> m_lastTouchPositions;
- QTouchDevice *m_touchDevice = nullptr;
+ QPointingDevicePtr m_touchDevice;
bool m_leftButtonDown = false;
QWindow *m_previousCaptureWindow = nullptr;
QEvent::Type m_lastEventType = QEvent::None;
diff --git a/src/plugins/platforms/windows/qwindowsnativeinterface.cpp b/src/plugins/platforms/windows/qwindowsnativeinterface.cpp
index 1195f15a59..e709123097 100644
--- a/src/plugins/platforms/windows/qwindowsnativeinterface.cpp
+++ b/src/plugins/platforms/windows/qwindowsnativeinterface.cpp
@@ -1,52 +1,13 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qwindowsnativeinterface.h"
-#include "qwindowsclipboard.h"
#include "qwindowswindow.h"
#include "qwindowsscreen.h"
#include "qwindowscontext.h"
#include "qwindowscursor.h"
#include "qwindowsopenglcontext.h"
-#include "qwindowsopengltester.h"
#include "qwindowsintegration.h"
-#include "qwindowsmime.h"
#include "qwindowstheme.h"
#include "qwin10helpers.h"
@@ -54,15 +15,11 @@
#include <QtGui/qopenglcontext.h>
#include <QtGui/qscreen.h>
#include <qpa/qplatformscreen.h>
-#include <QtFontDatabaseSupport/private/qwindowsfontdatabase_p.h>
QT_BEGIN_NAMESPACE
enum ResourceType {
RenderingContextType,
- EglContextType,
- EglDisplayType,
- EglConfigType,
HandleType,
GlHandleType,
GetDCType,
@@ -74,9 +31,6 @@ static int resourceType(const QByteArray &key)
{
static const char *names[] = { // match ResourceType
"renderingcontext",
- "eglcontext",
- "egldisplay",
- "eglconfig",
"handle",
"glhandle",
"getdc",
@@ -90,9 +44,6 @@ static int resourceType(const QByteArray &key)
return int(result - names);
}
-QWindowsWindowFunctions::WindowActivationBehavior QWindowsNativeInterface::m_windowActivationBehavior =
- QWindowsWindowFunctions::DefaultActivateWindow;
-
void *QWindowsNativeInterface::nativeResourceForWindow(const QByteArray &resource, QWindow *window)
{
if (!window || !window->handle()) {
@@ -154,41 +105,10 @@ void *QWindowsNativeInterface::nativeResourceForCursor(const QByteArray &resourc
}
#endif // !QT_NO_CURSOR
-static const char customMarginPropertyC[] = "WindowsCustomMargins";
-
-QVariant QWindowsNativeInterface::windowProperty(QPlatformWindow *window, const QString &name) const
-{
- auto *platformWindow = static_cast<QWindowsWindow *>(window);
- if (name == QLatin1String(customMarginPropertyC))
- return QVariant::fromValue(platformWindow->customMargins());
- return QVariant();
-}
-
-QVariant QWindowsNativeInterface::windowProperty(QPlatformWindow *window, const QString &name, const QVariant &defaultValue) const
-{
- const QVariant result = windowProperty(window, name);
- return result.isValid() ? result : defaultValue;
-}
-
-void QWindowsNativeInterface::setWindowProperty(QPlatformWindow *window, const QString &name, const QVariant &value)
-{
- auto *platformWindow = static_cast<QWindowsWindow *>(window);
- if (name == QLatin1String(customMarginPropertyC))
- platformWindow->setCustomMargins(qvariant_cast<QMargins>(value));
-}
-
-QVariantMap QWindowsNativeInterface::windowProperties(QPlatformWindow *window) const
-{
- QVariantMap result;
- const QString customMarginProperty = QLatin1String(customMarginPropertyC);
- result.insert(customMarginProperty, windowProperty(window, customMarginProperty));
- return result;
-}
-
void *QWindowsNativeInterface::nativeResourceForIntegration(const QByteArray &resource)
{
#ifdef QT_NO_OPENGL
- Q_UNUSED(resource)
+ Q_UNUSED(resource);
#else
if (resourceType(resource) == GlHandleType) {
if (const QWindowsStaticOpenGLContext *sc = QWindowsIntegration::staticOpenGLContext())
@@ -207,125 +127,9 @@ void *QWindowsNativeInterface::nativeResourceForContext(const QByteArray &resour
return nullptr;
}
- auto *glcontext = static_cast<QWindowsOpenGLContext *>(context->handle());
- switch (resourceType(resource)) {
- case RenderingContextType: // Fall through.
- case EglContextType:
- return glcontext->nativeContext();
- case EglDisplayType:
- return glcontext->nativeDisplay();
- case EglConfigType:
- return glcontext->nativeConfig();
- default:
- break;
- }
-
qWarning("%s: Invalid key '%s' requested.", __FUNCTION__, resource.constData());
return nullptr;
}
#endif // !QT_NO_OPENGL
-/*!
- \brief Creates a non-visible window handle for filtering messages.
-*/
-
-void *QWindowsNativeInterface::createMessageWindow(const QString &classNameTemplate,
- const QString &windowName,
- void *eventProc) const
-{
- QWindowsContext *ctx = QWindowsContext::instance();
- const HWND hwnd = ctx->createDummyWindow(classNameTemplate,
- (wchar_t*)windowName.utf16(),
- (WNDPROC)eventProc);
- return hwnd;
-}
-
-/*!
- \brief Registers a unique window class with a callback function based on \a classNameIn.
-*/
-
-QString QWindowsNativeInterface::registerWindowClass(const QString &classNameIn, void *eventProc) const
-{
- return QWindowsContext::instance()->registerWindowClass(classNameIn, (WNDPROC)eventProc);
-}
-
-bool QWindowsNativeInterface::asyncExpose() const
-{
- return QWindowsContext::instance()->asyncExpose();
-}
-
-void QWindowsNativeInterface::setAsyncExpose(bool value)
-{
- QWindowsContext::instance()->setAsyncExpose(value);
-}
-
-void QWindowsNativeInterface::registerWindowsMime(void *mimeIn)
-{
- QWindowsContext::instance()->mimeConverter().registerMime(reinterpret_cast<QWindowsMime *>(mimeIn));
-}
-
-void QWindowsNativeInterface::unregisterWindowsMime(void *mimeIn)
-{
- QWindowsContext::instance()->mimeConverter().unregisterMime(reinterpret_cast<QWindowsMime *>(mimeIn));
-}
-
-int QWindowsNativeInterface::registerMimeType(const QString &mimeType)
-{
- return QWindowsMime::registerMimeType(mimeType);
-}
-
-QFont QWindowsNativeInterface::logFontToQFont(const void *logFont, int verticalDpi)
-{
- return QWindowsFontDatabase::LOGFONT_to_QFont(*reinterpret_cast<const LOGFONT *>(logFont), verticalDpi);
-}
-
-bool QWindowsNativeInterface::isTabletMode()
-{
-#if QT_CONFIG(clipboard)
- if (const QWindowsClipboard *clipboard = QWindowsClipboard::instance())
- return qt_windowsIsTabletMode(clipboard->clipboardViewer());
-#endif
- return false;
-}
-
-QFunctionPointer QWindowsNativeInterface::platformFunction(const QByteArray &function) const
-{
- if (function == QWindowsWindowFunctions::setTouchWindowTouchTypeIdentifier())
- return QFunctionPointer(QWindowsWindow::setTouchWindowTouchTypeStatic);
- if (function == QWindowsWindowFunctions::setHasBorderInFullScreenIdentifier())
- return QFunctionPointer(QWindowsWindow::setHasBorderInFullScreenStatic);
- if (function == QWindowsWindowFunctions::setHasBorderInFullScreenDefaultIdentifier())
- return QFunctionPointer(QWindowsWindow::setHasBorderInFullScreenDefault);
- if (function == QWindowsWindowFunctions::setWindowActivationBehaviorIdentifier())
- return QFunctionPointer(QWindowsNativeInterface::setWindowActivationBehavior);
- if (function == QWindowsWindowFunctions::isTabletModeIdentifier())
- return QFunctionPointer(QWindowsNativeInterface::isTabletMode);
- return nullptr;
-}
-
-QVariant QWindowsNativeInterface::gpu() const
-{
- return GpuDescription::detect().toVariant();
-}
-
-QVariant QWindowsNativeInterface::gpuList() const
-{
- QVariantList result;
- const auto gpus = GpuDescription::detectAll();
- for (const auto &gpu : gpus)
- result.append(gpu.toVariant());
- return result;
-}
-
-bool QWindowsNativeInterface::isDarkMode() const
-{
- return QWindowsContext::isDarkMode();
-}
-
-// Dark mode support level 2 (style)
-bool QWindowsNativeInterface::isDarkModeStyle() const
-{
- return (QWindowsIntegration::instance()->options() & QWindowsIntegration::DarkModeStyle) != 0;
-}
-
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/windows/qwindowsnativeinterface.h b/src/plugins/platforms/windows/qwindowsnativeinterface.h
index 90ba7a44c9..a123c2b242 100644
--- a/src/plugins/platforms/windows/qwindowsnativeinterface.h
+++ b/src/plugins/platforms/windows/qwindowsnativeinterface.h
@@ -1,48 +1,11 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QWINDOWSNATIVEINTERFACE_H
#define QWINDOWSNATIVEINTERFACE_H
#include <QtGui/qfont.h>
#include <QtGui/qpa/qplatformnativeinterface.h>
-#include <QtPlatformHeaders/qwindowswindowfunctions.h>
QT_BEGIN_NAMESPACE
@@ -58,17 +21,11 @@ QT_BEGIN_NAMESPACE
\endlist
\internal
- \ingroup qt-lighthouse-win
*/
class QWindowsNativeInterface : public QPlatformNativeInterface
{
Q_OBJECT
- Q_PROPERTY(bool asyncExpose READ asyncExpose WRITE setAsyncExpose)
- Q_PROPERTY(bool darkMode READ isDarkMode STORED false NOTIFY darkModeChanged)
- Q_PROPERTY(bool darkModeStyle READ isDarkModeStyle STORED false)
- Q_PROPERTY(QVariant gpu READ gpu STORED false)
- Q_PROPERTY(QVariant gpuList READ gpuList STORED false)
public:
void *nativeResourceForIntegration(const QByteArray &resource) override;
@@ -80,45 +37,6 @@ public:
#ifndef QT_NO_CURSOR
void *nativeResourceForCursor(const QByteArray &resource, const QCursor &cursor) override;
#endif
- Q_INVOKABLE void *createMessageWindow(const QString &classNameTemplate,
- const QString &windowName,
- void *eventProc) const;
-
- Q_INVOKABLE QString registerWindowClass(const QString &classNameIn, void *eventProc) const;
-
- Q_INVOKABLE void registerWindowsMime(void *mimeIn);
- Q_INVOKABLE void unregisterWindowsMime(void *mime);
- Q_INVOKABLE int registerMimeType(const QString &mimeType);
- Q_INVOKABLE QFont logFontToQFont(const void *logFont, int verticalDpi);
-
- bool asyncExpose() const;
- void setAsyncExpose(bool value);
-
- bool isDarkMode() const;
- bool isDarkModeStyle() const;
-
- QVariant gpu() const;
- QVariant gpuList() const;
-
- QVariantMap windowProperties(QPlatformWindow *window) const override;
- QVariant windowProperty(QPlatformWindow *window, const QString &name) const override;
- QVariant windowProperty(QPlatformWindow *window, const QString &name, const QVariant &defaultValue) const override;
- void setWindowProperty(QPlatformWindow *window, const QString &name, const QVariant &value) override;
-
- static QWindowsWindowFunctions::WindowActivationBehavior windowActivationBehavior()
- { return QWindowsNativeInterface::m_windowActivationBehavior; }
- static void setWindowActivationBehavior(QWindowsWindowFunctions::WindowActivationBehavior b)
- { QWindowsNativeInterface::m_windowActivationBehavior = b; }
-
- static bool isTabletMode();
-
- QFunctionPointer platformFunction(const QByteArray &function) const override;
-
-Q_SIGNALS:
- void darkModeChanged(bool);
-
-private:
- static QWindowsWindowFunctions::WindowActivationBehavior m_windowActivationBehavior;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/windows/qwindowsole.cpp b/src/plugins/platforms/windows/qwindowsole.cpp
index f3450e2806..c01f716054 100644
--- a/src/plugins/platforms/windows/qwindowsole.cpp
+++ b/src/plugins/platforms/windows/qwindowsole.cpp
@@ -1,44 +1,8 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qwindowsole.h"
-#include "qwindowsmime.h"
+#include "qwindowsmimeregistry.h"
#include "qwindowscontext.h"
\
#include <QtGui/qevent.h>
@@ -70,7 +34,6 @@ QT_BEGIN_NAMESPACE
\endlist
\internal
- \ingroup qt-lighthouse-win
*/
QWindowsOleDataObject::QWindowsOleDataObject(QMimeData *mimeData) :
@@ -103,8 +66,8 @@ QWindowsOleDataObject::GetData(LPFORMATETC pformatetc, LPSTGMEDIUM pmedium)
HRESULT hr = ResultFromScode(DATA_E_FORMATETC);
if (data) {
- const QWindowsMimeConverter &mc = QWindowsContext::instance()->mimeConverter();
- if (QWindowsMime *converter = mc.converterFromMime(*pformatetc, data))
+ const QWindowsMimeRegistry &mc = QWindowsContext::instance()->mimeConverter();
+ if (auto converter = mc.converterFromMime(*pformatetc, data))
if (converter->convertFromMime(*pformatetc, data, pmedium))
hr = ResultFromScode(S_OK);
}
@@ -130,7 +93,7 @@ QWindowsOleDataObject::QueryGetData(LPFORMATETC pformatetc)
qCDebug(lcQpaMime) << __FUNCTION__;
if (data) {
- const QWindowsMimeConverter &mc = QWindowsContext::instance()->mimeConverter();
+ const QWindowsMimeRegistry &mc = QWindowsContext::instance()->mimeConverter();
hr = mc.converterFromMime(*pformatetc, data) ?
ResultFromScode(S_OK) : ResultFromScode(S_FALSE);
}
@@ -179,9 +142,9 @@ QWindowsOleDataObject::EnumFormatEtc(DWORD dwDirection, LPENUMFORMATETC FAR* ppe
SCODE sc = S_OK;
- QVector<FORMATETC> fmtetcs;
+ QList<FORMATETC> fmtetcs;
if (dwDirection == DATADIR_GET) {
- QWindowsMimeConverter &mc = QWindowsContext::instance()->mimeConverter();
+ QWindowsMimeRegistry &mc = QWindowsContext::instance()->mimeConverter();
fmtetcs = mc.allFormatsForMime(data);
} else {
FORMATETC formatetc;
@@ -228,10 +191,9 @@ QWindowsOleDataObject::EnumDAdvise(LPENUMSTATDATA FAR*)
\class QWindowsOleEnumFmtEtc
\brief Enumerates the FORMATETC structures supported by QWindowsOleDataObject.
\internal
- \ingroup qt-lighthouse-win
*/
-QWindowsOleEnumFmtEtc::QWindowsOleEnumFmtEtc(const QVector<FORMATETC> &fmtetcs)
+QWindowsOleEnumFmtEtc::QWindowsOleEnumFmtEtc(const QList<FORMATETC> &fmtetcs)
{
if (QWindowsContext::verbose > 1)
qCDebug(lcQpaMime) << __FUNCTION__ << fmtetcs;
@@ -248,7 +210,7 @@ QWindowsOleEnumFmtEtc::QWindowsOleEnumFmtEtc(const QVector<FORMATETC> &fmtetcs)
}
}
-QWindowsOleEnumFmtEtc::QWindowsOleEnumFmtEtc(const QVector<LPFORMATETC> &lpfmtetcs)
+QWindowsOleEnumFmtEtc::QWindowsOleEnumFmtEtc(const QList<LPFORMATETC> &lpfmtetcs)
{
if (QWindowsContext::verbose > 1)
qCDebug(lcQpaMime) << __FUNCTION__;
diff --git a/src/plugins/platforms/windows/qwindowsole.h b/src/plugins/platforms/windows/qwindowsole.h
index 6940657e88..016f9dd04c 100644
--- a/src/plugins/platforms/windows/qwindowsole.h
+++ b/src/plugins/platforms/windows/qwindowsole.h
@@ -1,51 +1,15 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QWINDOWSOLE_H
#define QWINDOWSOLE_H
-#include "qwindowscombase.h"
#include <QtCore/qt_windows.h>
+#include <QtCore/qlist.h>
#include <QtCore/qmap.h>
#include <QtCore/qpointer.h>
-#include <QtCore/qvector.h>
+#include <QtCore/private/qcomobject_p.h>
#include <objidl.h>
@@ -54,7 +18,7 @@ QT_BEGIN_NAMESPACE
class QMimeData;
class QWindow;
-class QWindowsOleDataObject : public QWindowsComBase<IDataObject>
+class QWindowsOleDataObject : public QComObject<IDataObject>
{
public:
explicit QWindowsOleDataObject(QMimeData *mimeData);
@@ -65,17 +29,17 @@ public:
DWORD reportedPerformedEffect() const;
// IDataObject methods
- STDMETHOD(GetData)(LPFORMATETC pformatetcIn, LPSTGMEDIUM pmedium);
- STDMETHOD(GetDataHere)(LPFORMATETC pformatetc, LPSTGMEDIUM pmedium);
- STDMETHOD(QueryGetData)(LPFORMATETC pformatetc);
- STDMETHOD(GetCanonicalFormatEtc)(LPFORMATETC pformatetc, LPFORMATETC pformatetcOut);
- STDMETHOD(SetData)(LPFORMATETC pformatetc, STGMEDIUM FAR * pmedium,
- BOOL fRelease);
- STDMETHOD(EnumFormatEtc)(DWORD dwDirection, LPENUMFORMATETC FAR* ppenumFormatEtc);
- STDMETHOD(DAdvise)(FORMATETC FAR* pFormatetc, DWORD advf,
- LPADVISESINK pAdvSink, DWORD FAR* pdwConnection);
- STDMETHOD(DUnadvise)(DWORD dwConnection);
- STDMETHOD(EnumDAdvise)(LPENUMSTATDATA FAR* ppenumAdvise);
+ STDMETHOD(GetData)(LPFORMATETC pformatetcIn, LPSTGMEDIUM pmedium) override;
+ STDMETHOD(GetDataHere)(LPFORMATETC pformatetc, LPSTGMEDIUM pmedium) override;
+ STDMETHOD(QueryGetData)(LPFORMATETC pformatetc) override;
+ STDMETHOD(GetCanonicalFormatEtc)(LPFORMATETC pformatetc, LPFORMATETC pformatetcOut) override;
+ STDMETHOD(SetData)(LPFORMATETC pformatetc, STGMEDIUM FAR *pmedium, BOOL fRelease) override;
+ STDMETHOD(EnumFormatEtc)(DWORD dwDirection, LPENUMFORMATETC FAR *ppenumFormatEtc) override;
+ STDMETHOD(DAdvise)
+ (FORMATETC FAR *pFormatetc, DWORD advf, LPADVISESINK pAdvSink,
+ DWORD FAR *pdwConnection) override;
+ STDMETHOD(DUnadvise)(DWORD dwConnection) override;
+ STDMETHOD(EnumDAdvise)(LPENUMSTATDATA FAR *ppenumAdvise) override;
private:
QPointer<QMimeData> data;
@@ -83,26 +47,26 @@ private:
DWORD performedEffect = DROPEFFECT_NONE;
};
-class QWindowsOleEnumFmtEtc : public QWindowsComBase<IEnumFORMATETC>
+class QWindowsOleEnumFmtEtc : public QComObject<IEnumFORMATETC>
{
public:
- explicit QWindowsOleEnumFmtEtc(const QVector<FORMATETC> &fmtetcs);
- explicit QWindowsOleEnumFmtEtc(const QVector<LPFORMATETC> &lpfmtetcs);
+ explicit QWindowsOleEnumFmtEtc(const QList<FORMATETC> &fmtetcs);
+ explicit QWindowsOleEnumFmtEtc(const QList<LPFORMATETC> &lpfmtetcs);
~QWindowsOleEnumFmtEtc() override;
bool isNull() const;
// IEnumFORMATETC methods
- STDMETHOD(Next)(ULONG celt, LPFORMATETC rgelt, ULONG FAR* pceltFetched);
- STDMETHOD(Skip)(ULONG celt);
- STDMETHOD(Reset)(void);
- STDMETHOD(Clone)(LPENUMFORMATETC FAR* newEnum);
+ STDMETHOD(Next)(ULONG celt, LPFORMATETC rgelt, ULONG FAR *pceltFetched) override;
+ STDMETHOD(Skip)(ULONG celt) override;
+ STDMETHOD(Reset)(void) override;
+ STDMETHOD(Clone)(LPENUMFORMATETC FAR *newEnum) override;
private:
bool copyFormatEtc(LPFORMATETC dest, const FORMATETC *src) const;
ULONG m_nIndex = 0;
- QVector<LPFORMATETC> m_lpfmtetcs;
+ QList<LPFORMATETC> m_lpfmtetcs;
bool m_isNull = false;
};
diff --git a/src/plugins/platforms/windows/qwindowsopenglcontext.h b/src/plugins/platforms/windows/qwindowsopenglcontext.h
index 1416a7e575..3fefe0ad91 100644
--- a/src/plugins/platforms/windows/qwindowsopenglcontext.h
+++ b/src/plugins/platforms/windows/qwindowsopenglcontext.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QWINDOWSOPENGLCONTEXT_H
#define QWINDOWSOPENGLCONTEXT_H
@@ -57,6 +21,7 @@ public:
virtual ~QWindowsStaticOpenGLContext() = default;
virtual QWindowsOpenGLContext *createContext(QOpenGLContext *context) = 0;
+ virtual QWindowsOpenGLContext *createContext(HGLRC context, HWND window) = 0;
virtual void *moduleHandle() const = 0;
virtual QOpenGLContext::OpenGLModuleType moduleType() const = 0;
virtual bool supportsThreadedOpenGL() const { return false; }
@@ -77,9 +42,6 @@ class QWindowsOpenGLContext : public QPlatformOpenGLContext
{
Q_DISABLE_COPY_MOVE(QWindowsOpenGLContext)
public:
- // Returns the native context handle (e.g. HGLRC for WGL, EGLContext for EGL).
- virtual void *nativeContext() const = 0;
-
// These should be implemented only for some winsys interfaces, for example EGL.
// For others, like WGL, they are not relevant.
virtual void *nativeDisplay() const { return nullptr; }
diff --git a/src/plugins/platforms/windows/qwindowsopengltester.cpp b/src/plugins/platforms/windows/qwindowsopengltester.cpp
index 72092a4481..6a790bcc1b 100644
--- a/src/plugins/platforms/windows/qwindowsopengltester.cpp
+++ b/src/plugins/platforms/windows/qwindowsopengltester.cpp
@@ -1,46 +1,11 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qwindowsopengltester.h"
#include "qwindowscontext.h"
#include <QtCore/qvariant.h>
+#include <QtCore/qmap.h>
#include <QtCore/qdebug.h>
#include <QtCore/qtextstream.h>
#include <QtCore/qcoreapplication.h>
@@ -49,13 +14,14 @@
#include <QtCore/qstandardpaths.h>
#include <QtCore/qlibraryinfo.h>
#include <QtCore/qhash.h>
+#include <private/qsystemlibrary_p.h>
+#include <QtGui/qtgui-config.h>
#ifndef QT_NO_OPENGL
#include <private/qopengl_p.h>
#endif
#include <QtCore/qt_windows.h>
-#include <private/qsystemlibrary_p.h>
#include <d3d9.h>
QT_BEGIN_NAMESPACE
@@ -69,7 +35,7 @@ static GpuDescription adapterIdentifierToGpuDescription(const D3DADAPTER_IDENTIF
result.deviceId = adapterIdentifier.DeviceId;
result.revision = adapterIdentifier.Revision;
result.subSysId = adapterIdentifier.SubSysId;
- QVector<int> version(4, 0);
+ QList<int> version(4, 0);
version[0] = HIWORD(adapterIdentifier.DriverVersion.HighPart); // Product
version[1] = LOWORD(adapterIdentifier.DriverVersion.HighPart); // Version
version[2] = HIWORD(adapterIdentifier.DriverVersion.LowPart); // Sub version
@@ -94,19 +60,12 @@ public:
bool retrieveAdapterIdentifier(UINT n, D3DADAPTER_IDENTIFIER9 *adapterIdentifier) const;
private:
- QSystemLibrary m_d3d9lib;
IDirect3D9 *m_direct3D9 = nullptr;
};
-QDirect3D9Handle::QDirect3D9Handle() :
- m_d3d9lib(QStringLiteral("d3d9"))
+QDirect3D9Handle::QDirect3D9Handle()
{
- using PtrDirect3DCreate9 = IDirect3D9 *(WINAPI *)(UINT);
-
- if (m_d3d9lib.load()) {
- if (auto direct3DCreate9 = (PtrDirect3DCreate9)m_d3d9lib.resolve("Direct3DCreate9"))
- m_direct3D9 = direct3DCreate9(D3D_SDK_VERSION);
- }
+ m_direct3D9 = Direct3DCreate9(D3D_SDK_VERSION);
}
QDirect3D9Handle::~QDirect3D9Handle()
@@ -169,9 +128,9 @@ GpuDescription GpuDescription::detect()
return result;
}
-QVector<GpuDescription> GpuDescription::detectAll()
+QList<GpuDescription> GpuDescription::detectAll()
{
- QVector<GpuDescription> result;
+ QList<GpuDescription> result;
QDirect3D9Handle direct3D9;
if (const UINT adapterCount = direct3D9.adapterCount()) {
for (UINT adp = 0; adp < adapterCount; ++adp) {
@@ -224,50 +183,30 @@ QVariant GpuDescription::toVariant() const
result.insert(QStringLiteral("deviceId"), QVariant(deviceId));
result.insert(QStringLiteral("subSysId"),QVariant(subSysId));
result.insert(QStringLiteral("revision"), QVariant(revision));
- result.insert(QStringLiteral("driver"), QVariant(QLatin1String(driverName)));
+ result.insert(QStringLiteral("driver"), QVariant(QLatin1StringView(driverName)));
result.insert(QStringLiteral("driverProduct"), QVariant(driverVersion.segmentAt(0)));
result.insert(QStringLiteral("driverVersion"), QVariant(driverVersion.segmentAt(1)));
result.insert(QStringLiteral("driverSubVersion"), QVariant(driverVersion.segmentAt(2)));
result.insert(QStringLiteral("driverBuild"), QVariant(driverVersion.segmentAt(3)));
result.insert(QStringLiteral("driverVersionString"), driverVersion.toString());
- result.insert(QStringLiteral("description"), QVariant(QLatin1String(description)));
+ result.insert(QStringLiteral("description"), QVariant(QLatin1StringView(description)));
result.insert(QStringLiteral("printable"), QVariant(toString()));
return result;
}
-QWindowsOpenGLTester::Renderer QWindowsOpenGLTester::requestedGlesRenderer()
-{
- const char platformVar[] = "QT_ANGLE_PLATFORM";
- if (qEnvironmentVariableIsSet(platformVar)) {
- const QByteArray anglePlatform = qgetenv(platformVar);
- if (anglePlatform == "d3d11")
- return QWindowsOpenGLTester::AngleRendererD3d11;
- if (anglePlatform == "d3d9")
- return QWindowsOpenGLTester::AngleRendererD3d9;
- if (anglePlatform == "warp")
- return QWindowsOpenGLTester::AngleRendererD3d11Warp;
- qCWarning(lcQpaGl) << "Invalid value set for " << platformVar << ": " << anglePlatform;
- }
- return QWindowsOpenGLTester::InvalidRenderer;
-}
-
QWindowsOpenGLTester::Renderer QWindowsOpenGLTester::requestedRenderer()
{
const char openGlVar[] = "QT_OPENGL";
- if (QCoreApplication::testAttribute(Qt::AA_UseOpenGLES)) {
- const Renderer glesRenderer = QWindowsOpenGLTester::requestedGlesRenderer();
- return glesRenderer != InvalidRenderer ? glesRenderer : Gles;
- }
+ if (QCoreApplication::testAttribute(Qt::AA_UseOpenGLES))
+ qWarning("Qt::AA_UseOpenGLES is no longer supported in Qt 6");
if (QCoreApplication::testAttribute(Qt::AA_UseDesktopOpenGL))
return QWindowsOpenGLTester::DesktopGl;
if (QCoreApplication::testAttribute(Qt::AA_UseSoftwareOpenGL))
return QWindowsOpenGLTester::SoftwareRasterizer;
if (qEnvironmentVariableIsSet(openGlVar)) {
const QByteArray requested = qgetenv(openGlVar);
- if (requested == "angle") {
- const Renderer glesRenderer = QWindowsOpenGLTester::requestedGlesRenderer();
- return glesRenderer != InvalidRenderer ? glesRenderer : Gles;
- }
+ if (requested == "angle")
+ qWarning("QT_OPENGL=angle is no longer supported in Qt 6");
if (requested == "desktop")
return QWindowsOpenGLTester::DesktopGl;
if (requested == "software")
@@ -283,7 +222,7 @@ static inline QString resolveBugListFile(const QString &fileName)
return fileName;
// Try QLibraryInfo::SettingsPath which is typically empty unless specified in qt.conf,
// then resolve via QStandardPaths::ConfigLocation.
- const QString settingsPath = QLibraryInfo::location(QLibraryInfo::SettingsPath);
+ const QString settingsPath = QLibraryInfo::path(QLibraryInfo::SettingsPath);
if (!settingsPath.isEmpty()) { // SettingsPath is empty unless specified in qt.conf.
const QFileInfo fi(settingsPath + u'/' + fileName);
if (fi.isFile())
@@ -301,9 +240,9 @@ QWindowsOpenGLTester::Renderers QWindowsOpenGLTester::detectSupportedRenderers(c
Renderer requested)
{
#if defined(QT_NO_OPENGL)
- Q_UNUSED(gpu)
- Q_UNUSED(requested)
- return 0;
+ Q_UNUSED(gpu);
+ Q_UNUSED(requested);
+ return {};
#else
QOpenGLConfig::Gpu qgpu = QOpenGLConfig::Gpu::fromDevice(gpu.vendorId, gpu.deviceId, gpu.driverVersion, gpu.description);
SupportedRenderersCache *srCache = supportedRenderersCache();
@@ -311,46 +250,29 @@ QWindowsOpenGLTester::Renderers QWindowsOpenGLTester::detectSupportedRenderers(c
if (it != srCache->cend())
return *it;
- QWindowsOpenGLTester::Renderers result(QWindowsOpenGLTester::AngleRendererD3d11
- | QWindowsOpenGLTester::AngleRendererD3d9
- | QWindowsOpenGLTester::AngleRendererD3d11Warp
- | QWindowsOpenGLTester::SoftwareRasterizer);
+ QWindowsOpenGLTester::Renderers result(QWindowsOpenGLTester::SoftwareRasterizer);
// Don't test for GL if explicitly requested or GLES only is requested
- if (requested == DesktopGl
- || ((requested & GlesMask) == 0 && testDesktopGL())) {
- result |= QWindowsOpenGLTester::DesktopGl;
- }
-
- const char bugListFileVar[] = "QT_OPENGL_BUGLIST";
- QString buglistFileName = QStringLiteral(":/qt-project.org/windows/openglblacklists/default.json");
-
- if (qEnvironmentVariableIsSet(bugListFileVar)) {
- const QString fileName = resolveBugListFile(QFile::decodeName(qgetenv(bugListFileVar)));
- if (!fileName.isEmpty())
- buglistFileName = fileName;
+ if (requested == DesktopGl || testDesktopGL())
+ result |= QWindowsOpenGLTester::DesktopGl;
+
+ QSet<QString> features; // empty by default -> nothing gets disabled
+ if (!qEnvironmentVariableIsSet("QT_NO_OPENGL_BUGLIST")) {
+ const char bugListFileVar[] = "QT_OPENGL_BUGLIST";
+ QString buglistFileName = QStringLiteral(":/qt-project.org/windows/openglblacklists/default.json");
+ if (qEnvironmentVariableIsSet(bugListFileVar)) {
+ const QString fileName = resolveBugListFile(QFile::decodeName(qgetenv(bugListFileVar)));
+ if (!fileName.isEmpty())
+ buglistFileName = fileName;
+ }
+ features = QOpenGLConfig::gpuFeatures(qgpu, buglistFileName);
}
-
- QSet<QString> features = QOpenGLConfig::gpuFeatures(qgpu, buglistFileName);
qCDebug(lcQpaGl) << "GPU features:" << features;
if (features.contains(QStringLiteral("disable_desktopgl"))) { // Qt-specific
qCDebug(lcQpaGl) << "Disabling Desktop GL: " << gpu;
result &= ~QWindowsOpenGLTester::DesktopGl;
}
- if (features.contains(QStringLiteral("disable_angle"))) { // Qt-specific keyword
- qCDebug(lcQpaGl) << "Disabling ANGLE: " << gpu;
- result &= ~QWindowsOpenGLTester::GlesMask;
- } else {
- if (features.contains(QStringLiteral("disable_d3d11"))) { // standard keyword
- qCDebug(lcQpaGl) << "Disabling D3D11: " << gpu;
- result &= ~QWindowsOpenGLTester::AngleRendererD3d11;
- }
- if (features.contains(QStringLiteral("disable_d3d9"))) { // Qt-specific
- qCDebug(lcQpaGl) << "Disabling D3D9: " << gpu;
- result &= ~QWindowsOpenGLTester::AngleRendererD3d9;
- }
- }
if (features.contains(QStringLiteral("disable_rotation"))) {
qCDebug(lcQpaGl) << "Disabling rotation: " << gpu;
result |= DisableRotationFlag;
@@ -395,7 +317,7 @@ bool QWindowsOpenGLTester::testDesktopGL()
// Test #1: Load opengl32.dll and try to resolve an OpenGL 2 function.
// This will typically fail on systems that do not have a real OpenGL driver.
- lib = LoadLibraryA("opengl32.dll");
+ lib = QSystemLibrary::load(L"opengl32");
if (lib) {
CreateContext = reinterpret_cast<CreateContextType>(
reinterpret_cast<QFunctionPointer>(::GetProcAddress(lib, "wglCreateContext")));
diff --git a/src/plugins/platforms/windows/qwindowsopengltester.h b/src/plugins/platforms/windows/qwindowsopengltester.h
index 9576dfbae0..abda0c2dc1 100644
--- a/src/plugins/platforms/windows/qwindowsopengltester.h
+++ b/src/plugins/platforms/windows/qwindowsopengltester.h
@@ -1,48 +1,12 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QWINDOWSOPENGLTESTER_H
#define QWINDOWSOPENGLTESTER_H
#include <QtCore/qbytearray.h>
#include <QtCore/qflags.h>
-#include <QtCore/qvector.h>
+#include <QtCore/qlist.h>
#include <QtCore/qversionnumber.h>
QT_BEGIN_NAMESPACE
@@ -53,7 +17,7 @@ class QVariant;
struct GpuDescription
{
static GpuDescription detect();
- static QVector<GpuDescription> detectAll();
+ static QList<GpuDescription> detectAll();
QString toString() const;
QVariant toVariant() const;
@@ -77,12 +41,6 @@ public:
enum Renderer {
InvalidRenderer = 0x0000,
DesktopGl = 0x0001,
- AngleRendererD3d11 = 0x0002,
- AngleRendererD3d9 = 0x0004,
- AngleRendererD3d11Warp = 0x0008, // "Windows Advanced Rasterization Platform"
- AngleBackendMask = AngleRendererD3d11 | AngleRendererD3d9 | AngleRendererD3d11Warp,
- Gles = 0x0010, // ANGLE/unspecified or Generic GLES for Windows CE.
- GlesMask = Gles | AngleBackendMask,
SoftwareRasterizer = 0x0020,
RendererMask = 0x00FF,
DisableRotationFlag = 0x0100,
@@ -90,7 +48,6 @@ public:
};
Q_DECLARE_FLAGS(Renderers, Renderer)
- static Renderer requestedGlesRenderer();
static Renderer requestedRenderer();
static QWindowsOpenGLTester::Renderers supportedRenderers(Renderer requested);
diff --git a/src/plugins/platforms/windows/qwindowspointerhandler.cpp b/src/plugins/platforms/windows/qwindowspointerhandler.cpp
index fba24d8696..71c7217671 100644
--- a/src/plugins/platforms/windows/qwindowspointerhandler.cpp
+++ b/src/plugins/platforms/windows/qwindowspointerhandler.cpp
@@ -1,50 +1,13 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 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$
-**
-****************************************************************************/
-
-#if defined(WINVER) && WINVER < 0x0603
-# undef WINVER
-#endif
-#if !defined(WINVER)
-# define WINVER 0x0603 // Enable pointer functions for MinGW
-#endif
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <QtCore/qt_windows.h>
#include "qwindowspointerhandler.h"
+#include "qwindowsmousehandler.h"
+#if QT_CONFIG(tabletevent)
+# include "qwindowstabletsupport.h"
+#endif
#include "qwindowskeymapper.h"
#include "qwindowscontext.h"
#include "qwindowswindow.h"
@@ -53,12 +16,11 @@
#include <QtGui/qguiapplication.h>
#include <QtGui/qscreen.h>
-#include <QtGui/qtouchdevice.h>
+#include <QtGui/qpointingdevice.h>
#include <QtGui/qwindow.h>
#include <QtGui/private/qguiapplication_p.h>
#include <QtCore/qvarlengtharray.h>
#include <QtCore/qloggingcategory.h>
-#include <QtCore/qoperatingsystemversion.h>
#include <QtCore/qqueue.h>
#include <algorithm>
@@ -75,12 +37,18 @@ enum {
QT_PT_TOUCHPAD = 5, // MinGW is missing PT_TOUCHPAD
};
+qint64 QWindowsPointerHandler::m_nextInputDeviceId = 1;
+
+QWindowsPointerHandler::~QWindowsPointerHandler()
+{
+}
+
bool QWindowsPointerHandler::translatePointerEvent(QWindow *window, HWND hwnd, QtWindows::WindowsEventType et, MSG msg, LRESULT *result)
{
*result = 0;
const quint32 pointerId = GET_POINTERID_WPARAM(msg.wParam);
- if (!QWindowsContext::user32dll.getPointerType(pointerId, &m_pointerType)) {
+ if (!GetPointerType(pointerId, &m_pointerType)) {
qWarning() << "GetPointerType() failed:" << qt_error_string();
return false;
}
@@ -94,12 +62,12 @@ bool QWindowsPointerHandler::translatePointerEvent(QWindow *window, HWND hwnd, Q
}
case QT_PT_TOUCH: {
quint32 pointerCount = 0;
- if (!QWindowsContext::user32dll.getPointerFrameTouchInfo(pointerId, &pointerCount, nullptr)) {
+ if (!GetPointerFrameTouchInfo(pointerId, &pointerCount, nullptr)) {
qWarning() << "GetPointerFrameTouchInfo() failed:" << qt_error_string();
return false;
}
QVarLengthArray<POINTER_TOUCH_INFO, 10> touchInfo(pointerCount);
- if (!QWindowsContext::user32dll.getPointerFrameTouchInfo(pointerId, &pointerCount, touchInfo.data())) {
+ if (!GetPointerFrameTouchInfo(pointerId, &pointerCount, touchInfo.data())) {
qWarning() << "GetPointerFrameTouchInfo() failed:" << qt_error_string();
return false;
}
@@ -112,10 +80,10 @@ bool QWindowsPointerHandler::translatePointerEvent(QWindow *window, HWND hwnd, Q
// dispatch any skipped frames if event compression is disabled by the app
if (historyCount > 1 && !QCoreApplication::testAttribute(Qt::AA_CompressHighFrequencyEvents)) {
touchInfo.resize(pointerCount * historyCount);
- if (!QWindowsContext::user32dll.getPointerFrameTouchInfoHistory(pointerId,
- &historyCount,
- &pointerCount,
- touchInfo.data())) {
+ if (!GetPointerFrameTouchInfoHistory(pointerId,
+ &historyCount,
+ &pointerCount,
+ touchInfo.data())) {
qWarning() << "GetPointerFrameTouchInfoHistory() failed:" << qt_error_string();
return false;
}
@@ -133,7 +101,7 @@ bool QWindowsPointerHandler::translatePointerEvent(QWindow *window, HWND hwnd, Q
}
case QT_PT_PEN: {
POINTER_PEN_INFO penInfo;
- if (!QWindowsContext::user32dll.getPointerPenInfo(pointerId, &penInfo)) {
+ if (!GetPointerPenInfo(pointerId, &penInfo)) {
qWarning() << "GetPointerPenInfo() failed:" << qt_error_string();
return false;
}
@@ -145,9 +113,7 @@ bool QWindowsPointerHandler::translatePointerEvent(QWindow *window, HWND hwnd, Q
|| !QCoreApplication::testAttribute(Qt::AA_CompressTabletEvents))) {
QVarLengthArray<POINTER_PEN_INFO, 10> penInfoHistory(historyCount);
- if (!QWindowsContext::user32dll.getPointerPenInfoHistory(pointerId,
- &historyCount,
- penInfoHistory.data())) {
+ if (!GetPointerPenInfoHistory(pointerId, &historyCount, penInfoHistory.data())) {
qWarning() << "GetPointerPenInfoHistory() failed:" << qt_error_string();
return false;
}
@@ -190,11 +156,11 @@ static inline MouseEvent eventFromMsg(const MSG &msg)
case WM_LBUTTONDBLCLK: // Qt QPA does not handle double clicks, send as press
return {QEvent::MouseButtonPress, Qt::LeftButton};
case WM_MBUTTONDOWN:
- return {QEvent::MouseButtonPress, Qt::MidButton};
+ return {QEvent::MouseButtonPress, Qt::MiddleButton};
case WM_MBUTTONUP:
- return {QEvent::MouseButtonRelease, Qt::MidButton};
+ return {QEvent::MouseButtonRelease, Qt::MiddleButton};
case WM_MBUTTONDBLCLK:
- return {QEvent::MouseButtonPress, Qt::MidButton};
+ return {QEvent::MouseButtonPress, Qt::MiddleButton};
case WM_RBUTTONDOWN:
return {QEvent::MouseButtonPress, Qt::RightButton};
case WM_RBUTTONUP:
@@ -216,11 +182,11 @@ static inline MouseEvent eventFromMsg(const MSG &msg)
case WM_NCLBUTTONDBLCLK:
return {QEvent::NonClientAreaMouseButtonPress, Qt::LeftButton};
case WM_NCMBUTTONDOWN:
- return {QEvent::NonClientAreaMouseButtonPress, Qt::MidButton};
+ return {QEvent::NonClientAreaMouseButtonPress, Qt::MiddleButton};
case WM_NCMBUTTONUP:
- return {QEvent::NonClientAreaMouseButtonRelease, Qt::MidButton};
+ return {QEvent::NonClientAreaMouseButtonRelease, Qt::MiddleButton};
case WM_NCMBUTTONDBLCLK:
- return {QEvent::NonClientAreaMouseButtonPress, Qt::MidButton};
+ return {QEvent::NonClientAreaMouseButtonPress, Qt::MiddleButton};
case WM_NCRBUTTONDOWN:
return {QEvent::NonClientAreaMouseButtonPress, Qt::RightButton};
case WM_NCRBUTTONUP:
@@ -258,7 +224,7 @@ static Qt::MouseButtons queryMouseButtons()
if (GetAsyncKeyState(VK_RBUTTON) < 0)
result |= mouseSwapped ? Qt::LeftButton : Qt::RightButton;
if (GetAsyncKeyState(VK_MBUTTON) < 0)
- result |= Qt::MidButton;
+ result |= Qt::MiddleButton;
if (GetAsyncKeyState(VK_XBUTTON1) < 0)
result |= Qt::XButton1;
if (GetAsyncKeyState(VK_XBUTTON2) < 0)
@@ -310,32 +276,38 @@ static bool isValidWheelReceiver(QWindow *candidate)
return false;
}
-static QTouchDevice *createTouchDevice()
-{
- const int digitizers = GetSystemMetrics(SM_DIGITIZER);
- if (!(digitizers & (NID_INTEGRATED_TOUCH | NID_EXTERNAL_TOUCH)))
- return nullptr;
- const int tabletPc = GetSystemMetrics(SM_TABLETPC);
- const int maxTouchPoints = GetSystemMetrics(SM_MAXIMUMTOUCHES);
- qCDebug(lcQpaEvents) << "Digitizers:" << Qt::hex << Qt::showbase << (digitizers & ~NID_READY)
- << "Ready:" << (digitizers & NID_READY) << Qt::dec << Qt::noshowbase
- << "Tablet PC:" << tabletPc << "Max touch points:" << maxTouchPoints;
- auto *result = new QTouchDevice;
- result->setType(digitizers & NID_INTEGRATED_TOUCH
- ? QTouchDevice::TouchScreen : QTouchDevice::TouchPad);
- QTouchDevice::Capabilities capabilities = QTouchDevice::Position | QTouchDevice::Area | QTouchDevice::NormalizedPosition;
- if (result->type() == QTouchDevice::TouchPad)
- capabilities |= QTouchDevice::MouseEmulation;
- result->setCapabilities(capabilities);
- result->setMaximumTouchPoints(maxTouchPoints);
- return result;
-}
-
-QTouchDevice *QWindowsPointerHandler::ensureTouchDevice()
+QWindowsPointerHandler::QPointingDevicePtr QWindowsPointerHandler::createTouchDevice(bool mouseEmulation)
{
- if (!m_touchDevice)
- m_touchDevice = createTouchDevice();
- return m_touchDevice;
+ const int digitizers = GetSystemMetrics(SM_DIGITIZER);
+ if (!(digitizers & (NID_INTEGRATED_TOUCH | NID_EXTERNAL_TOUCH)))
+ return nullptr;
+ const int tabletPc = GetSystemMetrics(SM_TABLETPC);
+ const int maxTouchPoints = GetSystemMetrics(SM_MAXIMUMTOUCHES);
+ const QPointingDevice::DeviceType type = (digitizers & NID_INTEGRATED_TOUCH)
+ ? QInputDevice::DeviceType::TouchScreen : QInputDevice::DeviceType::TouchPad;
+ QInputDevice::Capabilities capabilities = QInputDevice::Capability::Position
+ | QInputDevice::Capability::Area
+ | QInputDevice::Capability::NormalizedPosition;
+ if (type != QInputDevice::DeviceType::TouchScreen) {
+ capabilities.setFlag(QInputDevice::Capability::MouseEmulation);
+ capabilities.setFlag(QInputDevice::Capability::Scroll);
+ } else if (mouseEmulation) {
+ capabilities.setFlag(QInputDevice::Capability::MouseEmulation);
+ }
+
+ const int flags = digitizers & ~NID_READY;
+ qCDebug(lcQpaEvents) << "Digitizers:" << Qt::hex << Qt::showbase << flags
+ << "Ready:" << (digitizers & NID_READY) << Qt::dec << Qt::noshowbase
+ << "Tablet PC:" << tabletPc << "Max touch points:" << maxTouchPoints << "Capabilities:" << capabilities;
+
+ const int buttonCount = type == QInputDevice::DeviceType::TouchScreen ? 1 : 3;
+ // TODO: use system-provided name and device ID rather than empty-string and m_nextInputDeviceId
+ const qint64 systemId = m_nextInputDeviceId++ | (qint64(flags << 2));
+ auto d = new QPointingDevice(QString(), systemId, type,
+ QPointingDevice::PointerType::Finger,
+ capabilities, maxTouchPoints, buttonCount,
+ QString(), QPointingDeviceUniqueId::fromNumericId(systemId));
+ return QPointingDevicePtr(d);
}
void QWindowsPointerHandler::clearEvents()
@@ -447,6 +419,8 @@ bool QWindowsPointerHandler::translateTouchEvent(QWindow *window, HWND hwnd,
{
Q_UNUSED(hwnd);
+ auto *touchInfo = static_cast<POINTER_TOUCH_INFO *>(vTouchInfo);
+
if (et & QtWindows::NonClientEventFlag)
return false; // Let DefWindowProc() handle Non Client messages.
@@ -454,12 +428,24 @@ bool QWindowsPointerHandler::translateTouchEvent(QWindow *window, HWND hwnd,
return false;
if (msg.message == WM_POINTERCAPTURECHANGED) {
- QWindowSystemInterface::handleTouchCancelEvent(window, m_touchDevice,
- QWindowsKeyMapper::queryKeyboardModifiers());
- m_lastTouchPositions.clear();
+ const auto *keyMapper = QWindowsContext::instance()->keyMapper();
+ QWindowSystemInterface::handleTouchCancelEvent(window, msg.time, m_touchDevice.data(),
+ keyMapper->queryKeyboardModifiers());
+ m_lastTouchPoints.clear();
return true;
}
+ if (msg.message == WM_POINTERLEAVE) {
+ for (quint32 i = 0; i < count; ++i) {
+ const quint32 pointerId = touchInfo[i].pointerInfo.pointerId;
+ int id = m_touchInputIDToTouchPointID.value(pointerId, -1);
+ if (id != -1)
+ m_lastTouchPoints.remove(id);
+ }
+ // Send LeaveEvent to reset hover when the last finger leaves the touch screen (QTBUG-62912)
+ QWindowSystemInterface::handleEnterLeaveEvent(nullptr, window);
+ }
+
// Only handle down/up/update, ignore others like WM_POINTERENTER, WM_POINTERLEAVE, etc.
if (msg.message > WM_POINTERUP)
return false;
@@ -470,8 +456,6 @@ bool QWindowsPointerHandler::translateTouchEvent(QWindow *window, HWND hwnd,
if (!screen)
return false;
- auto *touchInfo = static_cast<POINTER_TOUCH_INFO *>(vTouchInfo);
-
const QRect screenGeometry = screen->geometry();
QList<QWindowSystemInterface::TouchPoint> touchPoints;
@@ -482,7 +466,8 @@ bool QWindowsPointerHandler::translateTouchEvent(QWindow *window, HWND hwnd,
<< " message=" << Qt::hex << msg.message
<< " count=" << Qt::dec << count;
- Qt::TouchPointStates allStates;
+ QEventPoint::States allStates;
+ QSet<int> inputIds;
for (quint32 i = 0; i < count; ++i) {
if (QWindowsContext::verbose > 1)
@@ -495,14 +480,17 @@ bool QWindowsPointerHandler::translateTouchEvent(QWindow *window, HWND hwnd,
const quint32 pointerId = touchInfo[i].pointerInfo.pointerId;
int id = m_touchInputIDToTouchPointID.value(pointerId, -1);
if (id == -1) {
+ // Start tracking after fingers touch the screen. Ignore bogus updates after touch is released.
+ if ((touchInfo[i].pointerInfo.pointerFlags & POINTER_FLAG_DOWN) == 0)
+ continue;
id = m_touchInputIDToTouchPointID.size();
m_touchInputIDToTouchPointID.insert(pointerId, id);
}
touchPoint.id = id;
touchPoint.pressure = (touchInfo[i].touchMask & TOUCH_MASK_PRESSURE) ?
touchInfo[i].pressure / 1024.0 : 1.0;
- if (m_lastTouchPositions.contains(touchPoint.id))
- touchPoint.normalPosition = m_lastTouchPositions.value(touchPoint.id);
+ if (m_lastTouchPoints.contains(touchPoint.id))
+ touchPoint.normalPosition = m_lastTouchPoints.value(touchPoint.id).normalPosition;
const QPointF screenPos = QPointF(touchInfo[i].pointerInfo.ptPixelLocation.x,
touchInfo[i].pointerInfo.ptPixelLocation.y);
@@ -517,32 +505,58 @@ bool QWindowsPointerHandler::translateTouchEvent(QWindow *window, HWND hwnd,
touchPoint.normalPosition = normalPosition;
if (touchInfo[i].pointerInfo.pointerFlags & POINTER_FLAG_DOWN) {
- touchPoint.state = Qt::TouchPointPressed;
- m_lastTouchPositions.insert(touchPoint.id, touchPoint.normalPosition);
+ touchPoint.state = QEventPoint::State::Pressed;
+ m_lastTouchPoints.insert(touchPoint.id, touchPoint);
} else if (touchInfo[i].pointerInfo.pointerFlags & POINTER_FLAG_UP) {
- touchPoint.state = Qt::TouchPointReleased;
- m_lastTouchPositions.remove(touchPoint.id);
+ touchPoint.state = QEventPoint::State::Released;
+ m_lastTouchPoints.remove(touchPoint.id);
} else {
- touchPoint.state = stationaryTouchPoint ? Qt::TouchPointStationary : Qt::TouchPointMoved;
- m_lastTouchPositions.insert(touchPoint.id, touchPoint.normalPosition);
+ touchPoint.state = stationaryTouchPoint ? QEventPoint::State::Stationary : QEventPoint::State::Updated;
+ m_lastTouchPoints.insert(touchPoint.id, touchPoint);
}
allStates |= touchPoint.state;
touchPoints.append(touchPoint);
+ inputIds.insert(touchPoint.id);
// Avoid getting repeated messages for this frame if there are multiple pointerIds
- QWindowsContext::user32dll.skipPointerFrameMessages(touchInfo[i].pointerInfo.pointerId);
+ SkipPointerFrameMessages(touchInfo[i].pointerInfo.pointerId);
+ }
+
+ // Some devices send touches for each finger in a different message/frame, instead of consolidating
+ // them in the same frame as we were expecting. We account for missing unreleased touches here.
+ for (auto tp : std::as_const(m_lastTouchPoints)) {
+ if (!inputIds.contains(tp.id)) {
+ tp.state = QEventPoint::State::Stationary;
+ allStates |= tp.state;
+ touchPoints.append(tp);
+ }
}
+ if (touchPoints.count() == 0)
+ return false;
+
// all touch points released, forget the ids we've seen.
- if (allStates == Qt::TouchPointReleased)
+ if (allStates == QEventPoint::State::Released)
m_touchInputIDToTouchPointID.clear();
- QWindowSystemInterface::handleTouchEvent(window, m_touchDevice, touchPoints,
- QWindowsKeyMapper::queryKeyboardModifiers());
+ const auto *keyMapper = QWindowsContext::instance()->keyMapper();
+ QWindowSystemInterface::handleTouchEvent(window, msg.time, m_touchDevice.data(), touchPoints,
+ keyMapper->queryKeyboardModifiers());
return false; // Allow mouse messages to be generated.
}
+#if QT_CONFIG(tabletevent)
+QWindowsPointerHandler::QPointingDevicePtr QWindowsPointerHandler::findTabletDevice(QPointingDevice::PointerType pointerType) const
+{
+ for (const auto &d : m_tabletDevices) {
+ if (d->pointerType() == pointerType)
+ return d;
+ }
+ return {};
+}
+#endif
+
bool QWindowsPointerHandler::translatePenEvent(QWindow *window, HWND hwnd, QtWindows::WindowsEventType et,
MSG msg, PVOID vPenInfo)
{
@@ -553,32 +567,35 @@ bool QWindowsPointerHandler::translatePenEvent(QWindow *window, HWND hwnd, QtWin
auto *penInfo = static_cast<POINTER_PEN_INFO *>(vPenInfo);
RECT pRect, dRect;
- if (!QWindowsContext::user32dll.getPointerDeviceRects(penInfo->pointerInfo.sourceDevice, &pRect, &dRect))
+ if (!GetPointerDeviceRects(penInfo->pointerInfo.sourceDevice, &pRect, &dRect))
return false;
- const auto sourceDevice = (qint64)penInfo->pointerInfo.sourceDevice;
+ const auto systemId = (qint64)penInfo->pointerInfo.sourceDevice;
const QPoint globalPos = QPoint(penInfo->pointerInfo.ptPixelLocation.x, penInfo->pointerInfo.ptPixelLocation.y);
const QPoint localPos = QWindowsGeometryHint::mapFromGlobal(hwnd, globalPos);
const QPointF hiResGlobalPos = QPointF(dRect.left + qreal(penInfo->pointerInfo.ptHimetricLocation.x - pRect.left)
/ (pRect.right - pRect.left) * (dRect.right - dRect.left),
dRect.top + qreal(penInfo->pointerInfo.ptHimetricLocation.y - pRect.top)
/ (pRect.bottom - pRect.top) * (dRect.bottom - dRect.top));
- const qreal pressure = (penInfo->penMask & PEN_MASK_PRESSURE) ? qreal(penInfo->pressure) / 1024.0 : 0.5;
- const qreal rotation = (penInfo->penMask & PEN_MASK_ROTATION) ? qreal(penInfo->rotation) : 0.0;
+ const bool hasPressure = (penInfo->penMask & PEN_MASK_PRESSURE) != 0;
+ const bool hasRotation = (penInfo->penMask & PEN_MASK_ROTATION) != 0;
+ const qreal pressure = hasPressure ? qreal(penInfo->pressure) / 1024.0 : 0.5;
+ const qreal rotation = hasRotation ? qreal(penInfo->rotation) : 0.0;
const qreal tangentialPressure = 0.0;
- const int xTilt = (penInfo->penMask & PEN_MASK_TILT_X) ? penInfo->tiltX : 0;
- const int yTilt = (penInfo->penMask & PEN_MASK_TILT_Y) ? penInfo->tiltY : 0;
+ const bool hasTiltX = (penInfo->penMask & PEN_MASK_TILT_X) != 0;
+ const bool hasTiltY = (penInfo->penMask & PEN_MASK_TILT_Y) != 0;
+ const int xTilt = hasTiltX ? penInfo->tiltX : 0;
+ const int yTilt = hasTiltY ? penInfo->tiltY : 0;
const int z = 0;
if (QWindowsContext::verbose > 1)
qCDebug(lcQpaEvents).noquote().nospace() << Qt::showbase
- << __FUNCTION__ << " sourceDevice=" << sourceDevice
+ << __FUNCTION__ << " systemId=" << systemId
<< " globalPos=" << globalPos << " localPos=" << localPos << " hiResGlobalPos=" << hiResGlobalPos
<< " message=" << Qt::hex << msg.message
<< " flags=" << Qt::hex << penInfo->pointerInfo.pointerFlags;
- const QTabletEvent::TabletDevice device = QTabletEvent::Stylus;
- QTabletEvent::PointerType type;
+ QPointingDevice::PointerType type;
// Since it may be the middle button, so if the checks fail then it should
// be set to Middle if it was used.
Qt::MouseButtons mouseButtons = queryMouseButtons();
@@ -588,16 +605,41 @@ bool QWindowsPointerHandler::translatePenEvent(QWindow *window, HWND hwnd, QtWin
mouseButtons = Qt::LeftButton;
if (penInfo->penFlags & (PEN_FLAG_ERASER | PEN_FLAG_INVERTED)) {
- type = QTabletEvent::Eraser;
+ type = QPointingDevice::PointerType::Eraser;
} else {
- type = QTabletEvent::Pen;
+ type = QPointingDevice::PointerType::Pen;
if (pointerInContact && penInfo->penFlags & PEN_FLAG_BARREL)
mouseButtons = Qt::RightButton; // Either left or right, not both
}
+ auto device = findTabletDevice(type);
+ if (device.isNull()) {
+ QInputDevice::Capabilities caps(QInputDevice::Capability::Position
+ | QInputDevice::Capability::MouseEmulation
+ | QInputDevice::Capability::Hover);
+ if (hasPressure)
+ caps |= QInputDevice::Capability::Pressure;
+ if (hasRotation)
+ caps |= QInputDevice::Capability::Rotation;
+ if (hasTiltX)
+ caps |= QInputDevice::Capability::XTilt;
+ if (hasTiltY)
+ caps |= QInputDevice::Capability::YTilt;
+ const qint64 uniqueId = systemId | (qint64(type) << 32L);
+ device.reset(new QPointingDevice(QStringLiteral("wmpointer"),
+ systemId, QInputDevice::DeviceType::Stylus,
+ type, caps, 1, 3, QString(),
+ QPointingDeviceUniqueId::fromNumericId(uniqueId)));
+ QWindowSystemInterface::registerInputDevice(device.data());
+ m_tabletDevices.append(device);
+ }
+
+ const auto uniqueId = device->uniqueId().numericId();
+ m_activeTabletDevice = device;
+
switch (msg.message) {
case WM_POINTERENTER: {
- QWindowSystemInterface::handleTabletEnterProximityEvent(device, type, sourceDevice);
+ QWindowSystemInterface::handleTabletEnterLeaveProximityEvent(window, msg.time, device.data(), true);
m_windowUnderPointer = window;
// The local coordinates may fall outside the window.
// Wait until the next update to send the enter event.
@@ -610,12 +652,12 @@ bool QWindowsPointerHandler::translatePenEvent(QWindow *window, HWND hwnd, QtWin
m_windowUnderPointer = nullptr;
m_currentWindow = nullptr;
}
- QWindowSystemInterface::handleTabletLeaveProximityEvent(device, type, sourceDevice);
+ QWindowSystemInterface::handleTabletEnterLeaveProximityEvent(window, msg.time, device.data(), false);
break;
case WM_POINTERDOWN:
case WM_POINTERUP:
case WM_POINTERUPDATE: {
- QWindow *target = QGuiApplicationPrivate::tabletDevicePoint(sourceDevice).target; // Pass to window that grabbed it.
+ QWindow *target = QGuiApplicationPrivate::tabletDevicePoint(uniqueId).target; // Pass to window that grabbed it.
if (!target && m_windowUnderPointer)
target = m_windowUnderPointer;
if (!target)
@@ -633,11 +675,13 @@ bool QWindowsPointerHandler::translatePenEvent(QWindow *window, HWND hwnd, QtWin
wumPlatformWindow->applyCursor();
}
}
- const Qt::KeyboardModifiers keyModifiers = QWindowsKeyMapper::queryKeyboardModifiers();
+ const auto *keyMapper = QWindowsContext::instance()->keyMapper();
+ const Qt::KeyboardModifiers keyModifiers = keyMapper->queryKeyboardModifiers();
- QWindowSystemInterface::handleTabletEvent(target, localPos, hiResGlobalPos, device, type, mouseButtons,
- pressure, xTilt, yTilt, tangentialPressure, rotation, z,
- sourceDevice, keyModifiers);
+ QWindowSystemInterface::handleTabletEvent(target, msg.time, device.data(),
+ localPos, hiResGlobalPos, mouseButtons,
+ pressure, xTilt, yTilt, tangentialPressure,
+ rotation, z, keyModifiers);
return false; // Allow mouse messages to be generated.
}
}
@@ -685,7 +729,7 @@ bool QWindowsPointerHandler::translateMouseWheelEvent(QWindow *window,
QPoint localPos = QWindowsGeometryHint::mapFromGlobal(receiver, globalPos);
- QWindowSystemInterface::handleWheelEvent(receiver, localPos, globalPos, QPoint(), angleDelta, keyModifiers);
+ QWindowSystemInterface::handleWheelEvent(receiver, msg.time, localPos, globalPos, QPoint(), angleDelta, keyModifiers);
return true;
}
@@ -698,25 +742,31 @@ bool QWindowsPointerHandler::translateMouseEvent(QWindow *window,
{
*result = 0;
- QPoint eventPos(GET_X_LPARAM(msg.lParam), GET_Y_LPARAM(msg.lParam));
- if ((et & QtWindows::NonClientEventFlag) == 0 && QWindowsBaseWindow::isRtlLayout(hwnd)) {
- RECT clientArea;
- GetClientRect(hwnd, &clientArea);
- eventPos.setX(clientArea.right - eventPos.x());
- }
-
QPoint localPos;
QPoint globalPos;
+ QPoint eventPos(GET_X_LPARAM(msg.lParam), GET_Y_LPARAM(msg.lParam));
if ((et == QtWindows::MouseWheelEvent) || (et & QtWindows::NonClientEventFlag)) {
globalPos = eventPos;
localPos = QWindowsGeometryHint::mapFromGlobal(hwnd, eventPos);
} else {
- localPos = eventPos;
+ if (QWindowsBaseWindow::isRtlLayout(hwnd)) {
+ RECT clientArea;
+ GetClientRect(hwnd, &clientArea);
+ eventPos.setX(clientArea.right - eventPos.x());
+ }
+
globalPos = QWindowsGeometryHint::mapToGlobal(hwnd, eventPos);
+ auto targetHwnd = hwnd;
+ if (auto *pw = window->handle())
+ targetHwnd = HWND(pw->winId());
+ localPos = targetHwnd == hwnd
+ ? eventPos
+ : QWindowsGeometryHint::mapFromGlobal(targetHwnd, globalPos);
}
- const Qt::KeyboardModifiers keyModifiers = QWindowsKeyMapper::queryKeyboardModifiers();
+ const auto *keyMapper = QWindowsContext::instance()->keyMapper();
+ const Qt::KeyboardModifiers keyModifiers = keyMapper->queryKeyboardModifiers();
QWindow *currentWindowUnderPointer = getWindowUnderPointer(window, globalPos);
if (et == QtWindows::MouseWheelEvent)
@@ -728,21 +778,35 @@ bool QWindowsPointerHandler::translateMouseEvent(QWindow *window,
// X11 and macOS.
bool discardEvent = false;
if (msg.message == WM_MOUSEMOVE) {
- static QPoint lastMouseMovePos;
+ Q_CONSTINIT static QPoint lastMouseMovePos;
if (msg.wParam == 0 && (m_windowUnderPointer.isNull() || globalPos == lastMouseMovePos))
discardEvent = true;
lastMouseMovePos = globalPos;
}
Qt::MouseEventSource source = Qt::MouseEventNotSynthesized;
+ const QPointingDevice *device = QWindowsMouseHandler::primaryMouse();
+
// Following the logic of the old mouse handler, only events synthesized
// for touch screen are marked as such. On some systems, using the bit 7 of
// the extra msg info for checking if synthesized for touch does not work,
// so we use the pointer type of the last pointer message.
- if (isMouseEventSynthesizedFromPenOrTouch() && m_pointerType == QT_PT_TOUCH) {
- if (QWindowsIntegration::instance()->options() & QWindowsIntegration::DontPassOsMouseEventsSynthesizedFromTouch)
+ if (isMouseEventSynthesizedFromPenOrTouch()) {
+ switch (m_pointerType) {
+ case QT_PT_TOUCH:
+ if (QWindowsIntegration::instance()->options() & QWindowsIntegration::DontPassOsMouseEventsSynthesizedFromTouch)
+ return false;
+ source = Qt::MouseEventSynthesizedBySystem;
+ if (!m_touchDevice.isNull())
+ device = m_touchDevice.data();
+ break;
+ case QT_PT_PEN:
+#if QT_CONFIG(tabletevent)
+ qCDebug(lcQpaTablet) << "ignoring synth-mouse event for tablet event from" << device;
return false;
- source = Qt::MouseEventSynthesizedBySystem;
+#endif
+ break;
+ }
}
const MouseEvent mouseEvent = eventFromMsg(msg);
@@ -762,19 +826,16 @@ bool QWindowsPointerHandler::translateMouseEvent(QWindow *window,
if (m_lastEventType == QEvent::NonClientAreaMouseButtonPress
&& (mouseEvent.type == QEvent::NonClientAreaMouseMove || mouseEvent.type == QEvent::MouseMove)
&& (m_lastEventButton & mouseButtons) == 0) {
- if (mouseEvent.type == QEvent::NonClientAreaMouseMove) {
- QWindowSystemInterface::handleFrameStrutMouseEvent(window, localPos, globalPos, mouseButtons, m_lastEventButton,
- QEvent::NonClientAreaMouseButtonRelease, keyModifiers, source);
- } else {
- QWindowSystemInterface::handleMouseEvent(window, localPos, globalPos, mouseButtons, m_lastEventButton,
- QEvent::MouseButtonRelease, keyModifiers, source);
- }
+ auto releaseType = mouseEvent.type == QEvent::NonClientAreaMouseMove ?
+ QEvent::NonClientAreaMouseButtonRelease : QEvent::MouseButtonRelease;
+ QWindowSystemInterface::handleMouseEvent(window, msg.time, device, localPos, globalPos, mouseButtons, m_lastEventButton,
+ releaseType, keyModifiers, source);
}
m_lastEventType = mouseEvent.type;
m_lastEventButton = mouseEvent.button;
if (mouseEvent.type >= QEvent::NonClientAreaMouseMove && mouseEvent.type <= QEvent::NonClientAreaMouseButtonDblClick) {
- QWindowSystemInterface::handleFrameStrutMouseEvent(window, localPos, globalPos, mouseButtons,
+ QWindowSystemInterface::handleMouseEvent(window, msg.time, device, localPos, globalPos, mouseButtons,
mouseEvent.button, mouseEvent.type, keyModifiers, source);
return false; // Allow further event processing
}
@@ -794,7 +855,7 @@ bool QWindowsPointerHandler::translateMouseEvent(QWindow *window,
handleEnterLeave(window, currentWindowUnderPointer, globalPos);
if (!discardEvent && mouseEvent.type != QEvent::None) {
- QWindowSystemInterface::handleMouseEvent(window, localPos, globalPos, mouseButtons,
+ QWindowSystemInterface::handleMouseEvent(window, msg.time, device, localPos, globalPos, mouseButtons,
mouseEvent.button, mouseEvent.type, keyModifiers, source);
}
diff --git a/src/plugins/platforms/windows/qwindowspointerhandler.h b/src/plugins/platforms/windows/qwindowspointerhandler.h
index 8874db27e3..b64a8c146a 100644
--- a/src/plugins/platforms/windows/qwindowspointerhandler.h
+++ b/src/plugins/platforms/windows/qwindowspointerhandler.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 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$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QWINDOWSPOINTERHANDLER_H
#define QWINDOWSPOINTERHANDLER_H
@@ -45,23 +9,31 @@
#include <QtCore/qpointer.h>
#include <QtCore/qscopedpointer.h>
+#include <QtCore/qsharedpointer.h>
#include <QtCore/qhash.h>
#include <QtGui/qevent.h>
+#include <qpa/qwindowsysteminterface.h>
QT_BEGIN_NAMESPACE
class QWindow;
-class QTouchDevice;
+class QPointingDevice;
class QWindowsPointerHandler
{
Q_DISABLE_COPY_MOVE(QWindowsPointerHandler)
public:
+ using QPointingDevicePtr = QSharedPointer<QPointingDevice>;
+
QWindowsPointerHandler() = default;
+ ~QWindowsPointerHandler();
bool translatePointerEvent(QWindow *window, HWND hwnd, QtWindows::WindowsEventType et, MSG msg, LRESULT *result);
bool translateMouseEvent(QWindow *window, HWND hwnd, QtWindows::WindowsEventType et, MSG msg, LRESULT *result);
- QTouchDevice *touchDevice() const { return m_touchDevice; }
- QTouchDevice *ensureTouchDevice();
+
+ const QPointingDevicePtr &touchDevice() const { return m_touchDevice; }
+ void setTouchDevice(const QPointingDevicePtr &d) { m_touchDevice = d; }
+ static QPointingDevicePtr createTouchDevice(bool mouseEmulation);
+
QWindow *windowUnderMouse() const { return m_windowUnderPointer.data(); }
void clearWindowUnderMouse() { m_windowUnderPointer = nullptr; }
void clearEvents();
@@ -72,9 +44,16 @@ private:
bool translateMouseWheelEvent(QWindow *window, QWindow *currentWindowUnderPointer, MSG msg, QPoint globalPos, Qt::KeyboardModifiers keyModifiers);
void handleCaptureRelease(QWindow *window, QWindow *currentWindowUnderPointer, HWND hwnd, QEvent::Type eventType, Qt::MouseButtons mouseButtons);
void handleEnterLeave(QWindow *window, QWindow *currentWindowUnderPointer, QPoint globalPos);
+#if QT_CONFIG(tabletevent)
+ QPointingDevicePtr findTabletDevice(QPointingDevice::PointerType pointerType) const;
+#endif
- QTouchDevice *m_touchDevice = nullptr;
- QHash<int, QPointF> m_lastTouchPositions;
+ QPointingDevicePtr m_touchDevice;
+#if QT_CONFIG(tabletevent)
+ QList<QPointingDevicePtr> m_tabletDevices;
+ QPointingDevicePtr m_activeTabletDevice;
+#endif
+ QHash<int, QWindowSystemInterface::TouchPoint> m_lastTouchPoints;
QHash<DWORD, int> m_touchInputIDToTouchPointID;
QPointer<QWindow> m_windowUnderPointer;
QPointer<QWindow> m_currentWindow;
@@ -83,6 +62,7 @@ private:
QEvent::Type m_lastEventType = QEvent::None;
Qt::MouseButton m_lastEventButton = Qt::NoButton;
DWORD m_pointerType = 0;
+ static qint64 m_nextInputDeviceId; // workaround until we know how to get system device IDs
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/windows/qwindowsscreen.cpp b/src/plugins/platforms/windows/qwindowsscreen.cpp
index c7a0c2e62e..a50f9fd4b0 100644
--- a/src/plugins/platforms/windows/qwindowsscreen.cpp
+++ b/src/plugins/platforms/windows/qwindowsscreen.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qwindowsscreen.h"
#include "qwindowscontext.h"
@@ -50,13 +14,28 @@
#include <QtGui/qpixmap.h>
#include <QtGui/qguiapplication.h>
#include <qpa/qwindowsysteminterface.h>
+#include <QtCore/private/qsystemerror_p.h>
+#include <QtGui/private/qedidparser_p.h>
#include <private/qhighdpiscaling_p.h>
+#include <private/qwindowsfontdatabasebase_p.h>
+#include <private/qpixmap_win_p.h>
+#include <private/quniquehandle_p.h>
+
#include <QtGui/qscreen.h>
#include <QtCore/qdebug.h>
+#include <memory>
+#include <type_traits>
+
+#include <cfgmgr32.h>
+#include <setupapi.h>
+#include <shellscalingapi.h>
+
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
static inline QDpi deviceDPI(HDC hdc)
{
return QDpi(GetDeviceCaps(hdc, LOGPIXELSX), GetDeviceCaps(hdc, LOGPIXELSY));
@@ -64,16 +43,222 @@ static inline QDpi deviceDPI(HDC hdc)
static inline QDpi monitorDPI(HMONITOR hMonitor)
{
- if (QWindowsContext::shcoredll.isValid()) {
- UINT dpiX;
- UINT dpiY;
- if (SUCCEEDED(QWindowsContext::shcoredll.getDpiForMonitor(hMonitor, 0, &dpiX, &dpiY)))
- return QDpi(dpiX, dpiY);
- }
+ UINT dpiX;
+ UINT dpiY;
+ if (SUCCEEDED(GetDpiForMonitor(hMonitor, MDT_EFFECTIVE_DPI, &dpiX, &dpiY)))
+ return QDpi(dpiX, dpiY);
return {0, 0};
}
-using WindowsScreenDataList = QVector<QWindowsScreenData>;
+static std::vector<DISPLAYCONFIG_PATH_INFO> getPathInfo(const MONITORINFOEX &viewInfo)
+{
+ // We might want to consider storing adapterId/id from DISPLAYCONFIG_PATH_TARGET_INFO.
+ std::vector<DISPLAYCONFIG_PATH_INFO> pathInfos;
+ std::vector<DISPLAYCONFIG_MODE_INFO> modeInfos;
+
+ // Fetch paths
+ LONG result;
+ UINT32 numPathArrayElements;
+ UINT32 numModeInfoArrayElements;
+ do {
+ // QueryDisplayConfig documentation doesn't say the number of needed elements is updated
+ // when the call fails with ERROR_INSUFFICIENT_BUFFER, so we need a separate call to
+ // look up the needed buffer sizes.
+ if (GetDisplayConfigBufferSizes(QDC_ONLY_ACTIVE_PATHS, &numPathArrayElements,
+ &numModeInfoArrayElements) != ERROR_SUCCESS) {
+ return {};
+ }
+ pathInfos.resize(numPathArrayElements);
+ modeInfos.resize(numModeInfoArrayElements);
+ result = QueryDisplayConfig(QDC_ONLY_ACTIVE_PATHS, &numPathArrayElements, pathInfos.data(),
+ &numModeInfoArrayElements, modeInfos.data(), nullptr);
+ } while (result == ERROR_INSUFFICIENT_BUFFER);
+
+ if (result != ERROR_SUCCESS)
+ return {};
+
+ // Find paths matching monitor name
+ auto discardThese =
+ std::remove_if(pathInfos.begin(), pathInfos.end(), [&](const auto &path) -> bool {
+ DISPLAYCONFIG_SOURCE_DEVICE_NAME deviceName;
+ deviceName.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME;
+ deviceName.header.size = sizeof(DISPLAYCONFIG_SOURCE_DEVICE_NAME);
+ deviceName.header.adapterId = path.sourceInfo.adapterId;
+ deviceName.header.id = path.sourceInfo.id;
+ if (DisplayConfigGetDeviceInfo(&deviceName.header) == ERROR_SUCCESS) {
+ return wcscmp(viewInfo.szDevice, deviceName.viewGdiDeviceName) != 0;
+ }
+ return true;
+ });
+
+ pathInfos.erase(discardThese, pathInfos.end());
+
+ return pathInfos;
+}
+
+#if 0
+// Needed later for HDR support
+static float getMonitorSDRWhiteLevel(DISPLAYCONFIG_PATH_TARGET_INFO *targetInfo)
+{
+ const float defaultSdrWhiteLevel = 200.0;
+ if (!targetInfo)
+ return defaultSdrWhiteLevel;
+
+ DISPLAYCONFIG_SDR_WHITE_LEVEL whiteLevel = {};
+ whiteLevel.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_SDR_WHITE_LEVEL;
+ whiteLevel.header.size = sizeof(DISPLAYCONFIG_SDR_WHITE_LEVEL);
+ whiteLevel.header.adapterId = targetInfo->adapterId;
+ whiteLevel.header.id = targetInfo->id;
+ if (DisplayConfigGetDeviceInfo(&whiteLevel.header) != ERROR_SUCCESS)
+ return defaultSdrWhiteLevel;
+ return whiteLevel.SDRWhiteLevel * 80.0 / 1000.0;
+}
+#endif
+
+using WindowsScreenDataList = QList<QWindowsScreenData>;
+
+namespace {
+
+struct DiRegKeyHandleTraits
+{
+ using Type = HKEY;
+ static Type invalidValue()
+ {
+ // The setupapi.h functions return INVALID_HANDLE_VALUE when failing to open a registry key
+ return reinterpret_cast<HKEY>(INVALID_HANDLE_VALUE);
+ }
+ static bool close(Type handle) { return RegCloseKey(handle) == ERROR_SUCCESS; }
+};
+
+using DiRegKeyHandle = QUniqueHandle<DiRegKeyHandleTraits>;
+
+}
+
+static void setMonitorDataFromSetupApi(QWindowsScreenData &data,
+ const std::vector<DISPLAYCONFIG_PATH_INFO> &pathGroup)
+{
+ if (pathGroup.empty()) {
+ return;
+ }
+
+ // The only property shared among monitors in a clone group is deviceName
+ {
+ DISPLAYCONFIG_TARGET_DEVICE_NAME deviceName = {};
+ deviceName.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME;
+ deviceName.header.size = sizeof(DISPLAYCONFIG_TARGET_DEVICE_NAME);
+ // The first element in the clone group is the main monitor.
+ deviceName.header.adapterId = pathGroup[0].targetInfo.adapterId;
+ deviceName.header.id = pathGroup[0].targetInfo.id;
+ if (DisplayConfigGetDeviceInfo(&deviceName.header) == ERROR_SUCCESS) {
+ data.devicePath = QString::fromWCharArray(deviceName.monitorDevicePath);
+ } else {
+ qCWarning(lcQpaScreen)
+ << u"Unable to get device information for %1:"_s.arg(pathGroup[0].targetInfo.id)
+ << QSystemError::windowsString();
+ }
+ }
+
+ // The rest must be concatenated into the resulting property
+ QStringList names;
+ QStringList manufacturers;
+ QStringList models;
+ QStringList serialNumbers;
+
+ for (const auto &path : pathGroup) {
+ DISPLAYCONFIG_TARGET_DEVICE_NAME deviceName = {};
+ deviceName.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME;
+ deviceName.header.size = sizeof(DISPLAYCONFIG_TARGET_DEVICE_NAME);
+ deviceName.header.adapterId = path.targetInfo.adapterId;
+ deviceName.header.id = path.targetInfo.id;
+ if (DisplayConfigGetDeviceInfo(&deviceName.header) != ERROR_SUCCESS) {
+ qCWarning(lcQpaScreen)
+ << u"Unable to get device information for %1:"_s.arg(path.targetInfo.id)
+ << QSystemError::windowsString();
+ continue;
+ }
+
+ // https://learn.microsoft.com/en-us/windows-hardware/drivers/install/guid-devinterface-monitor
+ constexpr GUID GUID_DEVINTERFACE_MONITOR = {
+ 0xe6f07b5f, 0xee97, 0x4a90, { 0xb0, 0x76, 0x33, 0xf5, 0x7b, 0xf4, 0xea, 0xa7 }
+ };
+ const HDEVINFO devInfo = SetupDiGetClassDevs(&GUID_DEVINTERFACE_MONITOR, nullptr, nullptr,
+ DIGCF_DEVICEINTERFACE);
+
+ SP_DEVICE_INTERFACE_DATA deviceInterfaceData{};
+ deviceInterfaceData.cbSize = sizeof(deviceInterfaceData);
+
+ if (!SetupDiOpenDeviceInterfaceW(devInfo, deviceName.monitorDevicePath, DIODI_NO_ADD,
+ &deviceInterfaceData)) {
+ qCWarning(lcQpaScreen)
+ << u"Unable to open monitor interface to %1:"_s.arg(data.deviceName)
+ << QSystemError::windowsString();
+ continue;
+ }
+
+ DWORD requiredSize{ 0 };
+ if (SetupDiGetDeviceInterfaceDetailW(devInfo, &deviceInterfaceData, nullptr, 0,
+ &requiredSize, nullptr)
+ || GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
+ continue;
+ }
+
+ const std::unique_ptr<std::byte[]> storage(new std::byte[requiredSize]);
+ auto *devicePath = reinterpret_cast<SP_DEVICE_INTERFACE_DETAIL_DATA_W *>(storage.get());
+ devicePath->cbSize = sizeof(std::remove_pointer_t<decltype(devicePath)>);
+ SP_DEVINFO_DATA deviceInfoData{};
+ deviceInfoData.cbSize = sizeof(deviceInfoData);
+ if (!SetupDiGetDeviceInterfaceDetailW(devInfo, &deviceInterfaceData, devicePath,
+ requiredSize, nullptr, &deviceInfoData)) {
+ qCDebug(lcQpaScreen) << u"Unable to get monitor metadata for %1:"_s.arg(data.deviceName)
+ << QSystemError::windowsString();
+ continue;
+ }
+
+ const DiRegKeyHandle edidRegistryKey{ SetupDiOpenDevRegKey(
+ devInfo, &deviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ) };
+
+ if (!edidRegistryKey.isValid())
+ continue;
+
+ DWORD edidDataSize{ 0 };
+ if (RegQueryValueExW(edidRegistryKey.get(), L"EDID", nullptr, nullptr, nullptr,
+ &edidDataSize)
+ != ERROR_SUCCESS) {
+ continue;
+ }
+
+ QByteArray edidData;
+ edidData.resize(edidDataSize);
+
+ if (RegQueryValueExW(edidRegistryKey.get(), L"EDID", nullptr, nullptr,
+ reinterpret_cast<unsigned char *>(edidData.data()), &edidDataSize)
+ != ERROR_SUCCESS) {
+ qCDebug(lcQpaScreen) << u"Unable to get EDID from the Registry for %1:"_s.arg(
+ data.deviceName)
+ << QSystemError::windowsString();
+ continue;
+ }
+
+ QEdidParser edid;
+
+ if (!edid.parse(edidData)) {
+ qCDebug(lcQpaScreen) << "Invalid EDID blob for" << data.deviceName;
+ continue;
+ }
+
+ // We skip edid.identifier because it is unreliable, and a better option
+ // is already available through DisplayConfigGetDeviceInfo (see below).
+ names << QString::fromWCharArray(deviceName.monitorFriendlyDeviceName);
+ manufacturers << edid.manufacturer;
+ models << edid.model;
+ serialNumbers << edid.serialNumber;
+ }
+
+ data.name = names.join(u"|"_s);
+ data.manufacturer = manufacturers.join(u"|"_s);
+ data.model = models.join(u"|"_s);
+ data.serialNumber = serialNumbers.join(u"|"_s);
+}
static bool monitorData(HMONITOR hMonitor, QWindowsScreenData *data)
{
@@ -86,8 +271,14 @@ static bool monitorData(HMONITOR hMonitor, QWindowsScreenData *data)
data->hMonitor = hMonitor;
data->geometry = QRect(QPoint(info.rcMonitor.left, info.rcMonitor.top), QPoint(info.rcMonitor.right - 1, info.rcMonitor.bottom - 1));
data->availableGeometry = QRect(QPoint(info.rcWork.left, info.rcWork.top), QPoint(info.rcWork.right - 1, info.rcWork.bottom - 1));
- data->name = QString::fromWCharArray(info.szDevice);
- if (data->name == u"WinDisc") {
+ data->deviceName = QString::fromWCharArray(info.szDevice);
+ const auto pathGroup = getPathInfo(info);
+ if (!pathGroup.empty()) {
+ setMonitorDataFromSetupApi(*data, pathGroup);
+ }
+ if (data->name.isEmpty())
+ data->name = data->deviceName;
+ if (data->deviceName == u"WinDisc") {
data->flags |= QWindowsScreenData::LockScreen;
} else {
if (const HDC hdc = CreateDC(info.szDevice, nullptr, nullptr, nullptr)) {
@@ -102,12 +293,41 @@ static bool monitorData(HMONITOR hMonitor, QWindowsScreenData *data)
DeleteDC(hdc);
} else {
qWarning("%s: Unable to obtain handle for monitor '%s', defaulting to %g DPI.",
- __FUNCTION__, qPrintable(QString::fromWCharArray(info.szDevice)),
+ __FUNCTION__, qPrintable(data->deviceName),
data->dpi.first);
} // CreateDC() failed
} // not lock screen
- data->orientation = data->geometry.height() > data->geometry.width() ?
- Qt::PortraitOrientation : Qt::LandscapeOrientation;
+
+ // ### We might want to consider storing adapterId/id from DISPLAYCONFIG_PATH_TARGET_INFO,
+ // if we are going to use DISPLAYCONFIG lookups more.
+ if (!pathGroup.empty()) {
+ // The first element in the clone group is the main monitor.
+ const auto &pathInfo = pathGroup[0];
+ switch (pathInfo.targetInfo.rotation) {
+ case DISPLAYCONFIG_ROTATION_IDENTITY:
+ data->orientation = Qt::LandscapeOrientation;
+ break;
+ case DISPLAYCONFIG_ROTATION_ROTATE90:
+ data->orientation = Qt::PortraitOrientation;
+ break;
+ case DISPLAYCONFIG_ROTATION_ROTATE180:
+ data->orientation = Qt::InvertedLandscapeOrientation;
+ break;
+ case DISPLAYCONFIG_ROTATION_ROTATE270:
+ data->orientation = Qt::InvertedPortraitOrientation;
+ break;
+ case DISPLAYCONFIG_ROTATION_FORCE_UINT32:
+ Q_UNREACHABLE();
+ break;
+ }
+ if (pathInfo.targetInfo.refreshRate.Numerator && pathInfo.targetInfo.refreshRate.Denominator)
+ data->refreshRateHz = static_cast<qreal>(pathInfo.targetInfo.refreshRate.Numerator)
+ / pathInfo.targetInfo.refreshRate.Denominator;
+ } else {
+ data->orientation = data->geometry.height() > data->geometry.width()
+ ? Qt::PortraitOrientation
+ : Qt::LandscapeOrientation;
+ }
// EnumDisplayMonitors (as opposed to EnumDisplayDevices) enumerates only
// virtual desktop screens.
data->flags |= QWindowsScreenData::VirtualDesktop;
@@ -116,12 +336,22 @@ static bool monitorData(HMONITOR hMonitor, QWindowsScreenData *data)
return true;
}
-// from QDesktopWidget, taking WindowsScreenDataList as LPARAM
+// from monitorData, taking WindowsScreenDataList as LPARAM
BOOL QT_WIN_CALLBACK monitorEnumCallback(HMONITOR hMonitor, HDC, LPRECT, LPARAM p)
{
QWindowsScreenData data;
if (monitorData(hMonitor, &data)) {
auto *result = reinterpret_cast<WindowsScreenDataList *>(p);
+ auto it = std::find_if(result->rbegin(), result->rend(),
+ [&data](QWindowsScreenData i){ return i.name == data.name; });
+ if (it != result->rend()) {
+ int previousIndex = 1;
+ if (it->deviceIndex.has_value())
+ previousIndex = it->deviceIndex.value();
+ else
+ (*it).deviceIndex = 1;
+ data.deviceIndex = previousIndex + 1;
+ }
// QWindowSystemInterface::handleScreenAdded() documentation specifies that first
// added screen will be the primary screen, so order accordingly.
// Note that the side effect of this policy is that there is no way to change primary
@@ -148,14 +378,14 @@ static QDebug operator<<(QDebug dbg, const QWindowsScreenData &d)
QDebugStateSaver saver(dbg);
dbg.nospace();
dbg.noquote();
- dbg << "Screen \"" << d.name << "\" "
- << d.geometry.width() << 'x' << d.geometry.height() << '+' << d.geometry.x() << '+' << d.geometry.y()
- << " avail: "
- << d.availableGeometry.width() << 'x' << d.availableGeometry.height() << '+' << d.availableGeometry.x() << '+' << d.availableGeometry.y()
- << " physical: " << d.physicalSizeMM.width() << 'x' << d.physicalSizeMM.height()
- << " DPI: " << d.dpi.first << 'x' << d.dpi.second << " Depth: " << d.depth
- << " Format: " << d.format
- << " hMonitor: " << d.hMonitor;
+ dbg << "Screen \"" << d.name << "\" " << d.geometry.width() << 'x' << d.geometry.height() << '+'
+ << d.geometry.x() << '+' << d.geometry.y() << " avail: " << d.availableGeometry.width()
+ << 'x' << d.availableGeometry.height() << '+' << d.availableGeometry.x() << '+'
+ << d.availableGeometry.y() << " physical: " << d.physicalSizeMM.width() << 'x'
+ << d.physicalSizeMM.height() << " DPI: " << d.dpi.first << 'x' << d.dpi.second
+ << " Depth: " << d.depth << " Format: " << d.format << " hMonitor: " << d.hMonitor
+ << " device name: " << d.deviceName << " manufacturer: " << d.manufacturer
+ << " model: " << d.model << " serial number: " << d.serialNumber;
if (d.flags & QWindowsScreenData::PrimaryScreen)
dbg << " primary";
if (d.flags & QWindowsScreenData::VirtualDesktop)
@@ -171,7 +401,6 @@ static QDebug operator<<(QDebug dbg, const QWindowsScreenData &d)
\brief Windows screen.
\sa QWindowsScreenManager
\internal
- \ingroup qt-lighthouse-win
*/
QWindowsScreen::QWindowsScreen(const QWindowsScreenData &data) :
@@ -182,7 +411,12 @@ QWindowsScreen::QWindowsScreen(const QWindowsScreenData &data) :
{
}
-Q_GUI_EXPORT QPixmap qt_pixmapFromWinHBITMAP(HBITMAP bitmap, int hbitmapFormat = 0);
+QString QWindowsScreen::name() const
+{
+ return m_data.deviceIndex.has_value()
+ ? (u"%1 (%2)"_s).arg(m_data.name, QString::number(m_data.deviceIndex.value()))
+ : m_data.name;
+}
QPixmap QWindowsScreen::grabWindow(WId window, int xIn, int yIn, int width, int height) const
{
@@ -242,7 +476,7 @@ QWindow *QWindowsScreen::topLevelAt(const QPoint &point) const
if (QWindow *child = QWindowsScreen::windowAt(point, CWP_SKIPINVISIBLE))
result = QWindowsWindow::topLevelOf(child);
if (QWindowsContext::verbose > 1)
- qCDebug(lcQpaWindows) <<__FUNCTION__ << point << result;
+ qCDebug(lcQpaScreen) <<__FUNCTION__ << point << result;
return result;
}
@@ -253,7 +487,7 @@ QWindow *QWindowsScreen::windowAt(const QPoint &screenPoint, unsigned flags)
findPlatformWindowAt(GetDesktopWindow(), screenPoint, flags))
result = bw->window();
if (QWindowsContext::verbose > 1)
- qCDebug(lcQpaWindows) <<__FUNCTION__ << screenPoint << " returns " << result;
+ qCDebug(lcQpaScreen) <<__FUNCTION__ << screenPoint << " returns " << result;
return result;
}
@@ -289,7 +523,7 @@ void QWindowsScreen::handleChanges(const QWindowsScreenData &newData)
m_data.physicalSizeMM = newData.physicalSizeMM;
if (m_data.hMonitor != newData.hMonitor) {
- qCDebug(lcQpaWindows) << "Monitor" << m_data.name
+ qCDebug(lcQpaScreen) << "Monitor" << m_data.name
<< "has had its hMonitor handle changed from"
<< m_data.hMonitor << "to" << newData.hMonitor;
m_data.hMonitor = newData.hMonitor;
@@ -302,10 +536,14 @@ void QWindowsScreen::handleChanges(const QWindowsScreenData &newData)
const bool dpiChanged = !qFuzzyCompare(m_data.dpi.first, newData.dpi.first)
|| !qFuzzyCompare(m_data.dpi.second, newData.dpi.second);
const bool orientationChanged = m_data.orientation != newData.orientation;
+ const bool primaryChanged = (newData.flags & QWindowsScreenData::PrimaryScreen)
+ && !(m_data.flags & QWindowsScreenData::PrimaryScreen);
m_data.dpi = newData.dpi;
m_data.orientation = newData.orientation;
m_data.geometry = newData.geometry;
m_data.availableGeometry = newData.availableGeometry;
+ m_data.flags = (m_data.flags & ~QWindowsScreenData::PrimaryScreen)
+ | (newData.flags & QWindowsScreenData::PrimaryScreen);
if (dpiChanged) {
QWindowSystemInterface::handleScreenLogicalDotsPerInchChange(screen(),
@@ -318,6 +556,8 @@ void QWindowsScreen::handleChanges(const QWindowsScreenData &newData)
QWindowSystemInterface::handleScreenGeometryChange(screen(),
newData.geometry, newData.availableGeometry);
}
+ if (primaryChanged)
+ QWindowSystemInterface::handlePrimaryScreenChanged(this);
}
HMONITOR QWindowsScreen::handle() const
@@ -334,62 +574,50 @@ QRect QWindowsScreen::virtualGeometry(const QPlatformScreen *screen) // cf QScre
return result;
}
-enum OrientationPreference : DWORD // matching Win32 API ORIENTATION_PREFERENCE
-{
- orientationPreferenceNone = 0,
- orientationPreferenceLandscape = 0x1,
- orientationPreferencePortrait = 0x2,
- orientationPreferenceLandscapeFlipped = 0x4,
- orientationPreferencePortraitFlipped = 0x8
-};
-
bool QWindowsScreen::setOrientationPreference(Qt::ScreenOrientation o)
{
bool result = false;
- if (QWindowsContext::user32dll.setDisplayAutoRotationPreferences) {
- DWORD orientationPreference = 0;
- switch (o) {
- case Qt::PrimaryOrientation:
- orientationPreference = orientationPreferenceNone;
- break;
- case Qt::PortraitOrientation:
- orientationPreference = orientationPreferencePortrait;
- break;
- case Qt::LandscapeOrientation:
- orientationPreference = orientationPreferenceLandscape;
- break;
- case Qt::InvertedPortraitOrientation:
- orientationPreference = orientationPreferencePortraitFlipped;
- break;
- case Qt::InvertedLandscapeOrientation:
- orientationPreference = orientationPreferenceLandscapeFlipped;
- break;
- }
- result = QWindowsContext::user32dll.setDisplayAutoRotationPreferences(orientationPreference);
+ ORIENTATION_PREFERENCE orientationPreference = ORIENTATION_PREFERENCE_NONE;
+ switch (o) {
+ case Qt::PrimaryOrientation:
+ break;
+ case Qt::PortraitOrientation:
+ orientationPreference = ORIENTATION_PREFERENCE_PORTRAIT;
+ break;
+ case Qt::LandscapeOrientation:
+ orientationPreference = ORIENTATION_PREFERENCE_LANDSCAPE;
+ break;
+ case Qt::InvertedPortraitOrientation:
+ orientationPreference = ORIENTATION_PREFERENCE_PORTRAIT_FLIPPED;
+ break;
+ case Qt::InvertedLandscapeOrientation:
+ orientationPreference = ORIENTATION_PREFERENCE_LANDSCAPE_FLIPPED;
+ break;
}
+ result = SetDisplayAutoRotationPreferences(orientationPreference);
return result;
}
Qt::ScreenOrientation QWindowsScreen::orientationPreference()
{
Qt::ScreenOrientation result = Qt::PrimaryOrientation;
- if (QWindowsContext::user32dll.getDisplayAutoRotationPreferences) {
- DWORD orientationPreference = 0;
- if (QWindowsContext::user32dll.getDisplayAutoRotationPreferences(&orientationPreference)) {
- switch (orientationPreference) {
- case orientationPreferenceLandscape:
- result = Qt::LandscapeOrientation;
- break;
- case orientationPreferencePortrait:
- result = Qt::PortraitOrientation;
- break;
- case orientationPreferenceLandscapeFlipped:
- result = Qt::InvertedLandscapeOrientation;
- break;
- case orientationPreferencePortraitFlipped:
- result = Qt::InvertedPortraitOrientation;
- break;
- }
+ ORIENTATION_PREFERENCE orientationPreference = ORIENTATION_PREFERENCE_NONE;
+ if (GetDisplayAutoRotationPreferences(&orientationPreference)) {
+ switch (orientationPreference) {
+ case ORIENTATION_PREFERENCE_NONE:
+ break;
+ case ORIENTATION_PREFERENCE_LANDSCAPE:
+ result = Qt::LandscapeOrientation;
+ break;
+ case ORIENTATION_PREFERENCE_PORTRAIT:
+ result = Qt::PortraitOrientation;
+ break;
+ case ORIENTATION_PREFERENCE_LANDSCAPE_FLIPPED:
+ result = Qt::InvertedLandscapeOrientation;
+ break;
+ case ORIENTATION_PREFERENCE_PORTRAIT_FLIPPED:
+ result = Qt::InvertedPortraitOrientation;
+ break;
}
}
return result;
@@ -402,9 +630,9 @@ QPlatformScreen::SubpixelAntialiasingType QWindowsScreen::subpixelAntialiasingTy
{
QPlatformScreen::SubpixelAntialiasingType type = QPlatformScreen::subpixelAntialiasingTypeHint();
if (type == QPlatformScreen::Subpixel_None) {
- QSettings settings(QLatin1String(R"(HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Avalon.Graphics\DISPLAY1)"),
+ QSettings settings(R"(HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Avalon.Graphics\DISPLAY1)"_L1,
QSettings::NativeFormat);
- int registryValue = settings.value(QLatin1String("PixelStructure"), -1).toInt();
+ int registryValue = settings.value("PixelStructure"_L1, -1).toInt();
switch (registryValue) {
case 0:
type = QPlatformScreen::Subpixel_None;
@@ -432,55 +660,68 @@ QPlatformScreen::SubpixelAntialiasingType QWindowsScreen::subpixelAntialiasingTy
\sa QWindowsScreen
\internal
- \ingroup qt-lighthouse-win
*/
-QWindowsScreenManager::QWindowsScreenManager() = default;
+extern "C" LRESULT QT_WIN_CALLBACK qDisplayChangeObserverWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ if (message == WM_DISPLAYCHANGE) {
+ qCDebug(lcQpaScreen) << "Handling WM_DISPLAYCHANGE";
+ if (QWindowsTheme *t = QWindowsTheme::instance())
+ t->displayChanged();
+ QWindowsWindow::displayChanged();
+ if (auto *context = QWindowsContext::instance())
+ context->screenManager().handleScreenChanges();
+ }
+ return DefWindowProc(hwnd, message, wParam, lParam);
+}
-bool QWindowsScreenManager::isSingleScreen()
+QWindowsScreenManager::QWindowsScreenManager() = default;
+
+void QWindowsScreenManager::initialize()
{
- return QWindowsContext::instance()->screenManager().screens().size() < 2;
-}
+ qCDebug(lcQpaScreen) << "Initializing screen manager";
-/*!
- \brief Triggers synchronization of screens (WM_DISPLAYCHANGE).
+ auto className = QWindowsContext::instance()->registerWindowClass(
+ QWindowsContext::classNamePrefix() + QLatin1String("ScreenChangeObserverWindow"),
+ qDisplayChangeObserverWndProc);
- Subsequent events are compressed since WM_DISPLAYCHANGE is sent to
- each top level window.
-*/
+ // HWND_MESSAGE windows do not get WM_DISPLAYCHANGE, so we need to create
+ // a real top level window that we never show.
+ m_displayChangeObserver = CreateWindowEx(0, reinterpret_cast<LPCWSTR>(className.utf16()),
+ nullptr, WS_TILED, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
+ nullptr, nullptr, GetModuleHandle(nullptr), nullptr);
+ Q_ASSERT(m_displayChangeObserver);
-bool QWindowsScreenManager::handleDisplayChange(WPARAM wParam, LPARAM lParam)
-{
- const int newDepth = int(wParam);
- const WORD newHorizontalResolution = LOWORD(lParam);
- const WORD newVerticalResolution = HIWORD(lParam);
- if (newDepth != m_lastDepth || newHorizontalResolution != m_lastHorizontalResolution
- || newVerticalResolution != m_lastVerticalResolution) {
- m_lastDepth = newDepth;
- m_lastHorizontalResolution = newHorizontalResolution;
- m_lastVerticalResolution = newVerticalResolution;
- qCDebug(lcQpaWindows) << __FUNCTION__ << "Depth=" << newDepth
- << ", resolution " << newHorizontalResolution << 'x' << newVerticalResolution;
- handleScreenChanges();
- }
- return false;
+ qCDebug(lcQpaScreen) << "Created display change observer" << m_displayChangeObserver;
+
+ handleScreenChanges();
+}
+
+QWindowsScreenManager::~QWindowsScreenManager()
+{
+ DestroyWindow(m_displayChangeObserver);
+}
+
+bool QWindowsScreenManager::isSingleScreen()
+{
+ return QWindowsContext::instance()->screenManager().screens().size() < 2;
}
static inline int indexOfMonitor(const QWindowsScreenManager::WindowsScreenList &screens,
- const QString &monitorName)
+ const QString &deviceName)
{
for (int i= 0; i < screens.size(); ++i)
- if (screens.at(i)->data().name == monitorName)
+ if (screens.at(i)->data().deviceName == deviceName)
return i;
return -1;
}
static inline int indexOfMonitor(const WindowsScreenDataList &screenData,
- const QString &monitorName)
+ const QString &deviceName)
{
for (int i = 0; i < screenData.size(); ++i)
- if (screenData.at(i).name == monitorName)
+ if (screenData.at(i).deviceName == deviceName)
return i;
return -1;
}
@@ -504,7 +745,7 @@ static void moveToVirtualScreen(QWindow *w, const QScreen *newScreen)
void QWindowsScreenManager::removeScreen(int index)
{
- qCDebug(lcQpaWindows) << "Removing Monitor:" << m_screens.at(index)->data();
+ qCDebug(lcQpaScreen) << "Removing Monitor:" << m_screens.at(index)->data();
QScreen *screen = m_screens.at(index)->screen();
QScreen *primaryScreen = QGuiApplication::primaryScreen();
// QTBUG-38650: When a screen is disconnected, Windows will automatically
@@ -546,7 +787,7 @@ bool QWindowsScreenManager::handleScreenChanges()
const bool lockScreen = newDataList.size() == 1 && (newDataList.front().flags & QWindowsScreenData::LockScreen);
bool primaryScreenChanged = false;
for (const QWindowsScreenData &newData : newDataList) {
- const int existingIndex = indexOfMonitor(m_screens, newData.name);
+ const int existingIndex = indexOfMonitor(m_screens, newData.deviceName);
if (existingIndex != -1) {
m_screens.at(existingIndex)->handleChanges(newData);
if (existingIndex == 0)
@@ -556,19 +797,21 @@ bool QWindowsScreenManager::handleScreenChanges()
m_screens.push_back(newScreen);
QWindowSystemInterface::handleScreenAdded(newScreen,
newData.flags & QWindowsScreenData::PrimaryScreen);
- qCDebug(lcQpaWindows) << "New Monitor: " << newData;
+ qCDebug(lcQpaScreen) << "New Monitor: " << newData;
} // exists
} // for new screens.
// Remove deleted ones but keep main monitors if we get only the
// temporary lock screen to avoid window recreation (QTBUG-33062).
if (!lockScreen) {
for (int i = m_screens.size() - 1; i >= 0; --i) {
- if (indexOfMonitor(newDataList, m_screens.at(i)->data().name) == -1)
+ if (indexOfMonitor(newDataList, m_screens.at(i)->data().deviceName) == -1)
removeScreen(i);
} // for existing screens
} // not lock screen
- if (primaryScreenChanged)
- QWindowsTheme::instance()->refreshFonts();
+ if (primaryScreenChanged) {
+ if (auto theme = QWindowsTheme::instance()) // QTBUG-85734/Wine
+ theme->refreshFonts();
+ }
return true;
}
diff --git a/src/plugins/platforms/windows/qwindowsscreen.h b/src/plugins/platforms/windows/qwindowsscreen.h
index 5c095808f2..0467ab2a0c 100644
--- a/src/plugins/platforms/windows/qwindowsscreen.h
+++ b/src/plugins/platforms/windows/qwindowsscreen.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QWINDOWSSCREEN_H
#define QWINDOWSSCREEN_H
@@ -43,10 +7,9 @@
#include "qtwindowsglobal.h"
#include <QtCore/qlist.h>
-#include <QtCore/qvector.h>
-#include <QtCore/qpair.h>
#include <QtCore/qscopedpointer.h>
#include <qpa/qplatformscreen.h>
+#include <QtGui/qscreen_platform.h>
QT_BEGIN_NAMESPACE
@@ -67,12 +30,18 @@ struct QWindowsScreenData
QImage::Format format = QImage::Format_ARGB32_Premultiplied;
unsigned flags = VirtualDesktop;
QString name;
+ QString manufacturer;
+ QString model;
+ QString serialNumber;
Qt::ScreenOrientation orientation = Qt::LandscapeOrientation;
qreal refreshRateHz = 60;
HMONITOR hMonitor = nullptr;
+ QString deviceName;
+ QString devicePath;
+ std::optional<int> deviceIndex = std::nullopt;
};
-class QWindowsScreen : public QPlatformScreen
+class QWindowsScreen : public QPlatformScreen, public QNativeInterface::QWindowsScreen
{
public:
#ifndef QT_NO_CURSOR
@@ -87,10 +56,13 @@ public:
QImage::Format format() const override { return m_data.format; }
QSizeF physicalSize() const override { return m_data.physicalSizeMM; }
QDpi logicalDpi() const override { return m_data.dpi; }
- QDpi logicalBaseDpi() const override { return QDpi(96, 96); };
+ QDpi logicalBaseDpi() const override { return QDpi(baseDpi, baseDpi); }
qreal devicePixelRatio() const override { return 1.0; }
qreal refreshRate() const override { return m_data.refreshRateHz; }
- QString name() const override { return m_data.name; }
+ QString name() const override;
+ QString manufacturer() const override { return m_data.manufacturer; }
+ QString model() const override { return m_data.model; }
+ QString serialNumber() const override { return m_data.serialNumber; }
Qt::ScreenOrientation orientation() const override { return m_data.orientation; }
QList<QPlatformScreen *> virtualSiblings() const override;
QWindow *topLevelAt(const QPoint &point) const override;
@@ -104,7 +76,7 @@ public:
inline void handleChanges(const QWindowsScreenData &newData);
- HMONITOR handle() const;
+ HMONITOR handle() const override;
#ifndef QT_NO_CURSOR
QPlatformCursor *cursor() const override { return m_cursor.data(); }
@@ -116,6 +88,7 @@ public:
const QWindowsScreenData &data() const { return m_data; }
static QRect virtualGeometry(const QPlatformScreen *screen);
+ static inline int baseDpi = 96;
private:
QWindowsScreenData m_data;
@@ -126,15 +99,17 @@ private:
class QWindowsScreenManager
{
+ Q_DISABLE_COPY_MOVE(QWindowsScreenManager)
public:
- using WindowsScreenList = QVector<QWindowsScreen *>;
+ using WindowsScreenList = QList<QWindowsScreen *>;
QWindowsScreenManager();
+ void initialize();
+ ~QWindowsScreenManager();
void clearScreens();
bool handleScreenChanges();
- bool handleDisplayChange(WPARAM wParam, LPARAM lParam);
const WindowsScreenList &screens() const { return m_screens; }
const QWindowsScreen *screenAtDp(const QPoint &p) const;
@@ -145,10 +120,8 @@ public:
private:
void removeScreen(int index);
+ HWND m_displayChangeObserver = nullptr;
WindowsScreenList m_screens;
- int m_lastDepth = -1;
- WORD m_lastHorizontalResolution = 0;
- WORD m_lastVerticalResolution = 0;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/windows/qwindowsservices.cpp b/src/plugins/platforms/windows/qwindowsservices.cpp
index 6a2708ee26..89f93fd161 100644
--- a/src/plugins/platforms/windows/qwindowsservices.cpp
+++ b/src/plugins/platforms/windows/qwindowsservices.cpp
@@ -1,71 +1,118 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
-
-#define QT_NO_URL_CAST_FROM_STRING
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
#include "qwindowsservices.h"
#include <QtCore/qt_windows.h>
#include <QtCore/qurl.h>
#include <QtCore/qdebug.h>
#include <QtCore/qdir.h>
+#include <QtCore/qscopedpointer.h>
+#include <QtCore/qthread.h>
#include <QtCore/private/qwinregistry_p.h>
+#include <QtCore/private/qfunctions_win_p.h>
#include <shlobj.h>
+#include <shlwapi.h>
#include <intshcut.h>
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
enum { debug = 0 };
+class QWindowsShellExecuteThread : public QThread
+{
+public:
+ explicit QWindowsShellExecuteThread(const wchar_t *operation, const wchar_t *file,
+ const wchar_t *parameters)
+ : m_operation(operation)
+ , m_file(file)
+ , m_parameters(parameters) { }
+
+ void run() override
+ {
+ QComHelper comHelper;
+ if (comHelper.isValid())
+ m_result = ShellExecute(nullptr, m_operation, m_file, m_parameters, nullptr,
+ SW_SHOWNORMAL);
+ }
+
+ HINSTANCE result() const { return m_result; }
+
+private:
+ HINSTANCE m_result = nullptr;
+ const wchar_t *m_operation;
+ const wchar_t *m_file;
+ const wchar_t *m_parameters;
+};
+
+static QString msgShellExecuteFailed(const QUrl &url, quintptr code)
+{
+ QString result;
+ QTextStream(&result) <<"ShellExecute '" << url.toString() << "' failed (error " << code << ").";
+ return result;
+}
+
+// Retrieve the web browser and open the URL. This should be used for URLs with
+// fragments which don't work when using ShellExecute() directly (QTBUG-14460,
+// QTBUG-55300).
+static bool openWebBrowser(const QUrl &url)
+{
+ WCHAR browserExecutable[MAX_PATH] = {};
+ const wchar_t operation[] = L"open";
+ DWORD browserExecutableSize = MAX_PATH;
+ if (FAILED(AssocQueryString(0, ASSOCSTR_EXECUTABLE, L"http", operation,
+ browserExecutable, &browserExecutableSize))) {
+ return false;
+ }
+ QString browser = QString::fromWCharArray(browserExecutable, browserExecutableSize - 1);
+ // Workaround for "old" MS Edge entries. Instead of LaunchWinApp.exe we can just use msedge.exe
+ if (browser.contains("LaunchWinApp.exe"_L1, Qt::CaseInsensitive))
+ browser = "msedge.exe"_L1;
+ const QString urlS = url.toString(QUrl::FullyEncoded);
+
+ // Run ShellExecute() in a thread since it may spin the event loop.
+ // Prevent it from interfering with processing of posted events (QTBUG-85676).
+ QWindowsShellExecuteThread thread(operation,
+ reinterpret_cast<const wchar_t *>(browser.utf16()),
+ reinterpret_cast<const wchar_t *>(urlS.utf16()));
+ thread.start();
+ thread.wait();
+
+ const auto result = reinterpret_cast<quintptr>(thread.result());
+ if (debug)
+ qDebug() << __FUNCTION__ << urlS << QString::fromWCharArray(browserExecutable) << result;
+ // ShellExecute returns a value greater than 32 if successful
+ if (result <= 32) {
+ qWarning("%s", qPrintable(msgShellExecuteFailed(url, result)));
+ return false;
+ }
+ return true;
+}
+
static inline bool shellExecute(const QUrl &url)
{
const QString nativeFilePath = url.isLocalFile() && !url.hasFragment() && !url.hasQuery()
? QDir::toNativeSeparators(url.toLocalFile())
: url.toString(QUrl::FullyEncoded);
- const auto result =
- reinterpret_cast<quintptr>(ShellExecute(nullptr, nullptr,
- reinterpret_cast<const wchar_t *>(nativeFilePath.utf16()),
- nullptr, nullptr, SW_SHOWNORMAL));
+
+
+ // Run ShellExecute() in a thread since it may spin the event loop.
+ // Prevent it from interfering with processing of posted events (QTBUG-85676).
+ QWindowsShellExecuteThread thread(nullptr,
+ reinterpret_cast<const wchar_t *>(nativeFilePath.utf16()),
+ nullptr);
+ thread.start();
+ thread.wait();
+
+ const auto result = reinterpret_cast<quintptr>(thread.result());
+
// ShellExecute returns a value greater than 32 if successful
if (result <= 32) {
- qWarning("ShellExecute '%s' failed (error %s).", qPrintable(url.toString()), qPrintable(QString::number(result)));
+ qWarning("%s", qPrintable(msgShellExecuteFailed(url, result)));
return false;
}
return true;
@@ -83,15 +130,15 @@ static inline QString mailCommand()
// Check if user has set preference, otherwise use default.
QString keyName = QWinRegistryKey(HKEY_CURRENT_USER, mailUserKey)
.stringValue( L"Progid");
- const QLatin1String mailto = keyName.isEmpty() ? QLatin1String("mailto") : QLatin1String();
- keyName += mailto + QLatin1String("\\Shell\\Open\\Command");
+ const auto mailto = keyName.isEmpty() ? "mailto"_L1 : QLatin1StringView();
+ keyName += mailto + "\\Shell\\Open\\Command"_L1;
if (debug)
qDebug() << __FUNCTION__ << "keyName=" << keyName;
const QString command = QWinRegistryKey(HKEY_CLASSES_ROOT, keyName).stringValue(L"");
// QTBUG-57816: As of Windows 10, if there is no mail client installed, an entry like
// "rundll32.exe .. url.dll,MailToProtocolHandler %l" is returned. Launching it
// silently fails or brings up a broken dialog after a long time, so exclude it and
- // fall back to ShellExecute() which brings up the URL assocation dialog.
+ // fall back to ShellExecute() which brings up the URL association dialog.
if (command.isEmpty() || command.contains(u",MailToProtocolHandler"))
return QString();
wchar_t expandedCommand[MAX_PATH] = {0};
@@ -104,13 +151,18 @@ static inline bool launchMail(const QUrl &url)
{
QString command = mailCommand();
if (command.isEmpty()) {
- qWarning("Cannot launch '%s': There is no mail program installed.", qPrintable(url.toString()));
+ qWarning("Cannot launch '%ls': There is no mail program installed.", qUtf16Printable(url.toString()));
+ return false;
+ }
+ // Fix mail launch if no param is expected in this command.
+ if (command.indexOf("%1"_L1) < 0) {
+ qWarning() << "The mail command lacks the '%1' parameter.";
return false;
}
//Make sure the path for the process is in quotes
const QChar doubleQuote = u'"';
if (!command.startsWith(doubleQuote)) {
- const int exeIndex = command.indexOf(QStringLiteral(".exe "), 0, Qt::CaseInsensitive);
+ const int exeIndex = command.indexOf(".exe "_L1, 0, Qt::CaseInsensitive);
if (exeIndex != -1) {
command.insert(exeIndex + 4, doubleQuote);
command.prepend(doubleQuote);
@@ -118,7 +170,7 @@ static inline bool launchMail(const QUrl &url)
}
// Pass the url as the parameter. Should use QProcess::startDetached(),
// but that cannot handle a Windows command line [yet].
- command.replace(QLatin1String("%1"), url.toString(QUrl::FullyEncoded));
+ command.replace("%1"_L1, url.toString(QUrl::FullyEncoded));
if (debug)
qDebug() << __FUNCTION__ << "Launching" << command;
//start the process
@@ -129,7 +181,7 @@ static inline bool launchMail(const QUrl &url)
si.cb = sizeof(si);
if (!CreateProcess(nullptr, reinterpret_cast<wchar_t *>(const_cast<ushort *>(command.utf16())),
nullptr, nullptr, FALSE, 0, nullptr, nullptr, &si, &pi)) {
- qErrnoWarning("Unable to launch '%s'", qPrintable(command));
+ qErrnoWarning("Unable to launch '%ls'", qUtf16Printable(command));
return false;
}
CloseHandle(pi.hProcess);
@@ -142,7 +194,8 @@ bool QWindowsServices::openUrl(const QUrl &url)
const QString scheme = url.scheme();
if (scheme == u"mailto" && launchMail(url))
return true;
- return shellExecute(url);
+ return url.isLocalFile() && url.hasFragment()
+ ? openWebBrowser(url) : shellExecute(url);
}
bool QWindowsServices::openDocument(const QUrl &url)
diff --git a/src/plugins/platforms/windows/qwindowsservices.h b/src/plugins/platforms/windows/qwindowsservices.h
index 5feb7c8490..56279f57fc 100644
--- a/src/plugins/platforms/windows/qwindowsservices.h
+++ b/src/plugins/platforms/windows/qwindowsservices.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QWINDOWSDESKTOPSERVICES_H
#define QWINDOWSDESKTOPSERVICES_H
diff --git a/src/plugins/platforms/windows/qwindowssessionmanager.cpp b/src/plugins/platforms/windows/qwindowssessionmanager.cpp
index 500fdc750c..487ebeba65 100644
--- a/src/plugins/platforms/windows/qwindowssessionmanager.cpp
+++ b/src/plugins/platforms/windows/qwindowssessionmanager.cpp
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Samuel Gaist <samuel.gaist@edeltech.ch>
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2013 Samuel Gaist <samuel.gaist@edeltech.ch>
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qwindowssessionmanager.h"
diff --git a/src/plugins/platforms/windows/qwindowssessionmanager.h b/src/plugins/platforms/windows/qwindowssessionmanager.h
index 0769ed1fce..320c1aedee 100644
--- a/src/plugins/platforms/windows/qwindowssessionmanager.h
+++ b/src/plugins/platforms/windows/qwindowssessionmanager.h
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Samuel Gaist <samuel.gaist@edeltech.ch>
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2013 Samuel Gaist <samuel.gaist@edeltech.ch>
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QWINDOWSSESSIONMANAGER_H
#define QWINDOWSSESSIONMANAGER_H
diff --git a/src/plugins/platforms/windows/qwindowssystemtrayicon.cpp b/src/plugins/platforms/windows/qwindowssystemtrayicon.cpp
index 53562c87dd..6f0680ac23 100644
--- a/src/plugins/platforms/windows/qwindowssystemtrayicon.cpp
+++ b/src/plugins/platforms/windows/qwindowssystemtrayicon.cpp
@@ -1,55 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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$
-**
-****************************************************************************/
-
-#if defined(WINVER) && WINVER < 0x0601
-# undef WINVER
-#endif
-#if !defined(WINVER)
-# define WINVER 0x0601 // required for NOTIFYICONDATA_V2_SIZE, ChangeWindowMessageFilterEx() (MinGW 5.3)
-#endif
-
-#if defined(NTDDI_VERSION) && NTDDI_VERSION < 0x06010000
-# undef NTDDI_VERSION
-#endif
-#if !defined(NTDDI_VERSION)
-# define NTDDI_VERSION 0x06010000 // required for Shell_NotifyIconGetRect (MinGW 5.3)
-#endif
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <QtCore/qt_windows.h>
#include "qwindowssystemtrayicon.h"
#include "qwindowscontext.h"
@@ -60,12 +12,11 @@
#include <QtGui/qguiapplication.h>
#include <QtGui/qpixmap.h>
#include <QtCore/qdebug.h>
+#include <QtCore/qlist.h>
#include <QtCore/qrect.h>
-#include <QtCore/qvector.h>
#include <QtCore/qsettings.h>
#include <qpa/qwindowsysteminterface.h>
-#include <qt_windows.h>
#include <commctrl.h>
#include <shellapi.h>
#include <shlobj.h>
@@ -73,6 +24,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::Literals::StringLiterals;
+
static const UINT q_uNOTIFYICONID = 0;
static uint MYWM_TASKBARCREATED = 0;
@@ -119,7 +72,7 @@ struct QWindowsHwndSystemTrayIconEntry
QWindowsSystemTrayIcon *trayIcon;
};
-using HwndTrayIconEntries = QVector<QWindowsHwndSystemTrayIconEntry>;
+using HwndTrayIconEntries = QList<QWindowsHwndSystemTrayIconEntry>;
Q_GLOBAL_STATIC(HwndTrayIconEntries, hwndTrayIconEntries)
@@ -136,9 +89,6 @@ static int indexOfHwnd(HWND hwnd)
extern "C" LRESULT QT_WIN_CALLBACK qWindowsTrayIconWndProc(HWND hwnd, UINT message,
WPARAM wParam, LPARAM lParam)
{
- // QTBUG-79248: Trigger screen update if there are no other windows.
- if (message == WM_DPICHANGED && QGuiApplication::topLevelWindows().isEmpty())
- QWindowsContext::instance()->screenManager().handleScreenChanges();
if (message == MYWM_TASKBARCREATED || message == MYWM_NOTIFYICON
|| message == WM_INITMENU || message == WM_INITMENUPOPUP
|| message == WM_CLOSE || message == WM_COMMAND) {
@@ -168,7 +118,7 @@ static inline HWND createTrayIconMessageWindow()
return nullptr;
// Register window class in the platform plugin.
const QString className =
- ctx->registerWindowClass(QWindowsContext::classNamePrefix() + QStringLiteral("TrayIconMessageWindowClass"),
+ ctx->registerWindowClass(QWindowsContext::classNamePrefix() + "TrayIconMessageWindowClass"_L1,
qWindowsTrayIconWndProc);
const wchar_t windowName[] = L"QTrayIconMessageWindow";
return CreateWindowEx(0, reinterpret_cast<const wchar_t *>(className.utf16()),
@@ -184,7 +134,6 @@ static inline HWND createTrayIconMessageWindow()
\brief Windows native system tray icon
\internal
- \ingroup qt-lighthouse-win
*/
QWindowsSystemTrayIcon::QWindowsSystemTrayIcon()
@@ -215,8 +164,7 @@ void QWindowsSystemTrayIcon::cleanup()
void QWindowsSystemTrayIcon::updateIcon(const QIcon &icon)
{
qCDebug(lcQpaTrayIcon) << __FUNCTION__ << '(' << icon << ')' << this;
- if (icon.cacheKey() == m_icon.cacheKey())
- return;
+ m_icon = icon;
const HICON hIconToDestroy = createIcon(icon);
if (ensureInstalled())
sendTrayMessage(NIM_MODIFY);
@@ -236,6 +184,9 @@ void QWindowsSystemTrayIcon::updateToolTip(const QString &tooltip)
QRect QWindowsSystemTrayIcon::geometry() const
{
+ if (!isIconVisible())
+ return QRect();
+
NOTIFYICONIDENTIFIER nid;
memset(&nid, 0, sizeof(nid));
nid.cbSize = sizeof(nid);
@@ -269,25 +220,19 @@ void QWindowsSystemTrayIcon::showMessage(const QString &title, const QString &me
qStringToLimitedWCharArray(title, tnd.szInfoTitle, 64);
tnd.uID = q_uNOTIFYICONID;
- tnd.dwInfoFlags = NIIF_USER;
-
- QSize size(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON));
- const QSize largeIcon(GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON));
- const QSize more = icon.actualSize(largeIcon);
- if (more.height() > (largeIcon.height() * 3/4) || more.width() > (largeIcon.width() * 3/4)) {
- tnd.dwInfoFlags |= NIIF_LARGE_ICON;
- size = largeIcon;
- }
+
+ const auto size = icon.actualSize(QSize(256, 256));
QPixmap pm = icon.pixmap(size);
+ if (m_hMessageIcon) {
+ DestroyIcon(m_hMessageIcon);
+ m_hMessageIcon = nullptr;
+ }
if (pm.isNull()) {
tnd.dwInfoFlags = NIIF_INFO;
} else {
- if (pm.size() != size) {
- qWarning("QSystemTrayIcon::showMessage: Wrong icon size (%dx%d), please add standard one: %dx%d",
- pm.size().width(), pm.size().height(), size.width(), size.height());
- pm = pm.scaled(size, Qt::IgnoreAspectRatio);
- }
- tnd.hBalloonIcon = qt_pixmapToWinHICON(pm);
+ tnd.dwInfoFlags = NIIF_USER | NIIF_LARGE_ICON;
+ m_hMessageIcon = qt_pixmapToWinHICON(pm);
+ tnd.hBalloonIcon = m_hMessageIcon;
}
tnd.hWnd = m_hwnd;
tnd.uTimeout = msecsIn <= 0 ? UINT(10000) : UINT(msecsIn); // 10s default
@@ -345,7 +290,10 @@ void QWindowsSystemTrayIcon::ensureCleanup()
}
if (m_hIcon != nullptr)
DestroyIcon(m_hIcon);
+ if (m_hMessageIcon != nullptr)
+ DestroyIcon(m_hMessageIcon);
m_hIcon = nullptr;
+ m_hMessageIcon = nullptr;
m_menu = nullptr; // externally owned
m_toolTip.clear();
}
@@ -362,6 +310,29 @@ bool QWindowsSystemTrayIcon::setIconVisible(bool visible)
return Shell_NotifyIcon(NIM_MODIFY, &tnd) == TRUE;
}
+bool QWindowsSystemTrayIcon::isIconVisible() const
+{
+ NOTIFYICONIDENTIFIER nid;
+ memset(&nid, 0, sizeof(nid));
+ nid.cbSize = sizeof(nid);
+ nid.hWnd = m_hwnd;
+ nid.uID = q_uNOTIFYICONID;
+ RECT rect;
+ const HRESULT hr = Shell_NotifyIconGetRect(&nid, &rect);
+ // Windows 10 returns S_FALSE if the icon is hidden
+ if (FAILED(hr) || hr == S_FALSE)
+ return false;
+
+ HMONITOR monitor = MonitorFromWindow(m_hwnd, MONITOR_DEFAULTTONEAREST);
+ MONITORINFO info;
+ info.cbSize = sizeof(MONITORINFO);
+ GetMonitorInfo(monitor, &info);
+ // Windows 11 seems to return a geometry outside of the current monitor's geometry in case of
+ // the icon being hidden. As it's impossible to change the alignment of the task bar on Windows
+ // 11 this check should be fine.
+ return rect.bottom <= info.rcMonitor.bottom;
+}
+
bool QWindowsSystemTrayIcon::sendTrayMessage(DWORD msg)
{
NOTIFYICONDATA tnd;
@@ -424,8 +395,12 @@ bool QWindowsSystemTrayIcon::winEvent(const MSG &message, long *result)
if (screen) {
emit contextMenuRequested(globalPos, screen);
emit activated(Context);
- if (m_menu)
+ if (m_menu) {
+ // Set the foreground window to the controlling window so that clicking outside
+ // of the menu or window will cause the menu to close
+ SetForegroundWindow(m_hwnd);
m_menu->trackPopupMenu(message.hwnd, globalPos.x(), globalPos.y());
+ }
}
}
break;
@@ -451,8 +426,15 @@ bool QWindowsSystemTrayIcon::winEvent(const MSG &message, long *result)
QWindowsPopupMenu::notifyTriggered(LOWORD(message.wParam));
break;
default:
- if (message.message == MYWM_TASKBARCREATED) // self-registered message id (tray crashed)
+ if (message.message == MYWM_TASKBARCREATED) {
+ // self-registered message id to handle that
+ // - screen resolution/DPR changed
+ const QIcon oldIcon = m_icon;
+ m_icon = QIcon(); // updateIcon is a no-op if the icon doesn't change
+ updateIcon(oldIcon);
+ // - or tray crashed
sendTrayMessage(NIM_ADD);
+ }
break;
}
return false;
diff --git a/src/plugins/platforms/windows/qwindowssystemtrayicon.h b/src/plugins/platforms/windows/qwindowssystemtrayicon.h
index 44e1bcc761..3ad5feb125 100644
--- a/src/plugins/platforms/windows/qwindowssystemtrayicon.h
+++ b/src/plugins/platforms/windows/qwindowssystemtrayicon.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QWINDOWSSYSTEMTRAYICON_H
#define QWINDOWSSYSTEMTRAYICON_H
@@ -85,12 +49,14 @@ private:
void ensureCleanup();
bool sendTrayMessage(DWORD msg);
bool setIconVisible(bool visible);
+ bool isIconVisible() const;
HICON createIcon(const QIcon &icon);
QIcon m_icon;
QString m_toolTip;
HWND m_hwnd = nullptr;
HICON m_hIcon = nullptr;
+ HICON m_hMessageIcon = nullptr;
mutable QPointer<QWindowsPopupMenu> m_menu;
bool m_ignoreNextMouseRelease = false;
bool m_visible = false;
diff --git a/src/plugins/platforms/windows/qwindowstabletsupport.cpp b/src/plugins/platforms/windows/qwindowstabletsupport.cpp
index cd5a78abb6..ceebb483d2 100644
--- a/src/plugins/platforms/windows/qwindowstabletsupport.cpp
+++ b/src/plugins/platforms/windows/qwindowstabletsupport.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qwindowstabletsupport.h"
@@ -133,11 +97,10 @@ QDebug operator<<(QDebug d, const QWindowsTabletDeviceData &t)
{
QDebugStateSaver saver(d);
d.nospace();
- d << "TabletDevice id:" << t.uniqueId << " pressure: " << t.minPressure
+ d << "TabletDevice id:" << t.systemId << " pressure: " << t.minPressure
<< ".." << t.maxPressure << " tan pressure: " << t.minTanPressure << ".."
<< t.maxTanPressure << " area: (" << t.minX << ',' << t.minY << ',' << t.minZ
- << ")..(" << t.maxX << ',' << t.maxY << ',' << t.maxZ << ") device "
- << t.currentDevice << " pointer " << t.currentPointerType;
+ << ")..(" << t.maxX << ',' << t.maxY << ',' << t.maxZ << ')';
return d;
}
@@ -166,6 +129,48 @@ QDebug operator<<(QDebug d, const LOGCONTEXT &lc)
}
#endif // !QT_NO_DEBUG_STREAM
+QWinTabPointingDevice *createInputDevice(const QSharedPointer<QWindowsTabletDeviceData> &d,
+ QInputDevice::DeviceType devType,
+ QPointingDevice::PointerType pointerType)
+{
+ const qint64 uniqueId = d->systemId | (qint64(devType) << 32)
+ | (qint64(pointerType) << 48L);
+ QInputDevice::Capabilities caps(QInputDevice::Capability::Position
+ | QInputDevice::Capability::Pressure
+ | QInputDevice::Capability::MouseEmulation
+ | QInputDevice::Capability::Hover);
+ if (d->zCapability)
+ caps |= QInputDevice::Capability::ZPosition;
+ if (d->tiltCapability) {
+ caps |= QInputDevice::Capability::XTilt
+ | QInputDevice::Capability::YTilt
+ | QInputDevice::Capability::Rotation
+ | QInputDevice::Capability::TangentialPressure;
+ }
+
+ auto result = new QWinTabPointingDevice(d, QStringLiteral("wintab"), d->systemId,
+ devType, pointerType, caps, 1,
+ d->buttonsMap.size(), QString(),
+ QPointingDeviceUniqueId::fromNumericId(uniqueId));
+ QWindowSystemInterface::registerInputDevice(result);
+ return result;
+}
+
+QWinTabPointingDevice::QWinTabPointingDevice(const QWinTabPointingDevice::DeviceDataPtr &data,
+ const QString &name, qint64 systemId,
+ QInputDevice::DeviceType devType,
+ QPointingDevice::PointerType pType,
+ QInputDevice::Capabilities caps,
+ int maxPoints, int buttonCount,
+ const QString &seatName,
+ QPointingDeviceUniqueId uniqueId,
+ QObject *parent)
+ : QPointingDevice(name, systemId, devType, pType, caps, maxPoints, buttonCount,
+ seatName, uniqueId, parent),
+ m_deviceData(data)
+{
+}
+
QWindowsWinTab32DLL QWindowsTabletSupport::m_winTab32DLL;
/*!
@@ -173,7 +178,6 @@ QWindowsWinTab32DLL QWindowsTabletSupport::m_winTab32DLL;
\brief Functions from wintabl32.dll shipped with WACOM tablets used by QWindowsTabletSupport.
\internal
- \ingroup qt-lighthouse-win
*/
bool QWindowsWinTab32DLL::init()
@@ -205,9 +209,10 @@ bool QWindowsWinTab32DLL::init()
\internal
\since 5.2
- \ingroup qt-lighthouse-win
*/
+int QWindowsTabletSupport::m_absoluteRange = 20;
+
QWindowsTabletSupport::QWindowsTabletSupport(HWND window, HCTX context)
: m_window(window)
, m_context(context)
@@ -320,56 +325,103 @@ void QWindowsTabletSupport::notifyActivate()
qCDebug(lcQpaTablet) << __FUNCTION__ << result;
}
-static inline int indexOfDevice(const QVector<QWindowsTabletDeviceData> &devices, qint64 uniqueId)
-{
- for (int i = 0; i < devices.size(); ++i)
- if (devices.at(i).uniqueId == uniqueId)
- return i;
- return -1;
-}
-
-static inline QTabletEvent::TabletDevice deviceType(const UINT cursorType)
+static inline QInputDevice::DeviceType deviceType(const UINT cursorType)
{
if (((cursorType & 0x0006) == 0x0002) && ((cursorType & CursorTypeBitMask) != 0x0902))
- return QTabletEvent::Stylus;
+ return QInputDevice::DeviceType::Stylus;
if (cursorType == 0x4020) // Surface Pro 2 tablet device
- return QTabletEvent::Stylus;
+ return QInputDevice::DeviceType::Stylus;
switch (cursorType & CursorTypeBitMask) {
case 0x0802:
- return QTabletEvent::Stylus;
+ return QInputDevice::DeviceType::Stylus;
case 0x0902:
- return QTabletEvent::Airbrush;
+ return QInputDevice::DeviceType::Airbrush;
case 0x0004:
- return QTabletEvent::FourDMouse;
+ return QInputDevice::DeviceType::Mouse;
case 0x0006:
- return QTabletEvent::Puck;
+ return QInputDevice::DeviceType::Puck;
case 0x0804:
- return QTabletEvent::RotationStylus;
+ return QInputDevice::DeviceType::Stylus;
default:
break;
}
- return QTabletEvent::NoDevice;
+ return QInputDevice::DeviceType::Unknown;
}
-static inline QTabletEvent::PointerType pointerType(unsigned currentCursor)
+static inline QPointingDevice::PointerType pointerType(unsigned currentCursor)
{
switch (currentCursor % 3) { // %3 for dual track
case 0:
- return QTabletEvent::Cursor;
+ return QPointingDevice::PointerType::Cursor;
case 1:
- return QTabletEvent::Pen;
+ return QPointingDevice::PointerType::Pen;
case 2:
- return QTabletEvent::Eraser;
+ return QPointingDevice::PointerType::Eraser;
default:
break;
}
- return QTabletEvent::UnknownPointer;
+ return QPointingDevice::PointerType::Unknown;
}
-QWindowsTabletDeviceData QWindowsTabletSupport::tabletInit(qint64 uniqueId, UINT cursorType) const
+inline void QWindowsTabletSupport::enterProximity(ulong time, QWindow *window)
+{
+ enterLeaveProximity(true, time, window);
+}
+
+inline void QWindowsTabletSupport::leaveProximity(ulong time, QWindow *window)
+{
+ enterLeaveProximity(false, time, window);
+}
+
+void QWindowsTabletSupport::enterLeaveProximity(bool enter, ulong time, QWindow *window)
+{
+ Q_ASSERT(!m_currentDevice.isNull());
+ if (time == 0) // Some leave events do not have a time associated
+ ++m_eventTime;
+ else
+ m_eventTime = time;
+ QWindowSystemInterface::handleTabletEnterLeaveProximityEvent(window, m_eventTime,
+ m_currentDevice.data(),
+ enter);
+}
+
+QWindowsTabletSupport::DevicePtr QWindowsTabletSupport::findDevice(qint64 systemId) const
+{
+ for (const auto &d : m_devices) {
+ if (d->deviceData()->systemId == systemId)
+ return d;
+ }
+ return {};
+}
+
+QWindowsTabletSupport::DevicePtr QWindowsTabletSupport::findDevice(qint64 systemId,
+ QInputDevice::DeviceType deviceType,
+ QPointingDevice::PointerType pointerType) const
+{
+ for (const auto &d : m_devices) {
+ if (d->deviceData()->systemId == systemId && d->type() == deviceType
+ && d->pointerType() == pointerType) {
+ return d;
+ }
+ }
+ return {};
+}
+
+// Clone a device for a new pointer type.
+QWindowsTabletSupport::DevicePtr QWindowsTabletSupport::clonePhysicalDevice(qint64 systemId,
+ QInputDevice::DeviceType deviceType,
+ QPointingDevice::PointerType pointerType)
+{
+ auto similar = findDevice(systemId);
+ if (similar.isNull())
+ return {};
+ DevicePtr result(createInputDevice(similar->deviceData(), deviceType, pointerType));
+ m_devices.append(result);
+ return result;
+}
+
+void QWindowsTabletSupport::updateData(QWindowsTabletDeviceData *data) const
{
- QWindowsTabletDeviceData result;
- result.uniqueId = uniqueId;
/* browse WinTab's many info items to discover pressure handling. */
AXIS axis;
LOGCONTEXT lc;
@@ -377,21 +429,40 @@ QWindowsTabletDeviceData QWindowsTabletSupport::tabletInit(qint64 uniqueId, UINT
QWindowsTabletSupport::m_winTab32DLL.wTGet(m_context, &lc);
/* get the size of the pressure axis. */
QWindowsTabletSupport::m_winTab32DLL.wTInfo(WTI_DEVICES + lc.lcDevice, DVC_NPRESSURE, &axis);
- result.minPressure = int(axis.axMin);
- result.maxPressure = int(axis.axMax);
+ data->minPressure = int(axis.axMin);
+ data->maxPressure = int(axis.axMax);
QWindowsTabletSupport::m_winTab32DLL.wTInfo(WTI_DEVICES + lc.lcDevice, DVC_TPRESSURE, &axis);
- result.minTanPressure = int(axis.axMin);
- result.maxTanPressure = int(axis.axMax);
+ data->minTanPressure = int(axis.axMin);
+ data->maxTanPressure = int(axis.axMax);
LOGCONTEXT defaultLc;
/* get default region */
QWindowsTabletSupport::m_winTab32DLL.wTInfo(WTI_DEFCONTEXT, 0, &defaultLc);
- result.maxX = int(defaultLc.lcInExtX) - int(defaultLc.lcInOrgX);
- result.maxY = int(defaultLc.lcInExtY) - int(defaultLc.lcInOrgY);
- result.maxZ = int(defaultLc.lcInExtZ) - int(defaultLc.lcInOrgZ);
- result.currentDevice = deviceType(cursorType);
- return result;
+ data->maxX = int(defaultLc.lcInExtX) - int(defaultLc.lcInOrgX);
+ data->maxY = int(defaultLc.lcInExtY) - int(defaultLc.lcInOrgY);
+ data->maxZ = int(defaultLc.lcInExtZ) - int(defaultLc.lcInOrgZ);
+}
+
+void QWindowsTabletSupport::updateButtons(unsigned currentCursor, QWindowsTabletDeviceData *data) const
+{
+ // We should check button map for changes on every proximity event, not
+ // only during initialization phase.
+ // WARNING: in 2016 there were some Wacom tablet drivers, which could mess up
+ // button mapping if the remapped button was pressed, while the
+ // application **didn't have input focus**. This bug is somehow
+ // related to the fact that Wacom drivers allow user to configure
+ // per-application button-mappings. If the bug shows up again,
+ // just move this button-map fetching into initialization block.
+ //
+ // See https://bugs.kde.org/show_bug.cgi?id=359561
+ BYTE logicalButtons[32];
+ memset(logicalButtons, 0, 32);
+ m_winTab32DLL.wTInfo(WTI_CURSORS + currentCursor, CSR_SYSBTNMAP, &logicalButtons);
+ data->buttonsMap.clear();
+ data->buttonsMap[0x1] = logicalButtons[0];
+ data->buttonsMap[0x2] = logicalButtons[1];
+ data->buttonsMap[0x4] = logicalButtons[2];
}
bool QWindowsTabletSupport::translateTabletProximityEvent(WPARAM /* wParam */, LPARAM lParam)
@@ -400,21 +471,11 @@ bool QWindowsTabletSupport::translateTabletProximityEvent(WPARAM /* wParam */, L
const int totalPacks = QWindowsTabletSupport::m_winTab32DLL.wTPacketsGet(m_context, 1, proximityBuffer);
if (!LOWORD(lParam)) {
- qCDebug(lcQpaTablet) << "leave proximity for device #" << m_currentDevice;
- if (m_currentDevice < 0 || m_currentDevice >= m_devices.size()) // QTBUG-65120, spurious leave observed
+ if (m_currentDevice.isNull()) // QTBUG-65120, spurious leave observed
return false;
+ qCDebug(lcQpaTablet) << "leave proximity for device #" << m_currentDevice.data();
m_state = PenUp;
- if (totalPacks > 0) {
- QWindowSystemInterface::handleTabletLeaveProximityEvent(proximityBuffer[0].pkTime,
- m_devices.at(m_currentDevice).currentDevice,
- m_devices.at(m_currentDevice).currentPointerType,
- m_devices.at(m_currentDevice).uniqueId);
- } else {
- QWindowSystemInterface::handleTabletLeaveProximityEvent(m_devices.at(m_currentDevice).currentDevice,
- m_devices.at(m_currentDevice).currentPointerType,
- m_devices.at(m_currentDevice).uniqueId);
-
- }
+ leaveProximity(totalPacks > 0 ? proximityBuffer[0].pkTime : 0u);
return true;
}
@@ -424,46 +485,37 @@ bool QWindowsTabletSupport::translateTabletProximityEvent(WPARAM /* wParam */, L
const UINT currentCursor = proximityBuffer[0].pkCursor;
UINT physicalCursorId;
QWindowsTabletSupport::m_winTab32DLL.wTInfo(WTI_CURSORS + currentCursor, CSR_PHYSID, &physicalCursorId);
+ const qint64 systemId = physicalCursorId;
UINT cursorType;
QWindowsTabletSupport::m_winTab32DLL.wTInfo(WTI_CURSORS + currentCursor, CSR_TYPE, &cursorType);
- const qint64 uniqueId = (qint64(cursorType & DeviceIdMask) << 32L) | qint64(physicalCursorId);
+
+ const QInputDevice::DeviceType currentType = deviceType(cursorType);
+ const QPointingDevice::PointerType currentPointerType = pointerType(currentCursor);
// initializing and updating the cursor should be done in response to
// WT_CSRCHANGE. We do it in WT_PROXIMITY because some wintab never send
// the event WT_CSRCHANGE even if asked with CXO_CSRMESSAGES
- m_currentDevice = indexOfDevice(m_devices, uniqueId);
- if (m_currentDevice < 0) {
- m_currentDevice = m_devices.size();
- m_devices.push_back(tabletInit(uniqueId, cursorType));
+ m_currentDevice = findDevice(systemId, currentType, currentPointerType);
+ if (m_currentDevice.isNull())
+ m_currentDevice = clonePhysicalDevice(systemId, currentType, currentPointerType);
+ if (m_currentDevice.isNull()) {
+ QWinTabPointingDevice::DeviceDataPtr data(new QWindowsTabletDeviceData);
+ data->systemId = systemId;
+ data->tiltCapability = m_tiltSupport;
+ data->zCapability = (cursorType == 0x0004);
+ updateButtons(currentCursor, data.data());
+ m_currentDevice.reset(createInputDevice(data, currentType, currentPointerType));
+ m_devices.append(m_currentDevice);
}
- /**
- * We should check button map for changes on every proximity event, not
- * only during initialization phase.
- *
- * WARNING: in 2016 there were some Wacom table drivers, which could mess up
- * button mapping if the remapped button was pressed, while the
- * application **didn't have input focus**. This bug is somehow
- * related to the fact that Wacom drivers allow user to configure
- * per-application button-mappings. If the bug shows up again,
- * just move this button-map fetching into initialization block.
- *
- * See https://bugs.kde.org/show_bug.cgi?id=359561
- */
- BYTE logicalButtons[32];
- memset(logicalButtons, 0, 32);
- m_winTab32DLL.wTInfo(WTI_CURSORS + currentCursor, CSR_SYSBTNMAP, &logicalButtons);
- m_devices[m_currentDevice].buttonsMap[0x1] = logicalButtons[0];
- m_devices[m_currentDevice].buttonsMap[0x2] = logicalButtons[1];
- m_devices[m_currentDevice].buttonsMap[0x4] = logicalButtons[2];
+ // The user can switch pressure sensitivity level in the driver,which
+ // will make our saved values invalid (this option is provided by Wacom
+ // drivers for compatibility reasons, and it can be adjusted on the fly)
+ updateData(m_currentDevice->deviceData().data());
- m_devices[m_currentDevice].currentPointerType = pointerType(currentCursor);
m_state = PenProximity;
qCDebug(lcQpaTablet) << "enter proximity for device #"
- << m_currentDevice << m_devices.at(m_currentDevice);
- QWindowSystemInterface::handleTabletEnterProximityEvent(proximityBuffer[0].pkTime,
- m_devices.at(m_currentDevice).currentDevice,
- m_devices.at(m_currentDevice).currentPointerType,
- m_devices.at(m_currentDevice).uniqueId);
+ << m_currentDevice.data();
+ enterProximity(proximityBuffer[0].pkTime);
return true;
}
@@ -517,12 +569,10 @@ bool QWindowsTabletSupport::translateTabletPacketEvent()
{
static PACKET localPacketBuf[TabletPacketQSize]; // our own tablet packet queue.
const int packetCount = QWindowsTabletSupport::m_winTab32DLL.wTPacketsGet(m_context, TabletPacketQSize, &localPacketBuf);
- if (!packetCount || m_currentDevice < 0)
+ if (!packetCount || m_currentDevice.isNull())
return false;
- const int currentDevice = m_devices.at(m_currentDevice).currentDevice;
- const int currentPointer = m_devices.at(m_currentDevice).currentPointerType;
- const qint64 uniqueId = m_devices.at(m_currentDevice).uniqueId;
+ const QWindowsTabletDeviceData &current = *m_currentDevice->deviceData();
// The tablet can be used in 2 different modes (reflected in enum Mode),
// depending on its settings:
@@ -542,21 +592,40 @@ bool QWindowsTabletSupport::translateTabletPacketEvent()
if (QWindowsContext::verbose > 1) {
qCDebug(lcQpaTablet) << __FUNCTION__ << "processing" << packetCount
- << "mode=" << m_mode << "target:"
- << QGuiApplicationPrivate::tabletDevicePoint(uniqueId).target;
+ << "mode=" << m_mode;
}
- const Qt::KeyboardModifiers keyboardModifiers = QWindowsKeyMapper::queryKeyboardModifiers();
+ const auto *keyMapper = QWindowsContext::instance()->keyMapper();
+ const Qt::KeyboardModifiers keyboardModifiers = keyMapper->queryKeyboardModifiers();
for (int i = 0; i < packetCount ; ++i) {
const PACKET &packet = localPacketBuf[i];
- const int z = currentDevice == QTabletEvent::FourDMouse ? int(packet.pkZ) : 0;
+ const int z = current.zCapability ? int(packet.pkZ) : 0;
+
+ const auto packetPointerType = pointerType(packet.pkCursor);
+
+ const Qt::MouseButtons buttons =
+ convertTabletButtons(packet.pkButtons, current);
+
+ if (buttons == Qt::NoButton && packetPointerType != m_currentDevice->pointerType()) {
+ leaveProximity(packet.pkTime);
+ Q_ASSERT(!m_currentDevice.isNull());
+ // Pointer type changed, find or clone a new device for this physical cursor.
+ const qint64 systemId = m_currentDevice->systemId();
+ const QInputDevice::DeviceType type = m_currentDevice->type();
+ m_currentDevice = findDevice(systemId, type, packetPointerType);
+ if (m_currentDevice.isNull())
+ m_currentDevice = clonePhysicalDevice(systemId, type, packetPointerType);
+ Q_ASSERT(!m_currentDevice.isNull());
+ enterProximity(packet.pkTime);
+ }
QPointF globalPosF =
- m_devices.at(m_currentDevice).scaleCoordinates(packet.pkX, packet.pkY, virtualDesktopArea);
+ current.scaleCoordinates(packet.pkX, packet.pkY, virtualDesktopArea);
- QWindow *target = QGuiApplicationPrivate::tabletDevicePoint(uniqueId).target; // Pass to window that grabbed it.
+ // Pass to window that grabbed it.
+ QWindow *target = QGuiApplicationPrivate::tabletDevicePoint(m_currentDevice->uniqueId().numericId()).target;
// Get Mouse Position and compare to tablet info
const QPoint mouseLocation = QWindowsCursor::mousePosition();
@@ -580,12 +649,12 @@ bool QWindowsTabletSupport::translateTabletPacketEvent()
Q_ASSERT(platformWindow);
const QPoint localPos = platformWindow->mapFromGlobal(globalPos);
- const qreal pressureNew = packet.pkButtons && (currentPointer == QTabletEvent::Pen || currentPointer == QTabletEvent::Eraser) ?
- m_devices.at(m_currentDevice).scalePressure(packet.pkNormalPressure) :
- qreal(0);
- const qreal tangentialPressure = currentDevice == QTabletEvent::Airbrush ?
- m_devices.at(m_currentDevice).scaleTangentialPressure(packet.pkTangentPressure) :
- qreal(0);
+ const qreal pressureNew = packet.pkButtons
+ && (m_currentDevice->pointerType() == QPointingDevice::PointerType::Pen
+ || m_currentDevice->pointerType() == QPointingDevice::PointerType::Eraser)
+ ? current.scalePressure(packet.pkNormalPressure) : qreal(0);
+ const qreal tangentialPressure = m_currentDevice->type() == QInputDevice::DeviceType::Airbrush
+ ? current.scaleTangentialPressure(packet.pkTangentPressure) : qreal(0);
int tiltX = 0;
int tiltY = 0;
@@ -614,20 +683,18 @@ bool QWindowsTabletSupport::translateTabletPacketEvent()
qCDebug(lcQpaTablet)
<< "Packet #" << i << '/' << packetCount << "button:" << packet.pkButtons
<< globalPosF << z << "to:" << target << localPos << "(packet" << packet.pkX
- << packet.pkY << ") dev:" << currentDevice << "pointer:"
- << currentPointer << "P:" << pressureNew << "tilt:" << tiltX << ','
- << tiltY << "tanP:" << tangentialPressure << "rotation:" << rotation;
+ << packet.pkY << ") dev:" << m_currentDevice->type() << "pointer:"
+ << m_currentDevice->pointerType() << "P:" << pressureNew << "tilt:" << tiltX << ','
+ << tiltY << "tanP:" << tangentialPressure << "rotation:" << rotation
+ << " target=" << target;
}
- Qt::MouseButtons buttons =
- convertTabletButtons(packet.pkButtons, m_devices.at(m_currentDevice));
-
- QWindowSystemInterface::handleTabletEvent(target, packet.pkTime, QPointF(localPos), globalPosF,
- currentDevice, currentPointer,
- buttons,
- pressureNew, tiltX, tiltY,
+ m_eventTime = packet.pkTime;
+ QWindowSystemInterface::handleTabletEvent(target, packet.pkTime,
+ m_currentDevice.data(),
+ QPointF(localPos), globalPosF,
+ buttons, pressureNew, tiltX, tiltY,
tangentialPressure, rotation, z,
- uniqueId,
keyboardModifiers);
}
return true;
diff --git a/src/plugins/platforms/windows/qwindowstabletsupport.h b/src/plugins/platforms/windows/qwindowstabletsupport.h
index 6bcf3357a5..fb639294d3 100644
--- a/src/plugins/platforms/windows/qwindowstabletsupport.h
+++ b/src/plugins/platforms/windows/qwindowstabletsupport.h
@@ -1,51 +1,17 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QWINDOWSTABLETSUPPORT_H
#define QWINDOWSTABLETSUPPORT_H
#include "qtwindowsglobal.h"
#include <QtGui/qtguiglobal.h>
+#include <QtGui/qpointingdevice.h>
-#include <QtCore/qvector.h>
-#include <QtCore/qpoint.h>
#include <QtCore/qhash.h>
+#include <QtCore/qlist.h>
+#include <QtCore/qpoint.h>
+#include <QtCore/qsharedpointer.h>
#include <wintab.h>
@@ -82,6 +48,8 @@ struct QWindowsWinTab32DLL
PtrWTQueueSizeSet wTQueueSizeSet = nullptr;
};
+// Data associated with a physical cursor (system ID) which is shared between
+// devices of varying device type/pointer type.
struct QWindowsTabletDeviceData
{
QPointF scaleCoordinates(int coordX, int coordY,const QRect &targetArea) const;
@@ -98,12 +66,31 @@ struct QWindowsTabletDeviceData
int maxY = 0;
int minZ = 0;
int maxZ = 0;
- qint64 uniqueId = 0;
- int currentDevice = 0;
- int currentPointerType = 0;
+ qint64 systemId = 0;
+ bool zCapability = false;
+ bool tiltCapability = false;
QHash<quint8, quint8> buttonsMap;
};
+class QWinTabPointingDevice : public QPointingDevice
+{
+public:
+ using DeviceDataPtr = QSharedPointer<QWindowsTabletDeviceData>;
+
+ explicit QWinTabPointingDevice(const DeviceDataPtr &data,
+ const QString &name, qint64 systemId,
+ QInputDevice::DeviceType devType,
+ PointerType pType, Capabilities caps, int maxPoints,
+ int buttonCount, const QString &seatName = QString(),
+ QPointingDeviceUniqueId uniqueId = QPointingDeviceUniqueId(),
+ QObject *parent = nullptr);
+
+ const DeviceDataPtr &deviceData() const { return m_deviceData; }
+
+private:
+ DeviceDataPtr m_deviceData;
+};
+
#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug d, const QWindowsTabletDeviceData &t);
#endif
@@ -115,6 +102,9 @@ class QWindowsTabletSupport
explicit QWindowsTabletSupport(HWND window, HCTX context);
public:
+ using DevicePtr = QSharedPointer<QWinTabPointingDevice>;
+ using Devices = QList<DevicePtr>;
+
enum Mode
{
PenMode,
@@ -138,22 +128,35 @@ public:
bool translateTabletProximityEvent(WPARAM wParam, LPARAM lParam);
bool translateTabletPacketEvent();
- int absoluteRange() const { return m_absoluteRange; }
- void setAbsoluteRange(int a) { m_absoluteRange = a; }
+ static int absoluteRange() { return m_absoluteRange; }
+ static void setAbsoluteRange(int a) { m_absoluteRange = a; }
private:
unsigned options() const;
QWindowsTabletDeviceData tabletInit(qint64 uniqueId, UINT cursorType) const;
+ void updateData(QWindowsTabletDeviceData *data) const;
+ void updateButtons(unsigned currentCursor, QWindowsTabletDeviceData *data) const;
+ void enterProximity(ulong time = 0, QWindow *window = nullptr);
+ void leaveProximity(ulong time = 0, QWindow *window = nullptr);
+ void enterLeaveProximity(bool enter, ulong time, QWindow *window = nullptr);
+ DevicePtr findDevice(qint64 systemId) const;
+ DevicePtr findDevice(qint64 systemId,
+ QInputDevice::DeviceType deviceType,
+ QPointingDevice::PointerType pointerType) const;
+ DevicePtr clonePhysicalDevice(qint64 systemId,
+ QInputDevice::DeviceType deviceType,
+ QPointingDevice::PointerType pointerType);
static QWindowsWinTab32DLL m_winTab32DLL;
const HWND m_window;
const HCTX m_context;
- int m_absoluteRange = 20;
+ static int m_absoluteRange;
bool m_tiltSupport = false;
- QVector<QWindowsTabletDeviceData> m_devices;
- int m_currentDevice = -1;
+ Devices m_devices;
+ DevicePtr m_currentDevice;
Mode m_mode = PenMode;
State m_state = PenUp;
+ ulong m_eventTime = 0;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/windows/qwindowstheme.cpp b/src/plugins/platforms/windows/qwindowstheme.cpp
index 325956b7ba..b0b6672487 100644
--- a/src/plugins/platforms/windows/qwindowstheme.cpp
+++ b/src/plugins/platforms/windows/qwindowstheme.cpp
@@ -1,109 +1,58 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
-
-// SHSTOCKICONINFO is only available since Vista
-#if _WIN32_WINNT < 0x0601
-# undef _WIN32_WINNT
-# define _WIN32_WINNT 0x0601
-#endif
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <QtCore/qt_windows.h>
#include "qwindowstheme.h"
#include "qwindowsmenu.h"
#include "qwindowsdialoghelpers.h"
#include "qwindowscontext.h"
+#include "qwindowsiconengine.h"
#include "qwindowsintegration.h"
#if QT_CONFIG(systemtrayicon)
# include "qwindowssystemtrayicon.h"
#endif
-#include "qt_windows.h"
+#include "qwindowsscreen.h"
#include <commctrl.h>
#include <objbase.h>
-#ifndef Q_CC_MINGW
-# include <commoncontrols.h>
-#endif
+#include <commoncontrols.h>
#include <shellapi.h>
+#include <QtCore/qapplicationstatic.h>
#include <QtCore/qvariant.h>
#include <QtCore/qcoreapplication.h>
#include <QtCore/qdebug.h>
-#include <QtCore/qtextstream.h>
-#include <QtCore/qoperatingsystemversion.h>
#include <QtCore/qsysinfo.h>
#include <QtCore/qcache.h>
#include <QtCore/qthread.h>
+#include <QtCore/qqueue.h>
#include <QtCore/qmutex.h>
#include <QtCore/qwaitcondition.h>
+#include <QtCore/qoperatingsystemversion.h>
#include <QtGui/qcolor.h>
#include <QtGui/qpalette.h>
#include <QtGui/qguiapplication.h>
#include <QtGui/qpainter.h>
#include <QtGui/qpixmapcache.h>
#include <qpa/qwindowsysteminterface.h>
-#include <QtThemeSupport/private/qabstractfileiconengine_p.h>
-#include <QtFontDatabaseSupport/private/qwindowsfontdatabase_p.h>
+#include <QtGui/private/qabstractfileiconengine_p.h>
+#include <QtGui/private/qwindowsfontdatabase_p.h>
#include <private/qhighdpiscaling_p.h>
#include <private/qsystemlibrary_p.h>
#include <private/qwinregistry_p.h>
+#include <QtCore/private/qfunctions_win_p.h>
#include <algorithm>
-#if defined(__IImageList_INTERFACE_DEFINED__) && defined(__IID_DEFINED__)
-# define USE_IIMAGELIST
-#endif
+#if QT_CONFIG(cpp_winrt)
+# include <QtCore/private/qt_winrtbase_p.h>
-QT_BEGIN_NAMESPACE
+# include <winrt/Windows.UI.ViewManagement.h>
+#endif // QT_CONFIG(cpp_winrt)
-static inline QColor COLORREFToQColor(COLORREF cr)
-{
- return QColor(GetRValue(cr), GetGValue(cr), GetBValue(cr));
-}
+QT_BEGIN_NAMESPACE
-static inline QTextStream& operator<<(QTextStream &str, const QColor &c)
-{
- str.setIntegerBase(16);
- str.setFieldWidth(2);
- str.setPadChar(u'0');
- str << " rgb: #" << c.red() << c.green() << c.blue();
- str.setIntegerBase(10);
- str.setFieldWidth(0);
- return str;
-}
+using namespace Qt::StringLiterals;
static inline bool booleanSystemParametersInfo(UINT what, bool defaultValue)
{
@@ -128,129 +77,159 @@ static inline QColor mixColors(const QColor &c1, const QColor &c2)
(c1.blue() + c2.blue()) / 2};
}
+enum AccentColorLevel {
+ AccentColorDarkest,
+ AccentColorNormal,
+ AccentColorLightest
+};
+
+#if QT_CONFIG(cpp_winrt)
+static constexpr QColor getSysColor(winrt::Windows::UI::Color &&color)
+{
+ return QColor(color.R, color.G, color.B, color.A);
+}
+#endif
+
+[[maybe_unused]] [[nodiscard]] static inline QColor qt_accentColor(AccentColorLevel level)
+{
+#if QT_CONFIG(cpp_winrt)
+ using namespace winrt::Windows::UI::ViewManagement;
+ const auto settings = UISettings();
+ const QColor accent = getSysColor(settings.GetColorValue(UIColorType::Accent));
+ const QColor accentLight = getSysColor(settings.GetColorValue(UIColorType::AccentLight1));
+ const QColor accentDarkest = getSysColor(settings.GetColorValue(UIColorType::AccentDark3));
+#else
+ const QWinRegistryKey registry(HKEY_CURRENT_USER, LR"(Software\Microsoft\Windows\DWM)");
+ if (!registry.isValid())
+ return {};
+ const QVariant value = registry.value(L"AccentColor");
+ if (!value.isValid())
+ return {};
+ // The retrieved value is in the #AABBGGRR format, we need to
+ // convert it to the #AARRGGBB format which Qt expects.
+ const QColor abgr = QColor::fromRgba(qvariant_cast<DWORD>(value));
+ if (!abgr.isValid())
+ return {};
+ const QColor accent = QColor::fromRgb(abgr.blue(), abgr.green(), abgr.red(), abgr.alpha());
+ const QColor accentLight = accent.lighter(120);
+ const QColor accentDarkest = accent.darker(120 * 120 * 120);
+#endif
+ if (level == AccentColorDarkest)
+ return accentDarkest;
+ else if (level == AccentColorLightest)
+ return accentLight;
+ return accent;
+}
+
static inline QColor getSysColor(int index)
{
- return COLORREFToQColor(GetSysColor(index));
+ COLORREF cr = GetSysColor(index);
+ return QColor(GetRValue(cr), GetGValue(cr), GetBValue(cr));
}
// QTBUG-48823/Windows 10: SHGetFileInfo() (as called by item views on file system
// models has been observed to trigger a WM_PAINT on the mainwindow. Suppress the
// behavior by running it in a thread.
-
-struct QShGetFileInfoParams
-{
- QShGetFileInfoParams(const QString &fn, DWORD a, SHFILEINFO *i, UINT f, bool *r)
- : fileName(fn), attributes(a), flags(f), info(i), result(r)
- { }
-
- const QString &fileName;
- const DWORD attributes;
- const UINT flags;
- SHFILEINFO *const info;
- bool *const result;
-};
-
class QShGetFileInfoThread : public QThread
{
public:
- explicit QShGetFileInfoThread()
- : QThread(), m_params(nullptr)
+ struct Task
+ {
+ Task(const QString &fn, DWORD a, UINT f)
+ : fileName(fn), attributes(a), flags(f)
+ {}
+ Q_DISABLE_COPY(Task)
+ ~Task()
+ {
+ DestroyIcon(hIcon);
+ hIcon = 0;
+ }
+ // Request
+ const QString fileName;
+ const DWORD attributes;
+ const UINT flags;
+ // Result
+ HICON hIcon = 0;
+ int iIcon = -1;
+ bool finished = false;
+ bool resultValid() const { return hIcon != 0 && iIcon >= 0 && finished; }
+ };
+
+ QShGetFileInfoThread()
+ : QThread()
{
- connect(this, &QThread::finished, this, &QObject::deleteLater);
+ start();
}
- void run() override
+ ~QShGetFileInfoThread()
{
- m_init = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
+ cancel();
+ wait();
+ }
- QMutexLocker readyLocker(&m_readyMutex);
- while (!m_cancelled.loadRelaxed()) {
- if (!m_params && !m_cancelled.loadRelaxed()
- && !m_readyCondition.wait(&m_readyMutex, QDeadlineTimer(1000ll)))
- continue;
+ QSharedPointer<Task> getNextTask()
+ {
+ QMutexLocker l(&m_waitForTaskMutex);
+ while (!isInterruptionRequested()) {
+ if (!m_taskQueue.isEmpty())
+ return m_taskQueue.dequeue();
+ m_waitForTaskCondition.wait(&m_waitForTaskMutex);
+ }
+ return nullptr;
+ }
- if (m_params) {
- const QString fileName = m_params->fileName;
+ void run() override
+ {
+ QComHelper comHelper(COINIT_MULTITHREADED);
+
+ while (!isInterruptionRequested()) {
+ auto task = getNextTask();
+ if (task) {
SHFILEINFO info;
- const bool result = SHGetFileInfo(reinterpret_cast<const wchar_t *>(fileName.utf16()),
- m_params->attributes, &info, sizeof(SHFILEINFO),
- m_params->flags);
- m_doneMutex.lock();
- if (!m_cancelled.loadRelaxed()) {
- *m_params->result = result;
- memcpy(m_params->info, &info, sizeof(SHFILEINFO));
+ const bool result = SHGetFileInfo(reinterpret_cast<const wchar_t *>(task->fileName.utf16()),
+ task->attributes, &info, sizeof(SHFILEINFO),
+ task->flags);
+ if (result) {
+ task->hIcon = info.hIcon;
+ task->iIcon = info.iIcon;
}
- m_params = nullptr;
-
+ task->finished = true;
m_doneCondition.wakeAll();
- m_doneMutex.unlock();
}
}
-
- if (m_init != S_FALSE)
- CoUninitialize();
}
- bool runWithParams(QShGetFileInfoParams *params, qint64 timeOutMSecs)
+ void runWithParams(const QSharedPointer<Task> &task,
+ std::chrono::milliseconds timeout = std::chrono::milliseconds(5000))
{
- QMutexLocker doneLocker(&m_doneMutex);
-
- m_readyMutex.lock();
- m_params = params;
- m_readyCondition.wakeAll();
- m_readyMutex.unlock();
+ {
+ QMutexLocker l(&m_waitForTaskMutex);
+ m_taskQueue.enqueue(task);
+ m_waitForTaskCondition.wakeAll();
+ }
- return m_doneCondition.wait(&m_doneMutex, QDeadlineTimer(timeOutMSecs));
+ QMutexLocker doneLocker(&m_doneMutex);
+ while (!task->finished && !isInterruptionRequested()) {
+ if (!m_doneCondition.wait(&m_doneMutex, QDeadlineTimer(timeout)))
+ return;
+ }
}
void cancel()
{
- QMutexLocker doneLocker(&m_doneMutex);
- m_cancelled.storeRelaxed(1);
- m_readyCondition.wakeAll();
+ requestInterruption();
+ m_doneCondition.wakeAll();
+ m_waitForTaskCondition.wakeAll();
}
private:
- HRESULT m_init;
- QShGetFileInfoParams *m_params;
- QAtomicInt m_cancelled;
- QWaitCondition m_readyCondition;
+ QQueue<QSharedPointer<Task>> m_taskQueue;
QWaitCondition m_doneCondition;
- QMutex m_readyMutex;
+ QWaitCondition m_waitForTaskCondition;
QMutex m_doneMutex;
+ QMutex m_waitForTaskMutex;
};
-
-static bool shGetFileInfoBackground(const QString &fileName, DWORD attributes,
- SHFILEINFO *info, UINT flags,
- qint64 timeOutMSecs = 5000)
-{
- static QShGetFileInfoThread *getFileInfoThread = nullptr;
- if (!getFileInfoThread) {
- getFileInfoThread = new QShGetFileInfoThread;
- getFileInfoThread->start();
- }
-
- bool result = false;
- QShGetFileInfoParams params(fileName, attributes, info, flags, &result);
- if (!getFileInfoThread->runWithParams(&params, timeOutMSecs)) {
- // Cancel and reset getFileInfoThread. It'll
- // be reinitialized the next time we get called.
- getFileInfoThread->cancel();
- getFileInfoThread = nullptr;
- qWarning().noquote() << "SHGetFileInfo() timed out for " << fileName;
- return false;
- }
- return result;
-}
-
-// Dark Mode constants
-enum DarkModeColors : QRgb {
- darkModeBtnHighlightRgb = 0xc0c0c0,
- darkModeBtnShadowRgb = 0x808080,
- darkModeHighlightRgb = 0x0055ff, // deviating from 0x800080
- darkModeMenuHighlightRgb = darkModeHighlightRgb,
- darkModeGrayTextRgb = 0x00ff00
-};
+Q_APPLICATION_STATIC(QShGetFileInfoThread, s_shGetFileInfoThread)
// from QStyle::standardPalette
static inline QPalette standardPalette()
@@ -269,57 +248,47 @@ static inline QPalette standardPalette()
return palette;
}
+static QColor placeHolderColor(QColor textColor)
+{
+ textColor.setAlpha(128);
+ return textColor;
+}
+
+/*
+ This is used when the theme is light mode, and when the theme is dark but the
+ application doesn't support dark mode. In the latter case, we need to check.
+*/
static void populateLightSystemBasePalette(QPalette &result)
{
+ const QColor background = getSysColor(COLOR_BTNFACE);
+ const QColor textColor = getSysColor(COLOR_WINDOWTEXT);
+
+ const QColor accent = qt_accentColor(AccentColorNormal);
+ const QColor accentDarkest = qt_accentColor(AccentColorDarkest);
+
+ const QColor linkColor = accent;
+ const QColor btnFace = background;
+ const QColor btnHighlight = getSysColor(COLOR_BTNHIGHLIGHT);
+
+ result.setColor(QPalette::Highlight, getSysColor(COLOR_HIGHLIGHT));
result.setColor(QPalette::WindowText, getSysColor(COLOR_WINDOWTEXT));
- const QColor btnFace = getSysColor(COLOR_BTNFACE);
result.setColor(QPalette::Button, btnFace);
- const QColor btnHighlight = getSysColor(COLOR_BTNHIGHLIGHT);
result.setColor(QPalette::Light, btnHighlight);
result.setColor(QPalette::Dark, getSysColor(COLOR_BTNSHADOW));
result.setColor(QPalette::Mid, result.button().color().darker(150));
- result.setColor(QPalette::Text, getSysColor(COLOR_WINDOWTEXT));
+ result.setColor(QPalette::Text, textColor);
+ result.setColor(QPalette::PlaceholderText, placeHolderColor(textColor));
result.setColor(QPalette::BrightText, btnHighlight);
result.setColor(QPalette::Base, getSysColor(COLOR_WINDOW));
result.setColor(QPalette::Window, btnFace);
result.setColor(QPalette::ButtonText, getSysColor(COLOR_BTNTEXT));
result.setColor(QPalette::Midlight, getSysColor(COLOR_3DLIGHT));
result.setColor(QPalette::Shadow, getSysColor(COLOR_3DDKSHADOW));
- result.setColor(QPalette::Highlight, getSysColor(COLOR_HIGHLIGHT));
result.setColor(QPalette::HighlightedText, getSysColor(COLOR_HIGHLIGHTTEXT));
-}
-
-static void populateDarkSystemBasePalette(QPalette &result)
-{
- const QColor darkModeWindowText = Qt::white;
- result.setColor(QPalette::WindowText, darkModeWindowText);
- const QColor darkModebtnFace = Qt::black;
- result.setColor(QPalette::Button, darkModebtnFace);
- const QColor btnHighlight = QColor(darkModeBtnHighlightRgb);
- result.setColor(QPalette::Light, btnHighlight);
- result.setColor(QPalette::Dark, QColor(darkModeBtnShadowRgb));
- result.setColor(QPalette::Mid, result.button().color().darker(150));
- result.setColor(QPalette::Text, darkModeWindowText);
- result.setColor(QPalette::BrightText, btnHighlight);
- result.setColor(QPalette::Base, darkModebtnFace);
- result.setColor(QPalette::Window, darkModebtnFace);
- result.setColor(QPalette::ButtonText, darkModeWindowText);
- result.setColor(QPalette::Midlight, darkModeWindowText);
- result.setColor(QPalette::Shadow, darkModeWindowText);
- result.setColor(QPalette::Highlight, QColor(darkModeHighlightRgb));
- result.setColor(QPalette::HighlightedText, darkModeWindowText);
-}
-
-static QPalette systemPalette(bool light)
-{
- QPalette result = standardPalette();
- if (light)
- populateLightSystemBasePalette(result);
- else
- populateDarkSystemBasePalette(result);
+ result.setColor(QPalette::Accent, accent);
- result.setColor(QPalette::Link, Qt::blue);
- result.setColor(QPalette::LinkVisited, Qt::magenta);
+ result.setColor(QPalette::Link, linkColor);
+ result.setColor(QPalette::LinkVisited, accentDarkest);
result.setColor(QPalette::Inactive, QPalette::Button, result.button().color());
result.setColor(QPalette::Inactive, QPalette::Window, result.window().color());
result.setColor(QPalette::Inactive, QPalette::Light, result.light().color());
@@ -327,35 +296,79 @@ static QPalette systemPalette(bool light)
if (result.midlight() == result.button())
result.setColor(QPalette::Midlight, result.button().color().lighter(110));
- if (result.window() != result.base()) {
- result.setColor(QPalette::Inactive, QPalette::Highlight, result.color(QPalette::Inactive, QPalette::Window));
- result.setColor(QPalette::Inactive, QPalette::HighlightedText, result.color(QPalette::Inactive, QPalette::Text));
- }
-
- const QColor disabled =
- mixColors(result.windowText().color(), result.button().color());
+}
- result.setColorGroup(QPalette::Disabled, result.windowText(), result.button(),
- result.light(), result.dark(), result.mid(),
- result.text(), result.brightText(), result.base(),
- result.window());
- result.setColor(QPalette::Disabled, QPalette::WindowText, disabled);
- result.setColor(QPalette::Disabled, QPalette::Text, disabled);
- result.setColor(QPalette::Disabled, QPalette::ButtonText, disabled);
- result.setColor(QPalette::Disabled, QPalette::Highlight,
- light ? getSysColor(COLOR_HIGHLIGHT) : QColor(darkModeHighlightRgb));
- result.setColor(QPalette::Disabled, QPalette::HighlightedText,
- light ? getSysColor(COLOR_HIGHLIGHTTEXT) : QColor(Qt::white));
- result.setColor(QPalette::Disabled, QPalette::Base,
- result.window().color());
- return result;
+static void populateDarkSystemBasePalette(QPalette &result)
+{
+#if QT_CONFIG(cpp_winrt)
+ using namespace winrt::Windows::UI::ViewManagement;
+ const auto settings = UISettings();
+
+ // We have to craft a palette from these colors. The settings.UIElementColor(UIElementType) API
+ // returns the old system colors, not the dark mode colors. If the background is black (which it
+ // usually), then override it with a dark gray instead so that we can go up and down the lightness.
+ const QColor foreground = getSysColor(settings.GetColorValue(UIColorType::Foreground));
+ const QColor background = [&settings]() -> QColor {
+ auto systemBackground = getSysColor(settings.GetColorValue(UIColorType::Background));
+ if (systemBackground == Qt::black)
+ systemBackground = QColor(0x1E, 0x1E, 0x1E);
+ return systemBackground;
+ }();
+
+ const QColor accent = getSysColor(settings.GetColorValue(UIColorType::Accent));
+ const QColor accentDark = getSysColor(settings.GetColorValue(UIColorType::AccentDark1));
+ const QColor accentDarker = getSysColor(settings.GetColorValue(UIColorType::AccentDark2));
+ const QColor accentDarkest = getSysColor(settings.GetColorValue(UIColorType::AccentDark3));
+ const QColor accentLight = getSysColor(settings.GetColorValue(UIColorType::AccentLight1));
+ const QColor accentLighter = getSysColor(settings.GetColorValue(UIColorType::AccentLight2));
+ const QColor accentLightest = getSysColor(settings.GetColorValue(UIColorType::AccentLight3));
+#else
+ const QColor foreground = Qt::white;
+ const QColor background = QColor(0x1E, 0x1E, 0x1E);
+ const QColor accent = qt_accentColor(AccentColorNormal);
+ const QColor accentDark = accent.darker(120);
+ const QColor accentDarker = accentDark.darker(120);
+ const QColor accentDarkest = accentDarker.darker(120);
+ const QColor accentLight = accent.lighter(120);
+ const QColor accentLighter = accentLight.lighter(120);
+ const QColor accentLightest = accentLighter.lighter(120);
+#endif
+ const QColor linkColor = accent;
+ const QColor buttonColor = background.lighter(200);
+
+ result.setColor(QPalette::All, QPalette::WindowText, foreground);
+ result.setColor(QPalette::All, QPalette::Text, foreground);
+ result.setColor(QPalette::All, QPalette::BrightText, accentLightest);
+
+ result.setColor(QPalette::All, QPalette::Button, buttonColor);
+ result.setColor(QPalette::All, QPalette::ButtonText, foreground);
+ result.setColor(QPalette::All, QPalette::Light, buttonColor.lighter(200));
+ result.setColor(QPalette::All, QPalette::Midlight, buttonColor.lighter(150));
+ result.setColor(QPalette::All, QPalette::Dark, buttonColor.darker(200));
+ result.setColor(QPalette::All, QPalette::Mid, buttonColor.darker(150));
+ result.setColor(QPalette::All, QPalette::Shadow, Qt::black);
+
+ result.setColor(QPalette::All, QPalette::Base, background.lighter(150));
+ result.setColor(QPalette::All, QPalette::Window, background);
+
+ result.setColor(QPalette::All, QPalette::Highlight, accent);
+ result.setColor(QPalette::All, QPalette::HighlightedText, accent.lightness() > 128 ? Qt::black : Qt::white);
+ result.setColor(QPalette::All, QPalette::Link, linkColor);
+ result.setColor(QPalette::All, QPalette::LinkVisited, accentDarkest);
+ result.setColor(QPalette::All, QPalette::AlternateBase, accentDarkest);
+ result.setColor(QPalette::All, QPalette::ToolTipBase, buttonColor);
+ result.setColor(QPalette::All, QPalette::ToolTipText, foreground.darker(120));
+ result.setColor(QPalette::All, QPalette::PlaceholderText, placeHolderColor(foreground));
+ result.setColor(QPalette::All, QPalette::Accent, accent);
}
static inline QPalette toolTipPalette(const QPalette &systemPalette, bool light)
{
QPalette result(systemPalette);
- const QColor tipBgColor = light ? getSysColor(COLOR_INFOBK) : QColor(Qt::black);
- const QColor tipTextColor = light ? getSysColor(COLOR_INFOTEXT) : QColor(Qt::white);
+ const QColor tipBgColor = light ? getSysColor(COLOR_INFOBK)
+ : systemPalette.button().color();
+ const QColor tipTextColor = light ? getSysColor(COLOR_INFOTEXT)
+ : systemPalette.buttonText().color().darker(120);
result.setColor(QPalette::All, QPalette::Button, tipBgColor);
result.setColor(QPalette::All, QPalette::Window, tipBgColor);
@@ -369,8 +382,7 @@ static inline QPalette toolTipPalette(const QPalette &systemPalette, bool light)
result.setColor(QPalette::All, QPalette::ButtonText, tipTextColor);
result.setColor(QPalette::All, QPalette::ToolTipBase, tipBgColor);
result.setColor(QPalette::All, QPalette::ToolTipText, tipTextColor);
- const QColor disabled =
- mixColors(result.windowText().color(), result.button().color());
+ const QColor disabled = mixColors(result.windowText().color(), result.button().color());
result.setColor(QPalette::Disabled, QPalette::WindowText, disabled);
result.setColor(QPalette::Disabled, QPalette::Text, disabled);
result.setColor(QPalette::Disabled, QPalette::ToolTipText, disabled);
@@ -382,11 +394,13 @@ static inline QPalette toolTipPalette(const QPalette &systemPalette, bool light)
static inline QPalette menuPalette(const QPalette &systemPalette, bool light)
{
+ if (!light)
+ return systemPalette;
+
QPalette result(systemPalette);
- const QColor menuColor = light ? getSysColor(COLOR_MENU) : QColor(Qt::black);
- const QColor menuTextColor = light ? getSysColor(COLOR_MENUTEXT) : QColor(Qt::white);
- const QColor disabled = light
- ? getSysColor(COLOR_GRAYTEXT) : QColor(darkModeGrayTextRgb);
+ const QColor menuColor = getSysColor(COLOR_MENU);
+ const QColor menuTextColor = getSysColor(COLOR_MENUTEXT);
+ const QColor disabled = getSysColor(COLOR_GRAYTEXT);
// we might need a special color group for the result.
result.setColor(QPalette::Active, QPalette::Button, menuColor);
result.setColor(QPalette::Active, QPalette::Text, menuTextColor);
@@ -395,9 +409,7 @@ static inline QPalette menuPalette(const QPalette &systemPalette, bool light)
result.setColor(QPalette::Disabled, QPalette::WindowText, disabled);
result.setColor(QPalette::Disabled, QPalette::Text, disabled);
const bool isFlat = booleanSystemParametersInfo(SPI_GETFLATMENU, false);
- const QColor highlightColor = light
- ? (getSysColor(isFlat ? COLOR_MENUHILIGHT : COLOR_HIGHLIGHT))
- : QColor(darkModeMenuHighlightRgb);
+ const QColor highlightColor = getSysColor(isFlat ? COLOR_MENUHILIGHT : COLOR_HIGHLIGHT);
result.setColor(QPalette::Disabled, QPalette::Highlight, highlightColor);
result.setColor(QPalette::Disabled, QPalette::HighlightedText, disabled);
result.setColor(QPalette::Disabled, QPalette::Button,
@@ -422,13 +434,14 @@ static inline QPalette menuPalette(const QPalette &systemPalette, bool light)
static inline QPalette *menuBarPalette(const QPalette &menuPalette, bool light)
{
QPalette *result = nullptr;
- if (booleanSystemParametersInfo(SPI_GETFLATMENU, false)) {
- result = new QPalette(menuPalette);
- const QColor menubar(light ? getSysColor(COLOR_MENUBAR) : QColor(Qt::black));
- result->setColor(QPalette::Active, QPalette::Button, menubar);
- result->setColor(QPalette::Disabled, QPalette::Button, menubar);
- result->setColor(QPalette::Inactive, QPalette::Button, menubar);
- }
+ if (!light || !booleanSystemParametersInfo(SPI_GETFLATMENU, false))
+ return result;
+
+ result = new QPalette(menuPalette);
+ const QColor menubar(getSysColor(COLOR_MENUBAR));
+ result->setColor(QPalette::Active, QPalette::Button, menubar);
+ result->setColor(QPalette::Disabled, QPalette::Button, menubar);
+ result->setColor(QPalette::Inactive, QPalette::Button, menubar);
return result;
}
@@ -453,13 +466,16 @@ QWindowsTheme::~QWindowsTheme()
static inline QStringList iconThemeSearchPaths()
{
- const QFileInfo appDir(QCoreApplication::applicationDirPath() + QLatin1String("/icons"));
+ const QFileInfo appDir(QCoreApplication::applicationDirPath() + "/icons"_L1);
return appDir.isDir() ? QStringList(appDir.absoluteFilePath()) : QStringList();
}
static inline QStringList styleNames()
{
- return { QStringLiteral("WindowsVista"), QStringLiteral("Windows") };
+ QStringList styles = { QStringLiteral("WindowsVista"), QStringLiteral("Windows") };
+ if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows11)
+ styles.prepend(QStringLiteral("Windows11"));
+ return styles;
}
static inline int uiEffects()
@@ -514,12 +530,21 @@ QVariant QWindowsTheme::themeHint(ThemeHint hint) const
}
case MouseDoubleClickDistance:
return GetSystemMetrics(SM_CXDOUBLECLK);
+ case MenuBarFocusOnAltPressRelease:
+ return true;
default:
break;
}
return QPlatformTheme::themeHint(hint);
}
+Qt::ColorScheme QWindowsTheme::colorScheme() const
+{
+ if (queryHighContrast())
+ return Qt::ColorScheme::Unknown;
+ return QWindowsContext::isDarkMode() ? Qt::ColorScheme::Dark : Qt::ColorScheme::Light;
+}
+
void QWindowsTheme::clearPalettes()
{
qDeleteAll(m_palettes, m_palettes + NPalettes);
@@ -528,29 +553,64 @@ void QWindowsTheme::clearPalettes()
void QWindowsTheme::refreshPalettes()
{
-
if (!QGuiApplication::desktopSettingsAware())
return;
const bool light =
!QWindowsContext::isDarkMode()
- || (QWindowsIntegration::instance()->options() & QWindowsIntegration::DarkModeStyle) == 0;
- m_palettes[SystemPalette] = new QPalette(systemPalette(light));
+ || !QWindowsIntegration::instance()->darkModeHandling().testFlag(QWindowsApplication::DarkModeStyle);
+ clearPalettes();
+ m_palettes[SystemPalette] = new QPalette(QWindowsTheme::systemPalette(light ? Qt::ColorScheme::Light : Qt::ColorScheme::Dark));
m_palettes[ToolTipPalette] = new QPalette(toolTipPalette(*m_palettes[SystemPalette], light));
m_palettes[MenuPalette] = new QPalette(menuPalette(*m_palettes[SystemPalette], light));
m_palettes[MenuBarPalette] = menuBarPalette(*m_palettes[MenuPalette], light);
if (!light) {
- m_palettes[ButtonPalette] = new QPalette(*m_palettes[SystemPalette]);
- m_palettes[ButtonPalette]->setColor(QPalette::Button, QColor(0x666666u));
- const QColor checkBoxBlue(0x0078d7u);
- const QColor white(Qt::white);
m_palettes[CheckBoxPalette] = new QPalette(*m_palettes[SystemPalette]);
- m_palettes[CheckBoxPalette]->setColor(QPalette::Window, checkBoxBlue);
- m_palettes[CheckBoxPalette]->setColor(QPalette::Base, checkBoxBlue);
- m_palettes[CheckBoxPalette]->setColor(QPalette::Button, checkBoxBlue);
- m_palettes[CheckBoxPalette]->setColor(QPalette::ButtonText, white);
+ m_palettes[CheckBoxPalette]->setColor(QPalette::Active, QPalette::Base, qt_accentColor(AccentColorNormal));
+ m_palettes[CheckBoxPalette]->setColor(QPalette::Active, QPalette::Button, qt_accentColor(AccentColorLightest));
+ m_palettes[CheckBoxPalette]->setColor(QPalette::Inactive, QPalette::Base, qt_accentColor(AccentColorDarkest));
m_palettes[RadioButtonPalette] = new QPalette(*m_palettes[CheckBoxPalette]);
+ }
+}
+QPalette QWindowsTheme::systemPalette(Qt::ColorScheme colorScheme)
+{
+ QPalette result = standardPalette();
+
+ switch (colorScheme) {
+ case Qt::ColorScheme::Light:
+ populateLightSystemBasePalette(result);
+ break;
+ case Qt::ColorScheme::Dark:
+ populateDarkSystemBasePalette(result);
+ break;
+ default:
+ qFatal("Unknown color scheme");
+ break;
+ }
+
+ if (result.window() != result.base()) {
+ result.setColor(QPalette::Inactive, QPalette::Highlight,
+ result.color(QPalette::Inactive, QPalette::Window));
+ result.setColor(QPalette::Inactive, QPalette::HighlightedText,
+ result.color(QPalette::Inactive, QPalette::Text));
+ result.setColor(QPalette::Inactive, QPalette::Accent,
+ result.color(QPalette::Inactive, QPalette::Window));
}
+
+ const QColor disabled = mixColors(result.windowText().color(), result.button().color());
+
+ result.setColorGroup(QPalette::Disabled, result.windowText(), result.button(),
+ result.light(), result.dark(), result.mid(),
+ result.text(), result.brightText(), result.base(),
+ result.window());
+ result.setColor(QPalette::Disabled, QPalette::WindowText, disabled);
+ result.setColor(QPalette::Disabled, QPalette::Text, disabled);
+ result.setColor(QPalette::Disabled, QPalette::ButtonText, disabled);
+ result.setColor(QPalette::Disabled, QPalette::Highlight, result.color(QPalette::Highlight));
+ result.setColor(QPalette::Disabled, QPalette::HighlightedText, result.color(QPalette::HighlightedText));
+ result.setColor(QPalette::Disabled, QPalette::Accent, disabled);
+ result.setColor(QPalette::Disabled, QPalette::Base, result.window().color());
+ return result;
}
void QWindowsTheme::clearFonts()
@@ -565,23 +625,49 @@ void QWindowsTheme::refresh()
refreshFonts();
}
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug d, const NONCLIENTMETRICS &m)
+{
+ QDebugStateSaver saver(d);
+ d.nospace();
+ d.noquote();
+ d << "NONCLIENTMETRICS(iMenu=" << m.iMenuWidth << 'x' << m.iMenuHeight
+ << ", lfCaptionFont=";
+ QWindowsFontDatabase::debugFormat(d, m.lfCaptionFont);
+ d << ", lfSmCaptionFont=";
+ QWindowsFontDatabase::debugFormat(d, m.lfSmCaptionFont);
+ d << ", lfMenuFont=";
+ QWindowsFontDatabase::debugFormat(d, m.lfMenuFont);
+ d << ", lfMessageFont=";
+ QWindowsFontDatabase::debugFormat(d, m.lfMessageFont);
+ d <<", lfStatusFont=";
+ QWindowsFontDatabase::debugFormat(d, m.lfStatusFont);
+ d << ')';
+ return d;
+}
+#endif // QT_NO_DEBUG_STREAM
+
void QWindowsTheme::refreshFonts()
{
clearFonts();
if (!QGuiApplication::desktopSettingsAware())
return;
+
+ const int dpi = 96;
NONCLIENTMETRICS ncm;
- QWindowsContext::nonClientMetrics(&ncm);
- const QFont menuFont = QWindowsFontDatabase::LOGFONT_to_QFont(ncm.lfMenuFont);
- const QFont messageBoxFont = QWindowsFontDatabase::LOGFONT_to_QFont(ncm.lfMessageFont);
- const QFont statusFont = QWindowsFontDatabase::LOGFONT_to_QFont(ncm.lfStatusFont);
- const QFont titleFont = QWindowsFontDatabase::LOGFONT_to_QFont(ncm.lfCaptionFont);
+ QWindowsContext::nonClientMetrics(&ncm, dpi);
+ qCDebug(lcQpaWindow) << __FUNCTION__ << ncm;
+
+ const QFont menuFont = QWindowsFontDatabase::LOGFONT_to_QFont(ncm.lfMenuFont, dpi);
+ const QFont messageBoxFont = QWindowsFontDatabase::LOGFONT_to_QFont(ncm.lfMessageFont, dpi);
+ const QFont statusFont = QWindowsFontDatabase::LOGFONT_to_QFont(ncm.lfStatusFont, dpi);
+ const QFont titleFont = QWindowsFontDatabase::LOGFONT_to_QFont(ncm.lfCaptionFont, dpi);
QFont fixedFont(QStringLiteral("Courier New"), messageBoxFont.pointSize());
fixedFont.setStyleHint(QFont::TypeWriter);
LOGFONT lfIconTitleFont;
- SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(lfIconTitleFont), &lfIconTitleFont, 0);
- const QFont iconTitleFont = QWindowsFontDatabase::LOGFONT_to_QFont(lfIconTitleFont);
+ SystemParametersInfoForDpi(SPI_GETICONTITLELOGFONT, sizeof(lfIconTitleFont), &lfIconTitleFont, 0, dpi);
+ const QFont iconTitleFont = QWindowsFontDatabase::LOGFONT_to_QFont(lfIconTitleFont, dpi);
m_fonts[SystemFont] = new QFont(QWindowsFontDatabase::systemDefaultFont());
m_fonts[MenuFont] = new QFont(menuFont);
@@ -638,13 +724,9 @@ void QWindowsTheme::refreshIconPixmapSizes()
fileIconSizes[LargeFileIcon] + fileIconSizes[LargeFileIcon] / 2;
fileIconSizes[JumboFileIcon] = 8 * fileIconSizes[LargeFileIcon]; // empirical, has not been observed to work
-#ifdef USE_IIMAGELIST
int *availEnd = fileIconSizes + JumboFileIcon + 1;
-#else
- int *availEnd = fileIconSizes + LargeFileIcon + 1;
-#endif // USE_IIMAGELIST
m_fileIconSizes = QAbstractFileIconEngine::toSizeList(fileIconSizes, availEnd);
- qCDebug(lcQpaWindows) << __FUNCTION__ << m_fileIconSizes;
+ qCDebug(lcQpaWindow) << __FUNCTION__ << m_fileIconSizes;
}
// Defined in qpixmap_win.cpp
@@ -755,15 +837,18 @@ QPixmap QWindowsTheme::standardPixmap(StandardPixmap sp, const QSizeF &pixmapSiz
}
if (stockId != SIID_INVALID) {
- QPixmap pixmap;
SHSTOCKICONINFO iconInfo;
memset(&iconInfo, 0, sizeof(iconInfo));
iconInfo.cbSize = sizeof(iconInfo);
- stockFlags |= (pixmapSize.width() > 16 ? SHGFI_LARGEICON : SHGFI_SMALLICON);
- if (SHGetStockIconInfo(stockId, SHGFI_ICON | stockFlags, &iconInfo) == S_OK) {
- pixmap = qt_pixmapFromWinHICON(iconInfo.hIcon);
- DestroyIcon(iconInfo.hIcon);
- return pixmap;
+ stockFlags |= SHGSI_ICONLOCATION;
+ if (SHGetStockIconInfo(stockId, stockFlags, &iconInfo) == S_OK) {
+ const auto iconSize = pixmapSize.width();
+ HICON icon;
+ if (SHDefExtractIcon(iconInfo.szPath, iconInfo.iIcon, 0, &icon, nullptr, iconSize) == S_OK) {
+ QPixmap pixmap = qt_pixmapFromWinHICON(icon);
+ DestroyIcon(icon);
+ return pixmap;
+ }
}
}
@@ -797,7 +882,7 @@ enum { // Shell image list ids
static QString dirIconPixmapCacheKey(int iIcon, int iconSize, int imageListSize)
{
- QString key = QLatin1String("qt_dir_") + QString::number(iIcon);
+ QString key = "qt_dir_"_L1 + QString::number(iIcon);
if (iconSize == SHGFI_LARGEICON)
key += u'l';
switch (imageListSize) {
@@ -816,7 +901,7 @@ class FakePointer
{
public:
- Q_STATIC_ASSERT_X(sizeof(T) <= sizeof(void *), "FakePointers can only go that far.");
+ static_assert(sizeof(T) <= sizeof(void *), "FakePointers can only go that far.");
static FakePointer *create(T thing)
{
@@ -833,10 +918,9 @@ public:
// Shell image list helper functions.
-static QPixmap pixmapFromShellImageList(int iImageList, const SHFILEINFO &info)
+static QPixmap pixmapFromShellImageList(int iImageList, int iIcon)
{
QPixmap result;
-#ifdef USE_IIMAGELIST
// For MinGW:
static const IID iID_IImageList = {0x46eb5926, 0x582e, 0x4017, {0x9f, 0xdf, 0xe8, 0x99, 0x8d, 0xaa, 0x9, 0x50}};
@@ -845,16 +929,12 @@ static QPixmap pixmapFromShellImageList(int iImageList, const SHFILEINFO &info)
if (hr != S_OK)
return result;
HICON hIcon;
- hr = imageList->GetIcon(info.iIcon, ILD_TRANSPARENT, &hIcon);
+ hr = imageList->GetIcon(iIcon, ILD_TRANSPARENT, &hIcon);
if (hr == S_OK) {
result = qt_pixmapFromWinHICON(hIcon);
DestroyIcon(hIcon);
}
imageList->Release();
-#else
- Q_UNUSED(iImageList)
- Q_UNUSED(info)
-#endif // USE_IIMAGELIST
return result;
}
@@ -864,7 +944,7 @@ public:
explicit QWindowsFileIconEngine(const QFileInfo &info, QPlatformTheme::IconOptions opts) :
QAbstractFileIconEngine(info, opts) {}
- QList<QSize> availableSizes(QIcon::Mode = QIcon::Normal, QIcon::State = QIcon::Off) const override
+ QList<QSize> availableSizes(QIcon::Mode = QIcon::Normal, QIcon::State = QIcon::Off) override
{ return QWindowsTheme::instance()->availableFileIconSizes(); }
protected:
@@ -888,19 +968,16 @@ QString QWindowsFileIconEngine::cacheKey() const
|| !suffix.compare(u"ico", Qt::CaseInsensitive)) {
return QString();
}
- return QLatin1String("qt_.")
+ return "qt_."_L1
+ (suffix.isEmpty() ? fileInfo().fileName() : std::move(suffix).toUpper()); // handle "Makefile" ;)
}
QPixmap QWindowsFileIconEngine::filePixmap(const QSize &size, QIcon::Mode, QIcon::State)
{
- /* We don't use the variable, but by storing it statically, we
- * ensure CoInitialize is only called once. */
- static HRESULT comInit = CoInitialize(nullptr);
- Q_UNUSED(comInit);
+ QComHelper comHelper;
static QCache<QString, FakePointer<int> > dirIconEntryCache(1000);
- static QMutex mx;
+ Q_CONSTINIT static QMutex mx;
static int defaultFolderIIcon = -1;
const bool useDefaultFolderIcon = options() & QPlatformTheme::DontUseCustomDirectoryIcons;
@@ -909,13 +986,9 @@ QPixmap QWindowsFileIconEngine::filePixmap(const QSize &size, QIcon::Mode, QIcon
const int width = int(size.width());
const int iconSize = width > fileIconSizes[SmallFileIcon] ? SHGFI_LARGEICON : SHGFI_SMALLICON;
const int requestedImageListSize =
-#ifdef USE_IIMAGELIST
width > fileIconSizes[ExtraLargeFileIcon]
? sHIL_JUMBO
: (width > fileIconSizes[LargeFileIcon] ? sHIL_EXTRALARGE : 0);
-#else
- 0;
-#endif // !USE_IIMAGELIST
bool cacheableDirIcon = fileInfo().isDir() && !fileInfo().isRoot();
if (cacheableDirIcon) {
QMutexLocker locker(&mx);
@@ -931,7 +1004,6 @@ QPixmap QWindowsFileIconEngine::filePixmap(const QSize &size, QIcon::Mode, QIcon
}
}
- SHFILEINFO info;
unsigned int flags = SHGFI_ICON | iconSize | SHGFI_SYSICONINDEX | SHGFI_ADDOVERLAYS | SHGFI_OVERLAYINDEX;
DWORD attributes = 0;
QString path = filePath;
@@ -943,43 +1015,43 @@ QPixmap QWindowsFileIconEngine::filePixmap(const QSize &size, QIcon::Mode, QIcon
flags |= SHGFI_USEFILEATTRIBUTES;
attributes |= FILE_ATTRIBUTE_NORMAL;
}
- const bool val = shGetFileInfoBackground(path, attributes, &info, flags);
-
+ auto task = QSharedPointer<QShGetFileInfoThread::Task>(
+ new QShGetFileInfoThread::Task(path, attributes, flags));
+ s_shGetFileInfoThread()->runWithParams(task);
// Even if GetFileInfo returns a valid result, hIcon can be empty in some cases
- if (val && info.hIcon) {
+ if (task->resultValid()) {
QString key;
if (cacheableDirIcon) {
if (useDefaultFolderIcon && defaultFolderIIcon < 0)
- defaultFolderIIcon = info.iIcon;
+ defaultFolderIIcon = task->iIcon;
//using the unique icon index provided by windows save us from duplicate keys
- key = dirIconPixmapCacheKey(info.iIcon, iconSize, requestedImageListSize);
+ key = dirIconPixmapCacheKey(task->iIcon, iconSize, requestedImageListSize);
QPixmapCache::find(key, &pixmap);
if (!pixmap.isNull()) {
QMutexLocker locker(&mx);
- dirIconEntryCache.insert(filePath, FakePointer<int>::create(info.iIcon));
+ dirIconEntryCache.insert(filePath, FakePointer<int>::create(task->iIcon));
}
}
if (pixmap.isNull()) {
if (requestedImageListSize) {
- pixmap = pixmapFromShellImageList(requestedImageListSize, info);
+ pixmap = pixmapFromShellImageList(requestedImageListSize, task->iIcon);
if (pixmap.isNull() && requestedImageListSize == sHIL_JUMBO)
- pixmap = pixmapFromShellImageList(sHIL_EXTRALARGE, info);
+ pixmap = pixmapFromShellImageList(sHIL_EXTRALARGE, task->iIcon);
}
if (pixmap.isNull())
- pixmap = qt_pixmapFromWinHICON(info.hIcon);
+ pixmap = qt_pixmapFromWinHICON(task->hIcon);
if (!pixmap.isNull()) {
if (cacheableDirIcon) {
QMutexLocker locker(&mx);
QPixmapCache::insert(key, pixmap);
- dirIconEntryCache.insert(filePath, FakePointer<int>::create(info.iIcon));
+ dirIconEntryCache.insert(filePath, FakePointer<int>::create(task->iIcon));
}
} else {
qWarning("QWindowsTheme::fileIconPixmap() no icon found");
}
}
- DestroyIcon(info.hIcon);
}
return pixmap;
@@ -990,6 +1062,11 @@ QIcon QWindowsTheme::fileIcon(const QFileInfo &fileInfo, QPlatformTheme::IconOpt
return QIcon(new QWindowsFileIconEngine(fileInfo, iconOptions));
}
+QIconEngine *QWindowsTheme::createIconEngine(const QString &iconName) const
+{
+ return new QWindowsIconEngine(iconName);
+}
+
static inline bool doUseNativeMenus()
{
const unsigned options = QWindowsIntegration::instance()->options();
@@ -1016,9 +1093,7 @@ bool QWindowsTheme::useNativeMenus()
bool QWindowsTheme::queryDarkMode()
{
- if (QOperatingSystemVersion::current()
- < QOperatingSystemVersion(QOperatingSystemVersion::Windows, 10, 0, 17763)
- || queryHighContrast()) {
+ if (queryHighContrast()) {
return false;
}
const auto setting = QWinRegistryKey(HKEY_CURRENT_USER, LR"(Software\Microsoft\Windows\CurrentVersion\Themes\Personalize)")
@@ -1028,7 +1103,11 @@ bool QWindowsTheme::queryDarkMode()
bool QWindowsTheme::queryHighContrast()
{
- return booleanSystemParametersInfo(SPI_GETHIGHCONTRAST, false);
+ HIGHCONTRAST hcf = {};
+ hcf.cbSize = static_cast<UINT>(sizeof(HIGHCONTRAST));
+ if (SystemParametersInfo(SPI_GETHIGHCONTRAST, hcf.cbSize, &hcf, FALSE))
+ return hcf.dwFlags & HCF_HIGHCONTRASTON;
+ return false;
}
QPlatformMenuItem *QWindowsTheme::createPlatformMenuItem() const
diff --git a/src/plugins/platforms/windows/qwindowstheme.h b/src/plugins/platforms/windows/qwindowstheme.h
index af28f2878c..bc16a9619e 100644
--- a/src/plugins/platforms/windows/qwindowstheme.h
+++ b/src/plugins/platforms/windows/qwindowstheme.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QWINDOWSTHEME_H
#define QWINDOWSTHEME_H
@@ -44,6 +8,8 @@
#include <QtCore/qsharedpointer.h>
#include <QtCore/qvariant.h>
+#include <QtCore/qlist.h>
+#include <QtCore/qsize.h>
QT_BEGIN_NAMESPACE
@@ -64,6 +30,9 @@ public:
QPlatformSystemTrayIcon *createPlatformSystemTrayIcon() const override;
#endif
QVariant themeHint(ThemeHint) const override;
+
+ Qt::ColorScheme colorScheme() const override;
+
const QPalette *palette(Palette type = SystemPalette) const override
{ return m_palettes[type]; }
const QFont *font(Font type = SystemFont) const override
@@ -72,6 +41,7 @@ public:
QPixmap standardPixmap(StandardPixmap sp, const QSizeF &size) const override;
QIcon fileIcon(const QFileInfo &fileInfo, QPlatformTheme::IconOptions iconOptions = {}) const override;
+ QIconEngine *createIconEngine(const QString &iconName) const override;
void windowsThemeChanged(QWindow *window);
void displayChanged() { refreshIconPixmapSizes(); }
@@ -92,6 +62,8 @@ public:
static const char *name;
+ static QPalette systemPalette(Qt::ColorScheme);
+
private:
void clearPalettes();
void refreshPalettes();
diff --git a/src/plugins/platforms/windows/qwindowsthreadpoolrunner.h b/src/plugins/platforms/windows/qwindowsthreadpoolrunner.h
index ffe2e62069..cc550d912b 100644
--- a/src/plugins/platforms/windows/qwindowsthreadpoolrunner.h
+++ b/src/plugins/platforms/windows/qwindowsthreadpoolrunner.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QWINDOWSTHREADPOOLRUNNER_H
#define QWINDOWSTHREADPOOLRUNNER_H
@@ -55,7 +19,6 @@ QT_BEGIN_NAMESPACE
to be done by using QWaitCondition/QMutex.
\internal
- \ingroup qt-lighthouse-win
*/
class QWindowsThreadPoolRunner
{
diff --git a/src/plugins/platforms/windows/qwindowsvulkaninstance.cpp b/src/plugins/platforms/windows/qwindowsvulkaninstance.cpp
index 812ea8193a..0c2ee9edf5 100644
--- a/src/plugins/platforms/windows/qwindowsvulkaninstance.cpp
+++ b/src/plugins/platforms/windows/qwindowsvulkaninstance.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qwindowsvulkaninstance.h"
diff --git a/src/plugins/platforms/windows/qwindowsvulkaninstance.h b/src/plugins/platforms/windows/qwindowsvulkaninstance.h
index cc7ef476d4..5e287d0302 100644
--- a/src/plugins/platforms/windows/qwindowsvulkaninstance.h
+++ b/src/plugins/platforms/windows/qwindowsvulkaninstance.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QWINDOWSVULKANINSTANCE_H
#define QWINDOWSVULKANINSTANCE_H
@@ -46,7 +10,7 @@
#define VK_USE_PLATFORM_WIN32_KHR
-#include <QtVulkanSupport/private/qbasicvulkanplatforminstance_p.h>
+#include <QtGui/private/qbasicvulkanplatforminstance_p.h>
#include <QtCore/qlibrary.h>
QT_BEGIN_NAMESPACE
diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp
index ee65b393d4..220c36cc19 100644
--- a/src/plugins/platforms/windows/qwindowswindow.cpp
+++ b/src/plugins/platforms/windows/qwindowswindow.cpp
@@ -1,48 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
-
-#if defined(WINVER) && WINVER < 0x0601
-# undef WINVER
-#endif
-#if !defined(WINVER)
-# define WINVER 0x0601 // Enable touch functions for MinGW
-#endif
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <QtCore/qt_windows.h>
#include "qwindowswindow.h"
#include "qwindowscontext.h"
@@ -68,7 +27,7 @@
#include <QtGui/qwindow.h>
#include <QtGui/qregion.h>
#include <QtGui/qopenglcontext.h>
-#include <private/qsystemlibrary_p.h>
+#include <QtGui/private/qwindowsthemecache_p.h>
#include <private/qwindow_p.h> // QWINDOWSIZE_MAX
#include <private/qguiapplication_p.h>
#include <private/qhighdpiscaling_p.h>
@@ -76,7 +35,6 @@
#include <QtCore/qdebug.h>
#include <QtCore/qlibraryinfo.h>
-#include <QtCore/qoperatingsystemversion.h>
#include <dwmapi.h>
@@ -84,6 +42,8 @@
#include "qwindowsvulkaninstance.h"
#endif
+#include <shellscalingapi.h>
+
QT_BEGIN_NAMESPACE
using QWindowCreationContextPtr = QSharedPointer<QWindowCreationContext>;
@@ -119,6 +79,34 @@ static QByteArray debugWinStyle(DWORD style)
rc += " WS_MINIMIZEBOX";
if (style & WS_MAXIMIZEBOX)
rc += " WS_MAXIMIZEBOX";
+ if (style & WS_BORDER)
+ rc += " WS_BORDER";
+ if (style & WS_CAPTION)
+ rc += " WS_CAPTION";
+ if (style & WS_CHILDWINDOW)
+ rc += " WS_CHILDWINDOW";
+ if (style & WS_DISABLED)
+ rc += " WS_DISABLED";
+ if (style & WS_GROUP)
+ rc += " WS_GROUP";
+ if (style & WS_HSCROLL)
+ rc += " WS_HSCROLL";
+ if (style & WS_ICONIC)
+ rc += " WS_ICONIC";
+ if (style & WS_MAXIMIZE)
+ rc += " WS_MAXIMIZE";
+ if (style & WS_MINIMIZE)
+ rc += " WS_MINIMIZE";
+ if (style & WS_SIZEBOX)
+ rc += " WS_SIZEBOX";
+ if (style & WS_TABSTOP)
+ rc += " WS_TABSTOP";
+ if (style & WS_TILED)
+ rc += " WS_TILED";
+ if (style & WS_VISIBLE)
+ rc += " WS_VISIBLE";
+ if (style & WS_VSCROLL)
+ rc += " WS_VSCROLL";
return rc;
}
@@ -138,6 +126,44 @@ static QByteArray debugWinExStyle(DWORD exStyle)
rc += " WS_EX_LAYOUTRTL";
if (exStyle & WS_EX_NOINHERITLAYOUT)
rc += " WS_EX_NOINHERITLAYOUT";
+ if (exStyle & WS_EX_ACCEPTFILES)
+ rc += " WS_EX_ACCEPTFILES";
+ if (exStyle & WS_EX_APPWINDOW)
+ rc += " WS_EX_APPWINDOW";
+ if (exStyle & WS_EX_CLIENTEDGE)
+ rc += " WS_EX_CLIENTEDGE";
+ if (exStyle & WS_EX_COMPOSITED)
+ rc += " WS_EX_COMPOSITED";
+ if (exStyle & WS_EX_CONTROLPARENT)
+ rc += " WS_EX_CONTROLPARENT";
+ if (exStyle & WS_EX_LEFT)
+ rc += " WS_EX_LEFT";
+ if (exStyle & WS_EX_LEFTSCROLLBAR)
+ rc += " WS_EX_LEFTSCROLLBAR";
+ if (exStyle & WS_EX_LTRREADING)
+ rc += " WS_EX_LTRREADING";
+ if (exStyle & WS_EX_MDICHILD)
+ rc += " WS_EX_MDICHILD";
+ if (exStyle & WS_EX_NOACTIVATE)
+ rc += " WS_EX_NOACTIVATE";
+ if (exStyle & WS_EX_NOPARENTNOTIFY)
+ rc += " WS_EX_NOPARENTNOTIFY";
+ if (exStyle & WS_EX_NOREDIRECTIONBITMAP)
+ rc += " WS_EX_NOREDIRECTIONBITMAP";
+ if (exStyle & WS_EX_RIGHT)
+ rc += " WS_EX_RIGHT";
+ if (exStyle & WS_EX_RIGHTSCROLLBAR)
+ rc += " WS_EX_RIGHTSCROLLBAR";
+ if (exStyle & WS_EX_RTLREADING)
+ rc += " WS_EX_RTLREADING";
+ if (exStyle & WS_EX_STATICEDGE)
+ rc += " WS_EX_STATICEDGE";
+ if (exStyle & WS_EX_TOPMOST)
+ rc += " WS_EX_TOPMOST";
+ if (exStyle & WS_EX_TRANSPARENT)
+ rc += " WS_EX_TRANSPARENT";
+ if (exStyle & WS_EX_WINDOWEDGE)
+ rc += " WS_EX_WINDOWEDGE";
return rc;
}
@@ -167,6 +193,62 @@ static QByteArray debugWinSwpPos(UINT flags)
rc += " SWP_NOZORDER";
if (flags & SWP_SHOWWINDOW)
rc += " SWP_SHOWWINDOW";
+ if (flags & SWP_ASYNCWINDOWPOS)
+ rc += " SWP_ASYNCWINDOWPOS";
+ if (flags & SWP_DEFERERASE)
+ rc += " SWP_DEFERERASE";
+ if (flags & SWP_DRAWFRAME)
+ rc += " SWP_DRAWFRAME";
+ if (flags & SWP_NOREPOSITION)
+ rc += " SWP_NOREPOSITION";
+ return rc;
+}
+
+[[nodiscard]] static inline QByteArray debugWindowPlacementFlags(const UINT flags)
+{
+ QByteArray rc = "0x";
+ rc += QByteArray::number(flags, 16);
+ if (flags & WPF_SETMINPOSITION)
+ rc += " WPF_SETMINPOSITION";
+ if (flags & WPF_RESTORETOMAXIMIZED)
+ rc += " WPF_RESTORETOMAXIMIZED";
+ if (flags & WPF_ASYNCWINDOWPLACEMENT)
+ rc += " WPF_ASYNCWINDOWPLACEMENT";
+ return rc;
+}
+
+[[nodiscard]] static inline QByteArray debugShowWindowCmd(const UINT cmd)
+{
+ QByteArray rc = {};
+ rc += QByteArray::number(cmd);
+ if (cmd == SW_HIDE)
+ rc += " SW_HIDE";
+ if (cmd == SW_SHOWNORMAL)
+ rc += " SW_SHOWNORMAL";
+ if (cmd == SW_NORMAL)
+ rc += " SW_NORMAL";
+ if (cmd == SW_SHOWMINIMIZED)
+ rc += " SW_SHOWMINIMIZED";
+ if (cmd == SW_SHOWMAXIMIZED)
+ rc += " SW_SHOWMAXIMIZED";
+ if (cmd == SW_MAXIMIZE)
+ rc += " SW_MAXIMIZE";
+ if (cmd == SW_SHOWNOACTIVATE)
+ rc += " SW_SHOWNOACTIVATE";
+ if (cmd == SW_SHOW)
+ rc += " SW_SHOW";
+ if (cmd == SW_MINIMIZE)
+ rc += " SW_MINIMIZE";
+ if (cmd == SW_SHOWMINNOACTIVE)
+ rc += " SW_SHOWMINNOACTIVE";
+ if (cmd == SW_SHOWNA)
+ rc += " SW_SHOWNA";
+ if (cmd == SW_RESTORE)
+ rc += " SW_RESTORE";
+ if (cmd == SW_SHOWDEFAULT)
+ rc += " SW_SHOWDEFAULT";
+ if (cmd == SW_FORCEMINIMIZE)
+ rc += " SW_FORCEMINIMIZE";
return rc;
}
@@ -202,7 +284,9 @@ QDebug operator<<(QDebug d, const RECT &r)
QDebug operator<<(QDebug d, const POINT &p)
{
- d << p.x << ',' << p.y;
+ QDebugStateSaver saver(d);
+ d.nospace();
+ d << "POINT(x=" << p.x << ", y=" << p.y << ')';
return d;
}
@@ -221,7 +305,7 @@ QDebug operator<<(QDebug d, const NCCALCSIZE_PARAMS &p)
{
QDebugStateSaver saver(d);
d.nospace();
- d << "NCCALCSIZE_PARAMS(rgrc=[" << p.rgrc[0] << ' ' << p.rgrc[1] << ' '
+ d << "NCCALCSIZE_PARAMS(rgrc=[" << p.rgrc[0] << ", " << p.rgrc[1] << ", "
<< p.rgrc[2] << "], lppos=" << *p.lppos << ')';
return d;
}
@@ -230,11 +314,10 @@ QDebug operator<<(QDebug d, const MINMAXINFO &i)
{
QDebugStateSaver saver(d);
d.nospace();
- d << "MINMAXINFO maxSize=" << i.ptMaxSize.x << ','
- << i.ptMaxSize.y << " maxpos=" << i.ptMaxPosition.x
- << ',' << i.ptMaxPosition.y << " mintrack="
- << i.ptMinTrackSize.x << ',' << i.ptMinTrackSize.y
- << " maxtrack=" << i.ptMaxTrackSize.x << ',' << i.ptMaxTrackSize.y;
+ d << "MINMAXINFO(maxSize=" << i.ptMaxSize << ", "
+ << "maxpos=" << i.ptMaxPosition << ", "
+ << "maxtrack=" << i.ptMaxTrackSize << ", "
+ << "mintrack=" << i.ptMinTrackSize << ')';
return d;
}
@@ -243,9 +326,10 @@ QDebug operator<<(QDebug d, const WINDOWPLACEMENT &wp)
QDebugStateSaver saver(d);
d.nospace();
d.noquote();
- d << "WINDOWPLACEMENT(flags=0x" << Qt::hex << wp.flags << Qt::dec << ", showCmd="
- << wp.showCmd << ", ptMinPosition=" << wp.ptMinPosition << ", ptMaxPosition=" << wp.ptMaxPosition
- << ", rcNormalPosition=" << wp.rcNormalPosition;
+ d << "WINDOWPLACEMENT(flags=" << debugWindowPlacementFlags(wp.flags) << ", showCmd="
+ << debugShowWindowCmd(wp.showCmd) << ", ptMinPosition=" << wp.ptMinPosition
+ << ", ptMaxPosition=" << wp.ptMaxPosition << ", rcNormalPosition="
+ << wp.rcNormalPosition << ')';
return d;
}
@@ -346,10 +430,8 @@ static inline bool windowIsAccelerated(const QWindow *w)
{
switch (w->surfaceType()) {
case QSurface::OpenGLSurface:
- return true;
- case QSurface::RasterGLSurface:
- return qt_window_private(const_cast<QWindow *>(w))->compositing;
case QSurface::VulkanSurface:
+ case QSurface::Direct3DSurface:
return true;
default:
return false;
@@ -358,20 +440,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;
@@ -392,20 +465,27 @@ static bool shouldShowMaximizeButton(const QWindow *w, Qt::WindowFlags flags)
w->maximumSize() == QSize(QWINDOWSIZE_MAX, QWINDOWSIZE_MAX);
}
+bool QWindowsWindow::hasNoNativeFrame(HWND hwnd, Qt::WindowFlags flags)
+{
+ const LONG_PTR style = GetWindowLongPtr(hwnd, GWL_STYLE);
+ return (style & WS_CHILD) || (flags & Qt::FramelessWindowHint);
+}
+
// Set the WS_EX_LAYERED flag on a HWND if required. This is required for
// translucent backgrounds, not fully opaque windows and for
// Qt::WindowTransparentForInput (in combination with WS_EX_TRANSPARENT).
bool QWindowsWindow::setWindowLayered(HWND hwnd, Qt::WindowFlags flags, bool hasAlpha, qreal opacity)
{
- const LONG exStyle = GetWindowLong(hwnd, GWL_EXSTYLE);
+ const LONG_PTR exStyle = GetWindowLongPtr(hwnd, GWL_EXSTYLE);
+ // Native children are frameless by nature, so check for that as well.
const bool needsLayered = (flags & Qt::WindowTransparentForInput)
- || (hasAlpha && (flags & Qt::FramelessWindowHint)) || opacity < 1.0;
+ || (hasAlpha && hasNoNativeFrame(hwnd, flags)) || opacity < 1.0;
const bool isLayered = (exStyle & WS_EX_LAYERED);
if (needsLayered != isLayered) {
if (needsLayered) {
- SetWindowLong(hwnd, GWL_EXSTYLE, exStyle | WS_EX_LAYERED);
+ SetWindowLongPtr(hwnd, GWL_EXSTYLE, exStyle | WS_EX_LAYERED);
} else {
- SetWindowLong(hwnd, GWL_EXSTYLE, exStyle & ~WS_EX_LAYERED);
+ SetWindowLongPtr(hwnd, GWL_EXSTYLE, exStyle & ~WS_EX_LAYERED);
}
}
return needsLayered;
@@ -415,7 +495,7 @@ static void setWindowOpacity(HWND hwnd, Qt::WindowFlags flags, bool hasAlpha, bo
{
if (QWindowsWindow::setWindowLayered(hwnd, flags, hasAlpha, level)) {
const BYTE alpha = BYTE(qRound(255.0 * level));
- if (hasAlpha && !accelerated && (flags & Qt::FramelessWindowHint)) {
+ if (hasAlpha && !accelerated && QWindowsWindow::hasNoNativeFrame(hwnd, flags)) {
// Non-GL windows with alpha: Use blend function to update.
BLENDFUNCTION blend = {AC_SRC_OVER, 0, alpha, AC_SRC_ALPHA};
UpdateLayeredWindow(hwnd, nullptr, nullptr, nullptr, nullptr, nullptr, 0, &blend, ULW_ALPHA);
@@ -438,31 +518,41 @@ static inline void updateGLWindowSettings(const QWindow *w, HWND hwnd, Qt::Windo
setWindowOpacity(hwnd, flags, hasAlpha, isAccelerated, opacity);
}
+[[nodiscard]] static inline int getResizeBorderThickness(const UINT dpi)
+{
+ // The width of the padded border will always be 0 if DWM composition is
+ // disabled, but since it will always be enabled and can't be programtically
+ // disabled from Windows 8, we are safe to go.
+ return GetSystemMetricsForDpi(SM_CXSIZEFRAME, dpi)
+ + GetSystemMetricsForDpi(SM_CXPADDEDBORDER, dpi);
+}
+
/*!
Calculates the dimensions of the invisible borders within the
- window frames in Windows 10, using an empirical expression that
- reproduces the measured values for standard DPI settings.
+ window frames which only exist on Windows 10 and onwards.
*/
static QMargins invisibleMargins(QPoint screenPoint)
{
- if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows10) {
- POINT pt = {screenPoint.x(), screenPoint.y()};
- if (HMONITOR hMonitor = MonitorFromPoint(pt, MONITOR_DEFAULTTONULL)) {
- if (QWindowsContext::shcoredll.isValid()) {
- UINT dpiX;
- UINT dpiY;
- if (SUCCEEDED(QWindowsContext::shcoredll.getDpiForMonitor(hMonitor, 0, &dpiX, &dpiY))) {
- const qreal sc = (dpiX - 96) / 96.0;
- const int gap = 7 + qRound(5*sc) - int(sc);
- return QMargins(gap, 0, gap, gap);
- }
- }
+ POINT pt = {screenPoint.x(), screenPoint.y()};
+ if (HMONITOR hMonitor = MonitorFromPoint(pt, MONITOR_DEFAULTTONULL)) {
+ UINT dpiX;
+ UINT dpiY;
+ if (SUCCEEDED(GetDpiForMonitor(hMonitor, MDT_EFFECTIVE_DPI, &dpiX, &dpiY))) {
+ const int gap = getResizeBorderThickness(dpiX);
+ return QMargins(gap, 0, gap, gap);
}
}
return QMargins();
}
+[[nodiscard]] static inline QMargins invisibleMargins(const HWND hwnd)
+{
+ const UINT dpi = GetDpiForWindow(hwnd);
+ const int gap = getResizeBorderThickness(dpi);
+ return QMargins(gap, 0, gap, gap);
+}
+
/*!
\class WindowCreationData
\brief Window creation code.
@@ -489,7 +579,6 @@ static QMargins invisibleMargins(QPoint screenPoint)
\sa QWindowCreationContext
\internal
- \ingroup qt-lighthouse-win
*/
struct WindowCreationData
@@ -553,13 +642,18 @@ static inline void fixTopLevelWindowFlags(Qt::WindowFlags &flags)
flags |= Qt::FramelessWindowHint;
}
-static QScreen *screenForName(const QWindow *w, const QString &name)
+static QScreen *screenForDeviceName(const QWindow *w, const QString &name)
{
+ const auto getDeviceName = [](const QScreen *screen) -> QString {
+ if (const auto s = static_cast<const QWindowsScreen *>(screen->handle()))
+ return s->data().deviceName;
+ return {};
+ };
QScreen *winScreen = w ? w->screen() : QGuiApplication::primaryScreen();
- if (winScreen && winScreen->name() != name) {
+ if (winScreen && getDeviceName(winScreen) != name) {
const auto screens = winScreen->virtualSiblings();
for (QScreen *screen : screens) {
- if (screen->name() == name)
+ if (getDeviceName(screen) == name)
return screen;
}
}
@@ -570,7 +664,7 @@ static QPoint calcPosition(const QWindow *w, const QWindowCreationContextPtr &co
{
const QPoint orgPos(context->frameX - invMargins.left(), context->frameY - invMargins.top());
- if (!w || (!w->isTopLevel() && w->surfaceType() != QWindow::OpenGLSurface))
+ if (!w || w->type() != Qt::Window)
return orgPos;
// Workaround for QTBUG-50371
@@ -703,55 +797,68 @@ void WindowCreationData::fromWindow(const QWindow *w, const Qt::WindowFlags flag
style = WS_CHILD;
}
- // if (!testAttribute(Qt::WA_PaintUnclipped))
- // ### Commented out for now as it causes some problems, but
- // this should be correct anyway, so dig some more into this
-#ifdef Q_FLATTEN_EXPOSE
- if (windowIsOpenGL(w)) // a bit incorrect since the is-opengl status may change from false to true at any time later on
- style |= WS_CLIPSIBLINGS | WS_CLIPCHILDREN; // see SetPixelFormat
-#else
- style |= WS_CLIPSIBLINGS | WS_CLIPCHILDREN ;
-#endif
- if (topLevel) {
- if ((type == Qt::Window || dialog || tool)) {
- if (!(flags & Qt::FramelessWindowHint)) {
- style |= WS_POPUP;
- if (flags & Qt::MSWindowsFixedSizeDialogHint) {
- style |= WS_DLGFRAME;
- } else {
- style |= WS_THICKFRAME;
- }
- if (flags & Qt::WindowTitleHint)
- style |= WS_CAPTION; // Contains WS_DLGFRAME
- }
- if (flags & Qt::WindowSystemMenuHint)
- style |= WS_SYSMENU;
- else if (dialog && (flags & Qt::WindowCloseButtonHint) && !(flags & Qt::FramelessWindowHint)) {
- style |= WS_SYSMENU | WS_BORDER; // QTBUG-2027, dialogs without system menu.
- exStyle |= WS_EX_DLGMODALFRAME;
+ style |= WS_CLIPSIBLINGS | WS_CLIPCHILDREN ;
+
+ if (topLevel) {
+ if ((type == Qt::Window || dialog || tool)) {
+ if (!(flags & Qt::FramelessWindowHint)) {
+ style |= WS_POPUP;
+ if (flags & Qt::MSWindowsFixedSizeDialogHint) {
+ style |= WS_DLGFRAME;
+ } else {
+ style |= WS_THICKFRAME;
}
- if (flags & Qt::WindowMinimizeButtonHint)
- style |= WS_MINIMIZEBOX;
- if (shouldShowMaximizeButton(w, flags))
- style |= WS_MAXIMIZEBOX;
- if (tool)
- exStyle |= WS_EX_TOOLWINDOW;
- if (flags & Qt::WindowContextHelpButtonHint)
- exStyle |= WS_EX_CONTEXTHELP;
- } else {
- exStyle |= WS_EX_TOOLWINDOW;
+ if (flags & Qt::WindowTitleHint)
+ style |= WS_CAPTION; // Contains WS_DLGFRAME
}
+ if (flags & Qt::WindowSystemMenuHint)
+ style |= WS_SYSMENU;
+ else if (dialog && (flags & Qt::WindowCloseButtonHint) && !(flags & Qt::FramelessWindowHint)) {
+ style |= WS_SYSMENU | WS_BORDER; // QTBUG-2027, dialogs without system menu.
+ exStyle |= WS_EX_DLGMODALFRAME;
+ }
+ const bool showMinimizeButton = flags & Qt::WindowMinimizeButtonHint;
+ if (showMinimizeButton)
+ style |= WS_MINIMIZEBOX;
+ const bool showMaximizeButton = shouldShowMaximizeButton(w, flags);
+ if (showMaximizeButton)
+ style |= WS_MAXIMIZEBOX;
+ if (showMinimizeButton || showMaximizeButton)
+ style |= WS_SYSMENU;
+ if (tool)
+ exStyle |= WS_EX_TOOLWINDOW;
+ if ((flags & Qt::WindowContextHelpButtonHint) && !showMinimizeButton
+ && !showMaximizeButton)
+ exStyle |= WS_EX_CONTEXTHELP;
+ } else {
+ exStyle |= WS_EX_TOOLWINDOW;
+ }
+
+ // make mouse events fall through this window
+ // NOTE: WS_EX_TRANSPARENT flag can make mouse inputs fall through a layered window
+ if (flagsIn & Qt::WindowTransparentForInput)
+ exStyle |= WS_EX_LAYERED | WS_EX_TRANSPARENT;
- // make mouse events fall through this window
- // NOTE: WS_EX_TRANSPARENT flag can make mouse inputs fall through a layered window
- if (flagsIn & Qt::WindowTransparentForInput)
- exStyle |= WS_EX_LAYERED | WS_EX_TRANSPARENT;
+ // Currently only compatible with D3D surfaces, use it with care.
+ if (qEnvironmentVariableIntValue("QT_QPA_DISABLE_REDIRECTION_SURFACE"))
+ exStyle |= WS_EX_NOREDIRECTIONBITMAP;
}
}
static inline bool shouldApplyDarkFrame(const QWindow *w)
{
- return w->isTopLevel() && !w->flags().testFlag(Qt::FramelessWindowHint);
+ if (!w->isTopLevel() || w->flags().testFlag(Qt::FramelessWindowHint))
+ return false;
+ // the application has explicitly opted out of dark frames
+ if (!QWindowsIntegration::instance()->darkModeHandling().testFlag(QWindowsApplication::DarkModeWindowFrames))
+ return false;
+
+ // if the application supports a dark border, and the palette is dark (window background color
+ // is darker than the text), then turn dark-border support on, otherwise use a light border.
+ auto *dWindow = QWindowPrivate::get(const_cast<QWindow*>(w));
+ const QPalette windowPal = dWindow->windowPalette();
+ return windowPal.color(QPalette::WindowText).lightness()
+ > windowPal.color(QPalette::Window).lightness();
}
QWindowsWindowData
@@ -782,11 +889,12 @@ QWindowsWindowData
style, exStyle));
QWindowsContext::instance()->setWindowCreationContext(context);
- const bool hasFrame = (style & (WS_DLGFRAME | WS_THICKFRAME));
+ const bool hasFrame = (style & (WS_DLGFRAME | WS_THICKFRAME))
+ && !(result.flags & Qt::FramelessWindowHint);
QMargins invMargins = topLevel && hasFrame && QWindowsGeometryHint::positionIncludesFrame(w)
? invisibleMargins(QPoint(context->frameX, context->frameY)) : QMargins();
- qCDebug(lcQpaWindows).nospace()
+ qCDebug(lcQpaWindow).nospace()
<< "CreateWindowEx: " << w << " class=" << windowClassName << " title=" << title
<< '\n' << *this << "\nrequested: " << rect << ": "
<< context->frameWidth << 'x' << context->frameHeight
@@ -812,7 +920,7 @@ QWindowsWindowData
pos.x(), pos.y(),
context->frameWidth, context->frameHeight,
parentHandle, nullptr, appinst, nullptr);
- qCDebug(lcQpaWindows).nospace()
+ qCDebug(lcQpaWindow).nospace()
<< "CreateWindowEx: returns " << w << ' ' << result.hwnd << " obtained geometry: "
<< context->obtainedPos << context->obtainedSize << ' ' << context->margins;
@@ -821,11 +929,8 @@ QWindowsWindowData
return result;
}
- if (QWindowsContext::isDarkMode()
- && (QWindowsIntegration::instance()->options() & QWindowsIntegration::DarkModeWindowFrames) != 0
- && shouldApplyDarkFrame(w)) {
+ if (QWindowsContext::isDarkMode() && shouldApplyDarkFrame(w))
QWindowsWindow::setDarkBorderToWindow(result.hwnd, true);
- }
if (mirrorParentWidth != 0) {
context->obtainedPos.setX(mirrorParentWidth - context->obtainedSize.width()
@@ -835,6 +940,7 @@ QWindowsWindowData
QRect obtainedGeometry(context->obtainedPos, context->obtainedSize);
result.geometry = obtainedGeometry;
+ result.restoreGeometry = frameGeometry(result.hwnd, topLevel);
result.fullFrameMargins = context->margins;
result.embedded = embedded;
result.hasFrame = hasFrame;
@@ -855,7 +961,7 @@ void WindowCreationData::applyWindowFlags(HWND hwnd) const
const LONG_PTR newExStyle = exStyle;
if (newExStyle != oldExStyle)
SetWindowLongPtr(hwnd, GWL_EXSTYLE, newExStyle);
- qCDebug(lcQpaWindows).nospace() << __FUNCTION__ << hwnd << *this
+ qCDebug(lcQpaWindow).nospace() << __FUNCTION__ << hwnd << *this
<< "\n Style from " << debugWinStyle(DWORD(oldStyle)) << "\n to "
<< debugWinStyle(DWORD(newStyle)) << "\n ExStyle from "
<< debugWinExStyle(DWORD(oldExStyle)) << " to "
@@ -909,6 +1015,21 @@ static QSize toNativeSizeConstrained(QSize dip, const QScreen *s)
return dip;
}
+// Helper for checking if frame adjustment needs to be skipped
+// NOTE: Unmaximized frameless windows will skip margins calculation
+static bool shouldOmitFrameAdjustment(const Qt::WindowFlags flags, DWORD style)
+{
+ return flags.testFlag(Qt::FramelessWindowHint) && !(style & WS_MAXIMIZE);
+}
+
+// Helper for checking if frame adjustment needs to be skipped
+// NOTE: Unmaximized frameless windows will skip margins calculation
+static bool shouldOmitFrameAdjustment(const Qt::WindowFlags flags, HWND hwnd)
+{
+ DWORD style = hwnd != nullptr ? DWORD(GetWindowLongPtr(hwnd, GWL_STYLE)) : 0;
+ return flags.testFlag(Qt::FramelessWindowHint) && !(style & WS_MAXIMIZE);
+}
+
/*!
\class QWindowsGeometryHint
\brief Stores geometry constraints and provides utility functions.
@@ -917,79 +1038,86 @@ static QSize toNativeSizeConstrained(QSize dip, const QScreen *s)
into account.
\internal
- \ingroup qt-lighthouse-win
*/
-QMargins QWindowsGeometryHint::frameOnPrimaryScreen(DWORD style, DWORD exStyle)
+QMargins QWindowsGeometryHint::frameOnPrimaryScreen(const QWindow *w, DWORD style, DWORD exStyle)
{
+ if (!w->isTopLevel() || shouldOmitFrameAdjustment(w->flags(), style))
+ return {};
RECT rect = {0,0,0,0};
style &= ~DWORD(WS_OVERLAPPED); // Not permitted, see docs.
if (AdjustWindowRectEx(&rect, style, FALSE, exStyle) == FALSE)
qErrnoWarning("%s: AdjustWindowRectEx failed", __FUNCTION__);
const QMargins result(qAbs(rect.left), qAbs(rect.top),
qAbs(rect.right), qAbs(rect.bottom));
- qCDebug(lcQpaWindows).nospace() << __FUNCTION__ << " style="
+ qCDebug(lcQpaWindow).nospace() << __FUNCTION__ << " style="
<< Qt::showbase << Qt::hex << style << " exStyle=" << exStyle << Qt::dec << Qt::noshowbase
<< ' ' << rect << ' ' << result;
return result;
}
-QMargins QWindowsGeometryHint::frameOnPrimaryScreen(HWND hwnd)
+QMargins QWindowsGeometryHint::frameOnPrimaryScreen(const QWindow *w, HWND hwnd)
{
- return frameOnPrimaryScreen(DWORD(GetWindowLongPtr(hwnd, GWL_STYLE)),
+ return frameOnPrimaryScreen(w, DWORD(GetWindowLongPtr(hwnd, GWL_STYLE)),
DWORD(GetWindowLongPtr(hwnd, GWL_EXSTYLE)));
}
-QMargins QWindowsGeometryHint::frame(DWORD style, DWORD exStyle, qreal dpi)
+QMargins QWindowsGeometryHint::frame(const QWindow *w, DWORD style, DWORD exStyle, qreal dpi)
{
- if (QWindowsContext::user32dll.adjustWindowRectExForDpi == nullptr)
- return frameOnPrimaryScreen(style, exStyle);
+ if (!w->isTopLevel() || shouldOmitFrameAdjustment(w->flags(), style))
+ return {};
RECT rect = {0,0,0,0};
style &= ~DWORD(WS_OVERLAPPED); // Not permitted, see docs.
- if (QWindowsContext::user32dll.adjustWindowRectExForDpi(&rect, style, FALSE, exStyle,
- unsigned(qRound(dpi))) == FALSE) {
+ if (AdjustWindowRectExForDpi(&rect, style, FALSE, exStyle, unsigned(qRound(dpi))) == FALSE) {
qErrnoWarning("%s: AdjustWindowRectExForDpi failed", __FUNCTION__);
}
const QMargins result(qAbs(rect.left), qAbs(rect.top),
qAbs(rect.right), qAbs(rect.bottom));
- qCDebug(lcQpaWindows).nospace() << __FUNCTION__ << " style="
+ qCDebug(lcQpaWindow).nospace() << __FUNCTION__ << " style="
<< Qt::showbase << Qt::hex << style << " exStyle=" << exStyle << Qt::dec << Qt::noshowbase
<< " dpi=" << dpi
<< ' ' << rect << ' ' << result;
return result;
}
-QMargins QWindowsGeometryHint::frame(HWND hwnd, DWORD style, DWORD exStyle)
+QMargins QWindowsGeometryHint::frame(const QWindow *w, HWND hwnd, DWORD style, DWORD exStyle)
{
+ if (!w->isTopLevel() || shouldOmitFrameAdjustment(w->flags(), style))
+ return {};
if (QWindowsScreenManager::isSingleScreen())
- return frameOnPrimaryScreen(style, exStyle);
- auto screenManager = QWindowsContext::instance()->screenManager();
+ return frameOnPrimaryScreen(w, style, exStyle);
+ auto &screenManager = QWindowsContext::instance()->screenManager();
auto screen = screenManager.screenForHwnd(hwnd);
if (!screen)
screen = screenManager.screens().value(0);
const auto dpi = screen ? screen->logicalDpi().first : qreal(96);
- return frame(style, exStyle, dpi);
+ return frame(w, style, exStyle, dpi);
+}
+
+QMargins QWindowsGeometryHint::frame(const QWindow *w, HWND hwnd)
+{
+ return frame(w, hwnd, DWORD(GetWindowLongPtr(hwnd, GWL_STYLE)),
+ DWORD(GetWindowLongPtr(hwnd, GWL_EXSTYLE)));
}
// For newly created windows.
QMargins QWindowsGeometryHint::frame(const QWindow *w, const QRect &geometry,
DWORD style, DWORD exStyle)
{
- if (!w->isTopLevel() || w->flags().testFlag(Qt::FramelessWindowHint))
+ if (!w->isTopLevel() || shouldOmitFrameAdjustment(w->flags(), style))
return {};
- if (!QWindowsContext::user32dll.adjustWindowRectExForDpi
- || QWindowsScreenManager::isSingleScreen()
+ if (QWindowsScreenManager::isSingleScreen()
|| !QWindowsContext::shouldHaveNonClientDpiScaling(w)) {
- return frameOnPrimaryScreen(style, exStyle);
+ return frameOnPrimaryScreen(w, style, exStyle);
}
qreal dpi = 96;
- auto screenManager = QWindowsContext::instance()->screenManager();
+ auto &screenManager = QWindowsContext::instance()->screenManager();
auto screen = screenManager.screenAtDp(geometry.center());
if (!screen)
screen = screenManager.screens().value(0);
if (screen)
dpi = screen->logicalDpi().first;
- return QWindowsGeometryHint::frame(style, exStyle, dpi);
+ return QWindowsGeometryHint::frame(w, style, exStyle, dpi);
}
bool QWindowsGeometryHint::handleCalculateSize(const QMargins &customMargins, const MSG &msg, LRESULT *result)
@@ -1005,7 +1133,7 @@ bool QWindowsGeometryHint::handleCalculateSize(const QMargins &customMargins, co
ncp->rgrc[0].right -= customMargins.right();
ncp->rgrc[0].bottom -= customMargins.bottom();
result = nullptr;
- qCDebug(lcQpaWindows).nospace() << __FUNCTION__ << oldClientArea << '+' << customMargins << "-->"
+ qCDebug(lcQpaWindow).nospace() << __FUNCTION__ << oldClientArea << '+' << customMargins << "-->"
<< ncp->rgrc[0] << ' ' << ncp->rgrc[1] << ' ' << ncp->rgrc[2]
<< ' ' << ncp->lppos->cx << ',' << ncp->lppos->cy;
return true;
@@ -1041,7 +1169,7 @@ void QWindowsGeometryHint::applyToMinMaxInfo(const QWindow *w,
QSize minimumSize;
QSize maximumSize;
frameSizeConstraints(w, screen, margins, &minimumSize, &maximumSize);
- qCDebug(lcQpaWindows).nospace() << '>' << __FUNCTION__ << '<' << " min="
+ qCDebug(lcQpaWindow).nospace() << '>' << __FUNCTION__ << '<' << " min="
<< minimumSize.width() << ',' << minimumSize.height()
<< " max=" << maximumSize.width() << ',' << maximumSize.height()
<< " margins=" << margins
@@ -1056,7 +1184,7 @@ void QWindowsGeometryHint::applyToMinMaxInfo(const QWindow *w,
mmi->ptMaxTrackSize.x = maximumSize.width();
if (maximumSize.height() < QWINDOWSIZE_MAX)
mmi->ptMaxTrackSize.y = maximumSize.height();
- qCDebug(lcQpaWindows).nospace() << '<' << __FUNCTION__ << " out " << *mmi;
+ qCDebug(lcQpaWindow).nospace() << '<' << __FUNCTION__ << " out " << *mmi;
}
void QWindowsGeometryHint::applyToMinMaxInfo(const QWindow *w,
@@ -1087,12 +1215,11 @@ bool QWindowsGeometryHint::positionIncludesFrame(const QWindow *w)
\since 5.6
\internal
- \ingroup qt-lighthouse-win
*/
bool QWindowsBaseWindow::isRtlLayout(HWND hwnd)
{
- return (GetWindowLongPtrW(hwnd, GWL_EXSTYLE) & WS_EX_LAYOUTRTL) != 0;
+ return (GetWindowLongPtr(hwnd, GWL_EXSTYLE) & WS_EX_LAYOUTRTL) != 0;
}
QWindowsBaseWindow *QWindowsBaseWindow::baseWindowOf(const QWindow *w)
@@ -1128,7 +1255,21 @@ QRect QWindowsBaseWindow::geometry_sys() const
QMargins QWindowsBaseWindow::frameMargins_sys() const
{
- return QWindowsGeometryHint::frame(handle(), style(), exStyle());
+ return QWindowsGeometryHint::frame(window(), handle(), style(), exStyle());
+}
+
+std::optional<QWindowsBaseWindow::TouchWindowTouchTypes>
+ QWindowsBaseWindow::touchWindowTouchTypes_sys() const
+{
+ ULONG touchFlags = 0;
+ if (IsTouchWindow(handle(), &touchFlags) == FALSE)
+ return {};
+ TouchWindowTouchTypes result;
+ if ((touchFlags & TWF_FINETOUCH) != 0)
+ result.setFlag(TouchWindowTouchType::FineTouch);
+ if ((touchFlags & TWF_WANTPALM) != 0)
+ result.setFlag(TouchWindowTouchType::WantPalmTouch);
+ return result;
}
void QWindowsBaseWindow::hide_sys() // Normal hide, do not activate other windows.
@@ -1139,7 +1280,7 @@ void QWindowsBaseWindow::hide_sys() // Normal hide, do not activate other window
void QWindowsBaseWindow::raise_sys()
{
- qCDebug(lcQpaWindows) << __FUNCTION__ << this << window();
+ qCDebug(lcQpaWindow) << __FUNCTION__ << this << window();
const Qt::WindowType type = window()->type();
if (type == Qt::Popup
|| type == Qt::SubWindow // Special case for QTBUG-63121: MDI subwindows with WindowStaysOnTopHint
@@ -1150,14 +1291,14 @@ void QWindowsBaseWindow::raise_sys()
void QWindowsBaseWindow::lower_sys()
{
- qCDebug(lcQpaWindows) << __FUNCTION__ << this << window();
+ qCDebug(lcQpaWindow) << __FUNCTION__ << this << window();
if (!(window()->flags() & Qt::WindowStaysOnTopHint))
SetWindowPos(handle(), HWND_BOTTOM, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
}
void QWindowsBaseWindow::setWindowTitle_sys(const QString &title)
{
- qCDebug(lcQpaWindows) << __FUNCTION__ << this << window() << title;
+ qCDebug(lcQpaWindow) << __FUNCTION__ << this << window() << title;
SetWindowText(handle(), reinterpret_cast<const wchar_t *>(title.utf16()));
}
@@ -1171,12 +1312,32 @@ QPoint QWindowsBaseWindow::mapFromGlobal(const QPoint &pos) const
return QWindowsGeometryHint::mapFromGlobal(handle(), pos);
}
+void QWindowsBaseWindow::setHasBorderInFullScreen(bool)
+{
+ Q_UNIMPLEMENTED();
+}
+
+bool QWindowsBaseWindow::hasBorderInFullScreen() const
+{
+ Q_UNIMPLEMENTED();
+ return false;
+}
+
+QMargins QWindowsBaseWindow::customMargins() const
+{
+ return {};
+}
+
+void QWindowsBaseWindow::setCustomMargins(const QMargins &)
+{
+ Q_UNIMPLEMENTED();
+}
+
/*!
\class QWindowsDesktopWindow
\brief Window wrapping GetDesktopWindow not allowing any manipulation.
\since 5.6
\internal
- \ingroup qt-lighthouse-win
*/
/*!
@@ -1189,7 +1350,6 @@ QPoint QWindowsBaseWindow::mapFromGlobal(const QPoint &pos) const
\since 5.6
\internal
- \ingroup qt-lighthouse-win
*/
QWindowsForeignWindow::QWindowsForeignWindow(QWindow *window, HWND hwnd)
@@ -1205,7 +1365,7 @@ void QWindowsForeignWindow::setParent(const QPlatformWindow *newParentWindow)
const HWND newParent = newParentWindow ? reinterpret_cast<HWND>(newParentWindow->winId()) : HWND(nullptr);
const bool isTopLevel = !newParent;
const DWORD oldStyle = style();
- qCDebug(lcQpaWindows) << __FUNCTION__ << window() << "newParent="
+ qCDebug(lcQpaWindow) << __FUNCTION__ << window() << "newParent="
<< newParentWindow << newParent << "oldStyle=" << debugWinStyle(oldStyle);
SetParent(m_hwnd, newParent);
if (wasTopLevel != isTopLevel) { // Top level window flags need to be set/cleared manually.
@@ -1223,7 +1383,7 @@ void QWindowsForeignWindow::setParent(const QPlatformWindow *newParentWindow)
void QWindowsForeignWindow::setVisible(bool visible)
{
- qCDebug(lcQpaWindows) << __FUNCTION__ << window() << visible;
+ qCDebug(lcQpaWindow) << __FUNCTION__ << window() << visible;
if (visible)
ShowWindow(handle(), SW_SHOWNOACTIVATE);
else
@@ -1248,7 +1408,6 @@ void QWindowsForeignWindow::setVisible(bool visible)
\sa WindowCreationData, QWindowsContext
\internal
- \ingroup qt-lighthouse-win
*/
QWindowCreationContext::QWindowCreationContext(const QWindow *w, const QScreen *s,
@@ -1261,13 +1420,16 @@ QWindowCreationContext::QWindowCreationContext(const QWindow *w, const QScreen *
requestedGeometry(geometry),
obtainedPos(geometryIn.topLeft()),
obtainedSize(geometryIn.size()),
- margins(QWindowsGeometryHint::frame(w, geometry, style, exStyle)),
- customMargins(cm)
+ margins(QWindowsGeometryHint::frame(w, geometry, style, exStyle))
{
// Geometry of toplevels does not consider window frames.
// TODO: No concept of WA_wasMoved yet that would indicate a
// CW_USEDEFAULT unless set. For now, assume that 0,0 means 'default'
// for toplevels.
+
+ if (!(w->flags() & Qt::FramelessWindowHint))
+ customMargins = cm;
+
if (geometry.isValid()
|| !qt_window_private(const_cast<QWindow *>(w))->resizeAutomatic) {
frameX = geometry.x();
@@ -1286,7 +1448,7 @@ QWindowCreationContext::QWindowCreationContext(const QWindow *w, const QScreen *
}
}
- qCDebug(lcQpaWindows).nospace()
+ qCDebug(lcQpaWindow).nospace()
<< __FUNCTION__ << ' ' << w << ' ' << geometry
<< " pos incl. frame=" << QWindowsGeometryHint::positionIncludesFrame(w)
<< " frame=" << frameWidth << 'x' << frameHeight << '+'
@@ -1306,7 +1468,7 @@ void QWindowCreationContext::applyToMinMaxInfo(MINMAXINFO *mmi) const
\list
\li Raster type: handleWmPaint() is implemented to
to bitblt the image. The DC can be accessed
- via getDC/Relase DC, which has a special handling
+ via getDC/releaseDC, which has special handling
when within a paint event (in that case, the DC obtained
from BeginPaint() is returned).
@@ -1318,18 +1480,17 @@ void QWindowCreationContext::applyToMinMaxInfo(MINMAXINFO *mmi) const
\endlist
\internal
- \ingroup qt-lighthouse-win
*/
const char *QWindowsWindow::embeddedNativeParentHandleProperty = "_q_embedded_native_parent_handle";
const char *QWindowsWindow::hasBorderInFullScreenProperty = "_q_has_border_in_fullscreen";
bool QWindowsWindow::m_borderInFullScreenDefault = false;
+bool QWindowsWindow::m_inSetgeometry = false;
QWindowsWindow::QWindowsWindow(QWindow *aWindow, const QWindowsWindowData &data) :
QWindowsBaseWindow(aWindow),
m_data(data),
- m_cursor(new CursorHandle),
- m_format(aWindow->requestedFormat())
+ m_cursor(new CursorHandle)
#if QT_CONFIG(vulkan)
, m_vkSurface(VK_NULL_HANDLE)
#endif
@@ -1338,21 +1499,23 @@ QWindowsWindow::QWindowsWindow(QWindow *aWindow, const QWindowsWindowData &data)
const Qt::WindowType type = aWindow->type();
if (type == Qt::Desktop)
return; // No further handling for Qt::Desktop
-#ifndef QT_NO_OPENGL
- if (aWindow->surfaceType() == QWindow::OpenGLSurface) {
- if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGL)
- setFlag(OpenGLSurface);
- else
- setFlag(OpenGL_ES2);
- }
-#endif // QT_NO_OPENGL
+ if (aWindow->surfaceType() == QWindow::Direct3DSurface)
+ setFlag(Direct3DSurface);
+#if QT_CONFIG(opengl)
+ if (aWindow->surfaceType() == QWindow::OpenGLSurface)
+ setFlag(OpenGLSurface);
+#endif
#if QT_CONFIG(vulkan)
if (aWindow->surfaceType() == QSurface::VulkanSurface)
setFlag(VulkanSurface);
#endif
updateDropSite(window()->isTopLevel());
- registerTouchWindow();
+ // Register touch unless if the flags are already set by a hook
+ // such as HCBT_CREATEWND
+ if (!touchWindowTouchTypes_sys().has_value())
+ registerTouchWindow();
+
const qreal opacity = qt_window_private(aWindow)->opacity;
if (!qFuzzyCompare(opacity, qreal(1.0)))
setOpacity(opacity);
@@ -1369,6 +1532,7 @@ QWindowsWindow::QWindowsWindow(QWindow *aWindow, const QWindowsWindowData &data)
QWindowsWindow::~QWindowsWindow()
{
setFlag(WithinDestroy);
+ QWindowsThemeCache::clearThemeCache(m_data.hwnd);
if (testFlag(TouchRegistered))
UnregisterTouchWindow(m_data.hwnd);
destroyWindow();
@@ -1389,14 +1553,20 @@ void QWindowsWindow::initialize()
if (w->type() != Qt::Desktop) {
const Qt::WindowState state = w->windowState();
const QRect obtainedGeometry(creationContext->obtainedPos, creationContext->obtainedSize);
+ QPlatformScreen *obtainedScreen = screenForGeometry(obtainedGeometry);
+ if (obtainedScreen && screen() != obtainedScreen)
+ QWindowSystemInterface::handleWindowScreenChanged<QWindowSystemInterface::SynchronousDelivery>(w, obtainedScreen->screen());
if (state != Qt::WindowMaximized && state != Qt::WindowFullScreen
&& creationContext->requestedGeometryIn != obtainedGeometry) {
QWindowSystemInterface::handleGeometryChange<QWindowSystemInterface::SynchronousDelivery>(w, obtainedGeometry);
}
- QPlatformScreen *obtainedScreen = screenForGeometry(obtainedGeometry);
- if (obtainedScreen && screen() != obtainedScreen)
- QWindowSystemInterface::handleWindowScreenChanged<QWindowSystemInterface::SynchronousDelivery>(w, obtainedScreen->screen());
}
+ QWindowsWindow::setSavedDpi(GetDpiForWindow(handle()));
+}
+
+QSurfaceFormat QWindowsWindow::format() const
+{
+ return window()->requestedFormat();
}
void QWindowsWindow::fireExpose(const QRegion &region, bool force)
@@ -1408,9 +1578,14 @@ void QWindowsWindow::fireExpose(const QRegion &region, bool force)
QWindowSystemInterface::handleExposeEvent(window(), region);
}
+void QWindowsWindow::fireFullExpose(bool force)
+{
+ fireExpose(QRect(QPoint(0, 0), m_data.geometry.size()), force);
+}
+
void QWindowsWindow::destroyWindow()
{
- qCDebug(lcQpaWindows) << __FUNCTION__ << this << window() << m_data.hwnd;
+ qCDebug(lcQpaWindow) << __FUNCTION__ << this << window() << m_data.hwnd;
if (m_data.hwnd) { // Stop event dispatching before Window is destroyed.
setFlag(WithinDestroy);
// Clear any transient child relationships as Windows will otherwise destroy them (QTBUG-35499, QTBUG-36666)
@@ -1517,7 +1692,7 @@ QScreen *QWindowsWindow::forcedScreenForGLWindow(const QWindow *w)
forceToScreen = GpuDescription::detect().gpuSuitableScreen;
m_screenForGLInitialized = true;
}
- return forceToScreen.isEmpty() ? nullptr : screenForName(w, forceToScreen);
+ return forceToScreen.isEmpty() ? nullptr : screenForDeviceName(w, forceToScreen);
}
// Returns topmost QWindowsWindow ancestor even if there are embedded windows in the chain.
@@ -1559,7 +1734,7 @@ QWindowsWindowData
void QWindowsWindow::setVisible(bool visible)
{
const QWindow *win = window();
- qCDebug(lcQpaWindows) << __FUNCTION__ << this << win << m_data.hwnd << visible;
+ qCDebug(lcQpaWindow) << __FUNCTION__ << this << win << m_data.hwnd << visible;
if (m_data.hwnd) {
if (visible) {
show_sys();
@@ -1568,7 +1743,7 @@ void QWindowsWindow::setVisible(bool visible)
// over the rendering of the window
// There is nobody waiting for this, so we don't need to flush afterwards.
if (isLayered())
- fireExpose(QRect(0, 0, win->width(), win->height()));
+ fireFullExpose();
// QTBUG-44928, QTBUG-7386: This is to resolve the problem where popups are
// opened from the system tray and not being implicitly activated
@@ -1739,7 +1914,7 @@ void QWindowsWindow::show_sys() const
void QWindowsWindow::setParent(const QPlatformWindow *newParent)
{
- qCDebug(lcQpaWindows) << __FUNCTION__ << window() << newParent;
+ qCDebug(lcQpaWindow) << __FUNCTION__ << window() << newParent;
if (m_data.hwnd)
setParent_sys(newParent);
@@ -1790,12 +1965,110 @@ void QWindowsWindow::handleHidden()
void QWindowsWindow::handleCompositionSettingsChanged()
{
const QWindow *w = window();
- if ((w->surfaceType() == QWindow::OpenGLSurface || w->surfaceType() == QWindow::VulkanSurface)
- && w->format().hasAlpha()) {
+ if ((w->surfaceType() == QWindow::OpenGLSurface
+ || w->surfaceType() == QWindow::VulkanSurface
+ || w->surfaceType() == QWindow::Direct3DSurface)
+ && w->format().hasAlpha())
+ {
applyBlurBehindWindow(handle());
}
}
+qreal QWindowsWindow::dpiRelativeScale(const UINT dpi) const
+{
+ return QHighDpiScaling::roundScaleFactor(qreal(dpi) / QWindowsScreen::baseDpi) /
+ QHighDpiScaling::roundScaleFactor(qreal(savedDpi()) / QWindowsScreen::baseDpi);
+}
+
+void QWindowsWindow::handleDpiScaledSize(WPARAM wParam, LPARAM lParam, LRESULT *result)
+{
+ // We want to keep QWindow's device independent size constant across the
+ // DPI change. To accomplish this, scale QPlatformWindow's native size
+ // by the change of DPI (e.g. 120 -> 144 = 1.2), also taking any scale
+ // factor rounding into account. The win32 window size includes the margins;
+ // add the margins for the new DPI to the window size.
+ const UINT dpi = UINT(wParam);
+ const qreal scale = dpiRelativeScale(dpi);
+ const QMargins margins = fullFrameMargins();
+ if (!(m_data.flags & Qt::FramelessWindowHint)) {
+ // We need to update the custom margins to match the current DPI, because
+ // we don't want our users manually hook into this message just to set a
+ // new margin, but here we can't call setCustomMargins() directly, that
+ // function will change the window geometry which conflicts with what we
+ // are currently doing.
+ m_data.customMargins *= scale;
+ }
+
+ const QSize windowSize = (geometry().size() * scale).grownBy((margins * scale) + customMargins());
+ SIZE *size = reinterpret_cast<SIZE *>(lParam);
+ size->cx = windowSize.width();
+ size->cy = windowSize.height();
+ *result = true; // Inform Windows that we've set a size
+}
+
+void QWindowsWindow::handleDpiChanged(HWND hwnd, WPARAM wParam, LPARAM lParam)
+{
+ const UINT dpi = HIWORD(wParam);
+ const qreal scale = dpiRelativeScale(dpi);
+ setSavedDpi(dpi);
+
+ QWindowsThemeCache::clearThemeCache(hwnd);
+
+ // Send screen change first, so that the new screen is set during any following resize
+ checkForScreenChanged(QWindowsWindow::FromDpiChange);
+
+ if (!IsZoomed(hwnd))
+ m_data.restoreGeometry.setSize(m_data.restoreGeometry.size() * scale);
+
+ // We get WM_DPICHANGED in one of two situations:
+ //
+ // 1. The DPI change is a "spontaneous" DPI change as a result of e.g.
+ // the user dragging the window to a new screen. In this case Windows
+ // first sends WM_GETDPISCALEDSIZE, where we set the new window size,
+ // followed by this event where we 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.
+ //
+ // 2. The DPI change is a result of a setGeometry() call. In this case
+ // Qt has already scaled the window size for the new DPI. Further, Windows
+ // does not call WM_GETDPISCALEDSIZE, and also applies its own scaling
+ // to the already scaled window size. Since there is no need to set the
+ // window geometry again, and the provided geometry is incorrect, we omit
+ // making the SetWindowPos() call.
+ if (!m_inSetgeometry) {
+ 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);
+ // If the window does not have a frame, WM_MOVE and WM_SIZE won't be
+ // called which prevents the content from being scaled appropriately
+ // after a DPI change.
+ if (shouldOmitFrameAdjustment(m_data.flags, m_data.hwnd))
+ handleGeometryChange();
+ }
+
+ // Re-apply mask now that we have a new DPI, which have resulted in
+ // a new scale factor.
+ setMask(QHighDpi::toNativeLocalRegion(window()->mask(), window()));
+}
+
+void QWindowsWindow::handleDpiChangedAfterParent(HWND hwnd)
+{
+ const UINT dpi = GetDpiForWindow(hwnd);
+ const qreal scale = dpiRelativeScale(dpi);
+ setSavedDpi(dpi);
+
+ checkForScreenChanged(QWindowsWindow::FromDpiChange);
+
+ // Child windows do not get WM_GETDPISCALEDSIZE messages to inform
+ // Windows about the new size, so we need to manually scale them.
+ QRect currentGeometry = geometry();
+ QRect scaledGeometry = QRect(currentGeometry.topLeft() * scale, currentGeometry.size() * scale);
+ setGeometry(scaledGeometry);
+}
+
static QRect normalFrameGeometry(HWND hwnd)
{
WINDOWPLACEMENT wp;
@@ -1814,7 +2087,7 @@ QRect QWindowsWindow::normalGeometry() const
m_savedFrameGeometry.isValid() && (window()->windowStates() & Qt::WindowFullScreen);
const QRect frame = fakeFullScreen ? m_savedFrameGeometry : normalFrameGeometry(m_data.hwnd);
const QMargins margins = fakeFullScreen
- ? QWindowsGeometryHint::frame(handle(), m_savedStyle, 0)
+ ? QWindowsGeometryHint::frame(window(), handle(), m_savedStyle, 0)
: fullFrameMargins();
return frame.isValid() ? frame.marginsRemoved(margins) : frame;
}
@@ -1866,6 +2139,8 @@ static QString msgUnableToSetGeometry(const QWindowsWindow *platformWindow,
void QWindowsWindow::setGeometry(const QRect &rectIn)
{
+ QBoolBlocker b(m_inSetgeometry);
+
QRect rect = rectIn;
// This means it is a call from QWindow::setFramePosition() and
// the coordinates include the frame (size is still the contents rectangle).
@@ -1873,8 +2148,12 @@ void QWindowsWindow::setGeometry(const QRect &rectIn)
const QMargins margins = frameMargins();
rect.moveTopLeft(rect.topLeft() + QPoint(margins.left(), margins.top()));
}
+
if (m_windowState & Qt::WindowMinimized)
m_data.geometry = rect; // Otherwise set by handleGeometryChange() triggered by event.
+ else
+ setWindowState(Qt::WindowNoState);// Update window state to WindowNoState unless minimized
+
if (m_data.hwnd) {
// A ResizeEvent with resulting geometry will be sent. If we cannot
// achieve that size (for example, window title minimal constraint),
@@ -1885,7 +2164,7 @@ void QWindowsWindow::setGeometry(const QRect &rectIn)
if (m_data.geometry != rect && (isVisible() || QLibraryInfo::isDebugBuild())) {
const auto warning =
msgUnableToSetGeometry(this, rectIn, m_data.geometry,
- m_data.fullFrameMargins, m_data.customMargins);
+ fullFrameMargins(), customMargins());
qWarning("%s: %s", __FUNCTION__, qPrintable(warning));
}
} else {
@@ -1900,8 +2179,41 @@ void QWindowsWindow::handleMoved()
handleGeometryChange();
}
-void QWindowsWindow::handleResized(int wParam)
+void QWindowsWindow::handleResized(int wParam, LPARAM lParam)
{
+ /* Prevents borderless windows from covering the taskbar when maximized. */
+ if ((m_data.flags.testFlag(Qt::FramelessWindowHint)
+ || (m_data.flags.testFlag(Qt::CustomizeWindowHint) && !m_data.flags.testFlag(Qt::WindowTitleHint)))
+ && IsZoomed(m_data.hwnd)) {
+ const int resizedWidth = LOWORD(lParam);
+ const int resizedHeight = HIWORD(lParam);
+
+ const HMONITOR monitor = MonitorFromWindow(m_data.hwnd, MONITOR_DEFAULTTOPRIMARY);
+ MONITORINFO monitorInfo = {};
+ monitorInfo.cbSize = sizeof(MONITORINFO);
+ GetMonitorInfoW(monitor, &monitorInfo);
+
+ int correctLeft = monitorInfo.rcMonitor.left;
+ int correctTop = monitorInfo.rcMonitor.top;
+ int correctWidth = monitorInfo.rcWork.right - monitorInfo.rcWork.left;
+ int correctHeight = monitorInfo.rcWork.bottom - monitorInfo.rcWork.top;
+
+ if (!m_data.flags.testFlag(Qt::FramelessWindowHint)) {
+ const int borderWidth = invisibleMargins(m_data.hwnd).left();
+ correctLeft -= borderWidth;
+ correctTop -= borderWidth;
+ correctWidth += borderWidth * 2;
+ correctHeight += borderWidth * 2;
+ }
+
+ if (resizedWidth != correctWidth || resizedHeight != correctHeight) {
+ qCDebug(lcQpaWindow) << __FUNCTION__ << "correcting: " << resizedWidth << "x"
+ << resizedHeight << " -> " << correctWidth << "x" << correctHeight;
+ SetWindowPos(m_data.hwnd, nullptr, correctLeft, correctTop, correctWidth, correctHeight,
+ SWP_NOZORDER | SWP_NOACTIVATE);
+ }
+ }
+
switch (wParam) {
case SIZE_MAXHIDE: // Some other window affected.
case SIZE_MAXSHOW:
@@ -1911,12 +2223,13 @@ void QWindowsWindow::handleResized(int wParam)
handleWindowStateChange(m_windowState | Qt::WindowMinimized);
return;
case SIZE_MAXIMIZED:
+ handleGeometryChange();
if (!testFlag(WithinSetStyle) && !testFlag(WithinSetGeometry))
handleWindowStateChange(Qt::WindowMaximized | (isFullScreen_sys() ? Qt::WindowFullScreen
: Qt::WindowNoState));
- handleGeometryChange();
break;
case SIZE_RESTORED:
+ handleGeometryChange();
if (!testFlag(WithinSetStyle) && !testFlag(WithinSetGeometry)) {
if (isFullScreen_sys())
handleWindowStateChange(
@@ -1925,7 +2238,6 @@ void QWindowsWindow::handleResized(int wParam)
else if (m_windowState != Qt::WindowNoState && !testFlag(MaximizeToFullScreen))
handleWindowStateChange(Qt::WindowNoState);
}
- handleGeometryChange();
break;
}
}
@@ -1937,45 +2249,43 @@ static inline bool equalDpi(const QDpi &d1, const QDpi &d2)
void QWindowsWindow::checkForScreenChanged(ScreenChangeMode mode)
{
- if (parent() || QWindowsScreenManager::isSingleScreen())
+ if ((parent() && !parent()->isForeignWindow()) || QWindowsScreenManager::isSingleScreen())
return;
QPlatformScreen *currentScreen = screen();
+ auto topLevel = isTopLevel_sys() ? m_data.hwnd : GetAncestor(m_data.hwnd, GA_ROOT);
const QWindowsScreen *newScreen =
- QWindowsContext::instance()->screenManager().screenForHwnd(m_data.hwnd);
+ QWindowsContext::instance()->screenManager().screenForHwnd(topLevel);
+
if (newScreen == nullptr || newScreen == currentScreen)
return;
// For screens with different DPI: postpone until WM_DPICHANGE
// Check on currentScreen as it can be 0 when resuming a session (QTBUG-80436).
- if (mode == FromGeometryChange && currentScreen != nullptr
- && !equalDpi(currentScreen->logicalDpi(), newScreen->logicalDpi())) {
+ const bool changingDpi = !equalDpi(QDpi(savedDpi(), savedDpi()), newScreen->logicalDpi());
+ if (mode == FromGeometryChange && currentScreen != nullptr && changingDpi)
return;
- }
- qCDebug(lcQpaWindows).noquote().nospace() << __FUNCTION__
+
+ qCDebug(lcQpaWindow).noquote().nospace() << __FUNCTION__
<< ' ' << window() << " \"" << (currentScreen ? currentScreen->name() : QString())
<< "\"->\"" << newScreen->name() << '"';
- if (mode == FromGeometryChange)
- setFlag(SynchronousGeometryChangeEvent);
updateFullFrameMargins();
- QWindowSystemInterface::handleWindowScreenChanged(window(), newScreen->screen());
+ QWindowSystemInterface::handleWindowScreenChanged<QWindowSystemInterface::SynchronousDelivery>(window(), newScreen->screen());
}
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
- }
+ updateFullFrameMargins();
QWindowSystemInterface::handleGeometryChange(window(), m_data.geometry);
- // QTBUG-32121: OpenGL/normal windows (with exception of ANGLE) do not receive
- // expose events when shrinking, synthesize.
- if (!testFlag(OpenGL_ES2) && isExposed()
+ // QTBUG-32121: OpenGL/normal windows (with exception of ANGLE
+ // which we no longer support in Qt 6) do not receive expose
+ // events when shrinking, synthesize.
+ if (isExposed()
&& m_data.geometry.size() != previousGeometry.size() // Exclude plain move
// One dimension grew -> Windows will send expose, no need to synthesize.
&& !(m_data.geometry.width() > previousGeometry.width() || m_data.geometry.height() > previousGeometry.height())) {
- fireExpose(QRect(QPoint(0, 0), m_data.geometry.size()), true);
+ fireFullExpose(true);
}
const bool wasSync = testFlag(SynchronousGeometryChangeEvent);
@@ -1984,6 +2294,9 @@ void QWindowsWindow::handleGeometryChange()
if (testFlag(SynchronousGeometryChangeEvent))
QWindowSystemInterface::flushWindowSystemEvents(QEventLoop::ExcludeUserInputEvents);
+ if (!testFlag(ResizeMoveActive))
+ updateRestoreGeometry();
+
if (!wasSync)
clearFlag(SynchronousGeometryChangeEvent);
qCDebug(lcQpaEvents) << __FUNCTION__ << this << window() << m_data.geometry;
@@ -1994,7 +2307,7 @@ void QWindowsBaseWindow::setGeometry_sys(const QRect &rect) const
const QMargins margins = fullFrameMargins();
const QRect frameGeometry = rect + margins;
- qCDebug(lcQpaWindows) << '>' << __FUNCTION__ << window()
+ qCDebug(lcQpaWindow) << '>' << __FUNCTION__ << window()
<< "\n from " << geometry_sys() << " frame: "
<< margins << " to " <<rect
<< " new frame: " << frameGeometry;
@@ -2025,7 +2338,7 @@ void QWindowsBaseWindow::setGeometry_sys(const QRect &rect) const
result = MoveWindow(hwnd, x, frameGeometry.y(),
frameGeometry.width(), frameGeometry.height(), true);
}
- qCDebug(lcQpaWindows) << '<' << __FUNCTION__ << window()
+ qCDebug(lcQpaWindow) << '<' << __FUNCTION__ << window()
<< "\n resulting " << result << geometry_sys();
}
@@ -2047,7 +2360,7 @@ HDC QWindowsWindow::getDC()
}
/*!
- Relases the HDC for the window or does nothing in
+ Releases the HDC for the window or does nothing in
case it was obtained from WinAPI BeginPaint within a WM_PAINT event.
\sa getDC()
@@ -2061,12 +2374,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)
@@ -2078,38 +2385,32 @@ static inline bool isSoftwareGl()
}
bool QWindowsWindow::handleWmPaint(HWND hwnd, UINT message,
- WPARAM, LPARAM)
+ WPARAM, LPARAM, LRESULT *result)
{
- if (message == WM_ERASEBKGND) // Backing store - ignored.
+ if (message == WM_ERASEBKGND) { // Backing store - ignored.
+ *result = 1;
return true;
+ }
// QTBUG-75455: Suppress WM_PAINT sent to invisible windows when setting WS_EX_LAYERED
- if (!window()->isVisible() && (GetWindowLong(hwnd, GWL_EXSTYLE) & WS_EX_LAYERED) != 0)
+ if (!window()->isVisible() && (GetWindowLongPtr(hwnd, GWL_EXSTYLE) & WS_EX_LAYERED) != 0)
return false;
// Ignore invalid update bounding rectangles
- RECT updateRect;
- if (!GetUpdateRect(m_data.hwnd, &updateRect, FALSE))
+ if (!GetUpdateRect(m_data.hwnd, 0, FALSE))
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)))
- {
- 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.
fireExpose(QRegion(qrectFromRECT(ps.rcPaint)), true);
- if (qSizeOfRect(updateRect) == m_data.geometry.size() && !QWindowsContext::instance()->asyncExpose())
+ if (!QWindowsContext::instance()->asyncExpose())
QWindowSystemInterface::flushWindowSystemEvents(QEventLoop::ExcludeUserInputEvents);
EndPaint(hwnd, &ps);
@@ -2123,7 +2424,7 @@ void QWindowsWindow::setWindowTitle(const QString &title)
void QWindowsWindow::setWindowFlags(Qt::WindowFlags flags)
{
- qCDebug(lcQpaWindows) << '>' << __FUNCTION__ << this << window() << "\n from: "
+ qCDebug(lcQpaWindow) << '>' << __FUNCTION__ << this << window() << "\n from: "
<< m_data.flags << "\n to: " << flags;
const QRect oldGeometry = geometry();
if (m_data.flags != flags) {
@@ -2141,7 +2442,7 @@ void QWindowsWindow::setWindowFlags(Qt::WindowFlags flags)
if (oldGeometry != newGeometry)
handleGeometryChange();
- qCDebug(lcQpaWindows) << '<' << __FUNCTION__ << "\n returns: "
+ qCDebug(lcQpaWindow) << '<' << __FUNCTION__ << "\n returns: "
<< m_data.flags << " geometry " << oldGeometry << "->" << newGeometry;
}
@@ -2156,12 +2457,14 @@ QWindowsWindowData QWindowsWindow::setWindowFlags_sys(Qt::WindowFlags wt,
QWindowsWindowData result = m_data;
result.flags = creationData.flags;
result.embedded = creationData.embedded;
+ result.hasFrame = (creationData.style & (WS_DLGFRAME | WS_THICKFRAME))
+ && !(creationData.flags & Qt::FramelessWindowHint);
return result;
}
void QWindowsWindow::handleWindowStateChange(Qt::WindowStates state)
{
- qCDebug(lcQpaWindows) << __FUNCTION__ << this << window()
+ qCDebug(lcQpaWindow) << __FUNCTION__ << this << window()
<< "\n from " << m_windowState << " to " << state;
m_windowState = state;
QWindowSystemInterface::handleWindowStateChanged(window(), state);
@@ -2169,12 +2472,20 @@ void QWindowsWindow::handleWindowStateChange(Qt::WindowStates state)
handleHidden();
QWindowSystemInterface::flushWindowSystemEvents(QEventLoop::ExcludeUserInputEvents); // Tell QQuickWindow to stop rendering now.
} else {
+ if (state & Qt::WindowMaximized) {
+ WINDOWPLACEMENT windowPlacement{};
+ windowPlacement.length = sizeof(WINDOWPLACEMENT);
+ GetWindowPlacement(m_data.hwnd, &windowPlacement);
+ const RECT geometry = RECTfromQRect(m_data.restoreGeometry);
+ windowPlacement.rcNormalPosition = geometry;
+ SetWindowPlacement(m_data.hwnd, &windowPlacement);
+ }
// QTBUG-17548: We send expose events when receiving WM_Paint, but for
// layered windows and transient children, we won't receive any WM_Paint.
QWindow *w = window();
bool exposeEventsSent = false;
if (isLayered()) {
- fireExpose(QRegion(0, 0, w->width(), w->height()));
+ fireFullExpose();
exposeEventsSent = true;
}
const QWindowList allWindows = QGuiApplication::allWindows();
@@ -2182,7 +2493,7 @@ void QWindowsWindow::handleWindowStateChange(Qt::WindowStates state)
if (child != w && child->isVisible() && child->transientParent() == w) {
QWindowsWindow *platformWindow = QWindowsWindow::windowsWindowOf(child);
if (platformWindow && platformWindow->isLayered()) {
- platformWindow->fireExpose(QRegion(0, 0, child->width(), child->height()));
+ platformWindow->fireFullExpose();
exposeEventsSent = true;
}
}
@@ -2192,6 +2503,11 @@ void QWindowsWindow::handleWindowStateChange(Qt::WindowStates state)
}
}
+void QWindowsWindow::updateRestoreGeometry()
+{
+ m_data.restoreGeometry = normalFrameGeometry(m_data.hwnd);
+}
+
void QWindowsWindow::setWindowState(Qt::WindowStates state)
{
if (m_data.hwnd) {
@@ -2228,7 +2544,7 @@ void QWindowsWindow::setWindowState_sys(Qt::WindowStates newState)
const Qt::WindowStates oldState = m_windowState;
if (oldState == newState)
return;
- qCDebug(lcQpaWindows) << '>' << __FUNCTION__ << this << window()
+ qCDebug(lcQpaWindow) << '>' << __FUNCTION__ << this << window()
<< " from " << oldState << " to " << newState;
const bool visible = isVisible();
@@ -2236,11 +2552,7 @@ void QWindowsWindow::setWindowState_sys(Qt::WindowStates newState)
if (stateChange & Qt::WindowFullScreen) {
if (newState & Qt::WindowFullScreen) {
-#ifndef Q_FLATTEN_EXPOSE
UINT newStyle = WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_POPUP;
-#else
- UINT newStyle = WS_POPUP;
-#endif
// Save geometry and style to be restored when fullscreen
// is turned off again, since on Windows, it is not a real
// Window state but emulated by changing geometry and style.
@@ -2263,26 +2575,26 @@ void QWindowsWindow::setWindowState_sys(Qt::WindowStates newState)
if (testFlag(HasBorderInFullScreen))
newStyle |= WS_BORDER;
setStyle(newStyle);
- // Use geometry of QWindow::screen() within creation or the virtual screen the
- // window is in (QTBUG-31166, QTBUG-30724).
- const QScreen *screen = window()->screen();
- if (!screen)
- screen = QGuiApplication::primaryScreen();
- const QRect r = screen ? QHighDpi::toNativePixels(screen->geometry(), window()) : m_savedFrameGeometry;
-
+ const HMONITOR monitor = MonitorFromWindow(m_data.hwnd, MONITOR_DEFAULTTONEAREST);
+ MONITORINFO monitorInfo = {};
+ monitorInfo.cbSize = sizeof(MONITORINFO);
+ GetMonitorInfoW(monitor, &monitorInfo);
+ const QRect screenGeometry(monitorInfo.rcMonitor.left, monitorInfo.rcMonitor.top,
+ monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left,
+ monitorInfo.rcMonitor.bottom - monitorInfo.rcMonitor.top);
if (newState & Qt::WindowMinimized) {
- setMinimizedGeometry(m_data.hwnd, r);
+ setMinimizedGeometry(m_data.hwnd, screenGeometry);
if (stateChange & Qt::WindowMaximized)
setRestoreMaximizedFlag(m_data.hwnd, newState & Qt::WindowMaximized);
} else {
const UINT swpf = SWP_FRAMECHANGED | SWP_NOACTIVATE;
const bool wasSync = testFlag(SynchronousGeometryChangeEvent);
setFlag(SynchronousGeometryChangeEvent);
- SetWindowPos(m_data.hwnd, HWND_TOP, r.left(), r.top(), r.width(), r.height(), swpf);
+ SetWindowPos(m_data.hwnd, HWND_TOP, screenGeometry.left(), screenGeometry.top(), screenGeometry.width(), screenGeometry.height(), swpf);
if (!wasSync)
clearFlag(SynchronousGeometryChangeEvent);
clearFlag(MaximizeToFullScreen);
- QWindowSystemInterface::handleGeometryChange(window(), r);
+ QWindowSystemInterface::handleGeometryChange(window(), screenGeometry);
QWindowSystemInterface::flushWindowSystemEvents(QEventLoop::ExcludeUserInputEvents);
}
} else {
@@ -2296,8 +2608,10 @@ void QWindowsWindow::setWindowState_sys(Qt::WindowStates newState)
if (!screen)
screen = QGuiApplication::primaryScreen();
// That area of the virtual desktop might not be covered by a screen anymore.
- if (!screen->geometry().intersects(m_savedFrameGeometry))
- m_savedFrameGeometry.moveTo(screen->geometry().topLeft());
+ if (const auto platformScreen = screen->handle()) {
+ if (!platformScreen->geometry().intersects(m_savedFrameGeometry))
+ m_savedFrameGeometry.moveTo(platformScreen->geometry().topLeft());
+ }
if (newState & Qt::WindowMinimized) {
setMinimizedGeometry(m_data.hwnd, m_savedFrameGeometry);
@@ -2352,12 +2666,12 @@ void QWindowsWindow::setWindowState_sys(Qt::WindowStates newState)
setRestoreMaximizedFlag(m_data.hwnd, newState & Qt::WindowMaximized);
}
}
- qCDebug(lcQpaWindows) << '<' << __FUNCTION__ << this << window() << newState;
+ qCDebug(lcQpaWindow) << '<' << __FUNCTION__ << this << window() << newState;
}
void QWindowsWindow::setStyle(unsigned s) const
{
- qCDebug(lcQpaWindows) << __FUNCTION__ << this << window() << debugWinStyle(s);
+ qCDebug(lcQpaWindow) << __FUNCTION__ << this << window() << debugWinStyle(s);
setFlag(WithinSetStyle);
SetWindowLongPtr(m_data.hwnd, GWL_STYLE, s);
clearFlag(WithinSetStyle);
@@ -2365,14 +2679,16 @@ void QWindowsWindow::setStyle(unsigned s) const
void QWindowsWindow::setExStyle(unsigned s) const
{
- qCDebug(lcQpaWindows).nospace() << __FUNCTION__ << ' ' << this << ' ' << window()
- << " 0x" << QByteArray::number(s, 16);
+ qCDebug(lcQpaWindow) << __FUNCTION__ << this << window() << debugWinExStyle(s);
SetWindowLongPtr(m_data.hwnd, GWL_EXSTYLE, s);
}
bool QWindowsWindow::windowEvent(QEvent *event)
{
switch (event->type()) {
+ case QEvent::ApplicationPaletteChange:
+ setDarkBorder(QWindowsContext::isDarkMode());
+ break;
case QEvent::WindowBlocked: // Blocked by another modal window.
setEnabled(false);
setFlag(BlockedByModal);
@@ -2392,12 +2708,24 @@ bool QWindowsWindow::windowEvent(QEvent *event)
void QWindowsWindow::propagateSizeHints()
{
- qCDebug(lcQpaWindows) << __FUNCTION__ << this << window();
+ qCDebug(lcQpaWindow) << __FUNCTION__ << this << window();
}
bool QWindowsWindow::handleGeometryChangingMessage(MSG *message, const QWindow *qWindow, const QMargins &margins)
{
auto *windowPos = reinterpret_cast<WINDOWPOS *>(message->lParam);
+ const QRect suggestedFrameGeometry(windowPos->x, windowPos->y,
+ windowPos->cx, windowPos->cy);
+ const QRect suggestedGeometry = suggestedFrameGeometry - margins;
+
+ // Tell Windows to discard the entire contents of the client area, as re-using
+ // parts of the client area would lead to jitter during resize.
+ // Check the suggestedGeometry against the current one to only discard during
+ // resize, and not a plain move. We also look for SWP_NOSIZE since that, too,
+ // implies an identical size, and comparing QRects wouldn't work with null cx/cy
+ if (!(windowPos->flags & SWP_NOSIZE) && suggestedGeometry.size() != qWindow->geometry().size())
+ windowPos->flags |= SWP_NOCOPYBITS;
+
if ((windowPos->flags & SWP_NOZORDER) == 0) {
if (QWindowsWindow *platformWindow = QWindowsWindow::windowsWindowOf(qWindow)) {
QWindow *parentWindow = qWindow->parent();
@@ -2410,11 +2738,8 @@ bool QWindowsWindow::handleGeometryChangingMessage(MSG *message, const QWindow *
}
if (!qWindow->isTopLevel()) // Implement hasHeightForWidth().
return false;
- if ((windowPos->flags & (SWP_NOCOPYBITS | SWP_NOSIZE)))
+ if (windowPos->flags & SWP_NOSIZE)
return false;
- const QRect suggestedFrameGeometry(windowPos->x, windowPos->y,
- windowPos->cx, windowPos->cy);
- const QRect suggestedGeometry = suggestedFrameGeometry - margins;
const QRectF correctedGeometryF = QPlatformWindow::closestAcceptableGeometry(qWindow, suggestedGeometry);
if (!correctedGeometryF.isValid())
return false;
@@ -2436,42 +2761,90 @@ bool QWindowsWindow::handleGeometryChanging(MSG *message) const
void QWindowsWindow::setFullFrameMargins(const QMargins &newMargins)
{
+ if (shouldOmitFrameAdjustment(m_data.flags, m_data.hwnd))
+ return;
if (m_data.fullFrameMargins != newMargins) {
- qCDebug(lcQpaWindows) << __FUNCTION__ << window() << m_data.fullFrameMargins << "->" << newMargins;
+ qCDebug(lcQpaWindow) << __FUNCTION__ << window() << m_data.fullFrameMargins << "->" << newMargins;
m_data.fullFrameMargins = newMargins;
}
}
void QWindowsWindow::updateFullFrameMargins()
{
- // Normally obtained from WM_NCCALCSIZE
+ // QTBUG-82580: If a native menu is present, force a WM_NCCALCSIZE.
+ if (GetMenu(m_data.hwnd))
+ QWindowsContext::forceNcCalcSize(m_data.hwnd);
+ else
+ calculateFullFrameMargins();
+}
+
+void QWindowsWindow::calculateFullFrameMargins()
+{
+ if (shouldOmitFrameAdjustment(m_data.flags, m_data.hwnd))
+ return;
+
+ // QTBUG-113736: systemMargins depends on AdjustWindowRectExForDpi. This doesn't take into
+ // account possible external modifications to the titlebar, as with ExtendsContentIntoTitleBar()
+ // from the Windows App SDK. We can fix this by comparing the WindowRect (which includes the
+ // frame) to the ClientRect. If a 'typical' frame is detected, i.e. only the titlebar has been
+ // modified, we can safely adjust the frame by deducting the bottom margin to the total Y
+ // difference between the two rects, to get the actual size of the titlebar and prevent
+ // unwanted client area slicing.
+
+ RECT windowRect{};
+ RECT clientRect{};
+ GetWindowRect(handle(), &windowRect);
+ GetClientRect(handle(), &clientRect);
+
+ // QTBUG-117704 It is also possible that the user has manually removed the frame (for example
+ // by handling WM_NCCALCSIZE). If that is the case, i.e., the client area and the window area
+ // have identical sizes, we don't want to override the user-defined margins.
+
+ if (qrectFromRECT(windowRect).size() == qrectFromRECT(clientRect).size())
+ return;
+
+ // Normally obtained from WM_NCCALCSIZE. This calculation only works
+ // when no native menu is present.
const auto systemMargins = testFlag(DisableNonClientScaling)
- ? QWindowsGeometryHint::frameOnPrimaryScreen(m_data.hwnd)
+ ? QWindowsGeometryHint::frameOnPrimaryScreen(window(), m_data.hwnd)
: frameMargins_sys();
- setFullFrameMargins(systemMargins + m_data.customMargins);
+ const QMargins actualMargins = systemMargins + customMargins();
+
+ const int yDiff = (windowRect.bottom - windowRect.top) - (clientRect.bottom - clientRect.top);
+ const bool typicalFrame = (actualMargins.left() == actualMargins.right())
+ && (actualMargins.right() == actualMargins.bottom());
+
+ const QMargins adjustedMargins = typicalFrame ?
+ QMargins(actualMargins.left(), (yDiff - actualMargins.bottom()),
+ actualMargins.right(), actualMargins.bottom())
+ : actualMargins;
+
+ setFullFrameMargins(adjustedMargins);
}
QMargins QWindowsWindow::frameMargins() const
{
QMargins result = fullFrameMargins();
if (isTopLevel() && m_data.hasFrame)
- result -= invisibleMargins(geometry().topLeft());
+ result -= invisibleMargins(m_data.hwnd);
return result;
}
QMargins QWindowsWindow::fullFrameMargins() const
{
+ if (shouldOmitFrameAdjustment(m_data.flags, m_data.hwnd))
+ return {};
return m_data.fullFrameMargins;
}
void QWindowsWindow::setOpacity(qreal level)
{
- qCDebug(lcQpaWindows) << __FUNCTION__ << level;
+ qCDebug(lcQpaWindow) << __FUNCTION__ << level;
if (!qFuzzyCompare(m_opacity, level)) {
m_opacity = level;
if (m_data.hwnd)
setWindowOpacity(m_data.hwnd, m_data.flags,
- window()->format().hasAlpha(), testFlag(OpenGLSurface) || testFlag(VulkanSurface),
+ window()->format().hasAlpha(), testFlag(OpenGLSurface) || testFlag(VulkanSurface) || testFlag(Direct3DSurface),
level);
}
}
@@ -2526,40 +2899,76 @@ void QWindowsWindow::setMask(const QRegion &region)
void QWindowsWindow::requestActivateWindow()
{
- qCDebug(lcQpaWindows) << __FUNCTION__ << this << window();
- // 'Active' state handling is based in focus since it needs to work for
- // child windows as well.
- if (m_data.hwnd) {
- const DWORD currentThread = GetCurrentThreadId();
- bool attached = false;
- DWORD foregroundThread = 0;
-
- // QTBUG-14062, QTBUG-37435: Windows normally only flashes the taskbar entry
- // when activating windows of inactive applications. Attach to the input of the
- // currently active window while setting the foreground window to always activate
- // the window when desired.
- if (QGuiApplication::applicationState() != Qt::ApplicationActive
- && QWindowsNativeInterface::windowActivationBehavior() == QWindowsWindowFunctions::AlwaysActivateWindow) {
- if (const HWND foregroundWindow = GetForegroundWindow()) {
- foregroundThread = GetWindowThreadProcessId(foregroundWindow, nullptr);
- if (foregroundThread && foregroundThread != currentThread)
- attached = AttachThreadInput(foregroundThread, currentThread, TRUE) == TRUE;
- if (attached) {
- if (!window()->flags().testFlag(Qt::WindowStaysOnBottomHint)
- && !window()->flags().testFlag(Qt::WindowStaysOnTopHint)
- && window()->type() != Qt::ToolTip) {
- const UINT swpFlags = SWP_NOMOVE | SWP_NOSIZE | SWP_NOOWNERZORDER;
- SetWindowPos(m_data.hwnd, HWND_TOPMOST, 0, 0, 0, 0, swpFlags);
- SetWindowPos(m_data.hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, swpFlags);
- }
- }
- }
- }
+ qCDebug(lcQpaWindow) << __FUNCTION__ << this << window();
+
+ if (!m_data.hwnd)
+ return;
+
+ const auto activationBehavior = QWindowsIntegration::instance()->windowActivationBehavior();
+ if (QGuiApplication::applicationState() == Qt::ApplicationActive
+ || activationBehavior != QWindowsApplication::AlwaysActivateWindow) {
SetForegroundWindow(m_data.hwnd);
SetFocus(m_data.hwnd);
- if (attached)
- AttachThreadInput(foregroundThread, currentThread, FALSE);
+ return;
+ }
+
+ // Force activate this window. The following code will bring the window to the
+ // foreground and activate it. If the window is hidden, it will show up. If
+ // the window is minimized, it will restore to the previous position.
+
+ // But first we need some sanity checks.
+ if (m_data.flags & Qt::WindowStaysOnBottomHint) {
+ qCWarning(lcQpaWindow) <<
+ "Windows with Qt::WindowStaysOnBottomHint can't be brought to the foreground.";
+ return;
+ }
+ if (m_data.flags & Qt::WindowStaysOnTopHint) {
+ qCWarning(lcQpaWindow) <<
+ "Windows with Qt::WindowStaysOnTopHint will always be on the foreground.";
+ return;
+ }
+ if (window()->type() == Qt::ToolTip) {
+ qCWarning(lcQpaWindow) << "ToolTip windows should not be activated.";
+ return;
+ }
+
+ // We need to show the window first, otherwise we won't be able to bring it to front.
+ if (!IsWindowVisible(m_data.hwnd))
+ ShowWindow(m_data.hwnd, SW_SHOW);
+
+ if (IsIconic(m_data.hwnd)) {
+ ShowWindow(m_data.hwnd, SW_RESTORE);
+ // When the window is restored, it will always become the foreground window.
+ // So return early here, we don't need the following code to bring it to front.
+ return;
+ }
+
+ // OK, our window is not minimized, so now we will try to bring it to front manually.
+ const HWND oldForegroundWindow = GetForegroundWindow();
+ if (!oldForegroundWindow) // It may be NULL, according to MS docs.
+ return;
+
+ // First try to send a message to the current foreground window to check whether
+ // it is currently hanging or not.
+ if (SendMessageTimeoutW(oldForegroundWindow, WM_NULL, 0, 0,
+ SMTO_BLOCK | SMTO_ABORTIFHUNG | SMTO_NOTIMEOUTIFNOTHUNG, 1000, nullptr) == 0) {
+ qCWarning(lcQpaWindow) << "The foreground window hangs, can't activate current window.";
+ return;
}
+
+ const DWORD windowThreadProcessId = GetWindowThreadProcessId(oldForegroundWindow, nullptr);
+ const DWORD currentThreadId = GetCurrentThreadId();
+
+ AttachThreadInput(windowThreadProcessId, currentThreadId, TRUE);
+ const auto cleanup = qScopeGuard([windowThreadProcessId, currentThreadId](){
+ AttachThreadInput(windowThreadProcessId, currentThreadId, FALSE);
+ });
+
+ BringWindowToTop(m_data.hwnd);
+
+ // Activate the window too. This will force us to the virtual desktop this
+ // window is on, if it's on another virtual desktop.
+ SetActiveWindow(m_data.hwnd);
}
bool QWindowsWindow::setKeyboardGrabEnabled(bool grab)
@@ -2568,7 +2977,7 @@ bool QWindowsWindow::setKeyboardGrabEnabled(bool grab)
qWarning("%s: No handle", __FUNCTION__);
return false;
}
- qCDebug(lcQpaWindows) << __FUNCTION__ << this << window() << grab;
+ qCDebug(lcQpaWindow) << __FUNCTION__ << this << window() << grab;
QWindowsContext *context = QWindowsContext::instance();
if (grab) {
@@ -2582,7 +2991,7 @@ bool QWindowsWindow::setKeyboardGrabEnabled(bool grab)
bool QWindowsWindow::setMouseGrabEnabled(bool grab)
{
- qCDebug(lcQpaWindows) << __FUNCTION__ << window() << grab;
+ qCDebug(lcQpaWindow) << __FUNCTION__ << window() << grab;
if (!m_data.hwnd) {
qWarning("%s: No handle", __FUNCTION__);
return false;
@@ -2629,7 +3038,7 @@ static inline DWORD edgesToWinOrientation(Qt::Edges edges)
bool QWindowsWindow::startSystemResize(Qt::Edges edges)
{
- if (Q_UNLIKELY(!(window()->flags() & Qt::MSWindowsFixedSizeDialogHint)))
+ if (Q_UNLIKELY(window()->flags().testFlag(Qt::MSWindowsFixedSizeDialogHint)))
return false;
ReleaseCapture();
@@ -2654,52 +3063,10 @@ void QWindowsWindow::setFrameStrutEventsEnabled(bool enabled)
}
}
-static int getBorderWidth(const QPlatformScreen *screen)
-{
- NONCLIENTMETRICS ncm;
- QWindowsContext::nonClientMetricsForScreen(&ncm, screen);
- return ncm.iBorderWidth + ncm.iPaddedBorderWidth + 2;
-}
-
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))
- && (m_data.flags.testFlag(Qt::FramelessWindowHint)
- || (m_data.flags.testFlag(Qt::CustomizeWindowHint) && !m_data.flags.testFlag(Qt::WindowTitleHint)))) {
- const QScreen *screen = window()->screen();
-
- // Documentation of MINMAXINFO states that it will only work for the primary screen
- if (screen && screen == QGuiApplication::primaryScreen()) {
- const QRect availableGeometry = QHighDpi::toNativePixels(screen->availableGeometry(), screen);
- mmi->ptMaxSize.y = availableGeometry.height();
-
- // Width, because you can have the taskbar on the sides too.
- mmi->ptMaxSize.x = availableGeometry.width();
-
- // If you have the taskbar on top, or on the left you don't want it at (0,0):
- mmi->ptMaxPosition.x = availableGeometry.x();
- mmi->ptMaxPosition.y = availableGeometry.y();
- if (!m_data.flags.testFlag(Qt::FramelessWindowHint)) {
- const int borderWidth = getBorderWidth(screen->handle());
- mmi->ptMaxSize.x += borderWidth * 2;
- mmi->ptMaxSize.y += borderWidth * 2;
- mmi->ptMaxTrackSize = mmi->ptMaxSize;
- mmi->ptMaxPosition.x -= borderWidth;
- mmi->ptMaxPosition.y -= borderWidth;
- }
- } else if (!screen){
- qWarning("window()->screen() returned a null screen");
- }
- }
-
- qCDebug(lcQpaWindows) << __FUNCTION__ << window() << *mmi;
+ QWindowsGeometryHint::applyToMinMaxInfo(window(), fullFrameMargins(), mmi);
+ qCDebug(lcQpaWindow) << __FUNCTION__ << window() << *mmi;
}
bool QWindowsWindow::handleNonClientHitTest(const QPoint &globalPos, LRESULT *result) const
@@ -2728,12 +3095,7 @@ bool QWindowsWindow::handleNonClientHitTest(const QPoint &globalPos, LRESULT *re
return true;
}
if (localPos.y() < 0) {
- // We want to return HTCAPTION/true only over the outer sizing frame, not the entire title bar,
- // otherwise the title bar buttons (close, etc.) become unresponsive on Windows 7 (QTBUG-78262).
- // However, neither frameMargins() nor GetSystemMetrics(SM_CYSIZEFRAME), etc., give the correct
- // sizing frame height in all Windows versions/scales. This empirical constant seems to work, though.
- const int sizingHeight = 9;
- const int topResizeBarPos = sizingHeight - frameMargins().top();
+ const int topResizeBarPos = invisibleMargins(m_data.hwnd).left() - frameMargins().top();
if (localPos.y() < topResizeBarPos) {
*result = HTCAPTION; // Extend caption over top resize bar, let's user move the window.
return true;
@@ -2807,9 +3169,16 @@ void QWindowsWindow::applyCursor()
void QWindowsWindow::setCursor(const CursorHandlePtr &c)
{
#ifndef QT_NO_CURSOR
- if (c->handle() != m_cursor->handle()) {
+ bool changed = c->handle() != m_cursor->handle();
+ // QTBUG-98856: Cursors can get out of sync after restoring override
+ // cursors on native windows. Force an update.
+ if (testFlag(RestoreOverrideCursor)) {
+ clearFlag(RestoreOverrideCursor);
+ changed = true;
+ }
+ if (changed) {
const bool apply = applyNewCursor(window());
- qCDebug(lcQpaWindows) << window() << __FUNCTION__
+ qCDebug(lcQpaWindow) << window() << __FUNCTION__
<< c->handle() << " doApply=" << apply;
m_cursor = c;
if (apply)
@@ -2878,7 +3247,8 @@ void QWindowsWindow::setEnabled(bool enabled)
static HICON createHIcon(const QIcon &icon, int xSize, int ySize)
{
if (!icon.isNull()) {
- const QPixmap pm = icon.pixmap(icon.actualSize(QSize(xSize, ySize)));
+ // QTBUG-90363, request DPR=1 for the title bar.
+ const QPixmap pm = icon.pixmap(icon.actualSize(QSize(xSize, ySize)), 1);
if (!pm.isNull())
return qt_pixmapToWinHICON(pm);
}
@@ -2920,7 +3290,7 @@ static bool queryDarkBorder(HWND hwnd)
SUCCEEDED(DwmGetWindowAttribute(hwnd, DwmwaUseImmersiveDarkMode, &result, sizeof(result)))
|| SUCCEEDED(DwmGetWindowAttribute(hwnd, DwmwaUseImmersiveDarkModeBefore20h1, &result, sizeof(result)));
if (!ok)
- qWarning("%s: Unable to retrieve dark window border setting.", __FUNCTION__);
+ qCWarning(lcQpaWindow, "%s: Unable to retrieve dark window border setting.", __FUNCTION__);
return result == TRUE;
}
@@ -2931,14 +3301,18 @@ bool QWindowsWindow::setDarkBorderToWindow(HWND hwnd, bool d)
SUCCEEDED(DwmSetWindowAttribute(hwnd, DwmwaUseImmersiveDarkMode, &darkBorder, sizeof(darkBorder)))
|| SUCCEEDED(DwmSetWindowAttribute(hwnd, DwmwaUseImmersiveDarkModeBefore20h1, &darkBorder, sizeof(darkBorder)));
if (!ok)
- qWarning("%s: Unable to set dark window border.", __FUNCTION__);
+ qCWarning(lcQpaWindow, "%s: Unable to set %s window border.", __FUNCTION__, d ? "dark" : "light");
return ok;
}
void QWindowsWindow::setDarkBorder(bool d)
{
- if (shouldApplyDarkFrame(window()) && queryDarkBorder(m_data.hwnd) != d)
- setDarkBorderToWindow(m_data.hwnd, d);
+ // respect explicit opt-out and incompatible palettes or styles
+ d = d && shouldApplyDarkFrame(window());
+ if (queryDarkBorder(m_data.hwnd) == d)
+ return;
+
+ setDarkBorderToWindow(m_data.hwnd, d);
}
QWindowsMenuBar *QWindowsWindow::menuBar() const
@@ -2951,6 +3325,13 @@ void QWindowsWindow::setMenuBar(QWindowsMenuBar *mb)
m_menuBar = mb;
}
+QMargins QWindowsWindow::customMargins() const
+{
+ if (m_data.flags & Qt::FramelessWindowHint)
+ return {};
+ return m_data.customMargins;
+}
+
/*!
\brief Sets custom margins to be added to the default margins determined by
the windows style in the handling of the WM_NCCALCSIZE message.
@@ -2963,6 +3344,10 @@ void QWindowsWindow::setMenuBar(QWindowsMenuBar *mb)
void QWindowsWindow::setCustomMargins(const QMargins &newCustomMargins)
{
+ if (m_data.flags & Qt::FramelessWindowHint) {
+ qCWarning(lcQpaWindow) << "You should not set custom margins for a frameless window.";
+ return;
+ }
if (newCustomMargins != m_data.customMargins) {
const QMargins oldCustomMargins = m_data.customMargins;
m_data.customMargins = newCustomMargins;
@@ -2971,7 +3356,7 @@ void QWindowsWindow::setCustomMargins(const QMargins &newCustomMargins)
const QPoint topLeft = currentFrameGeometry.topLeft();
QRect newFrame = currentFrameGeometry.marginsRemoved(oldCustomMargins) + m_data.customMargins;
newFrame.moveTo(topLeft);
- qCDebug(lcQpaWindows) << __FUNCTION__ << oldCustomMargins << "->" << newCustomMargins
+ qCDebug(lcQpaWindow) << __FUNCTION__ << oldCustomMargins << "->" << newCustomMargins
<< currentFrameGeometry << "->" << newFrame;
SetWindowPos(m_data.hwnd, nullptr, newFrame.x(), newFrame.y(), newFrame.width(), newFrame.height(), SWP_NOZORDER | SWP_FRAMECHANGED | SWP_NOACTIVATE);
}
@@ -2995,9 +3380,9 @@ void *QWindowsWindow::surface(void *nativeConfig, int *err)
return &m_vkSurface;
}
#elif defined(QT_NO_OPENGL)
- Q_UNUSED(err)
- Q_UNUSED(nativeConfig)
- return 0;
+ Q_UNUSED(err);
+ Q_UNUSED(nativeConfig);
+ return nullptr;
#endif
#ifndef QT_NO_OPENGL
if (!m_surface) {
@@ -3006,6 +3391,8 @@ void *QWindowsWindow::surface(void *nativeConfig, int *err)
}
return m_surface;
+#else
+ return nullptr;
#endif
}
@@ -3028,46 +3415,28 @@ void QWindowsWindow::invalidateSurface()
#endif // QT_NO_OPENGL
}
-void QWindowsWindow::setTouchWindowTouchTypeStatic(QWindow *window, QWindowsWindowFunctions::TouchWindowTouchTypes touchTypes)
+void QWindowsWindow::registerTouchWindow()
{
- if (!window->handle())
+ if ((QWindowsContext::instance()->systemInfo() & QWindowsContext::SI_SupportsTouch) == 0)
return;
- static_cast<QWindowsWindow *>(window->handle())->registerTouchWindow(touchTypes);
-}
-void QWindowsWindow::registerTouchWindow(QWindowsWindowFunctions::TouchWindowTouchTypes touchTypes)
-{
- if ((QWindowsContext::instance()->systemInfo() & QWindowsContext::SI_SupportsTouch)
- && !testFlag(TouchRegistered)) {
- ULONG touchFlags = 0;
- const bool ret = IsTouchWindow(m_data.hwnd, &touchFlags);
- // Return if it is not a touch window or the flags are already set by a hook
- // such as HCBT_CREATEWND
- if (ret || touchFlags != 0)
+ // Initially register or re-register to change the flags
+ const auto touchTypes = QWindowsIntegration::instance()->touchWindowTouchType();
+ if (testFlag(TouchRegistered)) {
+ const auto currentTouchTypes = touchWindowTouchTypes_sys();
+ if (currentTouchTypes.has_value() && currentTouchTypes.value() == touchTypes)
return;
- if (RegisterTouchWindow(m_data.hwnd, ULONG(touchTypes)))
- setFlag(TouchRegistered);
- else
- qErrnoWarning("RegisterTouchWindow() failed for window '%s'.", qPrintable(window()->objectName()));
}
-}
-void QWindowsWindow::aboutToMakeCurrent()
-{
-#ifndef QT_NO_OPENGL
- // For RasterGLSurface windows, that become OpenGL windows dynamically, it might be
- // time to set up some GL specifics. This is particularly important for layered
- // windows (WS_EX_LAYERED due to alpha > 0).
- const bool isCompositing = qt_window_private(window())->compositing;
- if (isCompositing != testFlag(Compositing)) {
- if (isCompositing)
- setFlag(Compositing);
- else
- clearFlag(Compositing);
-
- updateGLWindowSettings(window(), m_data.hwnd, m_data.flags, m_opacity);
- }
-#endif
+ ULONG touchFlags = 0;
+ if (touchTypes.testFlag(TouchWindowTouchType::FineTouch))
+ touchFlags |= TWF_FINETOUCH;
+ if (touchTypes.testFlag(TouchWindowTouchType::WantPalmTouch))
+ touchFlags |= TWF_WANTPALM;
+ if (RegisterTouchWindow(m_data.hwnd, touchFlags))
+ setFlag(TouchRegistered);
+ else
+ qErrnoWarning("RegisterTouchWindow() failed for window '%s'.", qPrintable(window()->objectName()));
}
void QWindowsWindow::setHasBorderInFullScreenStatic(QWindow *window, bool border)
@@ -3083,9 +3452,14 @@ void QWindowsWindow::setHasBorderInFullScreenDefault(bool border)
m_borderInFullScreenDefault = border;
}
+bool QWindowsWindow::hasBorderInFullScreen() const
+{
+ return testFlag(HasBorderInFullScreen);
+}
+
void QWindowsWindow::setHasBorderInFullScreen(bool border)
{
- if (testFlag(HasBorderInFullScreen) == border)
+ if (hasBorderInFullScreen() == border)
return;
if (border)
setFlag(HasBorderInFullScreen);
diff --git a/src/plugins/platforms/windows/qwindowswindow.h b/src/plugins/platforms/windows/qwindowswindow.h
index e1f7908687..024711e7f3 100644
--- a/src/plugins/platforms/windows/qwindowswindow.h
+++ b/src/plugins/platforms/windows/qwindowswindow.h
@@ -1,56 +1,23 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QWINDOWSWINDOW_H
#define QWINDOWSWINDOW_H
#include <QtCore/qt_windows.h>
#include <QtCore/qpointer.h>
+#include "qwindowsapplication.h"
#include "qwindowscursor.h"
#include <qpa/qplatformwindow.h>
-#include <QtPlatformHeaders/qwindowswindowfunctions.h>
+#include <qpa/qplatformwindow_p.h>
#if QT_CONFIG(vulkan)
#include "qwindowsvulkaninstance.h"
#endif
+#include <optional>
+
QT_BEGIN_NAMESPACE
class QWindowsOleDropTarget;
@@ -59,10 +26,11 @@ class QDebug;
struct QWindowsGeometryHint
{
- static QMargins frameOnPrimaryScreen(DWORD style, DWORD exStyle);
- static QMargins frameOnPrimaryScreen(HWND hwnd);
- static QMargins frame(DWORD style, DWORD exStyle, qreal dpi);
- static QMargins frame(HWND hwnd, DWORD style, DWORD exStyle);
+ static QMargins frameOnPrimaryScreen(const QWindow *w, DWORD style, DWORD exStyle);
+ static QMargins frameOnPrimaryScreen(const QWindow *w, HWND hwnd);
+ static QMargins frame(const QWindow *w, DWORD style, DWORD exStyle, qreal dpi);
+ static QMargins frame(const QWindow *w, HWND hwnd, DWORD style, DWORD exStyle);
+ static QMargins frame(const QWindow *w, HWND hwnd);
static QMargins frame(const QWindow *w, const QRect &geometry,
DWORD style, DWORD exStyle);
static bool handleCalculateSize(const QMargins &customMargins, const MSG &msg, LRESULT *result);
@@ -110,6 +78,7 @@ struct QWindowsWindowData
{
Qt::WindowFlags flags;
QRect geometry;
+ QRect restoreGeometry;
QMargins fullFrameMargins; // Do not use directly for windows, see FrameDirty.
QMargins customMargins; // User-defined, additional frame for NCCALCSIZE
HWND hwnd = nullptr;
@@ -121,10 +90,14 @@ struct QWindowsWindowData
const QString &title);
};
-class QWindowsBaseWindow : public QPlatformWindow
+class QWindowsBaseWindow : public QPlatformWindow,
+ public QNativeInterface::Private::QWindowsWindow
{
Q_DISABLE_COPY_MOVE(QWindowsBaseWindow)
public:
+ using TouchWindowTouchType = QNativeInterface::Private::QWindowsApplication::TouchWindowTouchType;
+ using TouchWindowTouchTypes = QNativeInterface::Private::QWindowsApplication::TouchWindowTouchTypes;
+
explicit QWindowsBaseWindow(QWindow *window) : QPlatformWindow(window) {}
WId winId() const override { return WId(handle()); }
@@ -134,6 +107,12 @@ public:
QPoint mapFromGlobal(const QPoint &pos) const override;
virtual QMargins fullFrameMargins() const { return frameMargins_sys(); }
+ void setHasBorderInFullScreen(bool border) override;
+ bool hasBorderInFullScreen() const override;
+
+ QMargins customMargins() const override;
+ void setCustomMargins(const QMargins &margins) override;
+
using QPlatformWindow::screenForGeometry;
virtual HWND handle() const = 0;
@@ -153,6 +132,7 @@ protected:
QRect geometry_sys() const;
void setGeometry_sys(const QRect &rect) const;
QMargins frameMargins_sys() const;
+ std::optional<TouchWindowTouchTypes> touchWindowTouchTypes_sys() const;
void hide_sys();
void raise_sys();
void lower_sys();
@@ -205,7 +185,6 @@ public:
WithinSetParent = 0x2,
WithinSetGeometry = 0x8,
OpenGLSurface = 0x10,
- OpenGL_ES2 = 0x20,
OpenGLDoubleBuffered = 0x40,
OpenGlPixelFormatInitialized = 0x80,
BlockedByModal = 0x100,
@@ -222,10 +201,11 @@ public:
MaximizeToFullScreen = 0x80000,
Compositing = 0x100000,
HasBorderInFullScreen = 0x200000,
- WithinDpiChanged = 0x400000,
- VulkanSurface = 0x800000,
- ResizeMoveActive = 0x1000000,
- DisableNonClientScaling = 0x2000000
+ VulkanSurface = 0x400000,
+ ResizeMoveActive = 0x800000,
+ DisableNonClientScaling = 0x1000000,
+ Direct3DSurface = 0x2000000,
+ RestoreOverrideCursor = 0x4000000
};
QWindowsWindow(QWindow *window, const QWindowsWindowData &data);
@@ -235,10 +215,12 @@ public:
using QPlatformWindow::screenForGeometry;
- QSurfaceFormat format() const override { return m_format; }
+ QSurfaceFormat format() const override;
void setGeometry(const QRect &rect) override;
QRect geometry() const override { return m_data.geometry; }
QRect normalGeometry() const override;
+ QRect restoreGeometry() const { return m_data.restoreGeometry; }
+ void updateRestoreGeometry();
void setVisible(bool visible) override;
bool isVisible() const;
@@ -293,18 +275,21 @@ public:
QWindowsMenuBar *menuBar() const;
void setMenuBar(QWindowsMenuBar *mb);
- QMargins customMargins() const { return m_data.customMargins; }
- void setCustomMargins(const QMargins &m);
+ QMargins customMargins() const override;
+ void setCustomMargins(const QMargins &m) override;
void setStyle(unsigned s) const;
void setExStyle(unsigned s) const;
- bool handleWmPaint(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
+ bool handleWmPaint(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT *result);
void handleMoved();
- void handleResized(int wParam);
+ void handleResized(int wParam, LPARAM lParam);
void handleHidden();
void handleCompositionSettingsChanged();
+ void handleDpiScaledSize(WPARAM wParam, LPARAM lParam, LRESULT *result);
+ void handleDpiChanged(HWND hwnd, WPARAM wParam, LPARAM lParam);
+ void handleDpiChangedAfterParent(HWND hwnd);
static void displayChanged();
static void settingsChanged();
@@ -314,6 +299,7 @@ public:
static inline void *userDataOf(HWND hwnd);
static inline void setUserDataOf(HWND hwnd, void *ud);
+ static bool hasNoNativeFrame(HWND hwnd, Qt::WindowFlags flags);
static bool setWindowLayered(HWND hwnd, Qt::WindowFlags flags, bool hasAlpha, qreal opacity);
bool isLayered() const;
@@ -338,7 +324,6 @@ public:
void *surface(void *nativeConfig, int *err);
void invalidateSurface() override;
- void aboutToMakeCurrent();
void setAlertState(bool enabled) override;
bool isAlertState() const override { return testFlag(AlertState); }
@@ -348,16 +333,20 @@ public:
enum ScreenChangeMode { FromGeometryChange, FromDpiChange };
void checkForScreenChanged(ScreenChangeMode mode = FromGeometryChange);
- static void setTouchWindowTouchTypeStatic(QWindow *window, QWindowsWindowFunctions::TouchWindowTouchTypes touchTypes);
- void registerTouchWindow(QWindowsWindowFunctions::TouchWindowTouchTypes touchTypes = QWindowsWindowFunctions::NormalTouch);
+ void registerTouchWindow();
static void setHasBorderInFullScreenStatic(QWindow *window, bool border);
static void setHasBorderInFullScreenDefault(bool border);
- void setHasBorderInFullScreen(bool border);
+ void setHasBorderInFullScreen(bool border) override;
+ bool hasBorderInFullScreen() const override;
static QString formatWindowTitle(const QString &title);
static const char *embeddedNativeParentHandleProperty;
static const char *hasBorderInFullScreenProperty;
+ void setSavedDpi(int dpi) { m_savedDpi = dpi; }
+ int savedDpi() const { return m_savedDpi; }
+ qreal dpiRelativeScale(const UINT dpi) const;
+
private:
inline void show_sys() const;
inline QWindowsWindowData setWindowFlags_sys(Qt::WindowFlags wt, unsigned flags = 0) const;
@@ -373,6 +362,8 @@ private:
void handleWindowStateChange(Qt::WindowStates state);
inline void destroyIcon();
void fireExpose(const QRegion &region, bool force=false);
+ void fireFullExpose(bool force=false);
+ void calculateFullFrameMargins();
mutable QWindowsWindowData m_data;
QPointer<QWindowsMenuBar> m_menuBar;
@@ -386,10 +377,10 @@ private:
QWindowsOleDropTarget *m_dropTarget = nullptr;
unsigned m_savedStyle = 0;
QRect m_savedFrameGeometry;
- const QSurfaceFormat m_format;
HICON m_iconSmall = nullptr;
HICON m_iconBig = nullptr;
void *m_surface = nullptr;
+ int m_savedDpi = 96;
static bool m_screenForGLInitialized;
@@ -398,6 +389,7 @@ private:
VkSurfaceKHR m_vkSurface = VK_NULL_HANDLE;
#endif
static bool m_borderInFullScreenDefault;
+ static bool m_inSetgeometry;
};
#ifndef QT_NO_DEBUG_STREAM
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiaaccessibility.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiaaccessibility.cpp
index 32a57473ad..1abb412ccd 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiaaccessibility.cpp
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiaaccessibility.cpp
@@ -1,46 +1,11 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtGui/qtguiglobal.h>
#if QT_CONFIG(accessibility)
#include "qwindowsuiaaccessibility.h"
+#include "qwindowsuiautomation.h"
#include "qwindowsuiamainprovider.h"
#include "qwindowsuiautils.h"
@@ -50,14 +15,15 @@
#include <QtGui/private/qguiapplication_p.h>
#include <QtCore/qt_windows.h>
#include <qpa/qplatformintegration.h>
-#include <QtWindowsUIAutomationSupport/private/qwindowsuiawrapper_p.h>
#include <QtCore/private/qwinregistry_p.h>
QT_BEGIN_NAMESPACE
using namespace QWindowsUiAutomation;
+using namespace Qt::Literals::StringLiterals;
+bool QWindowsUiaAccessibility::m_accessibleActive = false;
QWindowsUiaAccessibility::QWindowsUiaAccessibility()
{
@@ -72,6 +38,7 @@ bool QWindowsUiaAccessibility::handleWmGetObject(HWND hwnd, WPARAM wParam, LPARA
{
// Start handling accessibility internally
QGuiApplicationPrivate::platformIntegration()->accessibility()->setActive(true);
+ m_accessibleActive = true;
// Ignoring all requests while starting up / shutting down
if (QCoreApplication::startingUp() || QCoreApplication::closingDown())
@@ -80,7 +47,7 @@ bool QWindowsUiaAccessibility::handleWmGetObject(HWND hwnd, WPARAM wParam, LPARA
if (QWindow *window = QWindowsContext::instance()->findWindow(hwnd)) {
if (QAccessibleInterface *accessible = window->accessibleRoot()) {
QWindowsUiaMainProvider *provider = QWindowsUiaMainProvider::providerForAccessible(accessible);
- *lResult = QWindowsUiaWrapper::instance()->returnRawElementProvider(hwnd, wParam, lParam, provider);
+ *lResult = UiaReturnRawElementProvider(hwnd, wParam, lParam, provider);
return true;
}
}
@@ -105,14 +72,15 @@ static QString alertSound(const QObject *object)
case Critical:
return QStringLiteral("SystemHand");
}
+ return QString();
}
return QStringLiteral("SystemAsterisk");
}
static QString soundFileName(const QString &soundName)
{
- const QString key = QStringLiteral("AppEvents\\Schemes\\Apps\\.Default\\")
- + soundName + QStringLiteral("\\.Current");
+ const QString key = "AppEvents\\Schemes\\Apps\\.Default\\"_L1
+ + soundName + "\\.Current"_L1;
return QWinRegistryKey(HKEY_CURRENT_USER, key).stringValue(L"");
}
@@ -130,6 +98,7 @@ void QWindowsUiaAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event
if (!event)
return;
+ // Always handle system sound events
switch (event->type()) {
case QAccessible::PopupMenuStart:
playSystemSound(QStringLiteral("MenuPopup"));
@@ -144,16 +113,17 @@ void QWindowsUiaAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event
break;
}
- QAccessibleInterface *accessible = event->accessibleInterface();
- if (!isActive() || !accessible || !accessible->isValid())
+ // Ignore events sent before the first UI Automation
+ // request or while QAccessible is being activated.
+ if (!m_accessibleActive)
return;
- // Ensures QWindowsUiaWrapper is properly initialized.
- if (!QWindowsUiaWrapper::instance()->ready())
+ QAccessibleInterface *accessible = event->accessibleInterface();
+ if (!isActive() || !accessible || !accessible->isValid())
return;
// No need to do anything when nobody is listening.
- if (!QWindowsUiaWrapper::instance()->clientsAreListening())
+ if (!UiaClientsAreListening())
return;
switch (event->type()) {
@@ -166,6 +136,9 @@ void QWindowsUiaAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event
case QAccessible::ValueChanged:
QWindowsUiaMainProvider::notifyValueChange(static_cast<QAccessibleValueChangeEvent *>(event));
break;
+ case QAccessible::NameChanged:
+ QWindowsUiaMainProvider::notifyNameChange(event);
+ break;
case QAccessible::SelectionAdd:
QWindowsUiaMainProvider::notifySelectionChange(event);
break;
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiaaccessibility.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiaaccessibility.h
index 48b4f9fa6a..2e8ee585da 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiaaccessibility.h
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiaaccessibility.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QWINDOWSUIAACCESSIBILITY_H
#define QWINDOWSUIAACCESSIBILITY_H
@@ -43,6 +7,7 @@
#include <QtGui/qtguiglobal.h>
#if QT_CONFIG(accessibility)
+#include <QtCore/qt_windows.h>
#include "qwindowscontext.h"
#include <qpa/qplatformaccessibility.h>
@@ -56,6 +21,8 @@ public:
virtual ~QWindowsUiaAccessibility();
static bool handleWmGetObject(HWND hwnd, WPARAM wParam, LPARAM lParam, LRESULT *lResult);
void notifyAccessibilityUpdate(QAccessibleEvent *event) override;
+private:
+ static bool m_accessibleActive;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiabaseprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiabaseprovider.cpp
index 53c647512a..9abfcae247 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiabaseprovider.cpp
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiabaseprovider.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtGui/qtguiglobal.h>
#if QT_CONFIG(accessibility)
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiabaseprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiabaseprovider.h
index a20df28e3f..032679ab10 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiabaseprovider.h
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiabaseprovider.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QWINDOWSUIABASEPROVIDER_H
#define QWINDOWSUIABASEPROVIDER_H
@@ -46,8 +10,8 @@
#include <QtGui/qaccessible.h>
#include <QtCore/qpointer.h>
-#include <qwindowscombase.h>
-#include <QtWindowsUIAutomationSupport/private/qwindowsuiawrapper_p.h>
+#include "qwindowsuiautomation.h"
+#include <QtCore/private/qcomobject_p.h>
QT_BEGIN_NAMESPACE
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiaexpandcollapseprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiaexpandcollapseprovider.cpp
new file mode 100644
index 0000000000..8eb9baa8ef
--- /dev/null
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiaexpandcollapseprovider.cpp
@@ -0,0 +1,90 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
+
+#include "qwindowsuiaexpandcollapseprovider.h"
+#include "qwindowsuiautils.h"
+#include "qwindowscontext.h"
+
+#include <QtGui/qaccessible.h>
+#include <QtCore/qloggingcategory.h>
+#include <QtCore/qstring.h>
+
+QT_BEGIN_NAMESPACE
+
+using namespace QWindowsUiAutomation;
+
+static bool isExpanded(QAccessibleInterface *accessible)
+{
+ Q_ASSERT(accessible);
+ if (accessible->role() == QAccessible::MenuItem)
+ return accessible->childCount() > 0 && !accessible->child(0)->state().invisible;
+ else
+ return accessible->state().expandable && accessible->state().expanded;
+}
+
+QWindowsUiaExpandCollapseProvider::QWindowsUiaExpandCollapseProvider(QAccessible::Id id) :
+ QWindowsUiaBaseProvider(id)
+{
+}
+
+QWindowsUiaExpandCollapseProvider::~QWindowsUiaExpandCollapseProvider() = default;
+
+HRESULT STDMETHODCALLTYPE QWindowsUiaExpandCollapseProvider::Expand()
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ QAccessibleInterface *accessible = accessibleInterface();
+ if (!accessible)
+ return UIA_E_ELEMENTNOTAVAILABLE;
+
+ QAccessibleActionInterface *actionInterface = accessible->actionInterface();
+ if (!actionInterface)
+ return UIA_E_ELEMENTNOTAVAILABLE;
+
+ if (!isExpanded(accessible))
+ actionInterface->doAction(QAccessibleActionInterface::showMenuAction());
+
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsUiaExpandCollapseProvider::Collapse()
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ QAccessibleInterface *accessible = accessibleInterface();
+ if (!accessible)
+ return UIA_E_ELEMENTNOTAVAILABLE;
+
+ QAccessibleActionInterface *actionInterface = accessible->actionInterface();
+ if (!actionInterface)
+ return UIA_E_ELEMENTNOTAVAILABLE;
+
+ if (isExpanded(accessible))
+ actionInterface->doAction(QAccessibleActionInterface::showMenuAction());
+
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsUiaExpandCollapseProvider::get_ExpandCollapseState(__RPC__out ExpandCollapseState *pRetVal)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ if (!pRetVal)
+ return E_INVALIDARG;
+ *pRetVal = ExpandCollapseState_LeafNode;
+
+ QAccessibleInterface *accessible = accessibleInterface();
+ if (!accessible)
+ return UIA_E_ELEMENTNOTAVAILABLE;
+
+ *pRetVal = isExpanded(accessible) ? ExpandCollapseState_Expanded : ExpandCollapseState_Collapsed;
+
+ return S_OK;
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_CONFIG(accessibility)
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiaexpandcollapseprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiaexpandcollapseprovider.h
new file mode 100644
index 0000000000..b384eb521c
--- /dev/null
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiaexpandcollapseprovider.h
@@ -0,0 +1,33 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QWINDOWSUIAEXPANDCOLLAPSEPROVIDER_H
+#define QWINDOWSUIAEXPANDCOLLAPSEPROVIDER_H
+
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
+
+#include "qwindowsuiabaseprovider.h"
+
+QT_BEGIN_NAMESPACE
+
+// Implements the Expand/Collapse control pattern provider. Used for menu items with submenus.
+class QWindowsUiaExpandCollapseProvider : public QWindowsUiaBaseProvider,
+ public QComObject<IExpandCollapseProvider>
+{
+ Q_DISABLE_COPY_MOVE(QWindowsUiaExpandCollapseProvider)
+public:
+ explicit QWindowsUiaExpandCollapseProvider(QAccessible::Id id);
+ virtual ~QWindowsUiaExpandCollapseProvider() override;
+
+ // IExpandCollapseProvider
+ HRESULT STDMETHODCALLTYPE Expand() override;
+ HRESULT STDMETHODCALLTYPE Collapse() override;
+ HRESULT STDMETHODCALLTYPE get_ExpandCollapseState(__RPC__out ExpandCollapseState *pRetVal) override;
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_CONFIG(accessibility)
+
+#endif // QWINDOWSUIAEXPANDCOLLAPSEPROVIDER_H
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiagriditemprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiagriditemprovider.cpp
index 93d360c40b..a76128df58 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiagriditemprovider.cpp
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiagriditemprovider.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtGui/qtguiglobal.h>
#if QT_CONFIG(accessibility)
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiagriditemprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiagriditemprovider.h
index 3244122038..289a867869 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiagriditemprovider.h
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiagriditemprovider.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QWINDOWSUIAGRIDITEMPROVIDER_H
#define QWINDOWSUIAGRIDITEMPROVIDER_H
@@ -49,7 +13,7 @@ QT_BEGIN_NAMESPACE
// Implements the Grid Item control pattern provider. Used by items within a table/tree.
class QWindowsUiaGridItemProvider : public QWindowsUiaBaseProvider,
- public QWindowsComBase<IGridItemProvider>
+ public QComObject<IGridItemProvider>
{
Q_DISABLE_COPY_MOVE(QWindowsUiaGridItemProvider)
public:
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiagridprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiagridprovider.cpp
index cce9d8143c..9f62ef5fbe 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiagridprovider.cpp
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiagridprovider.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtGui/qtguiglobal.h>
#if QT_CONFIG(accessibility)
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiagridprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiagridprovider.h
index 0e5f81108e..d33bbd0429 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiagridprovider.h
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiagridprovider.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QWINDOWSUIAGRIDPROVIDER_H
#define QWINDOWSUIAGRIDPROVIDER_H
@@ -48,8 +12,7 @@
QT_BEGIN_NAMESPACE
// Implements the Grid control pattern provider. Used by tables/trees.
-class QWindowsUiaGridProvider : public QWindowsUiaBaseProvider,
- public QWindowsComBase<IGridProvider>
+class QWindowsUiaGridProvider : public QWindowsUiaBaseProvider, public QComObject<IGridProvider>
{
Q_DISABLE_COPY_MOVE(QWindowsUiaGridProvider)
public:
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiainvokeprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiainvokeprovider.cpp
index d09770bc81..e22c46ac4c 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiainvokeprovider.cpp
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiainvokeprovider.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtGui/qtguiglobal.h>
#if QT_CONFIG(accessibility)
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiainvokeprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiainvokeprovider.h
index 7d646894a1..ec006c673e 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiainvokeprovider.h
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiainvokeprovider.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QWINDOWSUIAINVOKEPROVIDER_H
#define QWINDOWSUIAINVOKEPROVIDER_H
@@ -48,8 +12,7 @@
QT_BEGIN_NAMESPACE
// Implements the Invoke control pattern provider.
-class QWindowsUiaInvokeProvider : public QWindowsUiaBaseProvider,
- public QWindowsComBase<IInvokeProvider>
+class QWindowsUiaInvokeProvider : public QWindowsUiaBaseProvider, public QComObject<IInvokeProvider>
{
Q_DISABLE_COPY_MOVE(QWindowsUiaInvokeProvider)
public:
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp
index 5f564f81c2..95ddbcced6 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtGui/qtguiglobal.h>
#if QT_CONFIG(accessibility)
@@ -53,7 +17,7 @@
#include "qwindowsuiagridprovider.h"
#include "qwindowsuiagriditemprovider.h"
#include "qwindowsuiawindowprovider.h"
-#include "qwindowscombase.h"
+#include "qwindowsuiaexpandcollapseprovider.h"
#include "qwindowscontext.h"
#include "qwindowsuiautils.h"
#include "qwindowsuiaprovidercache.h"
@@ -62,6 +26,7 @@
#include <QtGui/qaccessible.h>
#include <QtGui/qguiapplication.h>
#include <QtGui/qwindow.h>
+#include <qpa/qplatforminputcontextfactory_p.h>
#if !defined(Q_CC_BOR) && !defined (Q_CC_GNU)
#include <comdef.h>
@@ -73,10 +38,13 @@ QT_BEGIN_NAMESPACE
using namespace QWindowsUiAutomation;
+QMutex QWindowsUiaMainProvider::m_mutex;
-// Returns a cached instance of the provider for a specific acessible interface.
+// Returns a cached instance of the provider for a specific accessible interface.
QWindowsUiaMainProvider *QWindowsUiaMainProvider::providerForAccessible(QAccessibleInterface *accessible)
{
+ QMutexLocker locker(&m_mutex);
+
if (!accessible)
return nullptr;
@@ -93,9 +61,8 @@ QWindowsUiaMainProvider *QWindowsUiaMainProvider::providerForAccessible(QAccessi
return provider;
}
-QWindowsUiaMainProvider::QWindowsUiaMainProvider(QAccessibleInterface *a, int initialRefCount)
- : QWindowsUiaBaseProvider(QAccessible::uniqueId(a)),
- m_ref(initialRefCount)
+QWindowsUiaMainProvider::QWindowsUiaMainProvider(QAccessibleInterface *a)
+ : QWindowsUiaBaseProvider(QAccessible::uniqueId(a))
{
}
@@ -106,9 +73,13 @@ QWindowsUiaMainProvider::~QWindowsUiaMainProvider()
void QWindowsUiaMainProvider::notifyFocusChange(QAccessibleEvent *event)
{
if (QAccessibleInterface *accessible = event->accessibleInterface()) {
- if (QWindowsUiaMainProvider *provider = providerForAccessible(accessible)) {
- QWindowsUiaWrapper::instance()->raiseAutomationEvent(provider, UIA_AutomationFocusChangedEventId);
+ // If this is a complex element, raise event for the focused child instead.
+ if (accessible->childCount()) {
+ if (QAccessibleInterface *child = accessible->focusChild())
+ accessible = child;
}
+ if (QWindowsUiaMainProvider *provider = providerForAccessible(accessible))
+ UiaRaiseAutomationEvent(provider, UIA_AutomationFocusChangedEventId);
}
}
@@ -125,7 +96,7 @@ void QWindowsUiaMainProvider::notifyStateChange(QAccessibleStateChangeEvent *eve
if (accessible->state().checked)
toggleState = accessible->state().checkStateMixed ? ToggleState_Indeterminate : ToggleState_On;
setVariantI4(toggleState, &newVal);
- QWindowsUiaWrapper::instance()->raiseAutomationPropertyChangedEvent(provider, UIA_ToggleToggleStatePropertyId, oldVal, newVal);
+ UiaRaiseAutomationPropertyChangedEvent(provider, UIA_ToggleToggleStatePropertyId, oldVal, newVal);
}
}
}
@@ -134,9 +105,13 @@ void QWindowsUiaMainProvider::notifyStateChange(QAccessibleStateChangeEvent *eve
// Notifies window opened/closed.
if (QWindowsUiaMainProvider *provider = providerForAccessible(accessible)) {
if (accessible->state().active) {
- QWindowsUiaWrapper::instance()->raiseAutomationEvent(provider, UIA_Window_WindowOpenedEventId);
+ UiaRaiseAutomationEvent(provider, UIA_Window_WindowOpenedEventId);
+ if (QAccessibleInterface *focused = accessible->focusChild()) {
+ if (QWindowsUiaMainProvider *focusedProvider = providerForAccessible(focused))
+ UiaRaiseAutomationEvent(focusedProvider, UIA_AutomationFocusChangedEventId);
+ }
} else {
- QWindowsUiaWrapper::instance()->raiseAutomationEvent(provider, UIA_Window_WindowClosedEventId);
+ UiaRaiseAutomationEvent(provider, UIA_Window_WindowClosedEventId);
}
}
}
@@ -163,13 +138,13 @@ void QWindowsUiaMainProvider::notifyValueChange(QAccessibleValueChangeEvent *eve
}
}
}
- if (event->value().type() == QVariant::String) {
+ if (event->value().typeId() == QMetaType::QString) {
if (QWindowsUiaMainProvider *provider = providerForAccessible(accessible)) {
// Notifies changes in string values.
VARIANT oldVal, newVal;
clearVariant(&oldVal);
setVariantString(event->value().toString(), &newVal);
- QWindowsUiaWrapper::instance()->raiseAutomationPropertyChangedEvent(provider, UIA_ValueValuePropertyId, oldVal, newVal);
+ UiaRaiseAutomationPropertyChangedEvent(provider, UIA_ValueValuePropertyId, oldVal, newVal);
}
} else if (QAccessibleValueInterface *valueInterface = accessible->valueInterface()) {
if (QWindowsUiaMainProvider *provider = providerForAccessible(accessible)) {
@@ -177,7 +152,24 @@ void QWindowsUiaMainProvider::notifyValueChange(QAccessibleValueChangeEvent *eve
VARIANT oldVal, newVal;
clearVariant(&oldVal);
setVariantDouble(valueInterface->currentValue().toDouble(), &newVal);
- QWindowsUiaWrapper::instance()->raiseAutomationPropertyChangedEvent(provider, UIA_RangeValueValuePropertyId, oldVal, newVal);
+ UiaRaiseAutomationPropertyChangedEvent(provider, UIA_RangeValueValuePropertyId, oldVal, newVal);
+ }
+ }
+ }
+}
+
+void QWindowsUiaMainProvider::notifyNameChange(QAccessibleEvent *event)
+{
+ if (QAccessibleInterface *accessible = event->accessibleInterface()) {
+ // Restrict notification to combo boxes, which need it for accessibility,
+ // in order to avoid slowdowns with unnecessary notifications.
+ if (accessible->role() == QAccessible::ComboBox) {
+ if (QWindowsUiaMainProvider *provider = providerForAccessible(accessible)) {
+ VARIANT oldVal, newVal;
+ clearVariant(&oldVal);
+ setVariantString(accessible->text(QAccessible::Name), &newVal);
+ UiaRaiseAutomationPropertyChangedEvent(provider, UIA_NamePropertyId, oldVal, newVal);
+ ::SysFreeString(newVal.bstrVal);
}
}
}
@@ -187,7 +179,7 @@ void QWindowsUiaMainProvider::notifySelectionChange(QAccessibleEvent *event)
{
if (QAccessibleInterface *accessible = event->accessibleInterface()) {
if (QWindowsUiaMainProvider *provider = providerForAccessible(accessible)) {
- QWindowsUiaWrapper::instance()->raiseAutomationEvent(provider, UIA_SelectionItem_ElementSelectedEventId);
+ UiaRaiseAutomationEvent(provider, UIA_SelectionItem_ElementSelectedEventId);
}
}
}
@@ -199,13 +191,13 @@ void QWindowsUiaMainProvider::notifyTextChange(QAccessibleEvent *event)
if (accessible->textInterface()) {
if (QWindowsUiaMainProvider *provider = providerForAccessible(accessible)) {
if (event->type() == QAccessible::TextSelectionChanged) {
- QWindowsUiaWrapper::instance()->raiseAutomationEvent(provider, UIA_Text_TextSelectionChangedEventId);
+ UiaRaiseAutomationEvent(provider, UIA_Text_TextSelectionChangedEventId);
} else if (event->type() == QAccessible::TextCaretMoved) {
if (!accessible->state().readOnly) {
- QWindowsUiaWrapper::instance()->raiseAutomationEvent(provider, UIA_Text_TextSelectionChangedEventId);
+ UiaRaiseAutomationEvent(provider, UIA_Text_TextSelectionChangedEventId);
}
} else {
- QWindowsUiaWrapper::instance()->raiseAutomationEvent(provider, UIA_Text_TextChangedEventId);
+ UiaRaiseAutomationEvent(provider, UIA_Text_TextChangedEventId);
}
}
}
@@ -214,31 +206,26 @@ void QWindowsUiaMainProvider::notifyTextChange(QAccessibleEvent *event)
HRESULT STDMETHODCALLTYPE QWindowsUiaMainProvider::QueryInterface(REFIID iid, LPVOID *iface)
{
- if (!iface)
- return E_INVALIDARG;
- *iface = nullptr;
-
- QAccessibleInterface *accessible = accessibleInterface();
+ HRESULT result = QComObject::QueryInterface(iid, iface);
- const bool result = qWindowsComQueryUnknownInterfaceMulti<IRawElementProviderSimple>(this, iid, iface)
- || qWindowsComQueryInterface<IRawElementProviderSimple>(this, iid, iface)
- || qWindowsComQueryInterface<IRawElementProviderFragment>(this, iid, iface)
- || (accessible && hwndForAccessible(accessible) && qWindowsComQueryInterface<IRawElementProviderFragmentRoot>(this, iid, iface));
- return result ? S_OK : E_NOINTERFACE;
-}
+ if (SUCCEEDED(result) && iid == __uuidof(IRawElementProviderFragmentRoot)) {
+ QAccessibleInterface *accessible = accessibleInterface();
+ if (accessible && hwndForAccessible(accessible)) {
+ result = S_OK;
+ } else {
+ result = E_NOINTERFACE;
+ iface = nullptr;
+ }
+ }
-ULONG QWindowsUiaMainProvider::AddRef()
-{
- return ++m_ref;
+ return result;
}
ULONG STDMETHODCALLTYPE QWindowsUiaMainProvider::Release()
{
- if (!--m_ref) {
- delete this;
- return 0;
- }
- return m_ref;
+ QMutexLocker locker(&m_mutex);
+
+ return QComObject::Release();
}
HRESULT QWindowsUiaMainProvider::get_ProviderOptions(ProviderOptions *pRetVal)
@@ -288,22 +275,25 @@ HRESULT QWindowsUiaMainProvider::GetPatternProvider(PATTERNID idPattern, IUnknow
}
break;
case UIA_TogglePatternId:
- // Checkbox controls.
- if (accessible->role() == QAccessible::CheckBox
- || (accessible->role() == QAccessible::MenuItem && accessible->state().checkable)) {
+ // Checkboxes and other checkable controls.
+ if (accessible->state().checkable)
*pRetVal = new QWindowsUiaToggleProvider(id());
- }
break;
case UIA_SelectionPatternId:
- // Lists of items.
- if (accessible->role() == QAccessible::List) {
+ case UIA_SelectionPattern2Id:
+ // Selections via QAccessibleSelectionInterface or lists of items.
+ if (accessible->selectionInterface()
+ || accessible->role() == QAccessible::List
+ || accessible->role() == QAccessible::PageTabList) {
*pRetVal = new QWindowsUiaSelectionProvider(id());
}
break;
case UIA_SelectionItemPatternId:
- // Items within a list and radio buttons.
- if ((accessible->role() == QAccessible::RadioButton)
- || (accessible->role() == QAccessible::ListItem)) {
+ // Parent supports selection interface or items within a list and radio buttons.
+ if ((accessible->parent() && accessible->parent()->selectionInterface())
+ || (accessible->role() == QAccessible::RadioButton)
+ || (accessible->role() == QAccessible::ListItem)
+ || (accessible->role() == QAccessible::PageTab)) {
*pRetVal = new QWindowsUiaSelectionItemProvider(id());
}
break;
@@ -341,6 +331,16 @@ HRESULT QWindowsUiaMainProvider::GetPatternProvider(PATTERNID idPattern, IUnknow
*pRetVal = new QWindowsUiaInvokeProvider(id());
}
break;
+ case UIA_ExpandCollapsePatternId:
+ // Menu items with submenus.
+ if ((accessible->role() == QAccessible::MenuItem
+ && accessible->childCount() > 0
+ && accessible->child(0)->role() == QAccessible::PopupMenu)
+ || accessible->role() == QAccessible::ComboBox
+ || (accessible->role() == QAccessible::TreeItem && accessible->state().expandable)) {
+ *pRetVal = new QWindowsUiaExpandCollapseProvider(id());
+ }
+ break;
default:
break;
}
@@ -348,6 +348,28 @@ HRESULT QWindowsUiaMainProvider::GetPatternProvider(PATTERNID idPattern, IUnknow
return S_OK;
}
+void QWindowsUiaMainProvider::fillVariantArrayForRelation(QAccessibleInterface* accessible,
+ QAccessible::Relation relation, VARIANT *pRetVal)
+{
+ Q_ASSERT(accessible);
+
+ typedef QPair<QAccessibleInterface*, QAccessible::Relation> RelationPair;
+ const QList<RelationPair> relationInterfaces = accessible->relations(relation);
+ if (relationInterfaces.empty())
+ return;
+
+ SAFEARRAY *elements = SafeArrayCreateVector(VT_UNKNOWN, 0, relationInterfaces.size());
+ for (LONG i = 0; i < relationInterfaces.size(); ++i) {
+ if (QWindowsUiaMainProvider *childProvider = QWindowsUiaMainProvider::providerForAccessible(relationInterfaces.at(i).first)) {
+ SafeArrayPutElement(elements, &i, static_cast<IRawElementProviderSimple*>(childProvider));
+ childProvider->Release();
+ }
+ }
+
+ pRetVal->vt = VT_UNKNOWN | VT_ARRAY;
+ pRetVal->parray = elements;
+}
+
HRESULT QWindowsUiaMainProvider::GetPropertyValue(PROPERTYID idProp, VARIANT *pRetVal)
{
qCDebug(lcQpaUiAutomation) << __FUNCTION__ << idProp;
@@ -378,10 +400,19 @@ HRESULT QWindowsUiaMainProvider::GetPropertyValue(PROPERTYID idProp, VARIANT *pR
case UIA_ClassNamePropertyId:
// Class name.
if (QObject *o = accessible->object()) {
- QString className = QLatin1String(o->metaObject()->className());
+ QString className = QLatin1StringView(o->metaObject()->className());
setVariantString(className, pRetVal);
}
break;
+ case UIA_DescribedByPropertyId:
+ fillVariantArrayForRelation(accessible, QAccessible::DescriptionFor, pRetVal);
+ break;
+ case UIA_FlowsFromPropertyId:
+ fillVariantArrayForRelation(accessible, QAccessible::FlowsTo, pRetVal);
+ break;
+ case UIA_FlowsToPropertyId:
+ fillVariantArrayForRelation(accessible, QAccessible::FlowsFrom, pRetVal);
+ break;
case UIA_FrameworkIdPropertyId:
setVariantString(QStringLiteral("Qt"), pRetVal);
break;
@@ -393,10 +424,10 @@ HRESULT QWindowsUiaMainProvider::GetPropertyValue(PROPERTYID idProp, VARIANT *pR
// Control type converted from role.
auto controlType = roleToControlTypeId(accessible->role());
- // The native OSK should be disbled if the Qt OSK is in use,
+ // The native OSK should be disabled if the Qt OSK is in use,
// or if disabled via application attribute.
- static bool imModuleEmpty = qEnvironmentVariableIsEmpty("QT_IM_MODULE");
- bool nativeVKDisabled = QCoreApplication::testAttribute(Qt::AA_MSWindowsDisableVirtualKeyboard);
+ static bool imModuleEmpty = QPlatformInputContextFactory::requested().isEmpty();
+ bool nativeVKDisabled = QCoreApplication::testAttribute(Qt::AA_DisableNativeVirtualKeyboard);
// If we want to disable the native OSK auto-showing
// we have to report text fields as non-editable.
@@ -448,6 +479,10 @@ HRESULT QWindowsUiaMainProvider::GetPropertyValue(PROPERTYID idProp, VARIANT *pR
setVariantBool(wt == Qt::Popup || wt == Qt::ToolTip || wt == Qt::SplashScreen, pRetVal);
}
break;
+ case UIA_IsDialogPropertyId:
+ setVariantBool(accessible->role() == QAccessible::Dialog
+ || accessible->role() == QAccessible::AlertMessage, pRetVal);
+ break;
case UIA_FullDescriptionPropertyId:
setVariantString(accessible->text(QAccessible::Description), pRetVal);
break;
@@ -473,7 +508,7 @@ QString QWindowsUiaMainProvider::automationIdForAccessible(const QAccessibleInte
while (obj) {
QString name = obj->objectName();
if (name.isEmpty())
- return QString();
+ return result;
if (!result.isEmpty())
result.prepend(u'.');
result.prepend(name);
@@ -494,7 +529,7 @@ HRESULT QWindowsUiaMainProvider::get_HostRawElementProvider(IRawElementProviderS
// Returns a host provider only for controls associated with a native window handle. Others should return NULL.
if (QAccessibleInterface *accessible = accessibleInterface()) {
if (HWND hwnd = hwndForAccessible(accessible)) {
- return QWindowsUiaWrapper::instance()->hostProviderFromHwnd(hwnd, pRetVal);
+ return UiaHostProviderFromHwnd(hwnd, pRetVal);
}
}
return S_OK;
@@ -684,26 +719,18 @@ HRESULT QWindowsUiaMainProvider::ElementProviderFromPoint(double x, double y, IR
QPoint point;
nativeUiaPointToPoint(uiaPoint, window, &point);
- if (auto targetacc = accessible->childAt(point.x(), point.y())) {
- auto acc = accessible->childAt(point.x(), point.y());
- // Reject the cases where childAt() returns a different instance in each call for the same
- // element (e.g., QAccessibleTree), as it causes an endless loop with Youdao Dictionary installed.
- if (targetacc == acc) {
- // Controls can be embedded within grouping elements. By default returns the innermost control.
- while (acc) {
- targetacc = acc;
- // For accessibility tools it may be better to return the text element instead of its subcomponents.
- if (targetacc->textInterface()) break;
- acc = targetacc->childAt(point.x(), point.y());
- if (acc != targetacc->childAt(point.x(), point.y())) {
- qCDebug(lcQpaUiAutomation) << "Non-unique childAt() for" << targetacc;
- break;
- }
- }
- *pRetVal = providerForAccessible(targetacc);
- } else {
- qCDebug(lcQpaUiAutomation) << "Non-unique childAt() for" << accessible;
+ QAccessibleInterface *targetacc = accessible->childAt(point.x(), point.y());
+
+ if (targetacc) {
+ QAccessibleInterface *acc = targetacc;
+ // Controls can be embedded within grouping elements. By default returns the innermost control.
+ while (acc) {
+ targetacc = acc;
+ // For accessibility tools it may be better to return the text element instead of its subcomponents.
+ if (targetacc->textInterface()) break;
+ acc = acc->childAt(point.x(), point.y());
}
+ *pRetVal = providerForAccessible(targetacc);
}
return S_OK;
}
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.h
index cdc239ed99..99db0ed318 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.h
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QWINDOWSUIAMAINPROVIDER_H
#define QWINDOWSUIAMAINPROVIDER_H
@@ -47,6 +11,7 @@
#include <QtCore/qpointer.h>
#include <QtCore/qsharedpointer.h>
+#include <QtCore/qmutex.h>
#include <QtCore/qt_windows.h>
#include <QtGui/qaccessible.h>
@@ -55,25 +20,23 @@ QT_BEGIN_NAMESPACE
// The main UI Automation class.
class QWindowsUiaMainProvider :
public QWindowsUiaBaseProvider,
- public IRawElementProviderSimple,
- public IRawElementProviderFragment,
- public IRawElementProviderFragmentRoot
+ public QComObject<IRawElementProviderSimple, IRawElementProviderFragment, IRawElementProviderFragmentRoot>
{
Q_OBJECT
Q_DISABLE_COPY_MOVE(QWindowsUiaMainProvider)
public:
static QWindowsUiaMainProvider *providerForAccessible(QAccessibleInterface *accessible);
- explicit QWindowsUiaMainProvider(QAccessibleInterface *a, int initialRefCount = 1);
+ explicit QWindowsUiaMainProvider(QAccessibleInterface *a);
virtual ~QWindowsUiaMainProvider();
static void notifyFocusChange(QAccessibleEvent *event);
static void notifyStateChange(QAccessibleStateChangeEvent *event);
static void notifyValueChange(QAccessibleValueChangeEvent *event);
+ static void notifyNameChange(QAccessibleEvent *event);
static void notifySelectionChange(QAccessibleEvent *event);
static void notifyTextChange(QAccessibleEvent *event);
// IUnknown
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID id, LPVOID *iface) override;
- ULONG STDMETHODCALLTYPE AddRef() override;
ULONG STDMETHODCALLTYPE Release() override;
// IRawElementProviderSimple methods
@@ -96,7 +59,8 @@ public:
private:
QString automationIdForAccessible(const QAccessibleInterface *accessible);
- ULONG m_ref;
+ static void fillVariantArrayForRelation(QAccessibleInterface *accessible, QAccessible::Relation relation, VARIANT *pRetVal);
+ static QMutex m_mutex;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiaprovidercache.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiaprovidercache.cpp
index c55e827a46..ba2a88bb4e 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiaprovidercache.cpp
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiaprovidercache.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtGui/qtguiglobal.h>
#if QT_CONFIG(accessibility)
@@ -75,7 +39,7 @@ void QWindowsUiaProviderCache::insert(QAccessible::Id id, QWindowsUiaBaseProvide
m_providerTable[id] = provider;
m_inverseTable[provider] = id;
// Connects the destroyed signal to our slot, to remove deleted objects from the cache.
- QObject::connect(provider, &QObject::destroyed, this, &QWindowsUiaProviderCache::objectDestroyed);
+ QObject::connect(provider, &QObject::destroyed, this, &QWindowsUiaProviderCache::objectDestroyed, Qt::DirectConnection);
}
}
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiaprovidercache.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiaprovidercache.h
index f66dc2c170..08f315b4e6 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiaprovidercache.h
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiaprovidercache.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QWINDOWSUIAPROVIDERCACHE_H
#define QWINDOWSUIAPROVIDERCACHE_H
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiarangevalueprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiarangevalueprovider.cpp
index 7c1827387a..574bb7d2d6 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiarangevalueprovider.cpp
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiarangevalueprovider.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtGui/qtguiglobal.h>
#if QT_CONFIG(accessibility)
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiarangevalueprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiarangevalueprovider.h
index fc82d3a2cc..ffb5ae155b 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiarangevalueprovider.h
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiarangevalueprovider.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QWINDOWSUIARANGEVALUEPROVIDER_H
#define QWINDOWSUIARANGEVALUEPROVIDER_H
@@ -49,7 +13,7 @@ QT_BEGIN_NAMESPACE
// Implements the Range Value control pattern provider.
class QWindowsUiaRangeValueProvider : public QWindowsUiaBaseProvider,
- public QWindowsComBase<IRangeValueProvider>
+ public QComObject<IRangeValueProvider>
{
Q_DISABLE_COPY_MOVE(QWindowsUiaRangeValueProvider)
public:
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionitemprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionitemprovider.cpp
index a93a05c7bc..95bc2f7570 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionitemprovider.cpp
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionitemprovider.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtGui/qtguiglobal.h>
#if QT_CONFIG(accessibility)
@@ -72,12 +36,20 @@ HRESULT STDMETHODCALLTYPE QWindowsUiaSelectionItemProvider::Select()
if (!accessible)
return UIA_E_ELEMENTNOTAVAILABLE;
+ if (QAccessibleInterface *parent = accessible->parent()) {
+ if (QAccessibleSelectionInterface *selectionInterface = parent->selectionInterface()) {
+ selectionInterface->clear();
+ bool ok = selectionInterface->select(accessible);
+ return ok ? S_OK : S_FALSE;
+ }
+ }
+
QAccessibleActionInterface *actionInterface = accessible->actionInterface();
if (!actionInterface)
return UIA_E_ELEMENTNOTAVAILABLE;
- if (accessible->role() == QAccessible::RadioButton) {
- // For radio buttons we just invoke the selection action; others are automatically deselected.
+ if (accessible->role() == QAccessible::RadioButton || accessible->role() == QAccessible::PageTab) {
+ // For radio buttons/tabs we just invoke the selection action; others are automatically deselected.
actionInterface->doAction(QAccessibleActionInterface::pressAction());
} else {
// Toggle list item if not already selected. It must be done first to support all selection modes.
@@ -109,12 +81,19 @@ HRESULT STDMETHODCALLTYPE QWindowsUiaSelectionItemProvider::AddToSelection()
if (!accessible)
return UIA_E_ELEMENTNOTAVAILABLE;
+ if (QAccessibleInterface *parent = accessible->parent()) {
+ if (QAccessibleSelectionInterface *selectionInterface = parent->selectionInterface()) {
+ bool ok = selectionInterface->select(accessible);
+ return ok ? S_OK : S_FALSE;
+ }
+ }
+
QAccessibleActionInterface *actionInterface = accessible->actionInterface();
if (!actionInterface)
return UIA_E_ELEMENTNOTAVAILABLE;
- if (accessible->role() == QAccessible::RadioButton) {
- // For radio buttons we invoke the selection action.
+ if (accessible->role() == QAccessible::RadioButton || accessible->role() == QAccessible::PageTab) {
+ // For radio buttons and tabs we invoke the selection action.
actionInterface->doAction(QAccessibleActionInterface::pressAction());
} else {
// Toggle list item if not already selected.
@@ -134,11 +113,18 @@ HRESULT STDMETHODCALLTYPE QWindowsUiaSelectionItemProvider::RemoveFromSelection(
if (!accessible)
return UIA_E_ELEMENTNOTAVAILABLE;
+ if (QAccessibleInterface *parent = accessible->parent()) {
+ if (QAccessibleSelectionInterface *selectionInterface = parent->selectionInterface()) {
+ bool ok = selectionInterface->unselect(accessible);
+ return ok ? S_OK : S_FALSE;
+ }
+ }
+
QAccessibleActionInterface *actionInterface = accessible->actionInterface();
if (!actionInterface)
return UIA_E_ELEMENTNOTAVAILABLE;
- if (accessible->role() != QAccessible::RadioButton) {
+ if (accessible->role() != QAccessible::RadioButton && accessible->role() != QAccessible::PageTab) {
if (accessible->state().selected) {
actionInterface->doAction(QAccessibleActionInterface::toggleAction());
}
@@ -160,8 +146,18 @@ HRESULT STDMETHODCALLTYPE QWindowsUiaSelectionItemProvider::get_IsSelected(BOOL
if (!accessible)
return UIA_E_ELEMENTNOTAVAILABLE;
+ if (QAccessibleInterface *parent = accessible->parent()) {
+ if (QAccessibleSelectionInterface *selectionInterface = parent->selectionInterface()) {
+ bool selected = selectionInterface->isSelected(accessible);
+ *pRetVal = selected ? TRUE : FALSE;
+ return S_OK;
+ }
+ }
+
if (accessible->role() == QAccessible::RadioButton)
*pRetVal = accessible->state().checked;
+ else if (accessible->role() == QAccessible::PageTab)
+ *pRetVal = accessible->state().focused;
else
*pRetVal = accessible->state().selected;
return S_OK;
@@ -180,16 +176,21 @@ HRESULT STDMETHODCALLTYPE QWindowsUiaSelectionItemProvider::get_SelectionContain
if (!accessible)
return UIA_E_ELEMENTNOTAVAILABLE;
+ QAccessibleInterface *parent = accessible->parent();
+ if (parent && parent->selectionInterface()) {
+ *pRetVal = QWindowsUiaMainProvider::providerForAccessible(parent);
+ return S_OK;
+ }
+
QAccessibleActionInterface *actionInterface = accessible->actionInterface();
if (!actionInterface)
return UIA_E_ELEMENTNOTAVAILABLE;
// Radio buttons do not require a container.
- if (accessible->role() == QAccessible::ListItem) {
- if (QAccessibleInterface *parent = accessible->parent()) {
- if (parent->role() == QAccessible::List) {
- *pRetVal = QWindowsUiaMainProvider::providerForAccessible(parent);
- }
+ if (parent) {
+ if ((accessible->role() == QAccessible::ListItem && parent->role() == QAccessible::List)
+ || (accessible->role() == QAccessible::PageTab && parent->role() == QAccessible::PageTabList)) {
+ *pRetVal = QWindowsUiaMainProvider::providerForAccessible(parent);
}
}
return S_OK;
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionitemprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionitemprovider.h
index 4b59c4e40f..ee34fd9edd 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionitemprovider.h
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionitemprovider.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QWINDOWSUIASELECTIONITEMPROVIDER_H
#define QWINDOWSUIASELECTIONITEMPROVIDER_H
@@ -49,7 +13,7 @@ QT_BEGIN_NAMESPACE
// Implements the Selection Item control pattern provider. Used for List items and radio buttons.
class QWindowsUiaSelectionItemProvider : public QWindowsUiaBaseProvider,
- public QWindowsComBase<ISelectionItemProvider>
+ public QComObject<ISelectionItemProvider>
{
Q_DISABLE_COPY_MOVE(QWindowsUiaSelectionItemProvider)
public:
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionprovider.cpp
index fb41012cf4..37148c655a 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionprovider.cpp
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionprovider.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtGui/qtguiglobal.h>
#if QT_CONFIG(accessibility)
@@ -49,7 +13,6 @@
#include <QtCore/qloggingcategory.h>
#include <QtCore/qstring.h>
#include <QtCore/qlist.h>
-#include <QtCore/qvector.h>
QT_BEGIN_NAMESPACE
@@ -78,12 +41,24 @@ HRESULT STDMETHODCALLTYPE QWindowsUiaSelectionProvider::GetSelection(SAFEARRAY *
if (!accessible)
return UIA_E_ELEMENTNOTAVAILABLE;
- // First put selected items in a list, then build a safe array with the right size.
- QVector<QAccessibleInterface *> selectedList;
- for (int i = 0; i < accessible->childCount(); ++i) {
- if (QAccessibleInterface *child = accessible->child(i)) {
- if (child->state().selected) {
- selectedList.append(child);
+ // First get/create list of selected items, then build a safe array with the right size.
+ QList<QAccessibleInterface *> selectedList;
+ if (QAccessibleSelectionInterface *selectionInterface = accessible->selectionInterface()) {
+ selectedList = selectionInterface->selectedItems();
+ } else {
+ const int childCount = accessible->childCount();
+ selectedList.reserve(childCount);
+ for (int i = 0; i < childCount; ++i) {
+ if (QAccessibleInterface *child = accessible->child(i)) {
+ if (accessible->role() == QAccessible::PageTabList) {
+ if (child->role() == QAccessible::PageTab && child->state().focused) {
+ selectedList.append(child);
+ }
+ } else {
+ if (child->state().selected) {
+ selectedList.append(child);
+ }
+ }
}
}
}
@@ -127,18 +102,155 @@ HRESULT STDMETHODCALLTYPE QWindowsUiaSelectionProvider::get_IsSelectionRequired(
if (!accessible)
return UIA_E_ELEMENTNOTAVAILABLE;
- // Initially returns false if none are selected. After the first selection, it may be required.
- bool anySelected = false;
- for (int i = 0; i < accessible->childCount(); ++i) {
- if (QAccessibleInterface *child = accessible->child(i)) {
- if (child->state().selected) {
- anySelected = true;
- break;
+ if (accessible->role() == QAccessible::PageTabList) {
+ *pRetVal = TRUE;
+ } else {
+
+ // Initially returns false if none are selected. After the first selection, it may be required.
+ bool anySelected = false;
+ if (QAccessibleSelectionInterface *selectionInterface = accessible->selectionInterface()) {
+ anySelected = selectionInterface->selectedItem(0) != nullptr;
+ } else {
+ for (int i = 0; i < accessible->childCount(); ++i) {
+ if (QAccessibleInterface *child = accessible->child(i)) {
+ if (child->state().selected) {
+ anySelected = true;
+ break;
+ }
+ }
+ }
+ }
+
+ *pRetVal = anySelected && !accessible->state().multiSelectable && !accessible->state().extSelectable;
+ }
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsUiaSelectionProvider::get_FirstSelectedItem(__RPC__deref_out_opt IRawElementProviderSimple **pRetVal)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ if (!pRetVal)
+ return E_INVALIDARG;
+ *pRetVal = nullptr;
+
+ QAccessibleInterface *accessible = accessibleInterface();
+ if (!accessible)
+ return UIA_E_ELEMENTNOTAVAILABLE;
+
+ QAccessibleInterface *firstSelectedChild = nullptr;
+ if (QAccessibleSelectionInterface *selectionInterface = accessible->selectionInterface()) {
+ firstSelectedChild = selectionInterface->selectedItem(0);
+ if (!firstSelectedChild)
+ return UIA_E_ELEMENTNOTAVAILABLE;
+ } else {
+ int i = 0;
+ while (!firstSelectedChild && i < accessible->childCount()) {
+ if (QAccessibleInterface *child = accessible->child(i)) {
+ if (accessible->role() == QAccessible::PageTabList) {
+ if (child->role() == QAccessible::PageTab && child->state().focused)
+ firstSelectedChild = child;
+ } else if (child->state().selected) {
+ firstSelectedChild = child;
+ }
+ }
+ i++;
+ }
+ }
+
+ if (!firstSelectedChild)
+ return UIA_E_ELEMENTNOTAVAILABLE;
+
+ if (QWindowsUiaMainProvider *childProvider = QWindowsUiaMainProvider::providerForAccessible(firstSelectedChild))
+ {
+ *pRetVal = static_cast<IRawElementProviderSimple *>(childProvider);
+ return S_OK;
+ }
+
+ return S_FALSE;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsUiaSelectionProvider::get_LastSelectedItem(__RPC__deref_out_opt IRawElementProviderSimple **pRetVal)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ if (!pRetVal)
+ return E_INVALIDARG;
+ *pRetVal = nullptr;
+
+ QAccessibleInterface *accessible = accessibleInterface();
+ if (!accessible)
+ return UIA_E_ELEMENTNOTAVAILABLE;
+
+ QAccessibleInterface *lastSelectedChild = nullptr;
+ if (QAccessibleSelectionInterface *selectionInterface = accessible->selectionInterface()) {
+ const int selectedItemCount = selectionInterface->selectedItemCount();
+ if (selectedItemCount <= 0)
+ return UIA_E_ELEMENTNOTAVAILABLE;
+ lastSelectedChild = selectionInterface->selectedItem(selectedItemCount - 1);
+ } else {
+ int i = accessible->childCount() - 1;
+ while (!lastSelectedChild && i >= 0) {
+ if (QAccessibleInterface *child = accessible->child(i)) {
+ if (accessible->role() == QAccessible::PageTabList) {
+ if (child->role() == QAccessible::PageTab && child->state().focused)
+ lastSelectedChild = child;
+ } else if (child->state().selected) {
+ lastSelectedChild = child;
+ }
+ }
+ i--;
+ }
+ }
+
+ if (!lastSelectedChild)
+ return UIA_E_ELEMENTNOTAVAILABLE;
+
+ if (QWindowsUiaMainProvider *childProvider = QWindowsUiaMainProvider::providerForAccessible(lastSelectedChild))
+ {
+ *pRetVal = static_cast<IRawElementProviderSimple *>(childProvider);
+ return S_OK;
+ }
+
+ return S_FALSE;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsUiaSelectionProvider::get_CurrentSelectedItem(__RPC__deref_out_opt IRawElementProviderSimple **pRetVal)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+ return get_FirstSelectedItem(pRetVal);
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsUiaSelectionProvider::get_ItemCount(__RPC__out int *pRetVal)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ if (!pRetVal)
+ return E_INVALIDARG;
+ *pRetVal = -1;
+
+ QAccessibleInterface *accessible = accessibleInterface();
+ if (!accessible)
+ return UIA_E_ELEMENTNOTAVAILABLE;
+
+
+ if (QAccessibleSelectionInterface *selectionInterface = accessible->selectionInterface())
+ *pRetVal = selectionInterface->selectedItemCount();
+ else {
+ int selectedCount = 0;
+ for (int i = 0; i < accessible->childCount(); i++) {
+ if (QAccessibleInterface *child = accessible->child(i)) {
+ if (accessible->role() == QAccessible::PageTabList) {
+ if (child->role() == QAccessible::PageTab && child->state().focused)
+ selectedCount++;
+ } else if (child->state().selected) {
+ selectedCount++;
+ }
}
}
+ *pRetVal = selectedCount;
}
- *pRetVal = anySelected && !accessible->state().multiSelectable && !accessible->state().extSelectable;
return S_OK;
}
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionprovider.h
index ee1044ec7a..7a899e4261 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionprovider.h
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionprovider.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QWINDOWSUIASELECTIONPROVIDER_H
#define QWINDOWSUIASELECTIONPROVIDER_H
@@ -47,9 +11,22 @@
QT_BEGIN_NAMESPACE
+namespace QtPrivate {
+
+template <>
+struct QComObjectTraits<ISelectionProvider2>
+{
+ static constexpr bool isGuidOf(REFIID riid) noexcept
+ {
+ return QComObjectTraits<ISelectionProvider2, ISelectionProvider>::isGuidOf(riid);
+ }
+};
+
+} // namespace QtPrivate
+
// Implements the Selection control pattern provider. Used for Lists.
class QWindowsUiaSelectionProvider : public QWindowsUiaBaseProvider,
- public QWindowsComBase<ISelectionProvider>
+ public QComObject<ISelectionProvider2>
{
Q_DISABLE_COPY_MOVE(QWindowsUiaSelectionProvider)
public:
@@ -60,6 +37,12 @@ public:
HRESULT STDMETHODCALLTYPE GetSelection(SAFEARRAY **pRetVal) override;
HRESULT STDMETHODCALLTYPE get_CanSelectMultiple(BOOL *pRetVal) override;
HRESULT STDMETHODCALLTYPE get_IsSelectionRequired(BOOL *pRetVal) override;
+
+ // ISelectionProvider2
+ HRESULT STDMETHODCALLTYPE get_FirstSelectedItem(__RPC__deref_out_opt IRawElementProviderSimple **pRetVal) override;
+ HRESULT STDMETHODCALLTYPE get_LastSelectedItem(__RPC__deref_out_opt IRawElementProviderSimple **pRetVal) override;
+ HRESULT STDMETHODCALLTYPE get_CurrentSelectedItem(__RPC__deref_out_opt IRawElementProviderSimple **pRetVal) override;
+ HRESULT STDMETHODCALLTYPE get_ItemCount(__RPC__out int *pRetVal) override;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiatableitemprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiatableitemprovider.cpp
index 1348ec7cc0..f92c4b3af7 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiatableitemprovider.cpp
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiatableitemprovider.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtGui/qtguiglobal.h>
#if QT_CONFIG(accessibility)
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiatableitemprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiatableitemprovider.h
index 9804c35f8e..3bb0e1027e 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiatableitemprovider.h
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiatableitemprovider.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QWINDOWSUIATABLEITEMPROVIDER_H
#define QWINDOWSUIATABLEITEMPROVIDER_H
@@ -49,7 +13,7 @@ QT_BEGIN_NAMESPACE
// Implements the Table Item control pattern provider. Used by items within a table/tree.
class QWindowsUiaTableItemProvider : public QWindowsUiaBaseProvider,
- public QWindowsComBase<ITableItemProvider>
+ public QComObject<ITableItemProvider>
{
Q_DISABLE_COPY_MOVE(QWindowsUiaTableItemProvider)
public:
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiatableprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiatableprovider.cpp
index 80086f1d4f..9c7ede882d 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiatableprovider.cpp
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiatableprovider.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtGui/qtguiglobal.h>
#if QT_CONFIG(accessibility)
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiatableprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiatableprovider.h
index a8b16035ec..8beb11decf 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiatableprovider.h
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiatableprovider.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QWINDOWSUIATABLEPROVIDER_H
#define QWINDOWSUIATABLEPROVIDER_H
@@ -48,8 +12,7 @@
QT_BEGIN_NAMESPACE
// Implements the Table control pattern provider. Used by tables/trees.
-class QWindowsUiaTableProvider : public QWindowsUiaBaseProvider,
- public QWindowsComBase<ITableProvider>
+class QWindowsUiaTableProvider : public QWindowsUiaBaseProvider, public QComObject<ITableProvider>
{
Q_DISABLE_COPY_MOVE(QWindowsUiaTableProvider)
public:
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiatextprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiatextprovider.cpp
index 50ecfc7ecd..172836232e 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiatextprovider.cpp
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiatextprovider.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtGui/qtguiglobal.h>
#if QT_CONFIG(accessibility)
@@ -62,20 +26,6 @@ QWindowsUiaTextProvider::~QWindowsUiaTextProvider()
{
}
-HRESULT STDMETHODCALLTYPE QWindowsUiaTextProvider::QueryInterface(REFIID iid, LPVOID *iface)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__ << this;
-
- if (!iface)
- return E_INVALIDARG;
- *iface = nullptr;
-
- const bool result = qWindowsComQueryUnknownInterfaceMulti<ITextProvider>(this, iid, iface)
- || qWindowsComQueryInterface<ITextProvider>(this, iid, iface)
- || qWindowsComQueryInterface<ITextProvider2>(this, iid, iface);
- return result ? S_OK : E_NOINTERFACE;
-}
-
// Returns an array of providers for the selected text ranges.
HRESULT STDMETHODCALLTYPE QWindowsUiaTextProvider::GetSelection(SAFEARRAY **pRetVal)
{
@@ -182,9 +132,10 @@ HRESULT STDMETHODCALLTYPE QWindowsUiaTextProvider::RangeFromPoint(UiaPoint point
nativeUiaPointToPoint(point, window, &pt);
int offset = textInterface->offsetAtPoint(pt);
- if ((offset >= 0) && (offset < textInterface->characterCount())) {
- *pRetVal = new QWindowsUiaTextRangeProvider(id(), offset, offset);
- }
+ if (offset < 0 || offset >= textInterface->characterCount())
+ return UIA_E_ELEMENTNOTAVAILABLE;
+
+ *pRetVal = new QWindowsUiaTextRangeProvider(id(), offset, offset);
return S_OK;
}
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiatextprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiatextprovider.h
index ffab48b0e8..8f886510b4 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiatextprovider.h
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiatextprovider.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QWINDOWSUIATEXTPROVIDER_H
#define QWINDOWSUIATEXTPROVIDER_H
@@ -48,18 +12,27 @@
QT_BEGIN_NAMESPACE
+namespace QtPrivate {
+
+template <>
+struct QComObjectTraits<ITextProvider2>
+{
+ static constexpr bool isGuidOf(REFIID riid) noexcept
+ {
+ return QComObjectTraits<ITextProvider2, ITextProvider>::isGuidOf(riid);
+ }
+};
+
+} // namespace QtPrivate
+
// Implements the Text control pattern provider. Used for text controls.
-class QWindowsUiaTextProvider : public QWindowsUiaBaseProvider,
- public QWindowsComBase<ITextProvider2>
+class QWindowsUiaTextProvider : public QWindowsUiaBaseProvider, public QComObject<ITextProvider2>
{
Q_DISABLE_COPY_MOVE(QWindowsUiaTextProvider)
public:
explicit QWindowsUiaTextProvider(QAccessible::Id id);
~QWindowsUiaTextProvider();
- // IUnknown overrides
- HRESULT STDMETHODCALLTYPE QueryInterface(REFIID id, LPVOID *iface) override;
-
// ITextProvider
HRESULT STDMETHODCALLTYPE GetSelection(SAFEARRAY **pRetVal) override;
HRESULT STDMETHODCALLTYPE GetVisibleRanges(SAFEARRAY **pRetVal) override;
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiatextrangeprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiatextrangeprovider.cpp
index d8b8f7281d..a62a33cfe2 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiatextrangeprovider.cpp
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiatextrangeprovider.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtGui/qtguiglobal.h>
#if QT_CONFIG(accessibility)
@@ -143,7 +107,9 @@ HRESULT QWindowsUiaTextRangeProvider::ExpandToEnclosingUnit(TextUnit unit)
m_endOffset = m_startOffset + 1;
} else {
QString text = textInterface->text(0, len);
- for (int t = m_startOffset; t >= 0; --t) {
+ const int start = m_startOffset >= 0 && m_startOffset < len
+ ? m_startOffset : len - 1;
+ for (int t = start; t >= 0; --t) {
if (!isTextUnitSeparator(unit, text[t]) && ((t == 0) || isTextUnitSeparator(unit, text[t - 1]))) {
m_startOffset = t;
break;
@@ -201,6 +167,15 @@ HRESULT STDMETHODCALLTYPE QWindowsUiaTextRangeProvider::GetAttributeValue(TEXTAT
else
setVariantI4(CaretPosition_Unknown, pRetVal);
break;
+ case UIA_StrikethroughStyleAttributeId:
+ {
+ const QString value = valueForIA2Attribute(textInterface, QStringLiteral("text-line-through-type"));
+ if (value.isEmpty())
+ break;
+ const TextDecorationLineStyle uiaLineStyle = uiaLineStyleForIA2LineStyle(value);
+ setVariantI4(uiaLineStyle, pRetVal);
+ break;
+ }
default:
break;
}
@@ -341,14 +316,14 @@ HRESULT QWindowsUiaTextRangeProvider::Move(TextUnit unit, int count, int *pRetVa
int len = textInterface->characterCount();
- if (len < 1)
+ if (len < 1 || count == 0) // MSDN: "Zero has no effect."
return S_OK;
if (unit == TextUnit_Character) {
// Moves the start point, ensuring it lies within the bounds.
- int start = qBound(0, m_startOffset + count, len - 1);
+ int start = qBound(0, m_startOffset + count, len);
// If range was initially empty, leaves it as is; otherwise, normalizes it to one char.
- m_endOffset = (m_endOffset > m_startOffset) ? start + 1 : start;
+ m_endOffset = (m_endOffset > m_startOffset) ? qMin(start + 1, len) : start;
*pRetVal = start - m_startOffset; // Returns the actually moved distance.
m_startOffset = start;
} else {
@@ -419,7 +394,7 @@ HRESULT QWindowsUiaTextRangeProvider::MoveEndpointByUnit(TextPatternRangeEndpoin
if (unit == TextUnit_Character) {
if (endpoint == TextPatternRangeEndpoint_Start) {
- int boundedValue = qBound(0, m_startOffset + count, len - 1);
+ int boundedValue = qBound(0, m_startOffset + count, len);
*pRetVal = boundedValue - m_startOffset;
m_startOffset = boundedValue;
m_endOffset = qBound(m_startOffset, m_endOffset, len);
@@ -443,7 +418,9 @@ HRESULT QWindowsUiaTextRangeProvider::MoveEndpointByUnit(TextPatternRangeEndpoin
}
m_endOffset = qBound(m_startOffset, m_endOffset, len);
} else {
- for (int t = m_startOffset - 1; (t >= 0) && (moved > count); --t) {
+ const int start = m_startOffset >= 0 && m_startOffset <= len
+ ? m_startOffset : len;
+ for (int t = start - 1; (t >= 0) && (moved > count); --t) {
if (!isTextUnitSeparator(unit, text[t]) && ((t == 0) || isTextUnitSeparator(unit, text[t - 1]))) {
m_startOffset = t;
--moved;
@@ -549,6 +526,42 @@ HRESULT QWindowsUiaTextRangeProvider::unselect()
return S_OK;
}
+// helper method to retrieve the value of the given IAccessible2 text attribute,
+// or an empty string if not set
+QString QWindowsUiaTextRangeProvider::valueForIA2Attribute(QAccessibleTextInterface *textInterface,
+ const QString &key)
+{
+ Q_ASSERT(textInterface);
+
+ int startOffset;
+ int endOffset;
+ const QString attributes = textInterface->attributes(m_startOffset, &startOffset, &endOffset);
+ // don't report if attributes don't apply for the whole range
+ if (startOffset > m_startOffset || endOffset < m_endOffset)
+ return {};
+
+ for (auto attr : QStringTokenizer{attributes, u';'})
+ {
+ const QList<QStringView> items = attr.split(u':', Qt::SkipEmptyParts, Qt::CaseSensitive);
+ if (items.count() == 2 && items[0] == key)
+ return items[1].toString();
+ }
+
+ return {};
+}
+
+TextDecorationLineStyle QWindowsUiaTextRangeProvider::uiaLineStyleForIA2LineStyle(const QString &ia2LineStyle)
+{
+ if (ia2LineStyle == QStringLiteral("none"))
+ return TextDecorationLineStyle_None;
+ if (ia2LineStyle == QStringLiteral("single"))
+ return TextDecorationLineStyle_Single;
+ if (ia2LineStyle == QStringLiteral("double"))
+ return TextDecorationLineStyle_Double;
+
+ return TextDecorationLineStyle_Other;
+}
+
QT_END_NAMESPACE
#endif // QT_CONFIG(accessibility)
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiatextrangeprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiatextrangeprovider.h
index 3b4ec63ceb..a37429a603 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiatextrangeprovider.h
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiatextrangeprovider.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QWINDOWSUIATEXTRANGEPROVIDER_H
#define QWINDOWSUIATEXTRANGEPROVIDER_H
@@ -49,7 +13,7 @@ QT_BEGIN_NAMESPACE
// Implements the Text Range control pattern provider. Used for text controls.
class QWindowsUiaTextRangeProvider : public QWindowsUiaBaseProvider,
- public QWindowsComBase<ITextRangeProvider>
+ public QComObject<ITextRangeProvider>
{
Q_DISABLE_COPY_MOVE(QWindowsUiaTextRangeProvider)
public:
@@ -78,6 +42,8 @@ public:
private:
HRESULT unselect();
+ QString valueForIA2Attribute(QAccessibleTextInterface *textInterface, const QString &key);
+ TextDecorationLineStyle uiaLineStyleForIA2LineStyle(const QString &ia2LineStyle);
int m_startOffset;
int m_endOffset;
};
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiatoggleprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiatoggleprovider.cpp
index 32445e4ffb..694debd492 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiatoggleprovider.cpp
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiatoggleprovider.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtGui/qtguiglobal.h>
#if QT_CONFIG(accessibility)
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiatoggleprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiatoggleprovider.h
index 892b635b41..17150dfbe0 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiatoggleprovider.h
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiatoggleprovider.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QWINDOWSUIATOGGLEPROVIDER_H
#define QWINDOWSUIATOGGLEPROVIDER_H
@@ -48,8 +12,7 @@
QT_BEGIN_NAMESPACE
// Implements the Toggle control pattern provider. Used for checkboxes.
-class QWindowsUiaToggleProvider : public QWindowsUiaBaseProvider,
- public QWindowsComBase<IToggleProvider>
+class QWindowsUiaToggleProvider : public QWindowsUiaBaseProvider, public QComObject<IToggleProvider>
{
Q_DISABLE_COPY_MOVE(QWindowsUiaToggleProvider)
public:
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiautils.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiautils.cpp
index ab04384616..78ab3e890e 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiautils.cpp
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiautils.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtGui/qtguiglobal.h>
#if QT_CONFIG(accessibility)
@@ -132,22 +96,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.
@@ -161,7 +122,7 @@ long roleToControlTypeId(QAccessible::Role role)
{QAccessible::Sound, UIA_CustomControlTypeId},
{QAccessible::Cursor, UIA_CustomControlTypeId},
{QAccessible::Caret, UIA_CustomControlTypeId},
- {QAccessible::AlertMessage, UIA_CustomControlTypeId},
+ {QAccessible::AlertMessage, UIA_WindowControlTypeId},
{QAccessible::Window, UIA_WindowControlTypeId},
{QAccessible::Client, UIA_GroupControlTypeId},
{QAccessible::PopupMenu, UIA_MenuControlTypeId},
@@ -215,6 +176,9 @@ long roleToControlTypeId(QAccessible::Role role)
{QAccessible::PageTabList, UIA_TabControlTypeId},
{QAccessible::Clock, UIA_CustomControlTypeId},
{QAccessible::Splitter, UIA_CustomControlTypeId},
+ {QAccessible::Paragraph, UIA_TextControlTypeId},
+ {QAccessible::WebDocument, UIA_DocumentControlTypeId},
+ {QAccessible::Heading, UIA_TextControlTypeId},
};
return mapping.value(role, UIA_CustomControlTypeId);
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiautils.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiautils.h
index 6a482f6c1c..bf90211cec 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiautils.h
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiautils.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QWINDOWSUIAUTILS_H
#define QWINDOWSUIAUTILS_H
@@ -48,7 +12,7 @@
#include <QtGui/qaccessible.h>
#include <QtGui/qwindow.h>
#include <QtCore/qrect.h>
-#include <QtWindowsUIAutomationSupport/private/qwindowsuiawrapper_p.h>
+#include "qwindowsuiautomation.h"
QT_BEGIN_NAMESPACE
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiautomation.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiautomation.cpp
new file mode 100644
index 0000000000..1593a07202
--- /dev/null
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiautomation.cpp
@@ -0,0 +1,74 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
+
+#include "qwindowsuiautomation.h"
+
+#if defined(__MINGW32__) || defined(__MINGW64__)
+
+template<typename T, typename... TArg>
+struct winapi_func
+{
+ using func_t = T(WINAPI*)(TArg...);
+ const func_t func;
+ const T error_value;
+#ifdef __GNUC__
+# pragma GCC diagnostic ignored "-Wcast-function-type"
+#endif
+ winapi_func(const char *lib_name, const char *func_name, func_t func_proto,
+ T error_value = T(__HRESULT_FROM_WIN32(ERROR_PROC_NOT_FOUND))) :
+ func(reinterpret_cast<func_t>(GetProcAddress(LoadLibraryA(lib_name), func_name))),
+ error_value(error_value)
+ {
+ std::ignore = func_proto;
+ }
+#ifdef __GNUC__
+# pragma GCC diagnostic pop
+#endif
+ T invoke(TArg... arg)
+ {
+ if (!func)
+ return error_value;
+ return func(arg...);
+ }
+};
+
+#define FN(fn) #fn,fn
+
+BOOL WINAPI UiaClientsAreListening()
+{
+ static auto func = winapi_func("uiautomationcore", FN(UiaClientsAreListening), BOOL(false));
+ return func.invoke();
+}
+
+LRESULT WINAPI UiaReturnRawElementProvider(
+ HWND hwnd, WPARAM wParam, LPARAM lParam, IRawElementProviderSimple *el)
+{
+ static auto func = winapi_func("uiautomationcore", FN(UiaReturnRawElementProvider));
+ return func.invoke(hwnd, wParam, lParam, el);
+}
+
+HRESULT WINAPI UiaHostProviderFromHwnd(HWND hwnd, IRawElementProviderSimple **ppProvider)
+{
+ static auto func = winapi_func("uiautomationcore", FN(UiaHostProviderFromHwnd));
+ return func.invoke(hwnd, ppProvider);
+}
+
+HRESULT WINAPI UiaRaiseAutomationPropertyChangedEvent(
+ IRawElementProviderSimple *pProvider, PROPERTYID id, VARIANT oldValue, VARIANT newValue)
+{
+ static auto func = winapi_func("uiautomationcore", FN(UiaRaiseAutomationPropertyChangedEvent));
+ return func.invoke(pProvider, id, oldValue, newValue);
+}
+
+HRESULT WINAPI UiaRaiseAutomationEvent(IRawElementProviderSimple *pProvider, EVENTID id)
+{
+ static auto func = winapi_func("uiautomationcore", FN(UiaRaiseAutomationEvent));
+ return func.invoke(pProvider, id);
+}
+
+#endif // defined(__MINGW32__) || defined(__MINGW64__)
+
+#endif // QT_CONFIG(accessibility)
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiautomation.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiautomation.h
new file mode 100644
index 0000000000..a192b9b0fb
--- /dev/null
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiautomation.h
@@ -0,0 +1,70 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QWINDOWSUIAUTOMATION_H
+#define QWINDOWSUIAUTOMATION_H
+
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
+
+#include <uiautomation.h>
+
+#if defined(__MINGW32__) || defined(__MINGW64__)
+
+#define UIA_SelectionPattern2Id 10034
+#define UIA_IsReadOnlyAttributeId 40015
+#define UIA_StrikethroughStyleAttributeId 40026
+#define UIA_CaretPositionAttributeId 40038
+
+enum CaretPosition {
+ CaretPosition_Unknown = 0,
+ CaretPosition_EndOfLine = 1,
+ CaretPosition_BeginningOfLine = 2
+};
+
+enum TextDecorationLineStyle {
+ TextDecorationLineStyle_None = 0,
+ TextDecorationLineStyle_Single = 1,
+ TextDecorationLineStyle_WordsOnly = 2,
+ TextDecorationLineStyle_Double = 3,
+ TextDecorationLineStyle_Dot = 4,
+ TextDecorationLineStyle_Dash = 5,
+ TextDecorationLineStyle_DashDot = 6,
+ TextDecorationLineStyle_DashDotDot = 7,
+ TextDecorationLineStyle_Wavy = 8,
+ TextDecorationLineStyle_ThickSingle = 9,
+ TextDecorationLineStyle_DoubleWavy = 11,
+ TextDecorationLineStyle_ThickWavy = 12,
+ TextDecorationLineStyle_LongDash = 13,
+ TextDecorationLineStyle_ThickDash = 14,
+ TextDecorationLineStyle_ThickDashDot = 15,
+ TextDecorationLineStyle_ThickDashDotDot = 16,
+ TextDecorationLineStyle_ThickDot = 17,
+ TextDecorationLineStyle_ThickLongDash = 18,
+ TextDecorationLineStyle_Other = -1
+};
+
+BOOL WINAPI UiaClientsAreListening();
+
+#ifndef __ISelectionProvider2_INTERFACE_DEFINED__
+#define __ISelectionProvider2_INTERFACE_DEFINED__
+DEFINE_GUID(IID_ISelectionProvider2, 0x14f68475, 0xee1c, 0x44f6, 0xa8, 0x69, 0xd2, 0x39, 0x38, 0x1f, 0x0f, 0xe7);
+MIDL_INTERFACE("14f68475-ee1c-44f6-a869-d239381f0fe7")
+ISelectionProvider2 : public ISelectionProvider
+{
+public:
+ virtual HRESULT STDMETHODCALLTYPE get_FirstSelectedItem(__RPC__deref_out_opt IRawElementProviderSimple **retVal) = 0;
+ virtual HRESULT STDMETHODCALLTYPE get_LastSelectedItem(__RPC__deref_out_opt IRawElementProviderSimple **retVal) = 0;
+ virtual HRESULT STDMETHODCALLTYPE get_CurrentSelectedItem(__RPC__deref_out_opt IRawElementProviderSimple **retVal) = 0;
+ virtual HRESULT STDMETHODCALLTYPE get_ItemCount(__RPC__out int *retVal) = 0;
+};
+#ifdef __CRT_UUID_DECL
+__CRT_UUID_DECL(ISelectionProvider2, 0x14f68475, 0xee1c, 0x44f6, 0xa8, 0x69, 0xd2, 0x39, 0x38, 0x1f, 0x0f, 0xe7)
+#endif
+#endif // __ISelectionProvider2_INTERFACE_DEFINED__
+
+#endif // defined(__MINGW32__) || defined(__MINGW64__)
+
+#endif // QT_CONFIG(accessibility)
+
+#endif // QWINDOWSUIAUTOMATION_H
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiavalueprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiavalueprovider.cpp
index 8651bcff60..77f40cc2cc 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiavalueprovider.cpp
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiavalueprovider.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtGui/qtguiglobal.h>
#if QT_CONFIG(accessibility)
@@ -72,7 +36,7 @@ HRESULT STDMETHODCALLTYPE QWindowsUiaValueProvider::SetValue(LPCWSTR val)
return UIA_E_ELEMENTNOTAVAILABLE;
// First sets the value as a text.
- QString strVal = QString::fromUtf16(reinterpret_cast<const ushort *>(val));
+ QString strVal = QString::fromUtf16(reinterpret_cast<const char16_t *>(val));
accessible->setText(QAccessible::Value, strVal);
// Then, if the control supports the value interface (range value)
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiavalueprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiavalueprovider.h
index 3edfe7a08b..8c0a6b8ee7 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiavalueprovider.h
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiavalueprovider.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QWINDOWSUIAVALUEPROVIDER_H
#define QWINDOWSUIAVALUEPROVIDER_H
@@ -49,8 +13,7 @@ QT_BEGIN_NAMESPACE
// Implements the Value control pattern provider.
// Supported for all controls that can return text(QAccessible::Value).
-class QWindowsUiaValueProvider : public QWindowsUiaBaseProvider,
- public QWindowsComBase<IValueProvider>
+class QWindowsUiaValueProvider : public QWindowsUiaBaseProvider, public QComObject<IValueProvider>
{
Q_DISABLE_COPY_MOVE(QWindowsUiaValueProvider)
public:
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiawindowprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiawindowprovider.cpp
index 3738aa72ff..d86face0db 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiawindowprovider.cpp
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiawindowprovider.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 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$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtGui/qtguiglobal.h>
#if QT_CONFIG(accessibility)
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiawindowprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiawindowprovider.h
index 343fb275f7..89a1655232 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiawindowprovider.h
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiawindowprovider.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 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$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QWINDOWSUIAWINDOWPROVIDER_H
#define QWINDOWSUIAWINDOWPROVIDER_H
@@ -47,8 +11,7 @@
QT_BEGIN_NAMESPACE
-class QWindowsUiaWindowProvider : public QWindowsUiaBaseProvider,
- public QWindowsComBase<IWindowProvider>
+class QWindowsUiaWindowProvider : public QWindowsUiaBaseProvider, public QComObject<IWindowProvider>
{
Q_DISABLE_COPY(QWindowsUiaWindowProvider)
public:
diff --git a/src/plugins/platforms/windows/uiautomation/uiautomation.pri b/src/plugins/platforms/windows/uiautomation/uiautomation.pri
deleted file mode 100644
index ee9332e7ea..0000000000
--- a/src/plugins/platforms/windows/uiautomation/uiautomation.pri
+++ /dev/null
@@ -1,44 +0,0 @@
-qtHaveModule(windowsuiautomation_support-private): \
- QT += windowsuiautomation_support-private
-
-SOURCES += \
- $$PWD/qwindowsuiaaccessibility.cpp \
- $$PWD/qwindowsuiaprovidercache.cpp \
- $$PWD/qwindowsuiamainprovider.cpp \
- $$PWD/qwindowsuiabaseprovider.cpp \
- $$PWD/qwindowsuiavalueprovider.cpp \
- $$PWD/qwindowsuiatextprovider.cpp \
- $$PWD/qwindowsuiatextrangeprovider.cpp \
- $$PWD/qwindowsuiatoggleprovider.cpp \
- $$PWD/qwindowsuiaselectionprovider.cpp \
- $$PWD/qwindowsuiaselectionitemprovider.cpp \
- $$PWD/qwindowsuiainvokeprovider.cpp \
- $$PWD/qwindowsuiarangevalueprovider.cpp \
- $$PWD/qwindowsuiatableprovider.cpp \
- $$PWD/qwindowsuiatableitemprovider.cpp \
- $$PWD/qwindowsuiagridprovider.cpp \
- $$PWD/qwindowsuiagriditemprovider.cpp \
- $$PWD/qwindowsuiawindowprovider.cpp \
- $$PWD/qwindowsuiautils.cpp
-
-HEADERS += \
- $$PWD/qwindowsuiaaccessibility.h \
- $$PWD/qwindowsuiaprovidercache.h \
- $$PWD/qwindowsuiamainprovider.h \
- $$PWD/qwindowsuiabaseprovider.h \
- $$PWD/qwindowsuiavalueprovider.h \
- $$PWD/qwindowsuiatextprovider.h \
- $$PWD/qwindowsuiatextrangeprovider.h \
- $$PWD/qwindowsuiatoggleprovider.h \
- $$PWD/qwindowsuiaselectionprovider.h \
- $$PWD/qwindowsuiaselectionitemprovider.h \
- $$PWD/qwindowsuiainvokeprovider.h \
- $$PWD/qwindowsuiarangevalueprovider.h \
- $$PWD/qwindowsuiatableprovider.h \
- $$PWD/qwindowsuiatableitemprovider.h \
- $$PWD/qwindowsuiagridprovider.h \
- $$PWD/qwindowsuiagriditemprovider.h \
- $$PWD/qwindowsuiawindowprovider.h \
- $$PWD/qwindowsuiautils.h
-
-mingw: QMAKE_USE *= uuid
diff --git a/src/plugins/platforms/windows/windows.pri b/src/plugins/platforms/windows/windows.pri
deleted file mode 100644
index 95ba961df1..0000000000
--- a/src/plugins/platforms/windows/windows.pri
+++ /dev/null
@@ -1,130 +0,0 @@
-# Note: OpenGL32 must precede Gdi32 as it overwrites some functions.
-LIBS += -lwinspool -limm32 -loleaut32
-
-QT_FOR_CONFIG += gui
-
-qtConfig(opengl):!qtConfig(opengles2):!qtConfig(dynamicgl): LIBS *= -lopengl32
-
-mingw: QMAKE_USE *= uuid
-# For the dialog helpers:
-LIBS += -lshlwapi -lwtsapi32
-
-QMAKE_USE_PRIVATE += \
- advapi32 \
- d3d9/nolink \
- ole32 \
- shell32 \
- user32 \
- winmm
-
-DEFINES *= QT_NO_CAST_FROM_ASCII QT_NO_FOREACH
-
-SOURCES += \
- $$PWD/qwindowswindow.cpp \
- $$PWD/qwindowsintegration.cpp \
- $$PWD/qwindowscontext.cpp \
- $$PWD/qwindowsscreen.cpp \
- $$PWD/qwindowskeymapper.cpp \
- $$PWD/qwindowsmousehandler.cpp \
- $$PWD/qwindowspointerhandler.cpp \
- $$PWD/qwindowsole.cpp \
- $$PWD/qwindowsdropdataobject.cpp \
- $$PWD/qwindowsmime.cpp \
- $$PWD/qwindowsinternalmimedata.cpp \
- $$PWD/qwindowscursor.cpp \
- $$PWD/qwindowsinputcontext.cpp \
- $$PWD/qwindowstheme.cpp \
- $$PWD/qwindowsmenu.cpp \
- $$PWD/qwindowsdialoghelpers.cpp \
- $$PWD/qwindowsservices.cpp \
- $$PWD/qwindowsnativeinterface.cpp \
- $$PWD/qwindowsopengltester.cpp \
- $$PWD/qwin10helpers.cpp
-
-HEADERS += \
- $$PWD/qwindowscombase.h \
- $$PWD/qwindowswindow.h \
- $$PWD/qwindowsintegration.h \
- $$PWD/qwindowscontext.h \
- $$PWD/qwindowsscreen.h \
- $$PWD/qwindowskeymapper.h \
- $$PWD/qwindowsmousehandler.h \
- $$PWD/qwindowspointerhandler.h \
- $$PWD/qtwindowsglobal.h \
- $$PWD/qwindowsole.h \
- $$PWD/qwindowsdropdataobject.h \
- $$PWD/qwindowsmime.h \
- $$PWD/qwindowsinternalmimedata.h \
- $$PWD/qwindowscursor.h \
- $$PWD/qwindowsinputcontext.h \
- $$PWD/qwindowstheme.h \
- $$PWD/qwindowsmenu.h \
- $$PWD/qwindowsdialoghelpers.h \
- $$PWD/qwindowsservices.h \
- $$PWD/qwindowsnativeinterface.h \
- $$PWD/qwindowsopengltester.h \
- $$PWD/qwindowsthreadpoolrunner.h \
- $$PWD/qwin10helpers.h
-
-INCLUDEPATH += $$PWD
-
-qtConfig(opengl): HEADERS += $$PWD/qwindowsopenglcontext.h
-
-qtConfig(opengles2) {
- SOURCES += $$PWD/qwindowseglcontext.cpp
- HEADERS += $$PWD/qwindowseglcontext.h
-} else: qtConfig(opengl) {
- SOURCES += $$PWD/qwindowsglcontext.cpp
- HEADERS += $$PWD/qwindowsglcontext.h
-}
-
-# Dynamic GL needs both WGL and EGL
-qtConfig(dynamicgl) {
- SOURCES += $$PWD/qwindowseglcontext.cpp
- HEADERS += $$PWD/qwindowseglcontext.h
-}
-
-qtConfig(systemtrayicon) {
- SOURCES += $$PWD/qwindowssystemtrayicon.cpp
- HEADERS += $$PWD/qwindowssystemtrayicon.h
-}
-
-qtConfig(vulkan) {
- SOURCES += $$PWD/qwindowsvulkaninstance.cpp
- HEADERS += $$PWD/qwindowsvulkaninstance.h
-}
-
-qtConfig(clipboard) {
- SOURCES += $$PWD/qwindowsclipboard.cpp
- HEADERS += $$PWD/qwindowsclipboard.h
- # drag and drop on windows only works if a clipboard is available
- qtConfig(draganddrop) {
- HEADERS += $$PWD/qwindowsdrag.h
- SOURCES += $$PWD/qwindowsdrag.cpp
- }
-}
-
-qtConfig(tabletevent) {
- INCLUDEPATH += $$QT_SOURCE_TREE/src/3rdparty/wintab
- HEADERS += $$PWD/qwindowstabletsupport.h
- SOURCES += $$PWD/qwindowstabletsupport.cpp
-}
-
-qtConfig(sessionmanager) {
- SOURCES += $$PWD/qwindowssessionmanager.cpp
- HEADERS += $$PWD/qwindowssessionmanager.h
-}
-
-qtConfig(imageformat_png):RESOURCES += $$PWD/cursors.qrc
-
-RESOURCES += $$PWD/openglblacklists.qrc
-
-qtConfig(accessibility): include($$PWD/uiautomation/uiautomation.pri)
-
-qtConfig(combined-angle-lib) {
- DEFINES *= LIBEGL_NAME=$${LIBQTANGLE_NAME}
- DEFINES *= LIBGLESV2_NAME=$${LIBQTANGLE_NAME}
-} else {
- DEFINES *= LIBEGL_NAME=$${LIBEGL_NAME}
- DEFINES *= LIBGLESV2_NAME=$${LIBGLESV2_NAME}
-}
diff --git a/src/plugins/platforms/windows/windows.pro b/src/plugins/platforms/windows/windows.pro
deleted file mode 100644
index b14969cc3a..0000000000
--- a/src/plugins/platforms/windows/windows.pro
+++ /dev/null
@@ -1,36 +0,0 @@
-TARGET = qwindows
-
-QT += \
- core-private gui-private \
- eventdispatcher_support-private \
- fontdatabase_support-private theme_support-private
-
-qtHaveModule(platformcompositor_support-private): QT += platformcompositor_support-private
-
-qtConfig(accessibility): QT += accessibility_support-private
-qtConfig(vulkan): QT += vulkan_support-private
-
-qtConfig(directwrite3): DEFINES *= QT_USE_DIRECTWRITE2 QT_USE_DIRECTWRITE3
-
-LIBS += -ldwmapi
-QMAKE_USE_PRIVATE += gdi32
-
-include(windows.pri)
-
-SOURCES += \
- main.cpp \
- qwindowsbackingstore.cpp \
- qwindowsgdiintegration.cpp \
- qwindowsgdinativeinterface.cpp
-
-HEADERS += \
- qwindowsbackingstore.h \
- qwindowsgdiintegration.h \
- qwindowsgdinativeinterface.h
-
-OTHER_FILES += windows.json
-
-PLUGIN_TYPE = platforms
-PLUGIN_CLASS_NAME = QWindowsIntegrationPlugin
-!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = -
-load(qt_plugin)
diff --git a/src/plugins/platforms/winrt/main.cpp b/src/plugins/platforms/winrt/main.cpp
deleted file mode 100644
index a37bd1e3d8..0000000000
--- a/src/plugins/platforms/winrt/main.cpp
+++ /dev/null
@@ -1,66 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 "qwinrtintegration.h"
-
-#include <qpa/qplatformintegrationplugin.h>
-
-QT_BEGIN_NAMESPACE
-
-class QWinRTIntegrationPlugin : public QPlatformIntegrationPlugin
-{
- Q_OBJECT
- Q_PLUGIN_METADATA(IID QPlatformIntegrationFactoryInterface_iid FILE "winrt.json")
-
-public:
- QPlatformIntegration *create(const QString&, const QStringList&) override;
-};
-
-QPlatformIntegration *QWinRTIntegrationPlugin::create(const QString& system, const QStringList& paramList)
-{
- Q_UNUSED(paramList);
- if (!system.compare(QLatin1String("winrt"), Qt::CaseInsensitive))
- return QWinRTIntegration::create();
-
- return nullptr;
-}
-
-QT_END_NAMESPACE
-
-#include "main.moc"
diff --git a/src/plugins/platforms/winrt/qwinrtbackingstore.cpp b/src/plugins/platforms/winrt/qwinrtbackingstore.cpp
deleted file mode 100644
index fbf611d7f7..0000000000
--- a/src/plugins/platforms/winrt/qwinrtbackingstore.cpp
+++ /dev/null
@@ -1,194 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 "qwinrtbackingstore.h"
-
-#include "qwinrtscreen.h"
-#include "qwinrtwindow.h"
-#include "qwinrteglcontext.h"
-#include <QtGui/QOpenGLContext>
-#include <QtGui/QOpenGLFramebufferObject>
-
-#include <GLES3/gl3.h>
-
-QT_BEGIN_NAMESPACE
-
-class QWinRTBackingStorePrivate
-{
-public:
- bool initialized;
- QSize size;
- QScopedPointer<QOpenGLContext> context;
- QScopedPointer<QOpenGLFramebufferObject> fbo;
- QWinRTScreen *screen;
- QImage paintDevice;
-};
-
-QWinRTBackingStore::QWinRTBackingStore(QWindow *window)
- : QPlatformBackingStore(window), d_ptr(new QWinRTBackingStorePrivate)
-{
- Q_D(QWinRTBackingStore);
- qCInfo(lcQpaBackingStore) << __FUNCTION__ << this << window;
-
- d->initialized = false;
- d->screen = static_cast<QWinRTScreen*>(window->screen()->handle());
-
- if (window->surfaceType() == QSurface::RasterSurface)
- window->setSurfaceType(QSurface::OpenGLSurface);
-}
-
-bool QWinRTBackingStore::initialize()
-{
- Q_D(QWinRTBackingStore);
- qCDebug(lcQpaBackingStore) << __FUNCTION__ << d->initialized;
-
- if (d->initialized)
- return true;
-
- d->context.reset(new QOpenGLContext);
- QSurfaceFormat format = window()->format();
- d->context->setFormat(format);
- d->context->setScreen(window()->screen());
- if (!d->context->create())
- return false;
-
- if (!d->context->makeCurrent(window()))
- return false;
-
- d->context->doneCurrent();
- d->initialized = true;
- return true;
-}
-
-QWinRTBackingStore::~QWinRTBackingStore()
-{
- qCInfo(lcQpaBackingStore) << __FUNCTION__ << this;
-}
-
-QPaintDevice *QWinRTBackingStore::paintDevice()
-{
- Q_D(QWinRTBackingStore);
- return &d->paintDevice;
-}
-
-void QWinRTBackingStore::flush(QWindow *window, const QRegion &region, const QPoint &offset)
-{
- Q_D(QWinRTBackingStore);
- Q_UNUSED(offset)
-
- qCDebug(lcQpaBackingStore) << __FUNCTION__ << this << window << region;
-
- if (d->size.isEmpty())
- return;
-
- const QRect bounds = region.boundingRect() & d->paintDevice.rect();
- if (bounds.isEmpty())
- return;
-
- const bool ok = d->context->makeCurrent(window);
- if (!ok)
- qWarning("unable to flush");
-
- glBindTexture(GL_TEXTURE_2D, d->fbo->texture());
- // TODO: when ANGLE GLES3 support is finished, use the glPixelStorei functions to minimize upload
- glTexSubImage2D(GL_TEXTURE_2D, 0, 0, bounds.y(), d->size.width(), bounds.height(),
- GL_RGBA, GL_UNSIGNED_BYTE, d->paintDevice.constScanLine(bounds.y()));
- glBindTexture(GL_TEXTURE_2D, 0);
-
- glBindFramebuffer(GL_READ_FRAMEBUFFER_ANGLE, d->fbo->handle());
- glBindFramebuffer(GL_DRAW_FRAMEBUFFER_ANGLE, 0);
- const int y1 = bounds.y();
- const int y2 = y1 + bounds.height();
- const int x1 = bounds.x();
- const int x2 = x1 + bounds.width();
- glBlitFramebuffer(x1, y1, x2, y2,
- x1, d->size.height() - y1, x2, d->size.height() - y2,
- GL_COLOR_BUFFER_BIT, GL_NEAREST);
-
- d->context->swapBuffers(window);
- d->context->doneCurrent();
-}
-
-void QWinRTBackingStore::resize(const QSize &size, const QRegion &staticContents)
-{
- Q_D(QWinRTBackingStore);
- Q_UNUSED(staticContents)
-
- qCDebug(lcQpaBackingStore) << __FUNCTION__ << this << size;
-
- if (!initialize())
- return;
-
- if (d->size == size)
- return;
-
- d->size = size;
- if (d->size.isEmpty())
- return;
-
- d->paintDevice = QImage(d->size, QImage::Format_RGBA8888_Premultiplied);
-
- const bool ok = d->context->makeCurrent(window());
- if (!ok)
- qWarning("unable to resize");
-
- d->fbo.reset(new QOpenGLFramebufferObject(d->size));
-
- d->context->doneCurrent();
-}
-
-QImage QWinRTBackingStore::toImage() const
-{
- Q_D(const QWinRTBackingStore);
- return d->paintDevice;
-}
-
-void QWinRTBackingStore::beginPaint(const QRegion &region)
-{
- qCDebug(lcQpaBackingStore) << __FUNCTION__ << this << region;
-
- resize(window()->size(), region);
-}
-
-void QWinRTBackingStore::endPaint()
-{
- qCDebug(lcQpaBackingStore) << __FUNCTION__ << this;
-}
-
-QT_END_NAMESPACE
diff --git a/src/plugins/platforms/winrt/qwinrtbackingstore.h b/src/plugins/platforms/winrt/qwinrtbackingstore.h
deleted file mode 100644
index b62d340b82..0000000000
--- a/src/plugins/platforms/winrt/qwinrtbackingstore.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 QWINRTBACKINGSTORE_H
-#define QWINRTBACKINGSTORE_H
-
-#define GL_GLEXT_PROTOTYPES
-#include <qpa/qplatformbackingstore.h>
-#include <QtCore/QScopedPointer>
-#include <QtCore/QLoggingCategory>
-
-QT_BEGIN_NAMESPACE
-
-class QWinRTScreen;
-
-class QWinRTBackingStorePrivate;
-class QWinRTBackingStore : public QPlatformBackingStore
-{
-public:
- explicit QWinRTBackingStore(QWindow *window);
- ~QWinRTBackingStore() override;
- QPaintDevice *paintDevice() override;
- void beginPaint(const QRegion &) override;
- void endPaint() override;
- void flush(QWindow *window, const QRegion &region, const QPoint &offset) override;
- void resize(const QSize &size, const QRegion &staticContents) override;
- QImage toImage() const override;
-
-private:
- bool initialize();
-
- QScopedPointer<QWinRTBackingStorePrivate> d_ptr;
- Q_DECLARE_PRIVATE(QWinRTBackingStore)
-};
-
-QT_END_NAMESPACE
-
-#endif // QWINRTBACKINGSTORE_H
diff --git a/src/plugins/platforms/winrt/qwinrtcanvas.cpp b/src/plugins/platforms/winrt/qwinrtcanvas.cpp
deleted file mode 100644
index dd6b52d9cd..0000000000
--- a/src/plugins/platforms/winrt/qwinrtcanvas.cpp
+++ /dev/null
@@ -1,142 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 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 "qwinrtcanvas.h"
-#include "uiautomation/qwinrtuiaaccessibility.h"
-#include "uiautomation/qwinrtuiamainprovider.h"
-#include "uiautomation/qwinrtuiametadatacache.h"
-#include "uiautomation/qwinrtuiautils.h"
-
-#include <QtCore/QLoggingCategory>
-#include <QtCore/qfunctions_winrt.h>
-
-using namespace Microsoft::WRL;
-using namespace Microsoft::WRL::Wrappers;
-using namespace ABI::Windows::Foundation;
-using namespace ABI::Windows::System;
-using namespace ABI::Windows::UI;
-using namespace ABI::Windows::UI::Core;
-using namespace ABI::Windows::UI::Xaml;
-using namespace ABI::Windows::Foundation;
-using namespace ABI::Windows::Foundation::Collections;
-
-QT_BEGIN_NAMESPACE
-
-QWinRTCanvas::QWinRTCanvas(const std::function<QWindow*()> &delegateWindow)
-{
- ComPtr<Xaml::Controls::ICanvasFactory> factory;
- HRESULT hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_UI_Xaml_Controls_Canvas).Get(), IID_PPV_ARGS(&factory));
- Q_ASSERT_SUCCEEDED(hr);
-
- hr = factory->CreateInstance(this, &m_base, &m_core);
- Q_ASSERT_SUCCEEDED(hr);
-
- delegate = delegateWindow;
-}
-
-HRESULT STDMETHODCALLTYPE QWinRTCanvas::QueryInterface(REFIID iid, LPVOID *iface)
-{
- if (!iface)
- return E_POINTER;
- *iface = nullptr;
-
- if (iid == IID_IUnknown) {
- *iface = static_cast<Xaml::IUIElementOverrides *>(this);
- AddRef();
- return S_OK;
- } else if (iid == Xaml::IID_IUIElementOverrides) {
- *iface = static_cast<Xaml::IUIElementOverrides *>(this);
- AddRef();
- return S_OK;
- } else {
- return m_base.CopyTo(iid, iface);
- }
-}
-
-HRESULT STDMETHODCALLTYPE QWinRTCanvas::GetIids(ULONG *iidCount, IID **iids)
-{
- *iidCount = 0;
- *iids = nullptr;
- return S_OK;
-}
-
-HRESULT STDMETHODCALLTYPE QWinRTCanvas::GetRuntimeClassName(HSTRING *className)
-{
- const wchar_t *name = L"QWinRTCanvas";
- return ::WindowsCreateString(name, static_cast<UINT32>(::wcslen(name)), className);
-}
-
-HRESULT STDMETHODCALLTYPE QWinRTCanvas::GetTrustLevel(TrustLevel *trustLevel)
-{
- *trustLevel = TrustLevel::BaseTrust;
- return S_OK;
-}
-
-HRESULT STDMETHODCALLTYPE QWinRTCanvas::OnCreateAutomationPeer(Xaml::Automation::Peers::IAutomationPeer **returnValue)
-{
- if (!returnValue)
- return E_INVALIDARG;
- *returnValue = nullptr;
-
- if (delegate) {
- if (QWindow *window = delegate()) {
- QWinRTUiaAccessibility::activate();
- if (QAccessibleInterface *accessible = window->accessibleRoot()) {
- QAccessible::Id accid = QWinRTUiAutomation::idForAccessible(accessible);
- QWinRTUiaMetadataCache::instance()->load(accid);
- if (ComPtr<QWinRTUiaMainProvider> provider = QWinRTUiaMainProvider::providerForAccessibleId(accid))
- return provider.CopyTo(returnValue);
- }
- }
- }
- return m_base->OnCreateAutomationPeer(returnValue);
-}
-
-HRESULT STDMETHODCALLTYPE QWinRTCanvas::OnDisconnectVisualChildren()
-{
- return m_base->OnDisconnectVisualChildren();
-}
-
-HRESULT STDMETHODCALLTYPE QWinRTCanvas::FindSubElementsForTouchTargeting(Point point, Rect boundingRect, IIterable<IIterable<ABI::Windows::Foundation::Point>*> **returnValue)
-{
- return m_base->FindSubElementsForTouchTargeting(point, boundingRect, returnValue);
-}
-
-QT_END_NAMESPACE
-
diff --git a/src/plugins/platforms/winrt/qwinrtcanvas.h b/src/plugins/platforms/winrt/qwinrtcanvas.h
deleted file mode 100644
index bc3b708ac2..0000000000
--- a/src/plugins/platforms/winrt/qwinrtcanvas.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 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 QWINRTCANVAS_H
-#define QWINRTCANVAS_H
-
-#include <QtCore/qglobal.h>
-#include <QtGui/QWindow>
-
-#include <wrl.h>
-#include <windows.ui.xaml.h>
-#include <functional>
-
-QT_BEGIN_NAMESPACE
-
-class QWinRTCanvas:
- public Microsoft::WRL::RuntimeClass<ABI::Windows::UI::Xaml::IUIElementOverrides>
-{
-public:
- QWinRTCanvas(const std::function<QWindow*()> &delegateWindow);
- ~QWinRTCanvas() override = default;
-
- HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, LPVOID *iface) override;
- HRESULT STDMETHODCALLTYPE GetIids(ULONG *iidCount, IID **iids) override;
- HRESULT STDMETHODCALLTYPE GetRuntimeClassName(HSTRING *className) override;
- HRESULT STDMETHODCALLTYPE GetTrustLevel(TrustLevel *trustLevel) override;
- HRESULT STDMETHODCALLTYPE OnCreateAutomationPeer(ABI::Windows::UI::Xaml::Automation::Peers::IAutomationPeer **returnValue) override;
- HRESULT STDMETHODCALLTYPE OnDisconnectVisualChildren() override;
- HRESULT STDMETHODCALLTYPE FindSubElementsForTouchTargeting(ABI::Windows::Foundation::Point point, ABI::Windows::Foundation::Rect boundingRect, ABI::Windows::Foundation::Collections::IIterable<ABI::Windows::Foundation::Collections::IIterable<ABI::Windows::Foundation::Point>*> **returnValue) override;
-
-private:
- Microsoft::WRL::ComPtr<ABI::Windows::UI::Xaml::IUIElementOverrides> m_base;
- Microsoft::WRL::ComPtr<ABI::Windows::UI::Xaml::Controls::ICanvas> m_core;
- std::function<QWindow*()> delegate;
-};
-
-QT_END_NAMESPACE
-
-#endif // QWINRTCANVAS_H
diff --git a/src/plugins/platforms/winrt/qwinrtclipboard.cpp b/src/plugins/platforms/winrt/qwinrtclipboard.cpp
deleted file mode 100644
index fd0ed8aed2..0000000000
--- a/src/plugins/platforms/winrt/qwinrtclipboard.cpp
+++ /dev/null
@@ -1,188 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 "qwinrtclipboard.h"
-
-#include <QtCore/QCoreApplication>
-#include <QtCore/qfunctions_winrt.h>
-#include <QtCore/private/qeventdispatcher_winrt_p.h>
-
-#include <Windows.ApplicationModel.datatransfer.h>
-
-#include <functional>
-
-using namespace ABI::Windows::ApplicationModel::DataTransfer;
-using namespace ABI::Windows::Foundation;
-using namespace Microsoft::WRL;
-using namespace Microsoft::WRL::Wrappers;
-
-typedef IEventHandler<IInspectable *> ContentChangedHandler;
-
-#define RETURN_NULLPTR_IF_FAILED(msg) RETURN_IF_FAILED(msg, return nullptr)
-
-QT_BEGIN_NAMESPACE
-
-QWinRTClipboard::QWinRTClipboard()
- : m_mimeData(nullptr)
-{
- QEventDispatcherWinRT::runOnXamlThread([this]() {
- HRESULT hr;
- hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_ApplicationModel_DataTransfer_Clipboard).Get(),
- &m_nativeClipBoard);
- Q_ASSERT_SUCCEEDED(hr);
-
- EventRegistrationToken tok;
- hr = m_nativeClipBoard->add_ContentChanged(Callback<ContentChangedHandler>(this, &QWinRTClipboard::onContentChanged).Get(), &tok);
- Q_ASSERT_SUCCEEDED(hr);
-
- return hr;
- });
-}
-
-QMimeData *QWinRTClipboard::mimeData(QClipboard::Mode mode)
-{
- if (!supportsMode(mode))
- return nullptr;
-
- ComPtr<IDataPackageView> view;
- HRESULT hr;
- hr = m_nativeClipBoard->GetContent(&view);
- RETURN_NULLPTR_IF_FAILED("Could not get clipboard content.");
-
- ComPtr<IAsyncOperation<HSTRING>> op;
- HString result;
- // This throws a security exception (WinRT originate error / 0x40080201.
- // Unfortunately there seems to be no way to avoid this, neither
- // running on the XAML thread, nor some other way. Stack Overflow
- // confirms this problem since Windows (Phone) 8.0.
- hr = view->GetTextAsync(&op);
- RETURN_NULLPTR_IF_FAILED("Could not get clipboard text.");
-
- hr = QWinRTFunctions::await(op, result.GetAddressOf());
- RETURN_NULLPTR_IF_FAILED("Could not get clipboard text content");
-
- quint32 size;
- const wchar_t *textStr = result.GetRawBuffer(&size);
- QString text = QString::fromWCharArray(textStr, int(size));
- text.replace(QLatin1String("\r\n"), QLatin1String("\n"));
-
- if (m_mimeData) {
- if (m_mimeData->text() == text)
- return m_mimeData;
- delete m_mimeData;
- }
- m_mimeData = new QMimeData();
- m_mimeData->setText(text);
-
- return m_mimeData;
-}
-
-// Inspired by QWindowsMimeText::convertFromMime
-inline QString convertToWindowsLineEnding(const QString &text)
-{
- const QChar *u = text.unicode();
- QString res;
- const int s = text.length();
- int maxsize = s + s / 40 + 3;
- res.resize(maxsize);
- int ri = 0;
- bool cr = false;
- for (int i = 0; i < s; ++i) {
- if (*u == QLatin1Char('\r'))
- cr = true;
- else {
- if (*u == QLatin1Char('\n') && !cr)
- res[ri++] = QLatin1Char('\r');
- cr = false;
- }
- res[ri++] = *u;
- if (ri+3 >= maxsize) {
- maxsize += maxsize / 4;
- res.resize(maxsize);
- }
- ++u;
- }
- res.truncate(ri);
- return res;
-}
-
-void QWinRTClipboard::setMimeData(QMimeData *data, QClipboard::Mode mode)
-{
- if (!supportsMode(mode))
- return;
-
- const bool newData = !m_mimeData || m_mimeData != data;
- if (newData) {
- if (m_mimeData)
- delete m_mimeData;
- m_mimeData = data;
- }
- const QString text = data ? data->text() : QString();
- HRESULT hr = QEventDispatcherWinRT::runOnXamlThread([this, text]() {
- HRESULT hr;
- ComPtr<IDataPackage> package;
- hr = RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_ApplicationModel_DataTransfer_DataPackage).Get(),
- &package);
-
- const QString nativeString = convertToWindowsLineEnding(text);
- HStringReference textRef(reinterpret_cast<LPCWSTR>(nativeString.utf16()),
- uint(nativeString.length()));
-
- hr = package->SetText(textRef.Get());
- RETURN_HR_IF_FAILED("Could not set text to clipboard data package.");
-
- hr = m_nativeClipBoard->SetContent(package.Get());
- RETURN_HR_IF_FAILED("Could not set clipboard content.");
- return S_OK;
- });
- RETURN_VOID_IF_FAILED("Could not set clipboard text.");
-}
-
-bool QWinRTClipboard::supportsMode(QClipboard::Mode mode) const
-{
- return mode == QClipboard::Clipboard;
-}
-
-HRESULT QWinRTClipboard::onContentChanged(IInspectable *, IInspectable *)
-{
- emitChanged(QClipboard::Clipboard);
- return S_OK;
-}
-
-QT_END_NAMESPACE
diff --git a/src/plugins/platforms/winrt/qwinrtclipboard.h b/src/plugins/platforms/winrt/qwinrtclipboard.h
deleted file mode 100644
index 899fcbe730..0000000000
--- a/src/plugins/platforms/winrt/qwinrtclipboard.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 QWINRTPLATFORMCLIPBOARD_H
-#define QWINRTPLATFORMCLIPBOARD_H
-
-#include <qpa/qplatformclipboard.h>
-#include <QMimeData>
-
-#include <wrl.h>
-
-namespace ABI {
- namespace Windows {
- namespace ApplicationModel {
- namespace DataTransfer {
- struct IClipboardStatics;
- }
- }
- }
-}
-
-QT_BEGIN_NAMESPACE
-
-class QWinRTClipboard: public QPlatformClipboard
-{
-public:
- QWinRTClipboard();
-
- QMimeData *mimeData(QClipboard::Mode mode = QClipboard::Clipboard) override;
- void setMimeData(QMimeData *data, QClipboard::Mode mode = QClipboard::Clipboard) override;
- bool supportsMode(QClipboard::Mode mode) const override;
-
- HRESULT onContentChanged(IInspectable *, IInspectable *);
-private:
- Microsoft::WRL::ComPtr<ABI::Windows::ApplicationModel::DataTransfer::IClipboardStatics> m_nativeClipBoard;
- QMimeData *m_mimeData;
-};
-
-QT_END_NAMESPACE
-
-#endif // QWINRTPLATFORMCLIPBOARD_H
diff --git a/src/plugins/platforms/winrt/qwinrtcursor.cpp b/src/plugins/platforms/winrt/qwinrtcursor.cpp
deleted file mode 100644
index 180905945b..0000000000
--- a/src/plugins/platforms/winrt/qwinrtcursor.cpp
+++ /dev/null
@@ -1,230 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 "qwinrtcursor.h"
-#include "qwinrtscreen.h"
-#include <private/qeventdispatcher_winrt_p.h>
-
-#include <QtCore/qfunctions_winrt.h>
-#include <QtGui/QGuiApplication>
-#include <QtGui/QScreen>
-
-#include <functional>
-#include <wrl.h>
-#include <windows.ui.core.h>
-#include <windows.foundation.h>
-using namespace Microsoft::WRL;
-using namespace Microsoft::WRL::Wrappers;
-using namespace ABI::Windows::UI::Core;
-using namespace ABI::Windows::Foundation;
-
-QT_BEGIN_NAMESPACE
-
-static inline bool qIsPointInRect(const Point &p, const Rect &r)
-{
- return (p.X >= r.X && p.Y >= r.Y && p.X < r.X + r.Width && p.Y < r.Y + r.Height);
-}
-
-class QWinRTCursorPrivate
-{
-public:
- ComPtr<ICoreCursorFactory> cursorFactory;
-};
-
-QWinRTCursor::QWinRTCursor()
- : d_ptr(new QWinRTCursorPrivate)
-{
- Q_D(QWinRTCursor);
-
- HRESULT hr;
- hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_UI_Core_CoreCursor).Get(),
- IID_PPV_ARGS(&d->cursorFactory));
- Q_ASSERT_SUCCEEDED(hr);
-}
-
-#ifndef QT_NO_CURSOR
-void QWinRTCursor::changeCursor(QCursor *windowCursor, QWindow *window)
-{
- Q_D(QWinRTCursor);
-
- HRESULT hr;
- ICoreWindow *coreWindow = static_cast<QWinRTScreen *>(window->screen()->handle())->coreWindow();
-
- CoreCursorType type;
- switch (windowCursor ? windowCursor->shape() : Qt::ArrowCursor) {
- case Qt::BlankCursor:
- hr = QEventDispatcherWinRT::runOnXamlThread([coreWindow]() {
- coreWindow->put_PointerCursor(nullptr);
- return S_OK;
- });
- RETURN_VOID_IF_FAILED("Failed to set blank native cursor");
- return;
- default:
- case Qt::OpenHandCursor:
- case Qt::ClosedHandCursor:
- case Qt::DragCopyCursor:
- case Qt::DragMoveCursor:
- case Qt::DragLinkCursor:
- // (unavailable)
- case Qt::ArrowCursor:
- type = CoreCursorType_Arrow;
- break;
- case Qt::UpArrowCursor:
- type = CoreCursorType_UpArrow;
- break;
- case Qt::CrossCursor:
- type = CoreCursorType_Cross;
- break;
- case Qt::WaitCursor:
- case Qt::BusyCursor:
- type = CoreCursorType_Wait;
- break;
- case Qt::IBeamCursor:
- type = CoreCursorType_IBeam;
- break;
- case Qt::SizeVerCursor:
- case Qt::SplitVCursor:
- type = CoreCursorType_SizeNorthSouth;
- break;
- case Qt::SizeHorCursor:
- case Qt::SplitHCursor:
- type = CoreCursorType_SizeWestEast;
- break;
- case Qt::SizeBDiagCursor:
- type = CoreCursorType_SizeNortheastSouthwest;
- break;
- case Qt::SizeFDiagCursor:
- type = CoreCursorType_SizeNorthwestSoutheast;
- break;
- case Qt::SizeAllCursor:
- type = CoreCursorType_SizeAll;
- break;
- case Qt::PointingHandCursor:
- type = CoreCursorType_Hand;
- break;
- case Qt::ForbiddenCursor:
- type = CoreCursorType_UniversalNo;
- break;
- case Qt::WhatsThisCursor:
- type = CoreCursorType_Help;
- break;
- case Qt::BitmapCursor:
- case Qt::CustomCursor:
- // TODO: figure out if arbitrary bitmaps can be made into resource IDs
- // For now, we don't get enough info from QCursor to set a custom cursor
- type = CoreCursorType_Custom;
- break;
- }
-
- ComPtr<ICoreCursor> cursor;
- hr = d->cursorFactory->CreateCursor(type, 0, &cursor);
- RETURN_VOID_IF_FAILED("Failed to create native cursor.");
-
- hr = QEventDispatcherWinRT::runOnXamlThread([coreWindow, &cursor]() {
- return coreWindow->put_PointerCursor(cursor.Get());
- });
- RETURN_VOID_IF_FAILED("Failed to set native cursor");
-}
-#endif // QT_NO_CURSOR
-
-QPoint QWinRTCursor::pos() const
-{
- const QWinRTScreen *screen = static_cast<QWinRTScreen *>(QGuiApplication::primaryScreen()->handle());
- Q_ASSERT(screen);
- ICoreWindow *coreWindow = screen->coreWindow();
- Q_ASSERT(coreWindow);
- Point point;
- Rect bounds;
- HRESULT hr = QEventDispatcherWinRT::runOnXamlThread([coreWindow, &point, &bounds]() {
- HRESULT hr = coreWindow->get_PointerPosition(&point);
- RETURN_HR_IF_FAILED("Failed to obtain pointer position.");
- hr = coreWindow->get_Bounds(&bounds);
- RETURN_HR_IF_FAILED("Failed to obtain window bounds.");
- return hr;
- });
- Q_ASSERT_SUCCEEDED(hr);
- QPointF position(qreal(point.X), qreal(point.Y));
- // If no cursor get_PointerPosition returns SHRT_MIN for x and y
- if ((int(position.x()) == SHRT_MIN && int(position.y()) == SHRT_MIN)
- || FAILED(hr))
- return QPointF(Q_INFINITY, Q_INFINITY).toPoint();
- position.rx() -= qreal(bounds.X);
- position.ry() -= qreal(bounds.Y);
- position *= screen->scaleFactor();
- return position.toPoint();
-}
-
-void QWinRTCursor::setPos(const QPoint &pos)
-{
- QWinRTScreen *screen = static_cast<QWinRTScreen *>(QGuiApplication::primaryScreen()->handle());
- Q_ASSERT(screen);
- ComPtr<ICoreWindow> coreWindow = screen->coreWindow();
- Q_ASSERT(coreWindow);
- const QPointF scaledPos = QPointF(pos) / screen->scaleFactor();
- QWinRTScreen::MousePositionTransition t;
- HRESULT hr = QEventDispatcherWinRT::runOnXamlThread([coreWindow, scaledPos, &t]() {
- ComPtr<ICoreWindow2> coreWindow2;
- HRESULT hr = coreWindow.As(&coreWindow2);
- RETURN_HR_IF_FAILED("Failed to cast core window.");
- Rect bounds;
- hr = coreWindow->get_Bounds(&bounds);
- RETURN_HR_IF_FAILED("Failed to obtain window bounds.");
- Point mousePos;
- hr = coreWindow->get_PointerPosition(&mousePos);
- RETURN_HR_IF_FAILED("Failed to obtain mouse position.");
- const Point p = { FLOAT(scaledPos.x()) + bounds.X,
- FLOAT(scaledPos.y()) + bounds.Y };
- const bool wasInWindow = qIsPointInRect(mousePos, bounds);
- const bool willBeInWindow = qIsPointInRect(p, bounds);
- if (wasInWindow && willBeInWindow)
- t = QWinRTScreen::MousePositionTransition::StayedIn;
- else if (wasInWindow && !willBeInWindow)
- t = QWinRTScreen::MousePositionTransition::MovedOut;
- else if (!wasInWindow && willBeInWindow)
- t = QWinRTScreen::MousePositionTransition::MovedIn;
- else
- t = QWinRTScreen::MousePositionTransition::StayedOut;
- return coreWindow2->put_PointerPosition(p);
- });
- RETURN_VOID_IF_FAILED("Failed to set cursor position");
- screen->emulateMouseMove(scaledPos, t);
-}
-
-QT_END_NAMESPACE
-
diff --git a/src/plugins/platforms/winrt/qwinrtcursor.h b/src/plugins/platforms/winrt/qwinrtcursor.h
deleted file mode 100644
index eca3d8c7ca..0000000000
--- a/src/plugins/platforms/winrt/qwinrtcursor.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 QWINRTCURSOR_H
-#define QWINRTCURSOR_H
-
-#include <qpa/qplatformcursor.h>
-
-QT_BEGIN_NAMESPACE
-
-class QWinRTCursorPrivate;
-class QWinRTCursor : public QPlatformCursor
-{
-public:
- explicit QWinRTCursor();
- ~QWinRTCursor() override = default;
-#ifndef QT_NO_CURSOR
- void changeCursor(QCursor * windowCursor, QWindow *window) override;
-#endif
- QPoint pos() const override;
- void setPos(const QPoint &pos) override;
-
-private:
- QScopedPointer<QWinRTCursorPrivate> d_ptr;
- Q_DECLARE_PRIVATE(QWinRTCursor)
-};
-
-QT_END_NAMESPACE
-
-#endif // QWINRTCURSOR_H
diff --git a/src/plugins/platforms/winrt/qwinrtdrag.cpp b/src/plugins/platforms/winrt/qwinrtdrag.cpp
deleted file mode 100644
index 3ed4cd692d..0000000000
--- a/src/plugins/platforms/winrt/qwinrtdrag.cpp
+++ /dev/null
@@ -1,889 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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 "qwinrtdrag.h"
-
-#include <QtCore/qglobal.h>
-#include <QtCore/QMimeData>
-#include <QtCore/QStringList>
-#include <QtGui/QGuiApplication>
-#include <qpa/qwindowsysteminterface.h>
-
-#include <qfunctions_winrt.h>
-#include <private/qeventdispatcher_winrt_p.h>
-
-#include <Windows.ApplicationModel.datatransfer.h>
-#include <windows.ui.xaml.h>
-#include <windows.foundation.collections.h>
-#include <windows.graphics.imaging.h>
-#include <windows.storage.streams.h>
-#include <functional>
-#include <robuffer.h>
-
-using namespace ABI::Windows::ApplicationModel::DataTransfer;
-using namespace ABI::Windows::ApplicationModel::DataTransfer::DragDrop;
-using namespace ABI::Windows::Foundation;
-using namespace ABI::Windows::Foundation::Collections;
-using namespace ABI::Windows::Graphics::Imaging;
-using namespace ABI::Windows::Storage;
-using namespace ABI::Windows::Storage::Streams;
-using namespace ABI::Windows::UI::Xaml;
-using namespace Microsoft::WRL;
-using namespace Microsoft::WRL::Wrappers;
-
-QT_BEGIN_NAMESPACE
-
-Q_LOGGING_CATEGORY(lcQpaMime, "qt.qpa.mime")
-
-ComPtr<IBuffer> createIBufferFromData(const char *data, qint32 size)
-{
- static ComPtr<IBufferFactory> bufferFactory;
- HRESULT hr;
- if (!bufferFactory) {
- hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Storage_Streams_Buffer).Get(),
- IID_PPV_ARGS(&bufferFactory));
- Q_ASSERT_SUCCEEDED(hr);
- }
-
- ComPtr<IBuffer> buffer;
- const UINT32 length = UINT32(size);
- hr = bufferFactory->Create(length, &buffer);
- Q_ASSERT_SUCCEEDED(hr);
- hr = buffer->put_Length(length);
- Q_ASSERT_SUCCEEDED(hr);
-
- ComPtr<Windows::Storage::Streams::IBufferByteAccess> byteArrayAccess;
- hr = buffer.As(&byteArrayAccess);
- Q_ASSERT_SUCCEEDED(hr);
-
- byte *bytes;
- hr = byteArrayAccess->Buffer(&bytes);
- Q_ASSERT_SUCCEEDED(hr);
- memcpy(bytes, data, length);
- return buffer;
-}
-
-class DragThreadTransferData : public QObject
-{
- Q_OBJECT
-public slots:
- void handleDrag();
-public:
- explicit DragThreadTransferData(QObject *parent = nullptr);
- QWindow *window;
- QWinRTInternalMimeData *mime;
- QPoint point;
- Qt::DropActions actions;
- bool dropAction;
- ComPtr<IDragEventArgs> nativeArgs;
- ComPtr<IDragOperationDeferral> deferral;
-};
-
-inline QString hStringToQString(const HString &hString)
-{
- quint32 l;
- const wchar_t *raw = hString.GetRawBuffer(&l);
- return (QString::fromWCharArray(raw, int(l)));
-}
-
-inline HString qStringToHString(const QString &qString)
-{
- HString h;
- h.Set(reinterpret_cast<const wchar_t*>(qString.utf16()), uint(qString.size()));
- return h;
-}
-
-namespace NativeFormatStrings {
- static ComPtr<IStandardDataFormatsStatics> dataStatics;
- static HSTRING text; // text/plain
- static HSTRING html; // text/html
- static HSTRING storage; // text/uri-list
-}
-
-static inline DataPackageOperation translateFromQDragDropActions(const Qt::DropAction action)
-{
- switch (action) {
- case Qt::CopyAction:
- return DataPackageOperation_Copy;
- case Qt::MoveAction:
- return DataPackageOperation_Move;
- case Qt::LinkAction:
- return DataPackageOperation_Link;
- case Qt::IgnoreAction:
- default:
- return DataPackageOperation_None;
- }
-}
-
-static inline Qt::DropActions translateToQDragDropActions(const DataPackageOperation op)
-{
- Qt::DropActions actions = Qt::IgnoreAction;
- // None needs to be interpreted as the sender being able to handle
- // anything and let the receiver decide
- if (op == DataPackageOperation_None)
- actions = Qt::LinkAction | Qt::CopyAction | Qt::MoveAction;
- if (op & DataPackageOperation_Link)
- actions |= Qt::LinkAction;
- if (op & DataPackageOperation_Copy)
- actions |= Qt::CopyAction;
- if (op & DataPackageOperation_Move)
- actions |= Qt::MoveAction;
- return actions;
-}
-
-QWinRTInternalMimeData::QWinRTInternalMimeData()
- : QInternalMimeData()
-{
- qCDebug(lcQpaMime) << __FUNCTION__;
- if (!NativeFormatStrings::dataStatics) {
- HRESULT hr;
- hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_ApplicationModel_DataTransfer_StandardDataFormats).Get(),
- IID_PPV_ARGS(&NativeFormatStrings::dataStatics));
- Q_ASSERT_SUCCEEDED(hr);
- hr = NativeFormatStrings::dataStatics->get_Text(&NativeFormatStrings::text);
- Q_ASSERT_SUCCEEDED(hr);
- hr = NativeFormatStrings::dataStatics->get_Html(&NativeFormatStrings::html);
- Q_ASSERT_SUCCEEDED(hr);
- hr = NativeFormatStrings::dataStatics->get_StorageItems(&NativeFormatStrings::storage);
- Q_ASSERT_SUCCEEDED(hr);
- }
-}
-
-bool QWinRTInternalMimeData::hasFormat_sys(const QString &mimetype) const
-{
- qCDebug(lcQpaMime) << __FUNCTION__ << mimetype;
-
- if (!dataView)
- return false;
-
- return formats_sys().contains(mimetype);
-}
-
-QStringList QWinRTInternalMimeData::formats_sys() const
-{
- qCDebug(lcQpaMime) << __FUNCTION__;
-
- if (!dataView)
- return QStringList();
-
- if (!formats.isEmpty())
- return formats;
-
- HRESULT hr;
- hr = QEventDispatcherWinRT::runOnXamlThread([this]() {
- boolean contains;
- HRESULT hr;
- hr = dataView->Contains(NativeFormatStrings::text, &contains);
- if (SUCCEEDED(hr) && contains)
- formats.append(QLatin1String("text/plain"));
-
- hr = dataView->Contains(NativeFormatStrings::html, &contains);
- if (SUCCEEDED(hr) && contains)
- formats.append(QLatin1String("text/html"));
-
- hr = dataView->Contains(NativeFormatStrings::storage, &contains);
- if (SUCCEEDED(hr) && contains)
- formats.append(QLatin1String("text/uri-list"));
-
- // We need to add any additional format as well, for legacy windows
- // reasons, but also in case someone adds custom formats.
- ComPtr<IVectorView<HSTRING>> availableFormats;
- hr = dataView->get_AvailableFormats(&availableFormats);
- RETURN_OK_IF_FAILED("Could not query available formats.");
-
- quint32 size;
- hr = availableFormats->get_Size(&size);
- RETURN_OK_IF_FAILED("Could not query format vector size.");
- for (quint32 i = 0; i < size; ++i) {
- HString str;
- hr = availableFormats->GetAt(i, str.GetAddressOf());
- if (FAILED(hr))
- continue;
- formats.append(hStringToQString(str));
- }
- return S_OK;
- });
- Q_ASSERT_SUCCEEDED(hr);
-
- return formats;
-}
-
-QVariant QWinRTInternalMimeData::retrieveData_sys(const QString &mimetype, QVariant::Type preferredType) const
-{
- qCDebug(lcQpaMime) << __FUNCTION__ << mimetype << preferredType;
-
- if (!dataView || !formats.contains(mimetype))
- return QVariant();
-
- QVariant result;
- HRESULT hr;
- if (mimetype == QLatin1String("text/plain")) {
- hr = QEventDispatcherWinRT::runOnXamlThread([this, &result]() {
- HRESULT hr;
- ComPtr<IAsyncOperation<HSTRING>> op;
- HString res;
- hr = dataView->GetTextAsync(&op);
- Q_ASSERT_SUCCEEDED(hr);
- hr = QWinRTFunctions::await(op, res.GetAddressOf());
- Q_ASSERT_SUCCEEDED(hr);
- result.setValue(hStringToQString(res));
- return S_OK;
- });
- } else if (mimetype == QLatin1String("text/uri-list")) {
- hr = QEventDispatcherWinRT::runOnXamlThread([this, &result]() {
- HRESULT hr;
- ComPtr<IAsyncOperation<IVectorView<IStorageItem*>*>> op;
- hr = dataView->GetStorageItemsAsync(&op);
- Q_ASSERT_SUCCEEDED(hr);
- ComPtr<IVectorView<IStorageItem*>> nativeItems;
- hr = QWinRTFunctions::await(op, nativeItems.GetAddressOf());
- Q_ASSERT_SUCCEEDED(hr);
- QList<QVariant> items;
- quint32 count;
- hr = nativeItems->get_Size(&count);
- for (quint32 i = 0; i < count; ++i) {
- ComPtr<IStorageItem> item;
- hr = nativeItems->GetAt(i, &item);
- Q_ASSERT_SUCCEEDED(hr);
- HString path;
- hr = item->get_Path(path.GetAddressOf());
- Q_ASSERT_SUCCEEDED(hr);
- items.append(QUrl::fromLocalFile(hStringToQString(path)));
- }
- result.setValue(items);
- return S_OK;
- });
- } else if (mimetype == QLatin1String("text/html")) {
- hr = QEventDispatcherWinRT::runOnXamlThread([this, &result]() {
- HRESULT hr;
- ComPtr<IAsyncOperation<HSTRING>> op;
- HString res;
- hr = dataView->GetHtmlFormatAsync(&op);
- Q_ASSERT_SUCCEEDED(hr);
- hr = QWinRTFunctions::await(op, res.GetAddressOf());
- Q_ASSERT_SUCCEEDED(hr);
- result.setValue(hStringToQString(res));
- return S_OK;
- });
- } else {
- // Asking for custom data
- hr = QEventDispatcherWinRT::runOnXamlThread([this, &result, mimetype]() {
- HRESULT hr;
- ComPtr<IAsyncOperation<IInspectable*>> op;
- ComPtr<IInspectable> res;
- HString type;
- type.Set(reinterpret_cast<const wchar_t*>(mimetype.utf16()), uint(mimetype.size()));
- hr = dataView->GetDataAsync(type.Get(), &op);
- RETURN_OK_IF_FAILED("Could not query custom drag data.");
- hr = QWinRTFunctions::await(op, res.GetAddressOf());
- if (FAILED(hr) || !res) {
- qCDebug(lcQpaMime) << "Custom drop data operation returned no results or failed.";
- return S_OK;
- }
-
- // Test for properties
- ComPtr<IPropertyValue> propertyValue;
- hr = res.As(&propertyValue);
- if (SUCCEEDED(hr)) {
- // We need to check which type of custom data we are receiving
- PropertyType propertyType;
- propertyValue->get_Type(&propertyType);
- switch (propertyType) {
- case PropertyType_UInt8: {
- quint8 v;
- hr = propertyValue->GetUInt8(&v);
- Q_ASSERT_SUCCEEDED(hr);
- result.setValue(v);
- return S_OK;
- }
- case PropertyType_Int16: {
- qint16 v;
- hr = propertyValue->GetInt16(&v);
- Q_ASSERT_SUCCEEDED(hr);
- result.setValue(v);
- return S_OK;
- }
- case PropertyType_UInt16: {
- quint16 v;
- hr = propertyValue->GetUInt16(&v);
- Q_ASSERT_SUCCEEDED(hr);
- result.setValue(v);
- return S_OK;
- }
- case PropertyType_Int32: {
- qint32 v;
- hr = propertyValue->GetInt32(&v);
- Q_ASSERT_SUCCEEDED(hr);
- result.setValue(v);
- return S_OK;
- }
- case PropertyType_UInt32: {
- quint32 v;
- hr = propertyValue->GetUInt32(&v);
- Q_ASSERT_SUCCEEDED(hr);
- result.setValue(v);
- return S_OK;
- }
- case PropertyType_Int64: {
- qint64 v;
- hr = propertyValue->GetInt64(&v);
- Q_ASSERT_SUCCEEDED(hr);
- result.setValue(v);
- return S_OK;
- }
- case PropertyType_UInt64: {
- quint64 v;
- hr = propertyValue->GetUInt64(&v);
- Q_ASSERT_SUCCEEDED(hr);
- result.setValue(v);
- return S_OK;
- }
- case PropertyType_Single: {
- float v;
- hr = propertyValue->GetSingle(&v);
- Q_ASSERT_SUCCEEDED(hr);
- result.setValue(v);
- return S_OK;
- }
- case PropertyType_Double: {
- double v;
- hr = propertyValue->GetDouble(&v);
- Q_ASSERT_SUCCEEDED(hr);
- result.setValue(v);
- return S_OK;
- }
- case PropertyType_Char16: {
- wchar_t v;
- hr = propertyValue->GetChar16(&v);
- Q_ASSERT_SUCCEEDED(hr);
- result.setValue(QString::fromWCharArray(&v, 1));
- return S_OK;
- }
- case PropertyType_Boolean: {
- boolean v;
- hr = propertyValue->GetBoolean(&v);
- Q_ASSERT_SUCCEEDED(hr);
- result.setValue(v);
- return S_OK;
- }
- case PropertyType_String: {
- HString stringProperty;
- hr = propertyValue->GetString(stringProperty.GetAddressOf());
- Q_ASSERT_SUCCEEDED(hr);
- result.setValue(hStringToQString(stringProperty));
- return S_OK;
- }
- default:
- qCDebug(lcQpaMime) << "Unknown property type dropped:" << propertyType;
- }
- return S_OK;
- }
-
- // Custom data can be read via input streams
- ComPtr<IRandomAccessStream> randomAccessStream;
- hr = res.As(&randomAccessStream);
- if (SUCCEEDED(hr)) {
- UINT64 size;
- hr = randomAccessStream->get_Size(&size);
- Q_ASSERT_SUCCEEDED(hr);
- ComPtr<IInputStream> stream;
- hr = randomAccessStream.As(&stream);
- Q_ASSERT_SUCCEEDED(hr);
-
- ComPtr<IBufferFactory> bufferFactory;
- hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Storage_Streams_Buffer).Get(),
- IID_PPV_ARGS(&bufferFactory));
- Q_ASSERT_SUCCEEDED(hr);
-
- UINT32 length = UINT32(qBound(quint64(0), quint64(size), quint64(UINT_MAX)));
- ComPtr<IBuffer> buffer;
- hr = bufferFactory->Create(length, &buffer);
- Q_ASSERT_SUCCEEDED(hr);
-
- ComPtr<IAsyncOperationWithProgress<IBuffer *, UINT32>> readOp;
- hr = stream->ReadAsync(buffer.Get(), length, InputStreamOptions_None, &readOp);
-
- ComPtr<IBuffer> effectiveBuffer;
- hr = QWinRTFunctions::await(readOp, effectiveBuffer.GetAddressOf());
-
- hr = effectiveBuffer->get_Length(&length);
-
- ComPtr<Windows::Storage::Streams::IBufferByteAccess> byteArrayAccess;
- hr = effectiveBuffer.As(&byteArrayAccess);
-
- byte *bytes;
- hr = byteArrayAccess->Buffer(&bytes);
- QByteArray array((char *)bytes, int(length));
- result.setValue(array);
- return S_OK;
- }
-
- HSTRING runtimeClass;
- hr = res->GetRuntimeClassName(&runtimeClass);
- Q_ASSERT_SUCCEEDED(hr);
- HString converted;
- converted.Set(runtimeClass);
- qCDebug(lcQpaMime) << "Unknown drop data type received (" << hStringToQString(converted)
- << "). Ignoring...";
- return S_OK;
- });
- }
- return result;
-}
-
-void QWinRTInternalMimeData::setDataView(const Microsoft::WRL::ComPtr<IDataPackageView> &d)
-{
- dataView = d;
- formats.clear();
-}
-
-static HRESULT qt_drag_enter(IInspectable *sender, ABI::Windows::UI::Xaml::IDragEventArgs *e)
-{
- QWinRTDrag::instance()->handleNativeDragEvent(sender, e);
- return S_OK;
-}
-
-static HRESULT qt_drag_over(IInspectable *sender, ABI::Windows::UI::Xaml::IDragEventArgs *e)
-{
- QWinRTDrag::instance()->handleNativeDragEvent(sender, e);
- return S_OK;
-}
-
-static HRESULT qt_drag_leave(IInspectable *sender, ABI::Windows::UI::Xaml::IDragEventArgs *e)
-{
- // Qt internally checks for new drags and auto sends leave events
- // Also there is no QPA function for handling leave
- Q_UNUSED(sender);
- Q_UNUSED(e);
- return S_OK;
-}
-
-static HRESULT qt_drop(IInspectable *sender, ABI::Windows::UI::Xaml::IDragEventArgs *e)
-{
- QWinRTDrag::instance()->handleNativeDragEvent(sender, e, true);
- return S_OK;
-}
-
-#define Q_DECLARE_DRAGHANDLER(name,func) \
-class QtDragEventHandler##name : public IDragEventHandler \
-{ \
-public: \
- virtual ~QtDragEventHandler##name() {\
- }\
- STDMETHODIMP Invoke(IInspectable *sender, \
- ABI::Windows::UI::Xaml::IDragEventArgs *e) \
- { \
- return qt_##func(sender, e);\
- } \
- \
- STDMETHODIMP \
- QueryInterface(REFIID riid, void FAR* FAR* ppvObj) \
- { \
- if (riid == IID_IUnknown || riid == IID_IDragEventHandler) { \
- *ppvObj = this; \
- AddRef(); \
- return NOERROR; \
- } \
- *ppvObj = NULL; \
- return ResultFromScode(E_NOINTERFACE); \
- } \
- \
- STDMETHODIMP_(ULONG) \
- AddRef(void) \
- { \
- return ++m_refs; \
- } \
- \
- STDMETHODIMP_(ULONG) \
- Release(void) \
- { \
- if (--m_refs == 0) { \
- delete this; \
- return 0; \
- } \
- return m_refs; \
- } \
-private: \
-ULONG m_refs{0}; \
-};
-
-Q_DECLARE_DRAGHANDLER(Enter, drag_enter)
-Q_DECLARE_DRAGHANDLER(Over, drag_over)
-Q_DECLARE_DRAGHANDLER(Leave, drag_leave)
-Q_DECLARE_DRAGHANDLER(Drop, drop)
-
-#define Q_INST_DRAGHANDLER(name) QtDragEventHandler##name()
-
-Q_GLOBAL_STATIC(QWinRTDrag, gDrag);
-
-extern ComPtr<ABI::Windows::UI::Input::IPointerPoint> qt_winrt_lastPointerPoint; // qwinrtscreen.cpp
-
-QWinRTDrag::QWinRTDrag()
- : QPlatformDrag()
- , m_dragTarget(nullptr)
-{
- qCDebug(lcQpaMime) << __FUNCTION__;
- m_enter = new Q_INST_DRAGHANDLER(Enter);
- m_over = new Q_INST_DRAGHANDLER(Over);
- m_leave = new Q_INST_DRAGHANDLER(Leave);
- m_drop = new Q_INST_DRAGHANDLER(Drop);
- m_mimeData = new QWinRTInternalMimeData;
-}
-
-QWinRTDrag::~QWinRTDrag()
-{
- qCDebug(lcQpaMime) << __FUNCTION__;
- delete m_enter;
- delete m_over;
- delete m_leave;
- delete m_drop;
- delete m_mimeData;
-}
-
-QWinRTDrag *QWinRTDrag::instance()
-{
- return gDrag;
-}
-
-inline HRESULT resetUiElementDrag(ComPtr<IUIElement3> &elem3, EventRegistrationToken startingToken)
-{
- return QEventDispatcherWinRT::runOnXamlThread([elem3, startingToken]() {
- HRESULT hr;
- hr = elem3->put_CanDrag(false);
- Q_ASSERT_SUCCEEDED(hr);
- hr = elem3->remove_DragStarting(startingToken);
- Q_ASSERT_SUCCEEDED(hr);
- return S_OK;
- });
-}
-
-Qt::DropAction QWinRTDrag::drag(QDrag *drag)
-{
- qCDebug(lcQpaMime) << __FUNCTION__ << drag;
-
- if (!qt_winrt_lastPointerPoint) {
- Q_ASSERT_X(qt_winrt_lastPointerPoint, Q_FUNC_INFO, "No pointerpoint known");
- return Qt::IgnoreAction;
- }
-
- ComPtr<IUIElement3> elem3;
- HRESULT hr = m_ui.As(&elem3);
- Q_ASSERT_SUCCEEDED(hr);
-
- ComPtr<IAsyncOperation<ABI::Windows::ApplicationModel::DataTransfer::DataPackageOperation>> op;
- EventRegistrationToken startingToken;
-
- hr = QEventDispatcherWinRT::runOnXamlThread([drag, &op, &hr, elem3, &startingToken]() {
-
- hr = elem3->put_CanDrag(true);
- Q_ASSERT_SUCCEEDED(hr);
-
- auto startingCallback = Callback<ITypedEventHandler<UIElement*, DragStartingEventArgs*>> ([drag](IInspectable *, IDragStartingEventArgs *args) {
- qCDebug(lcQpaMime) << "Drag starting" << args;
-
- ComPtr<IDataPackage> dataPackage;
- HRESULT hr;
- hr = args->get_Data(dataPackage.GetAddressOf());
- Q_ASSERT_SUCCEEDED(hr);
- Qt::DropAction action = drag->defaultAction();
- hr = dataPackage->put_RequestedOperation(translateFromQDragDropActions(action));
- Q_ASSERT_SUCCEEDED(hr);
-
-#ifndef QT_WINRT_LIMITED_DRAGANDDROP
- ComPtr<IDragStartingEventArgs2> args2;
- hr = args->QueryInterface(IID_PPV_ARGS(&args2));
- Q_ASSERT_SUCCEEDED(hr);
-
- Qt::DropActions actions = drag->supportedActions();
- DataPackageOperation allowedOperations = DataPackageOperation_None;
- if (actions & Qt::CopyAction)
- allowedOperations |= DataPackageOperation_Copy;
- if (actions & Qt::MoveAction)
- allowedOperations |= DataPackageOperation_Move;
- if (actions & Qt::LinkAction)
- allowedOperations |= DataPackageOperation_Link;
- hr = args2->put_AllowedOperations(allowedOperations);
- Q_ASSERT_SUCCEEDED(hr);
-#endif // QT_WINRT_LIMITED_DRAGANDDROP
- QMimeData *mimeData = drag->mimeData();
- if (mimeData->hasText()) {
- hr = dataPackage->SetText(qStringToHString(mimeData->text()).Get());
- Q_ASSERT_SUCCEEDED(hr);
- }
- if (mimeData->hasHtml()) {
- hr = dataPackage->SetHtmlFormat(qStringToHString(mimeData->html()).Get());
- Q_ASSERT_SUCCEEDED(hr);
- }
- // ### TODO: Missing: weblink, image
-
- if (!drag->pixmap().isNull()) {
- const QImage image2 = drag->pixmap().toImage();
- const QImage image = image2.convertToFormat(QImage::Format_ARGB32);
- if (!image.isNull()) {
- // Create IBuffer containing image
- ComPtr<IBuffer> imageBuffer
- = createIBufferFromData(reinterpret_cast<const char*>(image.bits()), int(image.sizeInBytes()));
-
- ComPtr<ISoftwareBitmapFactory> bitmapFactory;
- hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Graphics_Imaging_SoftwareBitmap).Get(),
- IID_PPV_ARGS(&bitmapFactory));
- Q_ASSERT_SUCCEEDED(hr);
-
- ComPtr<ISoftwareBitmap> bitmap;
- hr = bitmapFactory->Create(BitmapPixelFormat_Rgba8, image.width(), image.height(), &bitmap);
- Q_ASSERT_SUCCEEDED(hr);
-
- hr = bitmap->CopyFromBuffer(imageBuffer.Get());
- Q_ASSERT_SUCCEEDED(hr);
-
- ComPtr<IDragUI> dragUi;
- hr = args->get_DragUI(dragUi.GetAddressOf());
- Q_ASSERT_SUCCEEDED(hr);
-
- hr = dragUi->SetContentFromSoftwareBitmap(bitmap.Get());
- Q_ASSERT_SUCCEEDED(hr);
- }
- }
-
- const QStringList formats = mimeData->formats();
- for (auto item : formats) {
- QByteArray data = mimeData->data(item);
-
- ComPtr<IBuffer> buffer = createIBufferFromData(data.constData(), data.size());
-
- // We cannot push the buffer to the data package as the result on
- // recipient side is different from native events. It still sends a
- // buffer, but that potentially cannot be parsed. Hence we need to create
- // a IRandomAccessStream which gets forwarded as is to the drop side.
- ComPtr<IRandomAccessStream> ras;
- hr = RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_Storage_Streams_InMemoryRandomAccessStream).Get(), &ras);
- Q_ASSERT_SUCCEEDED(hr);
-
- hr = ras->put_Size(UINT64(data.size()));
- ComPtr<IOutputStream> outputStream;
- hr = ras->GetOutputStreamAt(0, &outputStream);
- Q_ASSERT_SUCCEEDED(hr);
-
- ComPtr<IAsyncOperationWithProgress<UINT32,UINT32>> writeOp;
- hr = outputStream->WriteAsync(buffer.Get(), &writeOp);
- Q_ASSERT_SUCCEEDED(hr);
-
- UINT32 result;
- hr = QWinRTFunctions::await(writeOp, &result);
- Q_ASSERT_SUCCEEDED(hr);
-
- unsigned char flushResult;
- ComPtr<IAsyncOperation<bool>> flushOp;
- hr = outputStream->FlushAsync(&flushOp);
- Q_ASSERT_SUCCEEDED(hr);
-
- hr = QWinRTFunctions::await(flushOp, &flushResult);
- Q_ASSERT_SUCCEEDED(hr);
-
- hr = dataPackage->SetData(qStringToHString(item).Get(), ras.Get());
- Q_ASSERT_SUCCEEDED(hr);
- }
- return S_OK;
- });
-
- hr = elem3->add_DragStarting(startingCallback.Get(), &startingToken);
- Q_ASSERT_SUCCEEDED(hr);
-
- hr = elem3->StartDragAsync(qt_winrt_lastPointerPoint.Get(), &op);
- Q_ASSERT_SUCCEEDED(hr);
-
- return hr;
- });
- if (!op || FAILED(hr)) {
- qCDebug(lcQpaMime) << "Drag failed:" << hr;
- hr = resetUiElementDrag(elem3, startingToken);
- Q_ASSERT_SUCCEEDED(hr);
- return Qt::IgnoreAction;
- }
-
- DataPackageOperation nativeOperationType;
- // Do not yield, as that can cause deadlocks when dropping inside the same app
- hr = QWinRTFunctions::await(op, &nativeOperationType, QWinRTFunctions::ProcessThreadEvents);
- Q_ASSERT_SUCCEEDED(hr);
-
- hr = resetUiElementDrag(elem3, startingToken);
- Q_ASSERT_SUCCEEDED(hr);
-
- Qt::DropAction resultAction;
- switch (nativeOperationType) {
- case DataPackageOperation_Link:
- resultAction = Qt::LinkAction;
- break;
- case DataPackageOperation_Copy:
- resultAction = Qt::CopyAction;
- break;
- case DataPackageOperation_Move:
- resultAction = Qt::MoveAction;
- break;
- case DataPackageOperation_None:
- default:
- resultAction = Qt::IgnoreAction;
- break;
- }
-
- return resultAction;
-}
-
-void QWinRTDrag::setDropTarget(QWindow *target)
-{
- qCDebug(lcQpaMime) << __FUNCTION__ << target;
- m_dragTarget = target;
-}
-
-void QWinRTDrag::setUiElement(ComPtr<ABI::Windows::UI::Xaml::IUIElement> &element)
-{
- qCDebug(lcQpaMime) << __FUNCTION__;
- m_ui = element;
- // We set the element to always accept drops and then evaluate during
- // runtime
- HRESULT hr = element->put_AllowDrop(TRUE);
- EventRegistrationToken tok;
- hr = element->add_DragEnter(m_enter, &tok);
- RETURN_VOID_IF_FAILED("Failed to add DragEnter handler.");
- hr = element->add_DragOver(m_over, &tok);
- RETURN_VOID_IF_FAILED("Failed to add DragOver handler.");
- hr = element->add_DragLeave(m_leave, &tok);
- RETURN_VOID_IF_FAILED("Failed to add DragLeave handler.");
- hr = element->add_Drop(m_drop, &tok);
- RETURN_VOID_IF_FAILED("Failed to add Drop handler.");
-}
-
-void QWinRTDrag::handleNativeDragEvent(IInspectable *sender, ABI::Windows::UI::Xaml::IDragEventArgs *e, bool drop)
-{
- Q_UNUSED(sender);
-
- if (!m_dragTarget)
- return;
-
- HRESULT hr;
- Point relativePoint;
- hr = e->GetPosition(m_ui.Get(), &relativePoint);
- RETURN_VOID_IF_FAILED("Could not query drag position.");
- const QPoint p(int(relativePoint.X), int(relativePoint.Y));
-
- ComPtr<IDragEventArgs2> e2;
- hr = e->QueryInterface(IID_PPV_ARGS(&e2));
- RETURN_VOID_IF_FAILED("Could not convert drag event args");
-
- DragDropModifiers modifiers;
- hr = e2->get_Modifiers(&modifiers);
-
-#ifndef QT_WINRT_LIMITED_DRAGANDDROP
- ComPtr<IDragEventArgs3> e3;
- hr = e->QueryInterface(IID_PPV_ARGS(&e3));
- Q_ASSERT_SUCCEEDED(hr);
-
- DataPackageOperation dataOp;
- hr = e3->get_AllowedOperations(&dataOp);
- if (FAILED(hr))
- qCDebug(lcQpaMime) << __FUNCTION__ << "Could not query drag operations";
-
- const Qt::DropActions actions = translateToQDragDropActions(dataOp);
-#else // !QT_WINRT_LIMITED_DRAGANDDROP
- const Qt::DropActions actions = Qt::LinkAction | Qt::CopyAction | Qt::MoveAction;;
-#endif // !QT_WINRT_LIMITED_DRAGANDDROP
-
- ComPtr<IDataPackageView> dataView;
- hr = e2->get_DataView(&dataView);
- Q_ASSERT_SUCCEEDED(hr);
-
- m_mimeData->setDataView(dataView);
-
- // We use deferral as we need to jump to the Qt thread to handle
- // the drag event
- ComPtr<IDragOperationDeferral> deferral;
- hr = e2->GetDeferral(&deferral);
- Q_ASSERT_SUCCEEDED(hr);
-
- DragThreadTransferData *transferData = new DragThreadTransferData;
- transferData->moveToThread(qGuiApp->thread());
- transferData->window = m_dragTarget;
- transferData->point = p;
- transferData->mime = m_mimeData;
- transferData->actions = actions;
- transferData->dropAction = drop;
- transferData->nativeArgs = e;
- transferData->deferral = deferral;
- QMetaObject::invokeMethod(transferData, "handleDrag", Qt::QueuedConnection);
-}
-
-DragThreadTransferData::DragThreadTransferData(QObject *parent)
- : QObject(parent)
- , dropAction(false)
-{
-}
-
-void DragThreadTransferData::handleDrag()
-{
- bool accepted = false;
- Qt::DropAction acceptedAction;
- if (dropAction) {
- QPlatformDropQtResponse response = QWindowSystemInterface::handleDrop(window, mime, point, actions);
- accepted = response.isAccepted();
- acceptedAction = response.acceptedAction();
- } else {
- QPlatformDragQtResponse response = QWindowSystemInterface::handleDrag(window, mime, point, actions);
- accepted = response.isAccepted();
- acceptedAction = response.acceptedAction();
- }
-
- HRESULT hr;
- hr = QEventDispatcherWinRT::runOnXamlThread([accepted, acceptedAction, this]() {
- HRESULT hr;
- hr = nativeArgs->put_Handled(accepted);
- if (acceptedAction != Qt::IgnoreAction) {
- ComPtr<IDragEventArgs2> e2;
- hr = nativeArgs.As(&e2);
- if (SUCCEEDED(hr))
- hr = e2->put_AcceptedOperation(translateFromQDragDropActions(acceptedAction));
- }
- deferral->Complete();
- return S_OK;
- });
- Q_ASSERT_SUCCEEDED(hr);
- deleteLater();
-}
-
-QT_END_NAMESPACE
-
-#include "qwinrtdrag.moc"
diff --git a/src/plugins/platforms/winrt/qwinrtdrag.h b/src/plugins/platforms/winrt/qwinrtdrag.h
deleted file mode 100644
index ab57999bba..0000000000
--- a/src/plugins/platforms/winrt/qwinrtdrag.h
+++ /dev/null
@@ -1,116 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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 <qpa/qplatformdrag.h>
-
-#include <QtCore/QLoggingCategory>
-#include <QtCore/QMimeData>
-#include <QtGui/private/qdnd_p.h>
-#include <QtGui/private/qinternalmimedata_p.h>
-
-#include <wrl.h>
-
-namespace ABI {
- namespace Windows {
- namespace ApplicationModel {
- namespace DataTransfer {
- struct IDataPackageView;
- }
- }
- namespace UI {
- namespace Xaml {
- struct IUIElement;
- struct IDragEventArgs;
- struct IDragOperationDeferral;
- //struct IDataPackageView;
- }
- }
- }
-}
-
-QT_BEGIN_NAMESPACE
-
-Q_DECLARE_LOGGING_CATEGORY(lcQpaMime)
-
-class QtDragEventHandlerEnter;
-class QtDragEventHandlerOver;
-class QtDragEventHandlerLeave;
-class QtDragEventHandlerDrop;
-class QWinRTInternalMimeData;
-
-class QWinRTInternalMimeData : public QInternalMimeData {
-public:
- QWinRTInternalMimeData();
- ~QWinRTInternalMimeData() override = default;
-
- bool hasFormat_sys(const QString &mimetype) const override;
- QStringList formats_sys() const override;
- QVariant retrieveData_sys(const QString &mimetype, QVariant::Type preferredType) const override;
-
- void setDataView(const Microsoft::WRL::ComPtr<ABI::Windows::ApplicationModel::DataTransfer::IDataPackageView> &d);
-private:
- Microsoft::WRL::ComPtr<ABI::Windows::ApplicationModel::DataTransfer::IDataPackageView> dataView;
- mutable QStringList formats;
-};
-
-class QWinRTDrag : public QPlatformDrag {
-public:
- QWinRTDrag();
- ~QWinRTDrag() override;
- static QWinRTDrag *instance();
-
- Qt::DropAction drag(QDrag *) override;
-
- void setDropTarget(QWindow *target);
-
- // Native integration and registration
- void setUiElement(Microsoft::WRL::ComPtr<ABI::Windows::UI::Xaml::IUIElement> &element);
-
- void handleNativeDragEvent(IInspectable *sender, ABI::Windows::UI::Xaml::IDragEventArgs *e, bool drop = false);
-private:
- Microsoft::WRL::ComPtr<ABI::Windows::UI::Xaml::IUIElement> m_ui;
- QWindow *m_dragTarget;
- QtDragEventHandlerEnter *m_enter;
- QtDragEventHandlerOver *m_over;
- QtDragEventHandlerLeave *m_leave;
- QtDragEventHandlerDrop *m_drop;
- QWinRTInternalMimeData *m_mimeData;
-};
-
-QT_END_NAMESPACE
diff --git a/src/plugins/platforms/winrt/qwinrteglcontext.cpp b/src/plugins/platforms/winrt/qwinrteglcontext.cpp
deleted file mode 100644
index aa64ac1f99..0000000000
--- a/src/plugins/platforms/winrt/qwinrteglcontext.cpp
+++ /dev/null
@@ -1,371 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 "qwinrteglcontext.h"
-#include "qwinrtwindow.h"
-#include <private/qeventdispatcher_winrt_p.h>
-
-#include <functional>
-
-#include <d3d11.h>
-
-#include <EGL/egl.h>
-#define EGL_EGLEXT_PROTOTYPES
-#include <EGL/eglext.h>
-
-#include <QOffscreenSurface>
-#include <QOpenGLContext>
-#include <QtEglSupport/private/qeglconvenience_p.h>
-#include <QtEglSupport/private/qeglpbuffer_p.h>
-
-QT_BEGIN_NAMESPACE
-
-struct WinRTEGLDisplay
-{
- WinRTEGLDisplay() {
- }
- ~WinRTEGLDisplay() {
- eglTerminate(eglDisplay);
- }
-
- EGLDisplay eglDisplay;
-};
-
-Q_GLOBAL_STATIC(WinRTEGLDisplay, g)
-
-class QWinRTEGLContextPrivate
-{
-public:
- QWinRTEGLContextPrivate() : eglContext(EGL_NO_CONTEXT), eglShareContext(EGL_NO_CONTEXT) { }
- QSurfaceFormat format;
- EGLConfig eglConfig;
- EGLContext eglContext;
- EGLContext eglShareContext;
-};
-
-QWinRTEGLContext::QWinRTEGLContext(QOpenGLContext *context)
- : d_ptr(new QWinRTEGLContextPrivate)
-{
- Q_D(QWinRTEGLContext);
- d->format = context->format();
- d->format.setRenderableType(QSurfaceFormat::OpenGLES);
- if (QPlatformOpenGLContext *shareHandle = context->shareHandle())
- d->eglShareContext = static_cast<QWinRTEGLContext *>(shareHandle)->d_ptr->eglContext;
-}
-
-QWinRTEGLContext::~QWinRTEGLContext()
-{
- Q_D(QWinRTEGLContext);
- if (d->eglContext != EGL_NO_CONTEXT)
- eglDestroyContext(g->eglDisplay, d->eglContext);
-}
-
-void QWinRTEGLContext::initialize()
-{
- Q_D(QWinRTEGLContext);
-
- // Test if the hardware supports at least level 9_3
- D3D_FEATURE_LEVEL featureLevels[] = { D3D_FEATURE_LEVEL_9_3 }; // minimum feature level
- HRESULT hr = D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, NULL, 0, featureLevels, 1,
- D3D11_SDK_VERSION, nullptr, nullptr, nullptr);
- EGLint deviceType = SUCCEEDED(hr) ? EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE
- : EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE;
-
- eglBindAPI(EGL_OPENGL_ES_API);
-
- const EGLint displayAttributes[] = {
- EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE,
- EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE, deviceType,
- EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE, true,
- EGL_NONE,
- };
- g->eglDisplay = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, displayAttributes);
- if (Q_UNLIKELY(g->eglDisplay == EGL_NO_DISPLAY))
- qCritical("Failed to initialize EGL display: 0x%x", eglGetError());
-
- // eglInitialize checks for EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE
- // which adds a suspending handler. This needs to be added from the Xaml
- // thread itself, otherwise it will not be invoked. add_Suspending does
- // not return an error unfortunately, so it silently fails and causes
- // applications to not quit when the system wants to terminate the app
- // after suspend.
- hr = QEventDispatcherWinRT::runOnXamlThread([]() {
- if (!eglInitialize(g->eglDisplay, nullptr, nullptr))
- qCritical("Failed to initialize EGL: 0x%x", eglGetError());
- return S_OK;
- });
- d->eglConfig = q_configFromGLFormat(g->eglDisplay, d->format);
-
- const EGLint flags = d->format.testOption(QSurfaceFormat::DebugContext)
- ? EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR : 0;
- const int major = d->format.majorVersion();
- const int minor = d->format.minorVersion();
- if (major > 3 || (major == 3 && minor > 0))
- qWarning("QWinRTEGLContext: ANGLE only partially supports OpenGL ES > 3.0");
- const EGLint attributes[] = {
- EGL_CONTEXT_CLIENT_VERSION, d->format.majorVersion(),
- EGL_CONTEXT_MINOR_VERSION_KHR, d->format.minorVersion(),
- EGL_CONTEXT_FLAGS_KHR, flags,
- EGL_NONE
- };
- d->eglContext = eglCreateContext(g->eglDisplay, d->eglConfig, d->eglShareContext, attributes);
- if (d->eglContext == EGL_NO_CONTEXT) {
- qWarning("QEGLPlatformContext: Failed to create context: %x", eglGetError());
- return;
- }
-}
-
-bool QWinRTEGLContext::makeCurrent(QPlatformSurface *windowSurface)
-{
- Q_D(QWinRTEGLContext);
- Q_ASSERT(windowSurface->surface()->supportsOpenGL());
-
- EGLSurface surface;
- if (windowSurface->surface()->surfaceClass() == QSurface::Window) {
- QWinRTWindow *window = static_cast<QWinRTWindow *>(windowSurface);
- if (window->eglSurface() == EGL_NO_SURFACE)
- window->createEglSurface(g->eglDisplay, d->eglConfig);
-
- surface = window->eglSurface();
- } else { // Offscreen
- surface = static_cast<QEGLPbuffer *>(windowSurface)->pbuffer();
- }
-
- if (surface == EGL_NO_SURFACE)
- return false;
-
- const bool ok = eglMakeCurrent(g->eglDisplay, surface, surface, d->eglContext);
- if (!ok) {
- qWarning("QEGLPlatformContext: eglMakeCurrent failed: %x", eglGetError());
- return false;
- }
-
- eglSwapInterval(g->eglDisplay, d->format.swapInterval());
- return true;
-}
-
-void QWinRTEGLContext::doneCurrent()
-{
- const bool ok = eglMakeCurrent(g->eglDisplay, EGL_NO_SURFACE,
- EGL_NO_SURFACE, EGL_NO_CONTEXT);
- if (!ok)
- qWarning("QEGLPlatformContext: eglMakeCurrent failed: %x", eglGetError());
-}
-
-void QWinRTEGLContext::swapBuffers(QPlatformSurface *windowSurface)
-{
- Q_ASSERT(windowSurface->surface()->supportsOpenGL());
-
- const QWinRTWindow *window = static_cast<QWinRTWindow *>(windowSurface);
- eglSwapBuffers(g->eglDisplay, window->eglSurface());
-}
-
-QSurfaceFormat QWinRTEGLContext::format() const
-{
- Q_D(const QWinRTEGLContext);
- return d->format;
-}
-
-QFunctionPointer QWinRTEGLContext::getProcAddress(const char *procName)
-{
- static QHash<QByteArray, QFunctionPointer> standardFuncs;
- if (standardFuncs.isEmpty()) {
- standardFuncs.insert(QByteArrayLiteral("glBindTexture"), (QFunctionPointer)&glBindTexture);
- standardFuncs.insert(QByteArrayLiteral("glBlendFunc"), (QFunctionPointer)&glBlendFunc);
- standardFuncs.insert(QByteArrayLiteral("glClear"), (QFunctionPointer)&glClear);
- standardFuncs.insert(QByteArrayLiteral("glClearColor"), (QFunctionPointer)&glClearColor);
- standardFuncs.insert(QByteArrayLiteral("glClearStencil"), (QFunctionPointer)&glClearStencil);
- standardFuncs.insert(QByteArrayLiteral("glColorMask"), (QFunctionPointer)&glColorMask);
- standardFuncs.insert(QByteArrayLiteral("glCopyTexImage2D"), (QFunctionPointer)&glCopyTexImage2D);
- standardFuncs.insert(QByteArrayLiteral("glCopyTexSubImage2D"), (QFunctionPointer)&glCopyTexSubImage2D);
- standardFuncs.insert(QByteArrayLiteral("glCullFace"), (QFunctionPointer)&glCullFace);
- standardFuncs.insert(QByteArrayLiteral("glDeleteTextures"), (QFunctionPointer)&glDeleteTextures);
- standardFuncs.insert(QByteArrayLiteral("glDepthFunc"), (QFunctionPointer)&glDepthFunc);
- standardFuncs.insert(QByteArrayLiteral("glDepthMask"), (QFunctionPointer)&glDepthMask);
- standardFuncs.insert(QByteArrayLiteral("glDisable"), (QFunctionPointer)&glDisable);
- standardFuncs.insert(QByteArrayLiteral("glDrawArrays"), (QFunctionPointer)&glDrawArrays);
- standardFuncs.insert(QByteArrayLiteral("glDrawElements"), (QFunctionPointer)&glDrawElements);
- standardFuncs.insert(QByteArrayLiteral("glEnable"), (QFunctionPointer)&glEnable);
- standardFuncs.insert(QByteArrayLiteral("glFinish"), (QFunctionPointer)&glFinish);
- standardFuncs.insert(QByteArrayLiteral("glFlush"), (QFunctionPointer)&glFlush);
- standardFuncs.insert(QByteArrayLiteral("glFrontFace"), (QFunctionPointer)&glFrontFace);
- standardFuncs.insert(QByteArrayLiteral("glGenTextures"), (QFunctionPointer)&glGenTextures);
- standardFuncs.insert(QByteArrayLiteral("glGetBooleanv"), (QFunctionPointer)&glGetBooleanv);
- standardFuncs.insert(QByteArrayLiteral("glGetError"), (QFunctionPointer)&glGetError);
- standardFuncs.insert(QByteArrayLiteral("glGetFloatv"), (QFunctionPointer)&glGetFloatv);
- standardFuncs.insert(QByteArrayLiteral("glGetIntegerv"), (QFunctionPointer)&glGetIntegerv);
- standardFuncs.insert(QByteArrayLiteral("glGetString"), (QFunctionPointer)&glGetString);
- standardFuncs.insert(QByteArrayLiteral("glGetTexParameterfv"), (QFunctionPointer)&glGetTexParameterfv);
- standardFuncs.insert(QByteArrayLiteral("glGetTexParameteriv"), (QFunctionPointer)&glGetTexParameteriv);
- standardFuncs.insert(QByteArrayLiteral("glHint"), (QFunctionPointer)&glHint);
- standardFuncs.insert(QByteArrayLiteral("glIsEnabled"), (QFunctionPointer)&glIsEnabled);
- standardFuncs.insert(QByteArrayLiteral("glIsTexture"), (QFunctionPointer)&glIsTexture);
- standardFuncs.insert(QByteArrayLiteral("glLineWidth"), (QFunctionPointer)&glLineWidth);
- standardFuncs.insert(QByteArrayLiteral("glPixelStorei"), (QFunctionPointer)&glPixelStorei);
- standardFuncs.insert(QByteArrayLiteral("glPolygonOffset"), (QFunctionPointer)&glPolygonOffset);
- standardFuncs.insert(QByteArrayLiteral("glReadPixels"), (QFunctionPointer)&glReadPixels);
- standardFuncs.insert(QByteArrayLiteral("glScissor"), (QFunctionPointer)&glScissor);
- standardFuncs.insert(QByteArrayLiteral("glStencilFunc"), (QFunctionPointer)&glStencilFunc);
- standardFuncs.insert(QByteArrayLiteral("glStencilMask"), (QFunctionPointer)&glStencilMask);
- standardFuncs.insert(QByteArrayLiteral("glStencilOp"), (QFunctionPointer)&glStencilOp);
- standardFuncs.insert(QByteArrayLiteral("glTexImage2D"), (QFunctionPointer)&glTexImage2D);
- standardFuncs.insert(QByteArrayLiteral("glTexParameterf"), (QFunctionPointer)&glTexParameterf);
- standardFuncs.insert(QByteArrayLiteral("glTexParameterfv"), (QFunctionPointer)&glTexParameterfv);
- standardFuncs.insert(QByteArrayLiteral("glTexParameteri"), (QFunctionPointer)&glTexParameteri);
- standardFuncs.insert(QByteArrayLiteral("glTexParameteriv"), (QFunctionPointer)&glTexParameteriv);
- standardFuncs.insert(QByteArrayLiteral("glTexSubImage2D"), (QFunctionPointer)&glTexSubImage2D);
- standardFuncs.insert(QByteArrayLiteral("glViewport"), (QFunctionPointer)&glViewport);
- standardFuncs.insert(QByteArrayLiteral("glActiveTexture"), (QFunctionPointer)&glActiveTexture);
- standardFuncs.insert(QByteArrayLiteral("glAttachShader"), (QFunctionPointer)&glAttachShader);
- standardFuncs.insert(QByteArrayLiteral("glBindAttribLocation"), (QFunctionPointer)&glBindAttribLocation);
- standardFuncs.insert(QByteArrayLiteral("glBindBuffer"), (QFunctionPointer)&glBindBuffer);
- standardFuncs.insert(QByteArrayLiteral("glBindFramebuffer"), (QFunctionPointer)&glBindFramebuffer);
- standardFuncs.insert(QByteArrayLiteral("glBindRenderbuffer"), (QFunctionPointer)&glBindRenderbuffer);
- standardFuncs.insert(QByteArrayLiteral("glBlendColor"), (QFunctionPointer)&glBlendColor);
- standardFuncs.insert(QByteArrayLiteral("glBlendEquation"), (QFunctionPointer)&glBlendEquation);
- standardFuncs.insert(QByteArrayLiteral("glBlendEquationSeparate"), (QFunctionPointer)&glBlendEquationSeparate);
- standardFuncs.insert(QByteArrayLiteral("glBlendFuncSeparate"), (QFunctionPointer)&glBlendFuncSeparate);
- standardFuncs.insert(QByteArrayLiteral("glBufferData"), (QFunctionPointer)&glBufferData);
- standardFuncs.insert(QByteArrayLiteral("glBufferSubData"), (QFunctionPointer)&glBufferSubData);
- standardFuncs.insert(QByteArrayLiteral("glCheckFramebufferStatus"), (QFunctionPointer)&glCheckFramebufferStatus);
- standardFuncs.insert(QByteArrayLiteral("glCompileShader"), (QFunctionPointer)&glCompileShader);
- standardFuncs.insert(QByteArrayLiteral("glCompressedTexImage2D"), (QFunctionPointer)&glCompressedTexImage2D);
- standardFuncs.insert(QByteArrayLiteral("glCompressedTexSubImage2D"), (QFunctionPointer)&glCompressedTexSubImage2D);
- standardFuncs.insert(QByteArrayLiteral("glCreateProgram"), (QFunctionPointer)&glCreateProgram);
- standardFuncs.insert(QByteArrayLiteral("glCreateShader"), (QFunctionPointer)&glCreateShader);
- standardFuncs.insert(QByteArrayLiteral("glDeleteBuffers"), (QFunctionPointer)&glDeleteBuffers);
- standardFuncs.insert(QByteArrayLiteral("glDeleteFramebuffers"), (QFunctionPointer)&glDeleteFramebuffers);
- standardFuncs.insert(QByteArrayLiteral("glDeleteProgram"), (QFunctionPointer)&glDeleteProgram);
- standardFuncs.insert(QByteArrayLiteral("glDeleteRenderbuffers"), (QFunctionPointer)&glDeleteRenderbuffers);
- standardFuncs.insert(QByteArrayLiteral("glDeleteShader"), (QFunctionPointer)&glDeleteShader);
- standardFuncs.insert(QByteArrayLiteral("glDetachShader"), (QFunctionPointer)&glDetachShader);
- standardFuncs.insert(QByteArrayLiteral("glDisableVertexAttribArray"), (QFunctionPointer)&glDisableVertexAttribArray);
- standardFuncs.insert(QByteArrayLiteral("glEnableVertexAttribArray"), (QFunctionPointer)&glEnableVertexAttribArray);
- standardFuncs.insert(QByteArrayLiteral("glFramebufferRenderbuffer"), (QFunctionPointer)&glFramebufferRenderbuffer);
- standardFuncs.insert(QByteArrayLiteral("glFramebufferTexture2D"), (QFunctionPointer)&glFramebufferTexture2D);
- standardFuncs.insert(QByteArrayLiteral("glGenBuffers"), (QFunctionPointer)&glGenBuffers);
- standardFuncs.insert(QByteArrayLiteral("glGenerateMipmap"), (QFunctionPointer)&glGenerateMipmap);
- standardFuncs.insert(QByteArrayLiteral("glGenFramebuffers"), (QFunctionPointer)&glGenFramebuffers);
- standardFuncs.insert(QByteArrayLiteral("glGenRenderbuffers"), (QFunctionPointer)&glGenRenderbuffers);
- standardFuncs.insert(QByteArrayLiteral("glGetActiveAttrib"), (QFunctionPointer)&glGetActiveAttrib);
- standardFuncs.insert(QByteArrayLiteral("glGetActiveUniform"), (QFunctionPointer)&glGetActiveUniform);
- standardFuncs.insert(QByteArrayLiteral("glGetAttachedShaders"), (QFunctionPointer)&glGetAttachedShaders);
- standardFuncs.insert(QByteArrayLiteral("glGetAttribLocation"), (QFunctionPointer)&glGetAttribLocation);
- standardFuncs.insert(QByteArrayLiteral("glGetBufferParameteriv"), (QFunctionPointer)&glGetBufferParameteriv);
- standardFuncs.insert(QByteArrayLiteral("glGetFramebufferAttachmentParameteriv"), (QFunctionPointer)&glGetFramebufferAttachmentParameteriv);
- standardFuncs.insert(QByteArrayLiteral("glGetProgramiv"), (QFunctionPointer)&glGetProgramiv);
- standardFuncs.insert(QByteArrayLiteral("glGetProgramInfoLog"), (QFunctionPointer)&glGetProgramInfoLog);
- standardFuncs.insert(QByteArrayLiteral("glGetRenderbufferParameteriv"), (QFunctionPointer)&glGetRenderbufferParameteriv);
- standardFuncs.insert(QByteArrayLiteral("glGetShaderiv"), (QFunctionPointer)&glGetShaderiv);
- standardFuncs.insert(QByteArrayLiteral("glGetShaderInfoLog"), (QFunctionPointer)&glGetShaderInfoLog);
- standardFuncs.insert(QByteArrayLiteral("glGetShaderPrecisionFormat"), (QFunctionPointer)&glGetShaderPrecisionFormat);
- standardFuncs.insert(QByteArrayLiteral("glGetShaderSource"), (QFunctionPointer)&glGetShaderSource);
- standardFuncs.insert(QByteArrayLiteral("glGetUniformfv"), (QFunctionPointer)&glGetUniformfv);
- standardFuncs.insert(QByteArrayLiteral("glGetUniformiv"), (QFunctionPointer)&glGetUniformiv);
- standardFuncs.insert(QByteArrayLiteral("glGetUniformLocation"), (QFunctionPointer)&glGetUniformLocation);
- standardFuncs.insert(QByteArrayLiteral("glGetVertexAttribfv"), (QFunctionPointer)&glGetVertexAttribfv);
- standardFuncs.insert(QByteArrayLiteral("glGetVertexAttribiv"), (QFunctionPointer)&glGetVertexAttribiv);
- standardFuncs.insert(QByteArrayLiteral("glGetVertexAttribPointerv"), (QFunctionPointer)&glGetVertexAttribPointerv);
- standardFuncs.insert(QByteArrayLiteral("glIsBuffer"), (QFunctionPointer)&glIsBuffer);
- standardFuncs.insert(QByteArrayLiteral("glIsFramebuffer"), (QFunctionPointer)&glIsFramebuffer);
- standardFuncs.insert(QByteArrayLiteral("glIsProgram"), (QFunctionPointer)&glIsProgram);
- standardFuncs.insert(QByteArrayLiteral("glIsRenderbuffer"), (QFunctionPointer)&glIsRenderbuffer);
- standardFuncs.insert(QByteArrayLiteral("glIsShader"), (QFunctionPointer)&glIsShader);
- standardFuncs.insert(QByteArrayLiteral("glLinkProgram"), (QFunctionPointer)&glLinkProgram);
- standardFuncs.insert(QByteArrayLiteral("glReleaseShaderCompiler"), (QFunctionPointer)&glReleaseShaderCompiler);
- standardFuncs.insert(QByteArrayLiteral("glRenderbufferStorage"), (QFunctionPointer)&glRenderbufferStorage);
- standardFuncs.insert(QByteArrayLiteral("glSampleCoverage"), (QFunctionPointer)&glSampleCoverage);
- standardFuncs.insert(QByteArrayLiteral("glShaderBinary"), (QFunctionPointer)&glShaderBinary);
- standardFuncs.insert(QByteArrayLiteral("glShaderSource"), (QFunctionPointer)&glShaderSource);
- standardFuncs.insert(QByteArrayLiteral("glStencilFuncSeparate"), (QFunctionPointer)&glStencilFuncSeparate);
- standardFuncs.insert(QByteArrayLiteral("glStencilMaskSeparate"), (QFunctionPointer)&glStencilMaskSeparate);
- standardFuncs.insert(QByteArrayLiteral("glStencilOpSeparate"), (QFunctionPointer)&glStencilOpSeparate);
- standardFuncs.insert(QByteArrayLiteral("glUniform1f"), (QFunctionPointer)&glUniform1f);
- standardFuncs.insert(QByteArrayLiteral("glUniform1fv"), (QFunctionPointer)&glUniform1fv);
- standardFuncs.insert(QByteArrayLiteral("glUniform1i"), (QFunctionPointer)&glUniform1i);
- standardFuncs.insert(QByteArrayLiteral("glUniform1iv"), (QFunctionPointer)&glUniform1iv);
- standardFuncs.insert(QByteArrayLiteral("glUniform2f"), (QFunctionPointer)&glUniform2f);
- standardFuncs.insert(QByteArrayLiteral("glUniform2fv"), (QFunctionPointer)&glUniform2fv);
- standardFuncs.insert(QByteArrayLiteral("glUniform2i"), (QFunctionPointer)&glUniform2i);
- standardFuncs.insert(QByteArrayLiteral("glUniform2iv"), (QFunctionPointer)&glUniform2iv);
- standardFuncs.insert(QByteArrayLiteral("glUniform3f"), (QFunctionPointer)&glUniform3f);
- standardFuncs.insert(QByteArrayLiteral("glUniform3fv"), (QFunctionPointer)&glUniform3fv);
- standardFuncs.insert(QByteArrayLiteral("glUniform3i"), (QFunctionPointer)&glUniform3i);
- standardFuncs.insert(QByteArrayLiteral("glUniform3iv"), (QFunctionPointer)&glUniform3iv);
- standardFuncs.insert(QByteArrayLiteral("glUniform4f"), (QFunctionPointer)&glUniform4f);
- standardFuncs.insert(QByteArrayLiteral("glUniform4fv"), (QFunctionPointer)&glUniform4fv);
- standardFuncs.insert(QByteArrayLiteral("glUniform4i"), (QFunctionPointer)&glUniform4i);
- standardFuncs.insert(QByteArrayLiteral("glUniform4iv"), (QFunctionPointer)&glUniform4iv);
- standardFuncs.insert(QByteArrayLiteral("glUniformMatrix2fv"), (QFunctionPointer)&glUniformMatrix2fv);
- standardFuncs.insert(QByteArrayLiteral("glUniformMatrix3fv"), (QFunctionPointer)&glUniformMatrix3fv);
- standardFuncs.insert(QByteArrayLiteral("glUniformMatrix4fv"), (QFunctionPointer)&glUniformMatrix4fv);
- standardFuncs.insert(QByteArrayLiteral("glUseProgram"), (QFunctionPointer)&glUseProgram);
- standardFuncs.insert(QByteArrayLiteral("glValidateProgram"), (QFunctionPointer)&glValidateProgram);
- standardFuncs.insert(QByteArrayLiteral("glVertexAttrib1f"), (QFunctionPointer)&glVertexAttrib1f);
- standardFuncs.insert(QByteArrayLiteral("glVertexAttrib1fv"), (QFunctionPointer)&glVertexAttrib1fv);
- standardFuncs.insert(QByteArrayLiteral("glVertexAttrib2f"), (QFunctionPointer)&glVertexAttrib2f);
- standardFuncs.insert(QByteArrayLiteral("glVertexAttrib2fv"), (QFunctionPointer)&glVertexAttrib2fv);
- standardFuncs.insert(QByteArrayLiteral("glVertexAttrib3f"), (QFunctionPointer)&glVertexAttrib3f);
- standardFuncs.insert(QByteArrayLiteral("glVertexAttrib3fv"), (QFunctionPointer)&glVertexAttrib3fv);
- standardFuncs.insert(QByteArrayLiteral("glVertexAttrib4f"), (QFunctionPointer)&glVertexAttrib4f);
- standardFuncs.insert(QByteArrayLiteral("glVertexAttrib4fv"), (QFunctionPointer)&glVertexAttrib4fv);
- standardFuncs.insert(QByteArrayLiteral("glVertexAttribPointer"), (QFunctionPointer)&glVertexAttribPointer);
- standardFuncs.insert(QByteArrayLiteral("glClearDepthf"), (QFunctionPointer)&glClearDepthf);
- standardFuncs.insert(QByteArrayLiteral("glDepthRangef"), (QFunctionPointer)&glDepthRangef);
- };
-
- QHash<QByteArray, QFunctionPointer>::const_iterator i = standardFuncs.find(procName);
- if (i != standardFuncs.end())
- return i.value();
-
- return eglGetProcAddress(procName);
-}
-
-bool QWinRTEGLContext::isValid() const
-{
- Q_D(const QWinRTEGLContext);
- return d->eglContext != EGL_NO_CONTEXT;
-}
-
-EGLDisplay QWinRTEGLContext::display()
-{
- return g->eglDisplay;
-}
-
-QT_END_NAMESPACE
diff --git a/src/plugins/platforms/winrt/qwinrteglcontext.h b/src/plugins/platforms/winrt/qwinrteglcontext.h
deleted file mode 100644
index 8dbd0fc7d0..0000000000
--- a/src/plugins/platforms/winrt/qwinrteglcontext.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 QWINDOWSEGLCONTEXT_H
-#define QWINDOWSEGLCONTEXT_H
-
-#include <qpa/qplatformopenglcontext.h>
-#include <EGL/egl.h>
-
-QT_BEGIN_NAMESPACE
-
-class QWinRTEGLContextPrivate;
-class QWinRTEGLContext : public QPlatformOpenGLContext
-{
-public:
- explicit QWinRTEGLContext(QOpenGLContext *context);
- ~QWinRTEGLContext() override;
-
- void initialize() override;
-
- bool makeCurrent(QPlatformSurface *windowSurface) override;
- void doneCurrent() override;
- void swapBuffers(QPlatformSurface *windowSurface) override;
-
- QSurfaceFormat format() const override;
- QFunctionPointer getProcAddress(const char *procName) override;
- bool isValid() const override;
-
- static EGLDisplay display();
-private:
- QScopedPointer<QWinRTEGLContextPrivate> d_ptr;
- Q_DECLARE_PRIVATE(QWinRTEGLContext)
-};
-
-QT_END_NAMESPACE
-
-#endif // QWINDOWSEGLCONTEXT_H
diff --git a/src/plugins/platforms/winrt/qwinrteventdispatcher.cpp b/src/plugins/platforms/winrt/qwinrteventdispatcher.cpp
deleted file mode 100644
index eb59c22033..0000000000
--- a/src/plugins/platforms/winrt/qwinrteventdispatcher.cpp
+++ /dev/null
@@ -1,66 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 "qwinrteventdispatcher.h"
-#include <qpa/qwindowsysteminterface.h>
-#include <qpa/qplatformscreen.h>
-#include <QtCore/QThread>
-#include <QtGui/QGuiApplication>
-
-QT_BEGIN_NAMESPACE
-
-QWinRTEventDispatcher::QWinRTEventDispatcher(QObject *parent)
- : QEventDispatcherWinRT(parent)
-{
-}
-
-bool QWinRTEventDispatcher::hasPendingEvents()
-{
- return QEventDispatcherWinRT::hasPendingEvents() || QWindowSystemInterface::windowSystemEventsQueued();
-}
-
-bool QWinRTEventDispatcher::sendPostedEvents(QEventLoop::ProcessEventsFlags flags)
-{
- bool didProcess = QEventDispatcherWinRT::sendPostedEvents(flags);
- if (!(flags & QEventLoop::ExcludeUserInputEvents))
- didProcess |= QWindowSystemInterface::sendWindowSystemEvents(flags);
- return didProcess;
-}
-
-QT_END_NAMESPACE
diff --git a/src/plugins/platforms/winrt/qwinrteventdispatcher.h b/src/plugins/platforms/winrt/qwinrteventdispatcher.h
deleted file mode 100644
index 61c824f0a9..0000000000
--- a/src/plugins/platforms/winrt/qwinrteventdispatcher.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 QWINRTEVENTDISPATCHER_H
-#define QWINRTEVENTDISPATCHER_H
-
-#include <QtCore/private/qeventdispatcher_winrt_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class QWinRTEventDispatcher : public QEventDispatcherWinRT
-{
- Q_OBJECT
-public:
- explicit QWinRTEventDispatcher(QObject *parent = nullptr);
-
-protected:
- bool hasPendingEvents() override;
- bool sendPostedEvents(QEventLoop::ProcessEventsFlags flags) override;
-};
-
-QT_END_NAMESPACE
-
-#endif // QWINRTEVENTDISPATCHER_H
diff --git a/src/plugins/platforms/winrt/qwinrtfiledialoghelper.cpp b/src/plugins/platforms/winrt/qwinrtfiledialoghelper.cpp
deleted file mode 100644
index 114d6dacd8..0000000000
--- a/src/plugins/platforms/winrt/qwinrtfiledialoghelper.cpp
+++ /dev/null
@@ -1,588 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 "qwinrtfiledialoghelper.h"
-#include "qwinrtfileengine.h"
-
-#include <QtCore/qcoreapplication.h>
-#include <QtCore/QEventLoop>
-#include <QtCore/QMap>
-#include <QtCore/QVector>
-#include <QtCore/qfunctions_winrt.h>
-#include <private/qeventdispatcher_winrt_p.h>
-
-#include <functional>
-#include <wrl.h>
-#include <windows.foundation.h>
-#include <windows.storage.pickers.h>
-#include <Windows.Applicationmodel.Activation.h>
-
-using namespace Microsoft::WRL;
-using namespace Microsoft::WRL::Wrappers;
-using namespace ABI::Windows::ApplicationModel::Activation;
-using namespace ABI::Windows::Foundation;
-using namespace ABI::Windows::Foundation::Collections;
-using namespace ABI::Windows::Storage;
-using namespace ABI::Windows::Storage::Pickers;
-
-typedef IAsyncOperationCompletedHandler<StorageFile *> SingleFileHandler;
-typedef IAsyncOperationCompletedHandler<IVectorView<StorageFile *> *> MultipleFileHandler;
-typedef IAsyncOperationCompletedHandler<StorageFolder *> SingleFolderHandler;
-
-QT_BEGIN_NAMESPACE
-
-// Required for save file picker
-class WindowsStringVector : public RuntimeClass<IVector<HSTRING>>
-{
-public:
- HRESULT __stdcall GetAt(quint32 index, HSTRING *item)
- {
- *item = impl.at(int(index));
- return S_OK;
- }
- HRESULT __stdcall get_Size(quint32 *size)
- {
- *size = quint32(impl.size());
- return S_OK;
- }
- HRESULT __stdcall GetView(IVectorView<HSTRING> **view)
- {
- *view = nullptr;
- return E_NOTIMPL;
- }
- HRESULT __stdcall IndexOf(HSTRING value, quint32 *index, boolean *found)
- {
- *found = false;
- for (int i = 0; i < impl.size(); ++i) {
- qint32 result;
- HRESULT hr = WindowsCompareStringOrdinal(impl.at(i), value, &result);
- if (FAILED(hr))
- return hr;
- if (result == 0) {
- *index = quint32(i);
- *found = true;
- break;
- }
- }
- return S_OK;
- }
- HRESULT __stdcall SetAt(quint32 index, HSTRING item)
- {
- HSTRING newItem;
- HRESULT hr = WindowsDuplicateString(item, &newItem);
- if (FAILED(hr))
- return hr;
- impl[int(index)] = newItem;
- return S_OK;
- }
- HRESULT __stdcall InsertAt(quint32 index, HSTRING item)
- {
- HSTRING newItem;
- HRESULT hr = WindowsDuplicateString(item, &newItem);
- if (FAILED(hr))
- return hr;
- impl.insert(int(index), newItem);
- return S_OK;
- }
- HRESULT __stdcall RemoveAt(quint32 index)
- {
- WindowsDeleteString(impl.takeAt(int(index)));
- return S_OK;
- }
- HRESULT __stdcall Append(HSTRING item)
- {
- HSTRING newItem;
- HRESULT hr = WindowsDuplicateString(item, &newItem);
- if (FAILED(hr))
- return hr;
- impl.append(newItem);
- return S_OK;
- }
- HRESULT __stdcall RemoveAtEnd()
- {
- WindowsDeleteString(impl.takeLast());
- return S_OK;
- }
- HRESULT __stdcall Clear()
- {
- foreach (const HSTRING &item, impl)
- WindowsDeleteString(item);
- impl.clear();
- return S_OK;
- }
-private:
- QVector<HSTRING> impl;
-};
-
-template<typename T>
-static bool initializePicker(HSTRING runtimeId, T **picker, const QSharedPointer<QFileDialogOptions> &options)
-{
- HRESULT hr;
-
- ComPtr<IInspectable> basePicker;
- hr = RoActivateInstance(runtimeId, &basePicker);
- RETURN_FALSE_IF_FAILED("Failed to instantiate file picker");
- hr = basePicker.Get()->QueryInterface(IID_PPV_ARGS(picker));
- RETURN_FALSE_IF_FAILED("Failed to cast file picker");
-
- if (options->isLabelExplicitlySet(QFileDialogOptions::Accept)) {
- const QString labelText = options->labelText(QFileDialogOptions::Accept);
- HStringReference labelTextRef(reinterpret_cast<const wchar_t *>(labelText.utf16()),
- uint(labelText.length()));
- hr = (*picker)->put_CommitButtonText(labelTextRef.Get());
- RETURN_FALSE_IF_FAILED("Failed to set commit button text");
- }
-
- return true;
-}
-
-template<typename T>
-static bool initializeOpenPickerOptions(T *picker, const QSharedPointer<QFileDialogOptions> &options)
-{
- HRESULT hr;
- hr = picker->put_ViewMode(options->viewMode() == QFileDialogOptions::Detail
- ? PickerViewMode_Thumbnail : PickerViewMode_List);
- RETURN_FALSE_IF_FAILED("Failed to set picker view mode");
-
- ComPtr<IVector<HSTRING>> filters;
- hr = picker->get_FileTypeFilter(&filters);
- RETURN_FALSE_IF_FAILED("Failed to get file type filters list");
- for (const QString &namedFilter : options->nameFilters()) {
- for (const QString &filter : QPlatformFileDialogHelper::cleanFilterList(namedFilter)) {
- // Remove leading star
- const int offset = (filter.length() > 1 && filter.startsWith(QLatin1Char('*'))) ? 1 : 0;
- HStringReference filterRef(reinterpret_cast<const wchar_t *>(filter.utf16() + offset),
- uint(filter.length() - offset));
- hr = filters->Append(filterRef.Get());
- if (FAILED(hr)) {
- qWarning("Failed to add named file filter \"%s\": %s",
- qPrintable(filter), qPrintable(qt_error_string(hr)));
- }
- }
- }
- // The file dialog won't open with an empty list - add a default wildcard
- quint32 size;
- hr = filters->get_Size(&size);
- RETURN_FALSE_IF_FAILED("Failed to get file type filters list size");
- if (!size) {
- hr = filters->Append(HString::MakeReference(L"*").Get());
- RETURN_FALSE_IF_FAILED("Failed to add default wildcard to file type filters list");
- }
-
- return true;
-}
-
-static bool pickFiles(IFileOpenPicker *picker, QWinRTFileDialogHelper *helper, bool singleFile)
-{
- Q_ASSERT(picker);
- Q_ASSERT(helper);
- HRESULT hr;
- hr = QEventDispatcherWinRT::runOnXamlThread([picker, helper, singleFile]() {
- HRESULT hr;
- if (singleFile) {
- ComPtr<IAsyncOperation<StorageFile *>> op;
- hr = picker->PickSingleFileAsync(&op);
- RETURN_HR_IF_FAILED("Failed to open single file picker");
- hr = op->put_Completed(Callback<SingleFileHandler>(helper, &QWinRTFileDialogHelper::onSingleFilePicked).Get());
- RETURN_HR_IF_FAILED("Failed to attach file picker callback");
- } else {
- ComPtr<IAsyncOperation<IVectorView<StorageFile *> *>> op;
- hr = picker->PickMultipleFilesAsync(&op);
- RETURN_HR_IF_FAILED("Failed to open multi file picker");
- hr = op->put_Completed(Callback<MultipleFileHandler>(helper, &QWinRTFileDialogHelper::onMultipleFilesPicked).Get());
- RETURN_HR_IF_FAILED("Failed to attach multi file callback");
- }
- return S_OK;
- });
- return SUCCEEDED(hr);
-}
-
-static bool pickFolder(IFolderPicker *picker, QWinRTFileDialogHelper *helper)
-{
- Q_ASSERT(picker);
- Q_ASSERT(helper);
- HRESULT hr;
- hr = QEventDispatcherWinRT::runOnXamlThread([picker, helper]() {
- HRESULT hr;
- ComPtr<IAsyncOperation<StorageFolder *>> op;
- hr = picker->PickSingleFolderAsync(&op);
- RETURN_HR_IF_FAILED("Failed to open folder picker");
- hr = op->put_Completed(Callback<SingleFolderHandler>(helper, &QWinRTFileDialogHelper::onSingleFolderPicked).Get());
- RETURN_HR_IF_FAILED("Failed to attach folder picker callback");
- return S_OK;
- });
- return SUCCEEDED(hr);
-}
-
-static bool pickSaveFile(IFileSavePicker *picker, QWinRTFileDialogHelper *helper)
-{
- Q_ASSERT(picker);
- Q_ASSERT(helper);
- HRESULT hr;
- hr = QEventDispatcherWinRT::runOnXamlThread([picker, helper]() {
- HRESULT hr;
- ComPtr<IAsyncOperation<StorageFile *>> op;
- hr = picker->PickSaveFileAsync(&op);
- RETURN_HR_IF_FAILED("Failed to open save file picker");
- hr = op->put_Completed(Callback<SingleFileHandler>(helper, &QWinRTFileDialogHelper::onSingleFilePicked).Get());
- RETURN_HR_IF_FAILED("Failed to attach save file picker callback");
- return S_OK;
- });
- return SUCCEEDED(hr);
-}
-
-class QWinRTFileDialogHelperPrivate
-{
-public:
- bool shown;
- QEventLoop loop;
-
- // Input
- QUrl directory;
- QUrl saveFileName;
- QString selectedNameFilter;
-
- // Output
- QList<QUrl> selectedFiles;
-};
-
-QWinRTFileDialogHelper::QWinRTFileDialogHelper()
- : QPlatformFileDialogHelper(), d_ptr(new QWinRTFileDialogHelperPrivate)
-{
- Q_D(QWinRTFileDialogHelper);
-
- d->shown = false;
-}
-
-void QWinRTFileDialogHelper::exec()
-{
- Q_D(QWinRTFileDialogHelper);
-
- if (!d->shown)
- show(Qt::Dialog, Qt::ApplicationModal, nullptr);
- d->loop.exec();
-}
-
-bool QWinRTFileDialogHelper::show(Qt::WindowFlags windowFlags, Qt::WindowModality windowModality, QWindow *parent)
-{
- Q_UNUSED(windowFlags)
- Q_UNUSED(windowModality)
- Q_UNUSED(parent)
- Q_D(QWinRTFileDialogHelper);
-
- HRESULT hr;
- const QSharedPointer<QFileDialogOptions> dialogOptions = options();
- switch (dialogOptions->acceptMode()) {
- default:
- case QFileDialogOptions::AcceptOpen: {
- switch (dialogOptions->fileMode()) {
- case QFileDialogOptions::AnyFile:
- case QFileDialogOptions::ExistingFile:
- case QFileDialogOptions::ExistingFiles: {
- ComPtr<IFileOpenPicker> picker;
- if (!initializePicker(HString::MakeReference(RuntimeClass_Windows_Storage_Pickers_FileOpenPicker).Get(),
- picker.GetAddressOf(), dialogOptions)) {
- return false;
- }
- if (!initializeOpenPickerOptions(picker.Get(), dialogOptions))
- return false;
-
- if (!pickFiles(picker.Get(), this, dialogOptions->fileMode() == QFileDialogOptions::ExistingFile))
- return false;
-
- break;
- }
- case QFileDialogOptions::Directory:
- case QFileDialogOptions::DirectoryOnly: {
- ComPtr<IFolderPicker> picker;
- if (!initializePicker(HString::MakeReference(RuntimeClass_Windows_Storage_Pickers_FolderPicker).Get(),
- picker.GetAddressOf(), dialogOptions)) {
- return false;
- }
- if (!initializeOpenPickerOptions(picker.Get(), dialogOptions))
- return false;
-
- if (!pickFolder(picker.Get(), this))
- return false;
-
- break;
- }
- }
- break;
- }
- case QFileDialogOptions::AcceptSave: {
- ComPtr<IFileSavePicker> picker;
- if (!initializePicker(HString::MakeReference(RuntimeClass_Windows_Storage_Pickers_FileSavePicker).Get(),
- picker.GetAddressOf(), dialogOptions)) {
- return false;
- }
-
- if (!dialogOptions->nameFilters().isEmpty()) {
- ComPtr<IMap<HSTRING, IVector<HSTRING> *>> choices;
- hr = picker->get_FileTypeChoices(&choices);
- RETURN_FALSE_IF_FAILED("Failed to get file extension choices");
- const QStringList nameFilters = dialogOptions->nameFilters();
- for (const QString &namedFilter : nameFilters) {
- ComPtr<IVector<HSTRING>> entry = Make<WindowsStringVector>();
- const QStringList cleanFilter = QPlatformFileDialogHelper::cleanFilterList(namedFilter);
- for (const QString &filter : cleanFilter) {
- // Remove leading star
- const int starOffset = (filter.length() > 1 && filter.startsWith(QLatin1Char('*'))) ? 1 : 0;
- HStringReference filterRef(reinterpret_cast<const wchar_t *>(filter.utf16() + starOffset),
- uint(filter.length() - starOffset));
- hr = entry->Append(filterRef.Get());
- if (FAILED(hr)) {
- qWarning("Failed to add named file filter \"%s\": %s",
- qPrintable(filter), qPrintable(qt_error_string(hr)));
- }
- }
- const int offset = namedFilter.indexOf(QLatin1String(" ("));
- const QString filterTitle = namedFilter.mid(0, offset);
- HStringReference namedFilterRef(reinterpret_cast<const wchar_t *>(filterTitle.utf16()),
- uint(filterTitle.length()));
- boolean replaced;
- hr = choices->Insert(namedFilterRef.Get(), entry.Get(), &replaced);
- // Only print a warning as * or *.* is not a valid choice on Windows 10
- // but used on a regular basis on all other platforms
- if (FAILED(hr)) {
- qWarning("Failed to insert file extension choice entry: %s: %s",
- qPrintable(filterTitle), qPrintable(qt_error_string(hr)));
- }
- }
- }
-
- QString suffix = dialogOptions->defaultSuffix();
- if (!suffix.isEmpty()) {
- if (!suffix.startsWith(QLatin1Char('.')))
- suffix.prepend(QLatin1Char('.'));
- HStringReference nativeSuffix(reinterpret_cast<const wchar_t *>(suffix.utf16()),
- uint(suffix.length()));
- hr = picker->put_DefaultFileExtension(nativeSuffix.Get());
- RETURN_FALSE_IF_FAILED_WITH_ARGS("Failed to set default file extension \"%s\"", qPrintable(suffix));
- }
-
- const QString suggestedName = QFileInfo(d->saveFileName.toLocalFile()).fileName();
- if (!suggestedName.isEmpty()) {
- HStringReference nativeSuggestedName(reinterpret_cast<const wchar_t *>(suggestedName.utf16()),
- uint(suggestedName.length()));
- hr = picker->put_SuggestedFileName(nativeSuggestedName.Get());
- RETURN_FALSE_IF_FAILED("Failed to set suggested file name");
- }
-
- if (!pickSaveFile(picker.Get(), this))
- return false;
-
- break;
- }
- }
-
- d->shown = true;
- return true;
-}
-
-void QWinRTFileDialogHelper::hide()
-{
- Q_D(QWinRTFileDialogHelper);
-
- if (!d->shown)
- return;
-
- d->shown = false;
-}
-
-void QWinRTFileDialogHelper::setDirectory(const QUrl &directory)
-{
- Q_D(QWinRTFileDialogHelper);
- d->directory = directory;
-}
-
-QUrl QWinRTFileDialogHelper::directory() const
-{
- Q_D(const QWinRTFileDialogHelper);
- return d->directory;
-}
-
-void QWinRTFileDialogHelper::selectFile(const QUrl &saveFileName)
-{
- Q_D(QWinRTFileDialogHelper);
- d->saveFileName = saveFileName;
-}
-
-QList<QUrl> QWinRTFileDialogHelper::selectedFiles() const
-{
- Q_D(const QWinRTFileDialogHelper);
- return d->selectedFiles;
-}
-
-void QWinRTFileDialogHelper::selectNameFilter(const QString &selectedNameFilter)
-{
- Q_D(QWinRTFileDialogHelper);
- d->selectedNameFilter = selectedNameFilter;
-}
-
-QString QWinRTFileDialogHelper::selectedNameFilter() const
-{
- Q_D(const QWinRTFileDialogHelper);
- return d->selectedNameFilter;
-}
-
-HRESULT QWinRTFileDialogHelper::onSingleFilePicked(IAsyncOperation<StorageFile *> *args, AsyncStatus status)
-{
- Q_D(QWinRTFileDialogHelper);
-
- QEventLoopLocker locker(&d->loop);
- d->shown = false;
- d->selectedFiles.clear();
- if (status == Canceled || status == Error) {
- emit reject();
- return S_OK;
- }
-
- HRESULT hr;
- ComPtr<IStorageFile> file;
- hr = args->GetResults(&file);
- Q_ASSERT_SUCCEEDED(hr);
- return onFilePicked(file.Get());
-}
-
-HRESULT QWinRTFileDialogHelper::onMultipleFilesPicked(IAsyncOperation<IVectorView<StorageFile *> *> *args, AsyncStatus status)
-{
- Q_D(QWinRTFileDialogHelper);
-
- QEventLoopLocker locker(&d->loop);
- d->shown = false;
- d->selectedFiles.clear();
- if (status == Canceled || status == Error) {
- emit reject();
- return S_OK;
- }
-
- HRESULT hr;
- ComPtr<IVectorView<StorageFile *>> fileList;
- hr = args->GetResults(&fileList);
- RETURN_HR_IF_FAILED("Failed to get file list");
- return onFilesPicked(fileList.Get());
-}
-
-HRESULT QWinRTFileDialogHelper::onSingleFolderPicked(IAsyncOperation<StorageFolder *> *args, AsyncStatus status)
-{
- Q_D(QWinRTFileDialogHelper);
-
- QEventLoopLocker locker(&d->loop);
- d->shown = false;
- d->selectedFiles.clear();
- if (status == Canceled || status == Error) {
- emit reject();
- return S_OK;
- }
-
- HRESULT hr;
- ComPtr<IStorageFolder> folder;
- hr = args->GetResults(&folder);
- Q_ASSERT_SUCCEEDED(hr);
- return onFolderPicked(folder.Get());
-}
-
-HRESULT QWinRTFileDialogHelper::onFilesPicked(IVectorView<StorageFile *> *files)
-{
- HRESULT hr;
- quint32 size;
- hr = files->get_Size(&size);
- Q_ASSERT_SUCCEEDED(hr);
- if (!size) {
- emit reject();
- return S_OK;
- }
-
- for (quint32 i = 0; i < size; ++i) {
- ComPtr<IStorageFile> file;
- hr = files->GetAt(i, &file);
- Q_ASSERT_SUCCEEDED(hr);
- appendFile(file.Get());
- }
-
- emit accept();
- return S_OK;
-}
-
-HRESULT QWinRTFileDialogHelper::onFolderPicked(IStorageFolder *folder)
-{
- if (!folder) {
- emit reject();
- return S_OK;
- }
-
- appendFile(folder);
- emit accept();
- return S_OK;
-}
-
-HRESULT QWinRTFileDialogHelper::onFilePicked(IStorageFile *file)
-{
- if (!file) {
- emit reject();
- return S_OK;
- }
-
- appendFile(file);
- emit accept();
- return S_OK;
-}
-
-void QWinRTFileDialogHelper::appendFile(IInspectable *file)
-{
- Q_D(QWinRTFileDialogHelper);
-
- HRESULT hr;
- ComPtr<IStorageItem> item;
- hr = file->QueryInterface(IID_PPV_ARGS(&item));
- Q_ASSERT_SUCCEEDED(hr);
-
- HString path;
- hr = item->get_Path(path.GetAddressOf());
- Q_ASSERT_SUCCEEDED(hr);
-
- quint32 pathLen;
- const wchar_t *pathStr = path.GetRawBuffer(&pathLen);
- const QString filePath = QString::fromWCharArray(pathStr, pathLen);
- QWinRTFileEngineHandler::registerFile(filePath, item.Get());
- d->selectedFiles.append(QUrl::fromLocalFile(filePath));
-}
-
-QT_END_NAMESPACE
diff --git a/src/plugins/platforms/winrt/qwinrtfiledialoghelper.h b/src/plugins/platforms/winrt/qwinrtfiledialoghelper.h
deleted file mode 100644
index 994d099dcf..0000000000
--- a/src/plugins/platforms/winrt/qwinrtfiledialoghelper.h
+++ /dev/null
@@ -1,107 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 QWINRTFILEDIALOGHELPER_H
-#define QWINRTFILEDIALOGHELPER_H
-
-#include <qpa/qplatformdialoghelper.h>
-#include <QtCore/qt_windows.h>
-
-struct IInspectable;
-namespace ABI {
- namespace Windows {
- namespace Storage {
- class StorageFile;
- class StorageFolder;
- struct IStorageFile;
- struct IStorageFolder;
- }
- namespace Foundation {
- enum class AsyncStatus;
- template <typename T> struct IAsyncOperation;
- namespace Collections {
- template <typename T> struct IVectorView;
- }
- }
- }
-}
-
-QT_BEGIN_NAMESPACE
-
-class QWinRTFileDialogHelperPrivate;
-class QWinRTFileDialogHelper : public QPlatformFileDialogHelper
-{
- Q_OBJECT
-public:
- explicit QWinRTFileDialogHelper();
- ~QWinRTFileDialogHelper() override = default;
-
- void exec() override;
- bool show(Qt::WindowFlags, Qt::WindowModality, QWindow *) override;
- void hide() override;
-
- bool defaultNameFilterDisables() const override { return false; }
- void setDirectory(const QUrl &directory) override;
- QUrl directory() const override;
- void selectFile(const QUrl &saveFileName) override;
- QList<QUrl> selectedFiles() const override;
- void setFilter() override { }
- void selectNameFilter(const QString &selectedNameFilter) override;
- QString selectedNameFilter() const override;
-
- HRESULT onSingleFilePicked(ABI::Windows::Foundation::IAsyncOperation<ABI::Windows::Storage::StorageFile *> *,
- ABI::Windows::Foundation::AsyncStatus);
- HRESULT onMultipleFilesPicked(ABI::Windows::Foundation::IAsyncOperation<ABI::Windows::Foundation::Collections::IVectorView<ABI::Windows::Storage::StorageFile *> *> *,
- ABI::Windows::Foundation::AsyncStatus);
- HRESULT onSingleFolderPicked(ABI::Windows::Foundation::IAsyncOperation<ABI::Windows::Storage::StorageFolder *> *,
- ABI::Windows::Foundation::AsyncStatus);
-
-private:
- HRESULT onFilesPicked(ABI::Windows::Foundation::Collections::IVectorView<ABI::Windows::Storage::StorageFile *> *files);
- HRESULT onFolderPicked(ABI::Windows::Storage::IStorageFolder *folder);
- HRESULT onFilePicked(ABI::Windows::Storage::IStorageFile *file);
- void appendFile(IInspectable *);
-
- QScopedPointer<QWinRTFileDialogHelperPrivate> d_ptr;
- Q_DECLARE_PRIVATE(QWinRTFileDialogHelper)
-};
-
-QT_END_NAMESPACE
-
-#endif // QWINRTFILEDIALOGHELPER_H
diff --git a/src/plugins/platforms/winrt/qwinrtfileengine.cpp b/src/plugins/platforms/winrt/qwinrtfileengine.cpp
deleted file mode 100644
index 962e4ab938..0000000000
--- a/src/plugins/platforms/winrt/qwinrtfileengine.cpp
+++ /dev/null
@@ -1,554 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 "qwinrtfileengine.h"
-
-#include <QtCore/QDateTime>
-#include <QtCore/QCoreApplication>
-#include <QtCore/QHash>
-#include <QtCore/qfunctions_winrt.h>
-#include <QtCore/private/qfsfileengine_p.h>
-
-#include <wrl.h>
-#include <windows.storage.h>
-#include <robuffer.h>
-
-using namespace Microsoft::WRL;
-using namespace Microsoft::WRL::Wrappers;
-using namespace ABI::Windows::Foundation;
-using namespace ABI::Windows::Storage;
-using namespace ABI::Windows::Storage::Streams;
-
-typedef IAsyncOperationCompletedHandler<IRandomAccessStream *> StreamCompletedHandler;
-typedef IAsyncOperationWithProgressCompletedHandler<IBuffer *, UINT32> StreamReadCompletedHandler;
-
-QT_BEGIN_NAMESPACE
-
-#define RETURN_AND_SET_ERROR_IF_FAILED(error, ret) \
- setError(error, qt_error_string(hr)); \
- if (FAILED(hr)) \
- return ret;
-
-Q_GLOBAL_STATIC(QWinRTFileEngineHandler, handlerInstance)
-
-class QWinRTFileEngineHandlerPrivate
-{
-public:
- QHash<QString, ComPtr<IStorageItem>> files;
-};
-
-class QWinRTFileEnginePrivate
-{
-public:
- QWinRTFileEnginePrivate(const QString &fileName, IStorageItem *file)
- : fileName(fileName), file(file), openMode(QIODevice::NotOpen)
- {
- HRESULT hr;
- hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Storage_Streams_Buffer).Get(),
- IID_PPV_ARGS(&bufferFactory));
- Q_ASSERT_SUCCEEDED(hr);
-
- lastSeparator = fileName.size() - 1;
- for (int i = lastSeparator; i >= 0; --i) {
- if (fileName.at(i).unicode() == '/' || fileName.at(i).unicode() == '\\') {
- lastSeparator = i;
- break;
- }
- }
-
- firstDot = fileName.size();
- for (int i = lastSeparator; i < fileName.size(); ++i) {
- if (fileName.at(i).unicode() == '.') {
- firstDot = i;
- break;
- }
- }
- }
-
- ComPtr<IBufferFactory> bufferFactory;
-
- QString fileName;
- int lastSeparator;
- int firstDot;
- ComPtr<IStorageItem> file;
- ComPtr<IRandomAccessStream> stream;
- QIODevice::OpenMode openMode;
-
- qint64 pos;
-
-private:
- QWinRTFileEngineHandler *q_ptr;
- Q_DECLARE_PUBLIC(QWinRTFileEngineHandler)
-};
-
-
-QWinRTFileEngineHandler::QWinRTFileEngineHandler()
- : d_ptr(new QWinRTFileEngineHandlerPrivate)
-{
-}
-
-void QWinRTFileEngineHandler::registerFile(const QString &fileName, IStorageItem *file)
-{
- handlerInstance->d_func()->files.insert(QDir::cleanPath(fileName), file);
-}
-
-IStorageItem *QWinRTFileEngineHandler::registeredFile(const QString &fileName)
-{
- return handlerInstance->d_func()->files.value(fileName).Get();
-}
-
-QAbstractFileEngine *QWinRTFileEngineHandler::create(const QString &fileName) const
-{
- Q_D(const QWinRTFileEngineHandler);
-
- QHash<QString, ComPtr<IStorageItem>>::const_iterator file = d->files.find(fileName);
- if (file != d->files.end())
- return new QWinRTFileEngine(fileName, file.value().Get());
-
- return nullptr;
-}
-
-static HRESULT getDestinationFolder(const QString &fileName, const QString &newFileName,
- IStorageItem *file, IStorageFolder **folder)
-{
- HRESULT hr;
- ComPtr<IAsyncOperation<StorageFolder *>> op;
- QFileInfo newFileInfo(newFileName);
- QFileInfo fileInfo(fileName);
- if (fileInfo.dir() == newFileInfo.dir()) {
- ComPtr<IStorageItem2> item;
- hr = file->QueryInterface(IID_PPV_ARGS(&item));
- Q_ASSERT_SUCCEEDED(hr);
-
- hr = item->GetParentAsync(&op);
- } else {
- ComPtr<IStorageFolderStatics> folderFactory;
- hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Storage_StorageFolder).Get(),
- IID_PPV_ARGS(&folderFactory));
- Q_ASSERT_SUCCEEDED(hr);
-
- const QString newFilePath = QDir::toNativeSeparators(newFileInfo.absolutePath());
- HStringReference nativeNewFilePath(reinterpret_cast<LPCWSTR>(newFilePath.utf16()),
- uint(newFilePath.length()));
- hr = folderFactory->GetFolderFromPathAsync(nativeNewFilePath.Get(), &op);
- }
- if (FAILED(hr))
- return hr;
- return QWinRTFunctions::await(op, folder);
-}
-
-QWinRTFileEngine::QWinRTFileEngine(const QString &fileName, IStorageItem *file)
- : d_ptr(new QWinRTFileEnginePrivate(fileName, file))
-{
-}
-
-bool QWinRTFileEngine::open(QIODevice::OpenMode openMode)
-{
- Q_D(QWinRTFileEngine);
-
- FileAccessMode fileAccessMode = (openMode & QIODevice::WriteOnly)
- ? FileAccessMode_ReadWrite : FileAccessMode_Read;
-
- HRESULT hr;
- ComPtr<IStorageFile> file;
- hr = d->file.As(&file);
- RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::OpenError, false);
-
- ComPtr<IAsyncOperation<IRandomAccessStream *>> op;
- hr = file->OpenAsync(fileAccessMode, &op);
- RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::OpenError, false);
-
- hr = QWinRTFunctions::await(op, d->stream.GetAddressOf());
- RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::OpenError, false);
-
- const ProcessOpenModeResult res = processOpenModeFlags(openMode);
- if (!res.ok) {
- setError(QFileDevice::OpenError, res.error);
- return false;
- }
- d->openMode = res.openMode;
- if (d->openMode & QIODevice::Truncate) {
- if (!setSize(0)) {
- close();
- setError(QFileDevice::OpenError, QLatin1String("Could not truncate file"));
- return false;
- }
- }
-
- return SUCCEEDED(hr);
-}
-
-bool QWinRTFileEngine::close()
-{
- Q_D(QWinRTFileEngine);
-
- if (!d->stream)
- return false;
-
- ComPtr<IClosable> closable;
- HRESULT hr = d->stream.As(&closable);
- Q_ASSERT_SUCCEEDED(hr);
-
- hr = closable->Close();
- RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::UnspecifiedError, false);
- d->stream.Reset();
- d->openMode = QIODevice::NotOpen;
- return SUCCEEDED(hr);
-}
-
-bool QWinRTFileEngine::flush()
-{
- Q_D(QWinRTFileEngine);
-
- if (!d->stream)
- return false;
-
- if (!(d->openMode & QIODevice::WriteOnly))
- return true;
-
- ComPtr<IOutputStream> stream;
- HRESULT hr = d->stream.As(&stream);
- RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::WriteError, false);
- ComPtr<IAsyncOperation<bool>> flushOp;
- hr = stream->FlushAsync(&flushOp);
- RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::WriteError, false);
- boolean flushed;
- hr = QWinRTFunctions::await(flushOp, &flushed);
- RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::WriteError, false);
-
- return true;
-}
-
-qint64 QWinRTFileEngine::size() const
-{
- Q_D(const QWinRTFileEngine);
-
- if (!d->stream)
- return 0;
-
- UINT64 size;
- HRESULT hr;
- hr = d->stream->get_Size(&size);
- RETURN_IF_FAILED("Failed to get file size", return 0);
-
- return qint64(size);
-}
-
-bool QWinRTFileEngine::setSize(qint64 size)
-{
- Q_D(QWinRTFileEngine);
- if (!d->stream) {
- setError(QFileDevice::ResizeError, QLatin1String("File must be open to be resized"));
- return false;
- }
-
- if (size < 0) {
- setError(QFileDevice::ResizeError, QLatin1String("File size cannot be negative"));
- return false;
- }
-
- HRESULT hr = d->stream->put_Size(static_cast<quint64>(size));
- RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::ResizeError, false);
- if (!flush()) {
- setError(QFileDevice::ResizeError, QLatin1String("Could not flush file"));
- return false;
- }
-
- return true;
-}
-
-qint64 QWinRTFileEngine::pos() const
-{
- Q_D(const QWinRTFileEngine);
- return d->pos;
-}
-
-bool QWinRTFileEngine::seek(qint64 pos)
-{
- Q_D(QWinRTFileEngine);
-
- if (!d->stream)
- return false;
-
- HRESULT hr = d->stream->Seek(UINT64(pos));
- RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::PositionError, false);
- d->pos = pos;
- return SUCCEEDED(hr);
-}
-
-bool QWinRTFileEngine::remove()
-{
- Q_D(QWinRTFileEngine);
-
- ComPtr<IAsyncAction> op;
- HRESULT hr = d->file->DeleteAsync(StorageDeleteOption_Default, &op);
- RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::RemoveError, false);
-
- hr = QWinRTFunctions::await(op);
- RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::RemoveError, false);
- return SUCCEEDED(hr);
-}
-
-bool QWinRTFileEngine::copy(const QString &newName)
-{
- Q_D(QWinRTFileEngine);
-
- HRESULT hr;
- ComPtr<IStorageFolder> destinationFolder;
- hr = getDestinationFolder(d->fileName, newName, d->file.Get(), destinationFolder.GetAddressOf());
- RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::CopyError, false);
-
- ComPtr<IStorageFile> file;
- hr = d->file.As(&file);
- RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::CopyError, false);
-
- const QString destinationName = QFileInfo(newName).fileName();
- HStringReference nativeDestinationName(reinterpret_cast<LPCWSTR>(destinationName.utf16()),
- uint(destinationName.length()));
- ComPtr<IAsyncOperation<StorageFile *>> op;
- hr = file->CopyOverloadDefaultOptions(destinationFolder.Get(), nativeDestinationName.Get(), &op);
- RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::CopyError, false);
-
- ComPtr<IStorageFile> newFile;
- hr = QWinRTFunctions::await(op, newFile.GetAddressOf());
- RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::CopyError, false);
- return SUCCEEDED(hr);
-}
-
-bool QWinRTFileEngine::rename(const QString &newName)
-{
- Q_D(QWinRTFileEngine);
-
- HRESULT hr;
- ComPtr<IStorageFolder> destinationFolder;
- hr = getDestinationFolder(d->fileName, newName, d->file.Get(), destinationFolder.GetAddressOf());
- RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::RenameError, false);
-
- const QString destinationName = QFileInfo(newName).fileName();
- HStringReference nativeDestinationName(reinterpret_cast<LPCWSTR>(destinationName.utf16()),
- uint(destinationName.length()));
- ComPtr<IAsyncAction> op;
- hr = d->file->RenameAsyncOverloadDefaultOptions(nativeDestinationName.Get(), &op);
- RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::RenameError, false);
- return SUCCEEDED(hr);
-}
-
-bool QWinRTFileEngine::renameOverwrite(const QString &newName)
-{
- Q_D(QWinRTFileEngine);
-
- HRESULT hr;
- ComPtr<IStorageFolder> destinationFolder;
- hr = getDestinationFolder(d->fileName, newName, d->file.Get(), destinationFolder.GetAddressOf());
- RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::RenameError, false);
-
- const QString destinationName = QFileInfo(newName).fileName();
- HStringReference nativeDestinationName(reinterpret_cast<LPCWSTR>(destinationName.utf16()),
- uint(destinationName.length()));
- ComPtr<IAsyncAction> op;
- hr = d->file->RenameAsync(nativeDestinationName.Get(), NameCollisionOption_ReplaceExisting, &op);
- RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::RenameError, false);
- return SUCCEEDED(hr);
-}
-
-QAbstractFileEngine::FileFlags QWinRTFileEngine::fileFlags(FileFlags type) const
-{
- Q_D(const QWinRTFileEngine);
-
- FileFlags flags = ExistsFlag|ReadOwnerPerm|ReadUserPerm|WriteOwnerPerm|WriteUserPerm;
-
- HRESULT hr;
- FileAttributes attributes;
- hr = d->file->get_Attributes(&attributes);
- RETURN_IF_FAILED("Failed to get file attributes", return flags);
- if (attributes & FileAttributes_ReadOnly)
- flags ^= WriteUserPerm;
- if (attributes & FileAttributes_Directory)
- flags |= DirectoryType;
- else
- flags |= FileType;
-
- return type & flags;
-}
-
-bool QWinRTFileEngine::setPermissions(uint perms)
-{
- Q_UNUSED(perms);
- Q_UNIMPLEMENTED();
- return false;
-}
-
-QString QWinRTFileEngine::fileName(FileName type) const
-{
- Q_D(const QWinRTFileEngine);
-
- switch (type) {
- default:
- case DefaultName:
- case AbsoluteName:
- case CanonicalName:
- break;
- case BaseName:
- return d->lastSeparator < 0
- ? d->fileName : d->fileName.mid(d->lastSeparator, d->firstDot - d->lastSeparator);
- case PathName:
- case AbsolutePathName:
- case CanonicalPathName:
- return d->fileName.mid(0, d->lastSeparator);
- case LinkName:
- case BundleName:
- return QString();
- }
- return d->fileName;
-}
-
-QDateTime QWinRTFileEngine::fileTime(FileTime type) const
-{
- Q_D(const QWinRTFileEngine);
-
- HRESULT hr;
- DateTime dateTime = { 0 };
- switch (type) {
- case BirthTime:
- hr = d->file->get_DateCreated(&dateTime);
- RETURN_IF_FAILED("Failed to get file creation time", return QDateTime());
- break;
- case MetadataChangeTime:
- case ModificationTime:
- case AccessTime: {
- ComPtr<IAsyncOperation<FileProperties::BasicProperties *>> op;
- hr = d->file->GetBasicPropertiesAsync(&op);
- RETURN_IF_FAILED("Failed to initiate file properties", return QDateTime());
- ComPtr<FileProperties::IBasicProperties> properties;
- hr = QWinRTFunctions::await(op, properties.GetAddressOf());
- RETURN_IF_FAILED("Failed to get file properties", return QDateTime());
- hr = properties->get_DateModified(&dateTime);
- RETURN_IF_FAILED("Failed to get file date", return QDateTime());
- }
- break;
- }
-
- SYSTEMTIME systemTime;
- FileTimeToSystemTime((const FILETIME *)&dateTime, &systemTime);
- QDate date(systemTime.wYear, systemTime.wMonth, systemTime.wDay);
- QTime time(systemTime.wHour, systemTime.wMinute, systemTime.wSecond, systemTime.wMilliseconds);
- return QDateTime(date, time);
-}
-
-qint64 QWinRTFileEngine::read(char *data, qint64 maxlen)
-{
- Q_D(QWinRTFileEngine);
-
- if (!d->stream)
- return -1;
-
- ComPtr<IInputStream> stream;
- HRESULT hr = d->stream.As(&stream);
- RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::ReadError, -1);
-
- UINT32 length = UINT32(qBound(quint64(0), quint64(maxlen), quint64(UINT32_MAX)));
- ComPtr<IBuffer> buffer;
- hr = d->bufferFactory->Create(length, &buffer);
- RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::ReadError, -1);
-
- ComPtr<IAsyncOperationWithProgress<IBuffer *, UINT32>> op;
- hr = stream->ReadAsync(buffer.Get(), length, InputStreamOptions_None, &op);
- RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::ReadError, -1);
-
- // Quoting MSDN IInputStream::ReadAsync() documentation:
- // "Depending on the implementation, the data that's read might be placed
- // into the input buffer, or it might be returned in a different buffer."
- // Using GetAddressOf can cause ref counting errors leaking the original
- // buffer.
- ComPtr<IBuffer> effectiveBuffer;
- hr = QWinRTFunctions::await(op, effectiveBuffer.GetAddressOf());
- RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::ReadError, -1);
-
- hr = effectiveBuffer->get_Length(&length);
- RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::ReadError, -1);
-
- ComPtr<Windows::Storage::Streams::IBufferByteAccess> byteArrayAccess;
- hr = effectiveBuffer.As(&byteArrayAccess);
- RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::ReadError, -1);
-
- byte *bytes;
- hr = byteArrayAccess->Buffer(&bytes);
- RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::ReadError, -1);
- memcpy(data, bytes, length);
- return qint64(length);
-}
-
-qint64 QWinRTFileEngine::write(const char *data, qint64 maxlen)
-{
- Q_D(QWinRTFileEngine);
-
- if (!d->stream)
- return -1;
-
- ComPtr<IOutputStream> stream;
- HRESULT hr = d->stream.As(&stream);
- RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::WriteError, -1);
-
- UINT32 length = UINT32(qBound(quint64(0), quint64(maxlen), quint64(UINT_MAX)));
- ComPtr<IBuffer> buffer;
- hr = d->bufferFactory->Create(length, &buffer);
- RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::WriteError, -1);
- hr = buffer->put_Length(length);
- RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::WriteError, -1);
-
- ComPtr<Windows::Storage::Streams::IBufferByteAccess> byteArrayAccess;
- hr = buffer.As(&byteArrayAccess);
- RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::WriteError, -1);
-
- byte *bytes;
- hr = byteArrayAccess->Buffer(&bytes);
- RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::WriteError, -1);
- memcpy(bytes, data, length);
-
- ComPtr<IAsyncOperationWithProgress<UINT32, UINT32>> op;
- hr = stream->WriteAsync(buffer.Get(), &op);
- RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::WriteError, -1);
-
- hr = QWinRTFunctions::await(op, &length);
- RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::WriteError, -1);
-
- return qint64(length);
-}
-
-QT_END_NAMESPACE
diff --git a/src/plugins/platforms/winrt/qwinrtfileengine.h b/src/plugins/platforms/winrt/qwinrtfileengine.h
deleted file mode 100644
index 453565a95a..0000000000
--- a/src/plugins/platforms/winrt/qwinrtfileengine.h
+++ /dev/null
@@ -1,104 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 QWINRTFILEENGINE_H
-#define QWINRTFILEENGINE_H
-
-#include <private/qabstractfileengine_p.h>
-
-namespace ABI {
- namespace Windows {
- namespace Storage {
- struct IStorageItem;
- }
- }
-}
-
-QT_BEGIN_NAMESPACE
-
-class QWinRTFileEngineHandlerPrivate;
-class QWinRTFileEngineHandler : public QAbstractFileEngineHandler
-{
-public:
- QWinRTFileEngineHandler();
- ~QWinRTFileEngineHandler() override = default;
- QAbstractFileEngine *create(const QString &fileName) const override;
-
- static void registerFile(const QString &fileName, ABI::Windows::Storage::IStorageItem *file);
- static ABI::Windows::Storage::IStorageItem *registeredFile(const QString &fileName);
-
-private:
- QScopedPointer<QWinRTFileEngineHandlerPrivate> d_ptr;
- Q_DECLARE_PRIVATE(QWinRTFileEngineHandler)
-};
-
-class QWinRTFileEnginePrivate;
-class QWinRTFileEngine : public QAbstractFileEngine
-{
-public:
- QWinRTFileEngine(const QString &fileName, ABI::Windows::Storage::IStorageItem *file);
- ~QWinRTFileEngine() override = default;
-
- bool open(QIODevice::OpenMode openMode) override;
- bool close() override;
- bool flush() override;
- qint64 size() const override;
- bool setSize(qint64 size) override;
- qint64 pos() const override;
- bool seek(qint64 pos) override;
- bool remove() override;
- bool copy(const QString &newName) override;
- bool rename(const QString &newName) override;
- bool renameOverwrite(const QString &newName) override;
- FileFlags fileFlags(FileFlags type=FileInfoAll) const override;
- bool setPermissions(uint perms) override;
- QString fileName(FileName type=DefaultName) const override;
- QDateTime fileTime(FileTime type) const override;
-
- qint64 read(char *data, qint64 maxlen) override;
- qint64 write(const char *data, qint64 len) override;
-
-private:
- QScopedPointer<QWinRTFileEnginePrivate> d_ptr;
- Q_DECLARE_PRIVATE(QWinRTFileEngine)
-};
-
-QT_END_NAMESPACE
-
-#endif // QWINRTFILEENGINE_H
diff --git a/src/plugins/platforms/winrt/qwinrtinputcontext.cpp b/src/plugins/platforms/winrt/qwinrtinputcontext.cpp
deleted file mode 100644
index 5ae94ba613..0000000000
--- a/src/plugins/platforms/winrt/qwinrtinputcontext.cpp
+++ /dev/null
@@ -1,222 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 "qwinrtinputcontext.h"
-#include "qwinrtscreen.h"
-#include <QtGui/QGuiApplication>
-#include <QtGui/QWindow>
-#include <private/qeventdispatcher_winrt_p.h>
-
-#include <functional>
-#include <wrl.h>
-#include <roapi.h>
-#include <windows.ui.viewmanagement.h>
-#include <windows.ui.core.h>
-using namespace Microsoft::WRL;
-using namespace Microsoft::WRL::Wrappers;
-using namespace ABI::Windows::Foundation;
-using namespace ABI::Windows::UI::ViewManagement;
-using namespace ABI::Windows::UI::Core;
-
-typedef ITypedEventHandler<InputPane*, InputPaneVisibilityEventArgs*> InputPaneVisibilityHandler;
-
-QT_BEGIN_NAMESPACE
-
-Q_LOGGING_CATEGORY(lcQpaInputMethods, "qt.qpa.input.methods")
-
-inline QRectF getInputPaneRect(ComPtr<IInputPane> pane, qreal scaleFactor)
-{
- Rect rect;
- pane->get_OccludedRect(&rect);
- return QRectF(qRound(qreal(rect.X) * scaleFactor), qRound(qreal(rect.Y) * scaleFactor),
- qRound(qreal(rect.Width) * scaleFactor), qRound(qreal(rect.Height) * scaleFactor));
-}
-
-/*!
- \class QWinRTInputContext
- \brief Manages Input Method visibility
- \internal
- \ingroup qt-qpa-winrt
-
- Listens to the native virtual keyboard for hide/show events and provides
- hints to the OS for showing/hiding. On WinRT, showInputPanel()/hideInputPanel()
- have no effect because WinRT dictates that keyboard presence is user-driven:
- (http://msdn.microsoft.com/en-us/library/windows/apps/hh465404.aspx)
- Windows Phone, however, supports direct hiding/showing of the keyboard.
-*/
-
-QWinRTInputContext::QWinRTInputContext(QWinRTScreen *screen)
- : m_screen(screen)
-{
- qCDebug(lcQpaInputMethods) << __FUNCTION__ << screen;
-
- QEventDispatcherWinRT::runOnXamlThread([this]() {
- ComPtr<IInputPaneStatics> statics;
- if (FAILED(GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_UI_ViewManagement_InputPane).Get(),
- &statics))) {
- qWarning("failed to retrieve input pane statics.");
- return S_OK;
- }
-
- ComPtr<IInputPane> inputPane;
- statics->GetForCurrentView(&inputPane);
- if (inputPane) {
- EventRegistrationToken showToken, hideToken;
- inputPane->add_Showing(Callback<InputPaneVisibilityHandler>(
- this, &QWinRTInputContext::onShowing).Get(), &showToken);
- inputPane->add_Hiding(Callback<InputPaneVisibilityHandler>(
- this, &QWinRTInputContext::onHiding).Get(), &hideToken);
-
- m_keyboardRect = getInputPaneRect(inputPane, m_screen->scaleFactor());
- m_isInputPanelVisible = !m_keyboardRect.isEmpty();
- } else {
- qWarning("failed to retrieve InputPane.");
- }
- return S_OK;
- });
-
- connect(QGuiApplication::inputMethod(), &QInputMethod::cursorRectangleChanged,
- this, &QWinRTInputContext::updateScreenCursorRect);
-}
-
-QRectF QWinRTInputContext::keyboardRect() const
-{
- return m_keyboardRect;
-}
-
-bool QWinRTInputContext::isInputPanelVisible() const
-{
- return m_isInputPanelVisible;
-}
-
-void QWinRTInputContext::updateScreenCursorRect()
-{
- m_screen->setCursorRect(QGuiApplication::inputMethod()->cursorRectangle());
-}
-
-HRESULT QWinRTInputContext::onShowing(IInputPane *pane, IInputPaneVisibilityEventArgs *)
-{
- qCDebug(lcQpaInputMethods) << __FUNCTION__ << pane;
- m_isInputPanelVisible = true;
- emitInputPanelVisibleChanged();
- return handleVisibilityChange(pane);
-}
-
-HRESULT QWinRTInputContext::onHiding(IInputPane *pane, IInputPaneVisibilityEventArgs *)
-{
- qCDebug(lcQpaInputMethods) << __FUNCTION__ << pane;
- m_isInputPanelVisible = false;
- emitInputPanelVisibleChanged();
- return handleVisibilityChange(pane);
-}
-
-HRESULT QWinRTInputContext::handleVisibilityChange(IInputPane *pane)
-{
- qCDebug(lcQpaInputMethods) << __FUNCTION__ << pane;
- const QRectF keyboardRect = getInputPaneRect(pane, m_screen->scaleFactor());
- if (m_keyboardRect != keyboardRect) {
- m_keyboardRect = keyboardRect;
- m_screen->setKeyboardRect(m_keyboardRect);
- emitKeyboardRectChanged();
- }
- return S_OK;
-}
-
-static HRESULT getInputPane(ComPtr<IInputPane2> *inputPane2)
-{
- ComPtr<IInputPaneStatics> factory;
- HRESULT hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_UI_ViewManagement_InputPane).Get(),
- &factory);
- if (FAILED(hr)) {
- qErrnoWarning(hr, "Failed to get input pane factory.");
- return hr;
- }
-
- ComPtr<IInputPane> inputPane;
- hr = factory->GetForCurrentView(&inputPane);
- if (FAILED(hr)) {
- qErrnoWarning(hr, "Failed to get input pane.");
- return hr;
- }
-
- hr = inputPane.As(inputPane2);
- if (FAILED(hr)) {
- qErrnoWarning(hr, "Failed to get extended input pane.");
- return hr;
- }
- return hr;
-}
-
-void QWinRTInputContext::showInputPanel()
-{
- qCDebug(lcQpaInputMethods) << __FUNCTION__;
-
- QEventDispatcherWinRT::runOnXamlThread([&]() {
- ComPtr<IInputPane2> inputPane;
- HRESULT hr = getInputPane(&inputPane);
- if (FAILED(hr))
- return S_OK;
- boolean success;
- hr = inputPane->TryShow(&success);
- if (FAILED(hr) || !success)
- qErrnoWarning(hr, "Failed to show input panel.");
- return S_OK;
- });
-}
-
-void QWinRTInputContext::hideInputPanel()
-{
- qCDebug(lcQpaInputMethods) << __FUNCTION__;
- if (!m_isInputPanelVisible)
- return;
-
- QEventDispatcherWinRT::runOnXamlThread([&]() {
- ComPtr<IInputPane2> inputPane;
- HRESULT hr = getInputPane(&inputPane);
- if (FAILED(hr))
- return S_OK;
- boolean success;
- hr = inputPane->TryHide(&success);
- if (FAILED(hr) || !success)
- qErrnoWarning(hr, "Failed to hide input panel.");
- return S_OK;
- });
-}
-
-QT_END_NAMESPACE
diff --git a/src/plugins/platforms/winrt/qwinrtinputcontext.h b/src/plugins/platforms/winrt/qwinrtinputcontext.h
deleted file mode 100644
index 59db90231f..0000000000
--- a/src/plugins/platforms/winrt/qwinrtinputcontext.h
+++ /dev/null
@@ -1,99 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 QWINRTINPUTCONTEXT_H
-#define QWINRTINPUTCONTEXT_H
-
-#include <qpa/qplatforminputcontext.h>
-#include <QtCore/QRectF>
-#include <QtCore/QLoggingCategory>
-
-#include <wrl.h>
-
-namespace ABI {
- namespace Windows {
- namespace UI {
- namespace Core {
- struct ICoreWindow;
- }
- namespace ViewManagement {
- struct IInputPane;
- struct IInputPaneVisibilityEventArgs;
- }
- }
- }
-}
-
-QT_BEGIN_NAMESPACE
-
-Q_DECLARE_LOGGING_CATEGORY(lcQpaInputMethods)
-
-class QWinRTScreen;
-class QWinRTInputContext : public QPlatformInputContext
-{
-public:
- explicit QWinRTInputContext(QWinRTScreen *);
-
- QRectF keyboardRect() const override;
-
- bool isInputPanelVisible() const override;
-
- void showInputPanel() override;
- void hideInputPanel() override;
-
-private slots:
- void updateScreenCursorRect();
-
-private:
- HRESULT onShowing(ABI::Windows::UI::ViewManagement::IInputPane *,
- ABI::Windows::UI::ViewManagement::IInputPaneVisibilityEventArgs *);
- HRESULT onHiding(ABI::Windows::UI::ViewManagement::IInputPane *,
- ABI::Windows::UI::ViewManagement::IInputPaneVisibilityEventArgs *);
-
- HRESULT handleVisibilityChange(ABI::Windows::UI::ViewManagement::IInputPane *);
-
- QWinRTScreen *m_screen;
- QRectF m_keyboardRect;
- QRectF m_cursorRect;
- bool m_isInputPanelVisible;
-};
-
-QT_END_NAMESPACE
-
-#endif // QWINRTINPUTCONTEXT_H
diff --git a/src/plugins/platforms/winrt/qwinrtintegration.cpp b/src/plugins/platforms/winrt/qwinrtintegration.cpp
deleted file mode 100644
index dd8cd80fd9..0000000000
--- a/src/plugins/platforms/winrt/qwinrtintegration.cpp
+++ /dev/null
@@ -1,317 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 "qwinrtintegration.h"
-#include "qwinrtwindow.h"
-#include "qwinrteventdispatcher.h"
-#include "qwinrtbackingstore.h"
-#include "qwinrtscreen.h"
-#include "qwinrtinputcontext.h"
-#include "qwinrtservices.h"
-#include "qwinrteglcontext.h"
-#include "qwinrttheme.h"
-#include "qwinrtclipboard.h"
-#if QT_CONFIG(draganddrop)
-#include "qwinrtdrag.h"
-#endif
-#if QT_CONFIG(accessibility)
-# include "uiautomation/qwinrtuiaaccessibility.h"
-#endif
-#if QT_CONFIG(opengl)
-#include <QtPlatformCompositorSupport/qpa/qplatformbackingstoreopenglsupport.h>
-#endif
-
-#include <QtGui/QOffscreenSurface>
-#include <QtGui/QOpenGLContext>
-#include <QtGui/QSurface>
-
-#include <QtFontDatabaseSupport/private/qwinrtfontdatabase_p.h>
-#include <QtEglSupport/private/qeglpbuffer_p.h>
-#include <qpa/qwindowsysteminterface.h>
-#include <qpa/qplatformwindow.h>
-#include <qpa/qplatformoffscreensurface.h>
-
-#include <qfunctions_winrt.h>
-
-#include <functional>
-#include <wrl.h>
-#include <windows.ui.xaml.h>
-#include <windows.applicationmodel.h>
-#include <windows.applicationmodel.core.h>
-#include <windows.ui.core.h>
-#include <windows.ui.viewmanagement.h>
-#include <windows.graphics.display.h>
-
-using namespace Microsoft::WRL;
-using namespace Microsoft::WRL::Wrappers;
-using namespace ABI::Windows::Foundation;
-using namespace ABI::Windows::ApplicationModel;
-using namespace ABI::Windows::ApplicationModel::Core;
-using namespace ABI::Windows::UI;
-using namespace ABI::Windows::UI::Core;
-using namespace ABI::Windows::UI::ViewManagement;
-using namespace ABI::Windows::Graphics::Display;
-using namespace ABI::Windows::ApplicationModel::Core;
-
-typedef IEventHandler<IInspectable *> ResumeHandler;
-typedef IEventHandler<SuspendingEventArgs *> SuspendHandler;
-
-QT_BEGIN_NAMESPACE
-
-typedef HRESULT (__stdcall ICoreApplication::*CoreApplicationCallbackRemover)(EventRegistrationToken);
-uint qHash(CoreApplicationCallbackRemover key) { void *ptr = *(void **)(&key); return qHash(ptr); }
-
-class QWinRTIntegrationPrivate
-{
-public:
- QPlatformFontDatabase *fontDatabase;
- QPlatformServices *platformServices;
- QPlatformClipboard *clipboard;
- QWinRTScreen *mainScreen;
- QScopedPointer<QWinRTInputContext> inputContext;
-#if QT_CONFIG(accessibility)
- QWinRTUiaAccessibility *accessibility;
-#endif
-
- ComPtr<ICoreApplication> application;
- QHash<CoreApplicationCallbackRemover, EventRegistrationToken> applicationTokens;
-};
-
-QWinRTIntegration::QWinRTIntegration() : d_ptr(new QWinRTIntegrationPrivate)
-{
- Q_D(QWinRTIntegration);
-
- d->fontDatabase = new QWinRTFontDatabase;
-
- HRESULT hr;
- hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_ApplicationModel_Core_CoreApplication).Get(),
- IID_PPV_ARGS(&d->application));
- Q_ASSERT_SUCCEEDED(hr);
- hr = d->application->add_Suspending(Callback<SuspendHandler>(this, &QWinRTIntegration::onSuspended).Get(),
- &d->applicationTokens[&ICoreApplication::remove_Suspending]);
- Q_ASSERT_SUCCEEDED(hr);
- hr = d->application->add_Resuming(Callback<ResumeHandler>(this, &QWinRTIntegration::onResume).Get(),
- &d->applicationTokens[&ICoreApplication::remove_Resuming]);
- Q_ASSERT_SUCCEEDED(hr);
-
- QEventDispatcherWinRT::runOnXamlThread([d]() {
- d->mainScreen = new QWinRTScreen;
- return S_OK;
- });
- d->inputContext.reset(new QWinRTInputContext(d->mainScreen));
-
- QWindowSystemInterface::handleScreenAdded(d->mainScreen);
- d->platformServices = new QWinRTServices;
- d->clipboard = new QWinRTClipboard;
-#if QT_CONFIG(accessibility)
- d->accessibility = new QWinRTUiaAccessibility;
-#endif
-}
-
-QWinRTIntegration::~QWinRTIntegration()
-{
- Q_D(QWinRTIntegration);
- HRESULT hr;
-
- // Do not execute this on Windows Phone as the application is already
- // shutting down and trying to unregister suspending/resume handler will
- // cause exceptions and assert in debug mode
- for (QHash<CoreApplicationCallbackRemover, EventRegistrationToken>::const_iterator i = d->applicationTokens.begin(); i != d->applicationTokens.end(); ++i) {
- hr = (d->application.Get()->*i.key())(i.value());
- Q_ASSERT_SUCCEEDED(hr);
- }
-
- QWindowSystemInterface::handleScreenRemoved(d->mainScreen);
- Windows::Foundation::Uninitialize();
-}
-
-bool QWinRTIntegration::succeeded() const
-{
- Q_D(const QWinRTIntegration);
- return d->mainScreen;
-}
-
-QAbstractEventDispatcher *QWinRTIntegration::createEventDispatcher() const
-{
- return new QWinRTEventDispatcher;
-}
-
-void QWinRTIntegration::initialize()
-{
- Q_D(const QWinRTIntegration);
- QEventDispatcherWinRT::runOnXamlThread([d]() {
- d->mainScreen->initialize();
- return S_OK;
- });
-}
-
-bool QWinRTIntegration::hasCapability(QPlatformIntegration::Capability cap) const
-{
- switch (cap) {
- case ThreadedPixmaps:
- case OpenGL:
- case ApplicationState:
- case NonFullScreenWindows:
- case MultipleWindows:
- case RasterGLSurface:
- return true;
- default:
- return QPlatformIntegration::hasCapability(cap);
- }
-}
-
-QVariant QWinRTIntegration::styleHint(StyleHint hint) const
-{
- return QWinRTTheme::styleHint(hint);
-}
-
-QPlatformWindow *QWinRTIntegration::createPlatformWindow(QWindow *window) const
-{
- return new QWinRTWindow(window);
-}
-
-QPlatformBackingStore *QWinRTIntegration::createPlatformBackingStore(QWindow *window) const
-{
- auto *backingStore = new QWinRTBackingStore(window);
-#if QT_CONFIG(opengl)
- backingStore->setOpenGLSupport(new QPlatformBackingStoreOpenGLSupport(backingStore));
-#endif
- return backingStore;
-}
-
-QPlatformOpenGLContext *QWinRTIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const
-{
- return new QWinRTEGLContext(context);
-}
-
-QPlatformFontDatabase *QWinRTIntegration::fontDatabase() const
-{
- Q_D(const QWinRTIntegration);
- return d->fontDatabase;
-}
-
-QPlatformInputContext *QWinRTIntegration::inputContext() const
-{
- Q_D(const QWinRTIntegration);
- return d->inputContext.data();
-}
-
-QPlatformServices *QWinRTIntegration::services() const
-{
- Q_D(const QWinRTIntegration);
- return d->platformServices;
-}
-
-QPlatformClipboard *QWinRTIntegration::clipboard() const
-{
- Q_D(const QWinRTIntegration);
- return d->clipboard;
-}
-
-#if QT_CONFIG(draganddrop)
-QPlatformDrag *QWinRTIntegration::drag() const
-{
- return QWinRTDrag::instance();
-}
-#endif // QT_CONFIG(draganddrop)
-
-#if QT_CONFIG(accessibility)
-QPlatformAccessibility *QWinRTIntegration::accessibility() const
-{
- Q_D(const QWinRTIntegration);
- return d->accessibility;
-}
-#endif // QT_CONFIG(accessibility)
-
-Qt::KeyboardModifiers QWinRTIntegration::queryKeyboardModifiers() const
-{
- Q_D(const QWinRTIntegration);
- return d->mainScreen->keyboardModifiers();
-}
-
-QStringList QWinRTIntegration::themeNames() const
-{
- return QStringList(QLatin1String("winrt"));
-}
-
-QPlatformTheme *QWinRTIntegration::createPlatformTheme(const QString &name) const
-{
- if (name == QLatin1String("winrt"))
- return new QWinRTTheme();
-
- return 0;
-}
-
-// System-level integration points
-
-HRESULT QWinRTIntegration::onSuspended(IInspectable *, ISuspendingEventArgs *)
-{
- QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationSuspended);
- QWindowSystemInterface::flushWindowSystemEvents();
- return S_OK;
-}
-
-HRESULT QWinRTIntegration::onResume(IInspectable *, IInspectable *)
-{
- // First the system invokes onResume and then changes
- // the visibility of the screen to be active.
- QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationHidden);
- return S_OK;
-}
-
-QPlatformOffscreenSurface *QWinRTIntegration::createPlatformOffscreenSurface(QOffscreenSurface *surface) const
-{
- QEGLPbuffer *pbuffer = nullptr;
- HRESULT hr = QEventDispatcherWinRT::runOnXamlThread([&pbuffer, surface]() {
- pbuffer = new QEGLPbuffer(QWinRTEGLContext::display(), surface->requestedFormat(), surface);
- return S_OK;
- });
- if (hr == UI_E_WINDOW_CLOSED) {
- // This is only used for shutdown of applications.
- // In case we do not return an empty surface the scenegraph will try
- // to create a new native window during application exit causing crashes
- // or assertions.
- return new QPlatformOffscreenSurface(surface);
- }
-
- return pbuffer;
-}
-
-
-QT_END_NAMESPACE
diff --git a/src/plugins/platforms/winrt/qwinrtintegration.h b/src/plugins/platforms/winrt/qwinrtintegration.h
deleted file mode 100644
index e944ed5d79..0000000000
--- a/src/plugins/platforms/winrt/qwinrtintegration.h
+++ /dev/null
@@ -1,113 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 QWINRTINTEGRATION_H
-#define QWINRTINTEGRATION_H
-
-#include <qpa/qplatformintegration.h>
-
-namespace ABI {
- namespace Windows {
- namespace ApplicationModel {
- struct ISuspendingEventArgs;
- }
- namespace Foundation {
- struct IAsyncAction;
- }
- }
-}
-struct IAsyncInfo;
-struct IInspectable;
-
-QT_BEGIN_NAMESPACE
-
-class QAbstractEventDispatcher;
-
-class QWinRTIntegrationPrivate;
-class QWinRTIntegration : public QPlatformIntegration
-{
-private:
- explicit QWinRTIntegration();
-public:
- ~QWinRTIntegration() override;
-
- static QWinRTIntegration *create()
- {
- QScopedPointer<QWinRTIntegration> integration(new QWinRTIntegration);
- return integration->succeeded() ? integration.take() : nullptr;
- }
-
- bool succeeded() const;
-
- bool hasCapability(QPlatformIntegration::Capability cap) const override;
- QVariant styleHint(StyleHint hint) const override;
-
- QPlatformWindow *createPlatformWindow(QWindow *window) const override;
- QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const override;
- QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const override;
- QAbstractEventDispatcher *createEventDispatcher() const override;
- void initialize() override;
- QPlatformFontDatabase *fontDatabase() const override;
- QPlatformInputContext *inputContext() const override;
- QPlatformServices *services() const override;
- QPlatformClipboard *clipboard() const override;
-#if QT_CONFIG(draganddrop)
- QPlatformDrag *drag() const override;
-#endif
-#if QT_CONFIG(accessibility)
- QPlatformAccessibility *accessibility() const override;
-#endif
-
- Qt::KeyboardModifiers queryKeyboardModifiers() const override;
-
- QStringList themeNames() const override;
- QPlatformTheme *createPlatformTheme(const QString &name) const override;
-
- QPlatformOffscreenSurface *createPlatformOffscreenSurface(QOffscreenSurface *surface) const override;
-private:
- HRESULT onSuspended(IInspectable *, ABI::Windows::ApplicationModel::ISuspendingEventArgs *);
- HRESULT onResume(IInspectable *, IInspectable *);
-
- QScopedPointer<QWinRTIntegrationPrivate> d_ptr;
- Q_DECLARE_PRIVATE(QWinRTIntegration)
-};
-
-QT_END_NAMESPACE
-
-#endif // QWINRTINTEGRATION_H
diff --git a/src/plugins/platforms/winrt/qwinrtmessagedialoghelper.cpp b/src/plugins/platforms/winrt/qwinrtmessagedialoghelper.cpp
deleted file mode 100644
index 7016b47f7e..0000000000
--- a/src/plugins/platforms/winrt/qwinrtmessagedialoghelper.cpp
+++ /dev/null
@@ -1,247 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 "qwinrtmessagedialoghelper.h"
-#include "qwinrttheme.h"
-
-#include <QtGui/QTextDocument>
-#include <QtCore/qfunctions_winrt.h>
-#include <private/qeventdispatcher_winrt_p.h>
-
-#include <functional>
-#include <windows.ui.popups.h>
-#include <windows.foundation.h>
-#include <windows.foundation.collections.h>
-#include <wrl.h>
-
-using namespace ABI::Windows::Foundation;
-using namespace ABI::Windows::Foundation::Collections;
-using namespace ABI::Windows::UI::Popups;
-using namespace Microsoft::WRL;
-using namespace Microsoft::WRL::Wrappers;
-
-typedef IAsyncOperationCompletedHandler<IUICommand *> DialogCompletedHandler;
-
-QT_BEGIN_NAMESPACE
-
-class CommandId : public RuntimeClass<IInspectable>
-{
-public:
- CommandId(QPlatformDialogHelper::StandardButton button)
- : button(button) { }
- QPlatformDialogHelper::StandardButton button;
-};
-
-class QWinRTMessageDialogHelperPrivate
-{
-public:
- const QWinRTTheme *theme;
- bool shown;
- ComPtr<IAsyncInfo> info;
- QEventLoop loop;
-};
-
-QWinRTMessageDialogHelper::QWinRTMessageDialogHelper(const QWinRTTheme *theme)
- : QPlatformMessageDialogHelper(), d_ptr(new QWinRTMessageDialogHelperPrivate)
-{
- Q_D(QWinRTMessageDialogHelper);
-
- d->theme = theme;
- d->shown = false;
-}
-
-QWinRTMessageDialogHelper::~QWinRTMessageDialogHelper()
-{
- Q_D(QWinRTMessageDialogHelper);
-
- if (d->shown)
- hide();
-}
-
-void QWinRTMessageDialogHelper::exec()
-{
- Q_D(QWinRTMessageDialogHelper);
-
- if (!d->shown)
- show(Qt::Dialog, Qt::ApplicationModal, nullptr);
- d->loop.exec();
-}
-
-bool QWinRTMessageDialogHelper::show(Qt::WindowFlags windowFlags, Qt::WindowModality windowModality, QWindow *parent)
-{
- Q_UNUSED(windowFlags)
- Q_UNUSED(windowModality)
- Q_UNUSED(parent)
- Q_D(QWinRTMessageDialogHelper);
-
- QSharedPointer<QMessageDialogOptions> options = this->options();
- if (!options.data())
- return false;
-
- const QString informativeText = options->informativeText();
- const QString title = options->windowTitle();
- const QString text = informativeText.isEmpty() ? options->text() : (options->text() + QLatin1Char('\n') + informativeText);
- if (Qt::mightBeRichText(text)) {
- qWarning("Rich text detected, defaulting to QtWidgets-based dialog.");
- return false;
- }
-
- HRESULT hr;
- ComPtr<IMessageDialogFactory> dialogFactory;
- hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_UI_Popups_MessageDialog).Get(),
- IID_PPV_ARGS(&dialogFactory));
- RETURN_FALSE_IF_FAILED("Failed to create dialog factory");
-
- ComPtr<IUICommandFactory> commandFactory;
- hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_UI_Popups_UICommand).Get(),
- IID_PPV_ARGS(&commandFactory));
- RETURN_FALSE_IF_FAILED("Failed to create command factory");
-
- ComPtr<IMessageDialog> dialog;
- HStringReference nativeText(reinterpret_cast<LPCWSTR>(text.utf16()),
- uint(text.size()));
- if (!title.isEmpty()) {
- HStringReference nativeTitle(reinterpret_cast<LPCWSTR>(title.utf16()),
- uint(title.size()));
- hr = dialogFactory->CreateWithTitle(nativeText.Get(), nativeTitle.Get(), &dialog);
- RETURN_FALSE_IF_FAILED("Failed to create dialog with title");
- } else {
- hr = dialogFactory->Create(nativeText.Get(), &dialog);
- RETURN_FALSE_IF_FAILED("Failed to create dialog");
- }
-
- hr = QEventDispatcherWinRT::runOnXamlThread([this, d, options, commandFactory, dialog]() {
- HRESULT hr;
-
- // Add Buttons
- ComPtr<IVector<IUICommand *>> dialogCommands;
- hr = dialog->get_Commands(&dialogCommands);
- RETURN_HR_IF_FAILED("Failed to get dialog commands");
-
- // If no button is specified we need to create one to get close notification
- int buttons = options->standardButtons();
- if (buttons == 0)
- buttons = Ok;
-
- for (int i = FirstButton; i < LastButton; i<<=1) {
- if (!(buttons & i))
- continue;
- // Add native command
- const QString label = d->theme->standardButtonText(i);
- HStringReference nativeLabel(reinterpret_cast<LPCWSTR>(label.utf16()),
- uint(label.size()));
- ComPtr<IUICommand> command;
- hr = commandFactory->Create(nativeLabel.Get(), &command);
- RETURN_HR_IF_FAILED("Failed to create message box command");
- ComPtr<IInspectable> id = Make<CommandId>(static_cast<StandardButton>(i));
- hr = command->put_Id(id.Get());
- RETURN_HR_IF_FAILED("Failed to set command ID");
- hr = dialogCommands->Append(command.Get());
- if (hr == E_BOUNDS) {
- qErrnoWarning(hr, "The WinRT message dialog supports a maximum of three buttons");
- continue;
- }
- RETURN_HR_IF_FAILED("Failed to append message box command");
- if (i == Abort || i == Cancel || i == Close) {
- quint32 size;
- hr = dialogCommands->get_Size(&size);
- RETURN_HR_IF_FAILED("Failed to get command list size");
- hr = dialog->put_CancelCommandIndex(size - 1);
- RETURN_HR_IF_FAILED("Failed to set cancel index");
- }
- }
-
- ComPtr<IAsyncOperation<IUICommand *>> op;
- hr = dialog->ShowAsync(&op);
- RETURN_HR_IF_FAILED("Failed to show dialog");
- hr = op->put_Completed(Callback<DialogCompletedHandler>(this, &QWinRTMessageDialogHelper::onCompleted).Get());
- RETURN_HR_IF_FAILED("Failed to set dialog callback");
- d->shown = true;
- hr = op.As(&d->info);
- RETURN_HR_IF_FAILED("Failed to acquire AsyncInfo for MessageDialog");
- return hr;
- });
-
- RETURN_FALSE_IF_FAILED("Failed to show dialog")
- return true;
-}
-
-void QWinRTMessageDialogHelper::hide()
-{
- Q_D(QWinRTMessageDialogHelper);
-
- if (!d->shown)
- return;
-
- HRESULT hr = d->info->Cancel();
- if (FAILED(hr))
- qErrnoWarning(hr, "Failed to cancel dialog operation");
-
- d->shown = false;
-}
-
-HRESULT QWinRTMessageDialogHelper::onCompleted(IAsyncOperation<IUICommand *> *asyncInfo, AsyncStatus status)
-{
- Q_UNUSED(status);
- Q_D(QWinRTMessageDialogHelper);
-
- QEventLoopLocker locker(&d->loop);
-
- d->shown = false;
-
- if (status == Canceled) {
- emit reject();
- return S_OK;
- }
-
- HRESULT hr;
- ComPtr<IUICommand> command;
- hr = asyncInfo->GetResults(&command);
- RETURN_OK_IF_FAILED("Failed to get command");
-
- ComPtr<CommandId> id;
- hr = command->get_Id(&id);
- RETURN_OK_IF_FAILED("Failed to get command ID");
-
- ButtonRole role = buttonRole(id->button);
- emit clicked(id->button, role);
- return S_OK;
-}
-
-QT_END_NAMESPACE
diff --git a/src/plugins/platforms/winrt/qwinrtmessagedialoghelper.h b/src/plugins/platforms/winrt/qwinrtmessagedialoghelper.h
deleted file mode 100644
index ab704b1c7d..0000000000
--- a/src/plugins/platforms/winrt/qwinrtmessagedialoghelper.h
+++ /dev/null
@@ -1,88 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 QWINRTMESSAGEDIALOGHELPER_H
-#define QWINRTMESSAGEDIALOGHELPER_H
-
-#include <qpa/qplatformdialoghelper.h>
-#include <QtCore/qt_windows.h>
-
-namespace ABI {
- namespace Windows {
- namespace UI {
- namespace Popups {
- struct IUICommand;
- }
- }
- namespace Foundation {
- enum class AsyncStatus;
- template <typename T> struct IAsyncOperation;
- }
- }
-}
-
-QT_BEGIN_NAMESPACE
-
-class QWinRTTheme;
-
-class QWinRTMessageDialogHelperPrivate;
-class QWinRTMessageDialogHelper : public QPlatformMessageDialogHelper
-{
- Q_OBJECT
-public:
- explicit QWinRTMessageDialogHelper(const QWinRTTheme *theme);
- ~QWinRTMessageDialogHelper() override;
-
- void exec() override;
- bool show(Qt::WindowFlags windowFlags,
- Qt::WindowModality windowModality,
- QWindow *parent) override;
- void hide() override;
-
-private:
- HRESULT onCompleted(ABI::Windows::Foundation::IAsyncOperation<ABI::Windows::UI::Popups::IUICommand *> *asyncInfo,
- ABI::Windows::Foundation::AsyncStatus status);
-
- QScopedPointer<QWinRTMessageDialogHelperPrivate> d_ptr;
- Q_DECLARE_PRIVATE(QWinRTMessageDialogHelper)
-};
-
-QT_END_NAMESPACE
-
-#endif // QWINRTMESSAGEDIALOGHELPER_H
diff --git a/src/plugins/platforms/winrt/qwinrtscreen.cpp b/src/plugins/platforms/winrt/qwinrtscreen.cpp
deleted file mode 100644
index 86ab7651c6..0000000000
--- a/src/plugins/platforms/winrt/qwinrtscreen.cpp
+++ /dev/null
@@ -1,1543 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 "qwinrtscreen.h"
-
-#include "qwinrtbackingstore.h"
-#include "qwinrtinputcontext.h"
-#include "qwinrtcursor.h"
-#if QT_CONFIG(draganddrop)
-#include "qwinrtdrag.h"
-#endif
-#include "qwinrtwindow.h"
-#include "qwinrtcanvas.h"
-#include <private/qeventdispatcher_winrt_p.h>
-#include <private/qhighdpiscaling_p.h>
-
-#include <QtCore/qdebug.h>
-#include <QtCore/QLoggingCategory>
-#include <QtGui/QSurfaceFormat>
-#include <QtGui/QGuiApplication>
-#include <qpa/qwindowsysteminterface.h>
-#include <QtCore/qt_windows.h>
-#include <QtCore/qfunctions_winrt.h>
-
-#include <functional>
-#include <wrl.h>
-#include <windows.system.h>
-#include <Windows.ApplicationModel.h>
-#include <Windows.ApplicationModel.core.h>
-#include <windows.devices.input.h>
-#include <windows.ui.h>
-#include <windows.ui.core.h>
-#include <windows.ui.input.h>
-#include <windows.ui.xaml.h>
-#include <windows.ui.viewmanagement.h>
-#include <windows.graphics.display.h>
-#include <windows.foundation.h>
-
-using namespace Microsoft::WRL;
-using namespace Microsoft::WRL::Wrappers;
-using namespace ABI::Windows::ApplicationModel;
-using namespace ABI::Windows::ApplicationModel::Core;
-using namespace ABI::Windows::Foundation;
-using namespace ABI::Windows::System;
-using namespace ABI::Windows::UI;
-using namespace ABI::Windows::UI::Core;
-using namespace ABI::Windows::UI::Input;
-using namespace ABI::Windows::UI::ViewManagement;
-using namespace ABI::Windows::Devices::Input;
-using namespace ABI::Windows::Graphics::Display;
-
-typedef ITypedEventHandler<CoreWindow*, WindowActivatedEventArgs*> ActivatedHandler;
-typedef ITypedEventHandler<CoreWindow*, CoreWindowEventArgs*> ClosedHandler;
-typedef ITypedEventHandler<CoreWindow*, CharacterReceivedEventArgs*> CharacterReceivedHandler;
-typedef ITypedEventHandler<CoreWindow*, InputEnabledEventArgs*> InputEnabledHandler;
-typedef ITypedEventHandler<CoreWindow*, KeyEventArgs*> KeyHandler;
-typedef ITypedEventHandler<CoreWindow*, PointerEventArgs*> PointerHandler;
-typedef ITypedEventHandler<CoreWindow*, VisibilityChangedEventArgs*> VisibilityChangedHandler;
-typedef ITypedEventHandler<DisplayInformation*, IInspectable*> DisplayInformationHandler;
-typedef ITypedEventHandler<ICorePointerRedirector*, PointerEventArgs*> RedirectHandler;
-typedef ITypedEventHandler<ApplicationView*, IInspectable*> VisibleBoundsChangedHandler;
-
-QT_BEGIN_NAMESPACE
-
-Q_LOGGING_CATEGORY(lcQpaEvents, "qt.qpa.events")
-
-#if !defined(QT_NO_DEBUG_STREAM)
-QDebug operator<<(QDebug dbg, QWinRTScreen::MousePositionTransition transition)
-{
- QDebugStateSaver saver(dbg);
- dbg.nospace() << "QWinRTScreen::MousePositionTransition::";
- switch (transition) {
- case QWinRTScreen::MousePositionTransition::MovedOut:
- dbg << "MovedOut";
- break;
- case QWinRTScreen::MousePositionTransition::MovedIn:
- dbg << "MovedIn";
- break;
- case QWinRTScreen::MousePositionTransition::StayedOut:
- dbg << "StayedOut";
- break;
- case QWinRTScreen::MousePositionTransition::StayedIn:
- dbg << "StayedIn";
- break;
- }
- return dbg;
-}
-#endif
-
-struct KeyInfo {
- KeyInfo()
- {
- }
-
- KeyInfo(quint32 virtualKey)
- : virtualKey(virtualKey)
- {
- }
-
- QString text;
- quint32 virtualKey{0};
- bool isAutoRepeat{false};
-};
-
-static inline Qt::ScreenOrientations qtOrientationsFromNative(DisplayOrientations native)
-{
- Qt::ScreenOrientations orientations = Qt::PrimaryOrientation;
- if (native & DisplayOrientations_Portrait)
- orientations |= Qt::PortraitOrientation;
- if (native & DisplayOrientations_PortraitFlipped)
- orientations |= Qt::InvertedPortraitOrientation;
- if (native & DisplayOrientations_Landscape)
- orientations |= Qt::LandscapeOrientation;
- if (native & DisplayOrientations_LandscapeFlipped)
- orientations |= Qt::InvertedLandscapeOrientation;
- return orientations;
-}
-
-static inline DisplayOrientations nativeOrientationsFromQt(Qt::ScreenOrientations orientation)
-{
- DisplayOrientations native = DisplayOrientations_None;
- if (orientation & Qt::PortraitOrientation)
- native |= DisplayOrientations_Portrait;
- if (orientation & Qt::InvertedPortraitOrientation)
- native |= DisplayOrientations_PortraitFlipped;
- if (orientation & Qt::LandscapeOrientation)
- native |= DisplayOrientations_Landscape;
- if (orientation & Qt::InvertedLandscapeOrientation)
- native |= DisplayOrientations_LandscapeFlipped;
- return native;
-}
-
-static inline bool qIsNonPrintable(quint32 keyCode)
-{
- switch (keyCode) {
- case '\b':
- case '\n':
- case '\t':
- case '\r':
- case '\v':
- case '\f':
- return true;
- default:
- return false;
- }
-}
-
-// Return Qt meta key from VirtualKey
-static inline Qt::Key qKeyFromVirtual(VirtualKey key)
-{
- switch (key) {
-
- default:
- return Qt::Key_unknown;
-
- // Non-printable characters
- case VirtualKey_Enter:
- return Qt::Key_Enter;
- case VirtualKey_Tab:
- return Qt::Key_Tab;
- case VirtualKey_Back:
- return Qt::Key_Backspace;
-
- // Modifiers
- case VirtualKey_Shift:
- case VirtualKey_LeftShift:
- case VirtualKey_RightShift:
- return Qt::Key_Shift;
- case VirtualKey_Control:
- case VirtualKey_LeftControl:
- case VirtualKey_RightControl:
- return Qt::Key_Control;
- case VirtualKey_Menu:
- case VirtualKey_LeftMenu:
- case VirtualKey_RightMenu:
- return Qt::Key_Alt;
- case VirtualKey_LeftWindows:
- case VirtualKey_RightWindows:
- return Qt::Key_Meta;
-
- // Toggle keys
- case VirtualKey_CapitalLock:
- return Qt::Key_CapsLock;
- case VirtualKey_NumberKeyLock:
- return Qt::Key_NumLock;
- case VirtualKey_Scroll:
- return Qt::Key_ScrollLock;
-
- // East-Asian language keys
- case VirtualKey_Kana:
- //case VirtualKey_Hangul: // Same enum as Kana
- return Qt::Key_Kana_Shift;
- case VirtualKey_Junja:
- return Qt::Key_Hangul_Jeonja;
- case VirtualKey_Kanji:
- //case VirtualKey_Hanja: // Same enum as Kanji
- return Qt::Key_Kanji;
- case VirtualKey_ModeChange:
- return Qt::Key_Mode_switch;
- case VirtualKey_Convert:
- return Qt::Key_Henkan;
- case VirtualKey_NonConvert:
- return Qt::Key_Muhenkan;
-
- // Misc. keys
- case VirtualKey_Cancel:
- return Qt::Key_Cancel;
- case VirtualKey_Clear:
- return Qt::Key_Clear;
- case VirtualKey_Application:
- return Qt::Key_ApplicationLeft;
- case VirtualKey_Sleep:
- return Qt::Key_Sleep;
- case VirtualKey_Pause:
- return Qt::Key_Pause;
- case VirtualKey_PageUp:
- return Qt::Key_PageUp;
- case VirtualKey_PageDown:
- return Qt::Key_PageDown;
- case VirtualKey_End:
- return Qt::Key_End;
- case VirtualKey_Home:
- return Qt::Key_Home;
- case VirtualKey_Left:
- return Qt::Key_Left;
- case VirtualKey_Up:
- return Qt::Key_Up;
- case VirtualKey_Right:
- return Qt::Key_Right;
- case VirtualKey_Down:
- return Qt::Key_Down;
- case VirtualKey_Select:
- return Qt::Key_Select;
- case VirtualKey_Print:
- return Qt::Key_Print;
- case VirtualKey_Execute:
- return Qt::Key_Execute;
- case VirtualKey_Insert:
- return Qt::Key_Insert;
- case VirtualKey_Delete:
- return Qt::Key_Delete;
- case VirtualKey_Help:
- return Qt::Key_Help;
- case VirtualKey_Snapshot:
- return Qt::Key_Camera;
- case VirtualKey_Escape:
- return Qt::Key_Escape;
-
- // Function Keys
- case VirtualKey_F1:
- return Qt::Key_F1;
- case VirtualKey_F2:
- return Qt::Key_F2;
- case VirtualKey_F3:
- return Qt::Key_F3;
- case VirtualKey_F4:
- return Qt::Key_F4;
- case VirtualKey_F5:
- return Qt::Key_F5;
- case VirtualKey_F6:
- return Qt::Key_F6;
- case VirtualKey_F7:
- return Qt::Key_F7;
- case VirtualKey_F8:
- return Qt::Key_F8;
- case VirtualKey_F9:
- return Qt::Key_F9;
- case VirtualKey_F10:
- return Qt::Key_F10;
- case VirtualKey_F11:
- return Qt::Key_F11;
- case VirtualKey_F12:
- return Qt::Key_F12;
- case VirtualKey_F13:
- return Qt::Key_F13;
- case VirtualKey_F14:
- return Qt::Key_F14;
- case VirtualKey_F15:
- return Qt::Key_F15;
- case VirtualKey_F16:
- return Qt::Key_F16;
- case VirtualKey_F17:
- return Qt::Key_F17;
- case VirtualKey_F18:
- return Qt::Key_F18;
- case VirtualKey_F19:
- return Qt::Key_F19;
- case VirtualKey_F20:
- return Qt::Key_F20;
- case VirtualKey_F21:
- return Qt::Key_F21;
- case VirtualKey_F22:
- return Qt::Key_F22;
- case VirtualKey_F23:
- return Qt::Key_F23;
- case VirtualKey_F24:
- return Qt::Key_F24;
-
- // Character keys
- case VirtualKey_Space:
- return Qt::Key_Space;
- case VirtualKey_Number0:
- case VirtualKey_NumberPad0:
- return Qt::Key_0;
- case VirtualKey_Number1:
- case VirtualKey_NumberPad1:
- return Qt::Key_1;
- case VirtualKey_Number2:
- case VirtualKey_NumberPad2:
- return Qt::Key_2;
- case VirtualKey_Number3:
- case VirtualKey_NumberPad3:
- return Qt::Key_3;
- case VirtualKey_Number4:
- case VirtualKey_NumberPad4:
- return Qt::Key_4;
- case VirtualKey_Number5:
- case VirtualKey_NumberPad5:
- return Qt::Key_5;
- case VirtualKey_Number6:
- case VirtualKey_NumberPad6:
- return Qt::Key_6;
- case VirtualKey_Number7:
- case VirtualKey_NumberPad7:
- return Qt::Key_7;
- case VirtualKey_Number8:
- case VirtualKey_NumberPad8:
- return Qt::Key_8;
- case VirtualKey_Number9:
- case VirtualKey_NumberPad9:
- return Qt::Key_9;
- case VirtualKey_A:
- return Qt::Key_A;
- case VirtualKey_B:
- return Qt::Key_B;
- case VirtualKey_C:
- return Qt::Key_C;
- case VirtualKey_D:
- return Qt::Key_D;
- case VirtualKey_E:
- return Qt::Key_E;
- case VirtualKey_F:
- return Qt::Key_F;
- case VirtualKey_G:
- return Qt::Key_G;
- case VirtualKey_H:
- return Qt::Key_H;
- case VirtualKey_I:
- return Qt::Key_I;
- case VirtualKey_J:
- return Qt::Key_J;
- case VirtualKey_K:
- return Qt::Key_K;
- case VirtualKey_L:
- return Qt::Key_L;
- case VirtualKey_M:
- return Qt::Key_M;
- case VirtualKey_N:
- return Qt::Key_N;
- case VirtualKey_O:
- return Qt::Key_O;
- case VirtualKey_P:
- return Qt::Key_P;
- case VirtualKey_Q:
- return Qt::Key_Q;
- case VirtualKey_R:
- return Qt::Key_R;
- case VirtualKey_S:
- return Qt::Key_S;
- case VirtualKey_T:
- return Qt::Key_T;
- case VirtualKey_U:
- return Qt::Key_U;
- case VirtualKey_V:
- return Qt::Key_V;
- case VirtualKey_W:
- return Qt::Key_W;
- case VirtualKey_X:
- return Qt::Key_X;
- case VirtualKey_Y:
- return Qt::Key_Y;
- case VirtualKey_Z:
- return Qt::Key_Z;
- case VirtualKey_Multiply:
- return Qt::Key_9;
- case VirtualKey_Add:
- return Qt::Key_9;
- case VirtualKey_Separator:
- return Qt::Key_9;
- case VirtualKey_Subtract:
- return Qt::Key_9;
- case VirtualKey_Decimal:
- return Qt::Key_9;
- case VirtualKey_Divide:
- return Qt::Key_9;
-
- /* Keys with no matching Qt enum (?)
- case VirtualKey_None:
- case VirtualKey_LeftButton:
- case VirtualKey_RightButton:
- case VirtualKey_MiddleButton:
- case VirtualKey_XButton1:
- case VirtualKey_XButton2:
- case VirtualKey_Final:
- case VirtualKey_Accept:*/
- }
-}
-
-// Some keys like modifiers, caps lock etc. should not be automatically repeated if the key is held down
-static inline bool shouldAutoRepeat(Qt::Key key)
-{
- switch (key) {
- case Qt::Key_Shift:
- case Qt::Key_Control:
- case Qt::Key_Alt:
- case Qt::Key_Meta:
- case Qt::Key_CapsLock:
- case Qt::Key_NumLock:
- case Qt::Key_ScrollLock:
- return false;
- default:
- return true;
- }
-}
-
-static inline Qt::Key qKeyFromCode(quint32 code, int mods)
-{
- if (code >= 'a' && code <= 'z')
- code = toupper(code);
- if ((mods & Qt::ControlModifier) != 0) {
- if (code >= 0 && code <= 31) // Ctrl+@..Ctrl+A..CTRL+Z..Ctrl+_
- code += '@'; // to @..A..Z.._
- }
- return static_cast<Qt::Key>(code & 0xff);
-}
-
-typedef HRESULT (__stdcall ICoreWindow::*CoreWindowCallbackRemover)(EventRegistrationToken);
-uint qHash(CoreWindowCallbackRemover key) { void *ptr = *(void **)(&key); return qHash(ptr); }
-typedef HRESULT (__stdcall IDisplayInformation::*DisplayCallbackRemover)(EventRegistrationToken);
-uint qHash(DisplayCallbackRemover key) { void *ptr = *(void **)(&key); return qHash(ptr); }
-typedef HRESULT (__stdcall ICorePointerRedirector::*RedirectorCallbackRemover)(EventRegistrationToken);
-uint qHash(RedirectorCallbackRemover key) { void *ptr = *(void **)(&key); return qHash(ptr); }
-typedef HRESULT (__stdcall IApplicationView2::*ApplicationView2CallbackRemover)(EventRegistrationToken);
-uint qHash(ApplicationView2CallbackRemover key) { void *ptr = *(void **)(&key); return qHash(ptr); }
-
-class QWinRTScreenPrivate
-{
-public:
- QTouchDevice *touchDevice;
- ComPtr<ICoreWindow> coreWindow;
- ComPtr<ICorePointerRedirector> redirect;
- ComPtr<QWinRTCanvas> canvas;
- ComPtr<IApplicationView> view;
- ComPtr<IDisplayInformation> displayInformation;
-
- QScopedPointer<QWinRTCursor> cursor;
- QHash<quint32, QWindowSystemInterface::TouchPoint> touchPoints;
- QRectF logicalRect;
- QRectF visibleRect;
- QSurfaceFormat surfaceFormat;
- qreal logicalDpi;
- QDpi physicalDpi;
- qreal scaleFactor;
- Qt::ScreenOrientation nativeOrientation;
- Qt::ScreenOrientation orientation;
- QList<QWindow *> visibleWindows;
- QHash<Qt::Key, KeyInfo> activeKeys;
- QHash<CoreWindowCallbackRemover, EventRegistrationToken> windowTokens;
- QHash<DisplayCallbackRemover, EventRegistrationToken> displayTokens;
- QHash<RedirectorCallbackRemover, EventRegistrationToken> redirectTokens;
- QHash<ApplicationView2CallbackRemover, EventRegistrationToken> view2Tokens;
- ComPtr<IApplicationView2> view2;
- QAtomicPointer<QWinRTWindow> mouseGrabWindow;
- QAtomicPointer<QWinRTWindow> keyboardGrabWindow;
- QWindow *currentPressWindow = nullptr;
- QWindow *currentTargetWindow = nullptr;
- bool firstMouseMove = true;
- bool resizePending = false;
-};
-
-// To be called from the XAML thread
-QWinRTScreen::QWinRTScreen()
- : d_ptr(new QWinRTScreenPrivate)
-{
- Q_D(QWinRTScreen);
- qCDebug(lcQpaWindows) << __FUNCTION__;
- d->orientation = Qt::PrimaryOrientation;
- d->touchDevice = nullptr;
-
- HRESULT hr;
- ComPtr<Xaml::IWindowStatics> windowStatics;
- hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_UI_Xaml_Window).Get(),
- IID_PPV_ARGS(&windowStatics));
- Q_ASSERT_SUCCEEDED(hr);
- ComPtr<Xaml::IWindow> window;
- hr = windowStatics->get_Current(&window);
- Q_ASSERT_SUCCEEDED(hr);
- hr = window->Activate();
- Q_ASSERT_SUCCEEDED(hr);
-
- hr = window->get_CoreWindow(&d->coreWindow);
- Q_ASSERT_SUCCEEDED(hr);
-
- hr = d->coreWindow.As(&d->redirect);
- Q_ASSERT_SUCCEEDED(hr);
-
- hr = d->coreWindow->Activate();
- Q_ASSERT_SUCCEEDED(hr);
-
- Rect rect;
- hr = d->coreWindow->get_Bounds(&rect);
- Q_ASSERT_SUCCEEDED(hr);
- d->logicalRect = QRectF(0.0f, 0.0f, rect.Width, rect.Height);
- d->visibleRect = QRectF(0.0f, 0.0f, rect.Width, rect.Height);
-
- // Orientation handling
- ComPtr<IDisplayInformationStatics> displayInformationStatics;
- hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Graphics_Display_DisplayInformation).Get(),
- IID_PPV_ARGS(&displayInformationStatics));
- Q_ASSERT_SUCCEEDED(hr);
-
- hr = displayInformationStatics->GetForCurrentView(&d->displayInformation);
- Q_ASSERT_SUCCEEDED(hr);
-
- // Set native orientation
- DisplayOrientations displayOrientation;
- hr = d->displayInformation->get_NativeOrientation(&displayOrientation);
- Q_ASSERT_SUCCEEDED(hr);
- d->nativeOrientation = static_cast<Qt::ScreenOrientation>(static_cast<int>(qtOrientationsFromNative(displayOrientation)));
- // Set initial pixel density
- onDpiChanged(nullptr, nullptr);
- d->orientation = d->nativeOrientation;
-
- ComPtr<IApplicationViewStatics2> applicationViewStatics;
- hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_UI_ViewManagement_ApplicationView).Get(),
- IID_PPV_ARGS(&applicationViewStatics));
- RETURN_VOID_IF_FAILED("Could not get ApplicationViewStatics");
-
- hr = applicationViewStatics->GetForCurrentView(&d->view);
- RETURN_VOID_IF_FAILED("Could not access currentView");
-
- d->canvas = Make<QWinRTCanvas>([this]() { return topWindow(); });
-
- ComPtr<Xaml::IFrameworkElement> frameworkElement;
- hr = d->canvas.As(&frameworkElement);
- Q_ASSERT_SUCCEEDED(hr);
- hr = frameworkElement->put_Width(d->logicalRect.width());
- Q_ASSERT_SUCCEEDED(hr);
- hr = frameworkElement->put_Height(d->logicalRect.height());
- Q_ASSERT_SUCCEEDED(hr);
-
- ComPtr<Xaml::IUIElement> uiElement;
- hr = d->canvas.As(&uiElement);
- Q_ASSERT_SUCCEEDED(hr);
-
-#if QT_CONFIG(draganddrop)
- QWinRTDrag::instance()->setUiElement(uiElement);
-#endif
- hr = window->put_Content(uiElement.Get());
- Q_ASSERT_SUCCEEDED(hr);
-
- d->cursor.reset(new QWinRTCursor);
-
- hr = d->view.As(&d->view2);
- Q_ASSERT_SUCCEEDED(hr);
-}
-
-QWinRTScreen::~QWinRTScreen()
-{
- Q_D(QWinRTScreen);
- qCDebug(lcQpaWindows) << __FUNCTION__ << this;
-
- // Unregister callbacks
- HRESULT hr;
- hr = QEventDispatcherWinRT::runOnXamlThread([this, d]() {
- HRESULT hr;
- for (QHash<CoreWindowCallbackRemover, EventRegistrationToken>::const_iterator i = d->windowTokens.begin(); i != d->windowTokens.end(); ++i) {
- hr = (d->coreWindow.Get()->*i.key())(i.value());
- Q_ASSERT_SUCCEEDED(hr);
- }
- for (QHash<DisplayCallbackRemover, EventRegistrationToken>::const_iterator i = d->displayTokens.begin(); i != d->displayTokens.end(); ++i) {
- hr = (d->displayInformation.Get()->*i.key())(i.value());
- Q_ASSERT_SUCCEEDED(hr);
- }
- for (QHash<RedirectorCallbackRemover, EventRegistrationToken>::const_iterator i = d->redirectTokens.begin(); i != d->redirectTokens.end(); ++i) {
- hr = (d->redirect.Get()->*i.key())(i.value());
- Q_ASSERT_SUCCEEDED(hr);
- }
- for (QHash<ApplicationView2CallbackRemover, EventRegistrationToken>::const_iterator i = d->view2Tokens.begin(); i != d->view2Tokens.end(); ++i) {
- hr = (d->view2.Get()->*i.key())(i.value());
- Q_ASSERT_SUCCEEDED(hr);
- }
- return hr;
- });
- RETURN_VOID_IF_FAILED("Failed to unregister screen event callbacks");
-}
-
-QRect QWinRTScreen::geometry() const
-{
- Q_D(const QWinRTScreen);
- return QRect(QPoint(), QSizeF(d->logicalRect.size() * d->scaleFactor).toSize());
-}
-
-QRect QWinRTScreen::availableGeometry() const
-{
- Q_D(const QWinRTScreen);
- return QRectF((d->visibleRect.x() - d->logicalRect.x())* d->scaleFactor,
- (d->visibleRect.y() - d->logicalRect.y()) * d->scaleFactor,
- d->visibleRect.width() * d->scaleFactor,
- d->visibleRect.height() * d->scaleFactor).toRect();
-}
-
-int QWinRTScreen::depth() const
-{
- return 32;
-}
-
-QImage::Format QWinRTScreen::format() const
-{
- return QImage::Format_RGB32;
-}
-
-QSizeF QWinRTScreen::physicalSize() const
-{
- Q_D(const QWinRTScreen);
- return QSizeF(d->logicalRect.width() * d->scaleFactor / d->physicalDpi.first * qreal(25.4),
- d->logicalRect.height() * d->scaleFactor / d->physicalDpi.second * qreal(25.4));
-}
-
-QDpi QWinRTScreen::logicalDpi() const
-{
- Q_D(const QWinRTScreen);
- return QDpi(d->logicalDpi, d->logicalDpi);
-}
-
-qreal QWinRTScreen::scaleFactor() const
-{
- Q_D(const QWinRTScreen);
- return d->scaleFactor;
-}
-
-QPlatformCursor *QWinRTScreen::cursor() const
-{
- Q_D(const QWinRTScreen);
- return d->cursor.data();
-}
-
-Qt::KeyboardModifiers QWinRTScreen::keyboardModifiers() const
-{
- Q_D(const QWinRTScreen);
-
- Qt::KeyboardModifiers mods;
- CoreVirtualKeyStates mod;
- HRESULT hr = d->coreWindow->GetAsyncKeyState(VirtualKey_Shift, &mod);
- Q_ASSERT_SUCCEEDED(hr);
- if (mod & CoreVirtualKeyStates_Down)
- mods |= Qt::ShiftModifier;
- hr = d->coreWindow->GetAsyncKeyState(VirtualKey_Menu, &mod);
- Q_ASSERT_SUCCEEDED(hr);
- if (mod & CoreVirtualKeyStates_Down)
- mods |= Qt::AltModifier;
- hr = d->coreWindow->GetAsyncKeyState(VirtualKey_Control, &mod);
- Q_ASSERT_SUCCEEDED(hr);
- if (mod & CoreVirtualKeyStates_Down)
- mods |= Qt::ControlModifier;
- hr = d->coreWindow->GetAsyncKeyState(VirtualKey_LeftWindows, &mod);
- Q_ASSERT_SUCCEEDED(hr);
- if (mod & CoreVirtualKeyStates_Down) {
- mods |= Qt::MetaModifier;
- } else {
- hr = d->coreWindow->GetAsyncKeyState(VirtualKey_RightWindows, &mod);
- Q_ASSERT_SUCCEEDED(hr);
- if (mod & CoreVirtualKeyStates_Down)
- mods |= Qt::MetaModifier;
- }
- return mods;
-}
-
-Qt::ScreenOrientation QWinRTScreen::nativeOrientation() const
-{
- Q_D(const QWinRTScreen);
- return d->nativeOrientation;
-}
-
-Qt::ScreenOrientation QWinRTScreen::orientation() const
-{
- Q_D(const QWinRTScreen);
- return d->orientation;
-}
-
-ICoreWindow *QWinRTScreen::coreWindow() const
-{
- Q_D(const QWinRTScreen);
- return d->coreWindow.Get();
-}
-
-Xaml::IDependencyObject *QWinRTScreen::canvas() const
-{
- Q_D(const QWinRTScreen);
- Xaml::IDependencyObject *depCanvas;
- if (SUCCEEDED(d->canvas.CopyTo(&depCanvas)))
- return depCanvas;
- return nullptr;
-}
-
-void QWinRTScreen::initialize()
-{
- Q_D(QWinRTScreen);
- HRESULT hr;
- hr = d->coreWindow->add_KeyDown(Callback<KeyHandler>(this, &QWinRTScreen::onKeyDown).Get(), &d->windowTokens[&ICoreWindow::remove_KeyDown]);
- Q_ASSERT_SUCCEEDED(hr);
- hr = d->coreWindow->add_KeyUp(Callback<KeyHandler>(this, &QWinRTScreen::onKeyUp).Get(), &d->windowTokens[&ICoreWindow::remove_KeyUp]);
- Q_ASSERT_SUCCEEDED(hr);
- hr = d->coreWindow->add_CharacterReceived(Callback<CharacterReceivedHandler>(this, &QWinRTScreen::onCharacterReceived).Get(), &d->windowTokens[&ICoreWindow::remove_CharacterReceived]);
- Q_ASSERT_SUCCEEDED(hr);
- hr = d->coreWindow->add_PointerEntered(Callback<PointerHandler>(this, &QWinRTScreen::onPointerEntered).Get(), &d->windowTokens[&ICoreWindow::remove_PointerEntered]);
- Q_ASSERT_SUCCEEDED(hr);
- hr = d->coreWindow->add_PointerExited(Callback<PointerHandler>(this, &QWinRTScreen::onPointerExited).Get(), &d->windowTokens[&ICoreWindow::remove_PointerExited]);
- Q_ASSERT_SUCCEEDED(hr);
- hr = d->coreWindow->add_PointerMoved(Callback<PointerHandler>(this, &QWinRTScreen::onPointerUpdated).Get(), &d->windowTokens[&ICoreWindow::remove_PointerMoved]);
- Q_ASSERT_SUCCEEDED(hr);
- hr = d->coreWindow->add_PointerPressed(Callback<PointerHandler>(this, &QWinRTScreen::onPointerUpdated).Get(), &d->windowTokens[&ICoreWindow::remove_PointerPressed]);
- Q_ASSERT_SUCCEEDED(hr);
- hr = d->coreWindow->add_PointerReleased(Callback<PointerHandler>(this, &QWinRTScreen::onPointerUpdated).Get(), &d->windowTokens[&ICoreWindow::remove_PointerReleased]);
- Q_ASSERT_SUCCEEDED(hr);
- hr = d->coreWindow->add_PointerWheelChanged(Callback<PointerHandler>(this, &QWinRTScreen::onPointerUpdated).Get(), &d->windowTokens[&ICoreWindow::remove_PointerWheelChanged]);
- Q_ASSERT_SUCCEEDED(hr);
- hr = d->view2->add_VisibleBoundsChanged(Callback<VisibleBoundsChangedHandler>(this, &QWinRTScreen::onWindowSizeChanged).Get(), &d->view2Tokens[&IApplicationView2::remove_VisibleBoundsChanged]);
- Q_ASSERT_SUCCEEDED(hr);
- hr = d->coreWindow->add_Activated(Callback<ActivatedHandler>(this, &QWinRTScreen::onActivated).Get(), &d->windowTokens[&ICoreWindow::remove_Activated]);
- Q_ASSERT_SUCCEEDED(hr);
- hr = d->coreWindow->add_Closed(Callback<ClosedHandler>(this, &QWinRTScreen::onClosed).Get(), &d->windowTokens[&ICoreWindow::remove_Closed]);
- Q_ASSERT_SUCCEEDED(hr);
- hr = d->coreWindow->add_VisibilityChanged(Callback<VisibilityChangedHandler>(this, &QWinRTScreen::onVisibilityChanged).Get(), &d->windowTokens[&ICoreWindow::remove_VisibilityChanged]);
- Q_ASSERT_SUCCEEDED(hr);
- hr = d->displayInformation->add_OrientationChanged(Callback<DisplayInformationHandler>(this, &QWinRTScreen::onOrientationChanged).Get(), &d->displayTokens[&IDisplayInformation::remove_OrientationChanged]);
- Q_ASSERT_SUCCEEDED(hr);
- hr = d->displayInformation->add_DpiChanged(Callback<DisplayInformationHandler>(this, &QWinRTScreen::onDpiChanged).Get(), &d->displayTokens[&IDisplayInformation::remove_DpiChanged]);
- Q_ASSERT_SUCCEEDED(hr);
- onOrientationChanged(nullptr, nullptr);
- onVisibilityChanged(nullptr, nullptr);
-
- hr = d->redirect->add_PointerRoutedReleased(Callback<RedirectHandler>(this, &QWinRTScreen::onRedirectReleased).Get(), &d->redirectTokens[&ICorePointerRedirector::remove_PointerRoutedReleased]);
- Q_ASSERT_SUCCEEDED(hr);
-}
-
-void QWinRTScreen::setCursorRect(const QRectF &cursorRect)
-{
- mCursorRect = cursorRect;
-}
-
-void QWinRTScreen::setKeyboardRect(const QRectF &keyboardRect)
-{
- Q_D(QWinRTScreen);
- QRectF visibleRectF;
- HRESULT hr;
- Rect windowSize;
-
- hr = d->coreWindow->get_Bounds(&windowSize);
- if (FAILED(hr)) {
- qErrnoWarning(hr, "Failed to get window bounds");
- return;
- }
- d->logicalRect = QRectF(windowSize.X, windowSize.Y, windowSize.Width, windowSize.Height);
- Rect visibleRect;
- hr = d->view2->get_VisibleBounds(&visibleRect);
- if (FAILED(hr)) {
- qErrnoWarning(hr, "Failed to get window visible bounds");
- return;
- }
- visibleRectF = QRectF(visibleRect.X, visibleRect.Y, visibleRect.Width, visibleRect.Height);
- // if keyboard is snapped to the bottom of the screen and would cover the cursor the content is
- // moved up to make it visible
- if (keyboardRect.intersects(mCursorRect)
- && qFuzzyCompare(geometry().height(), keyboardRect.y() + keyboardRect.height())) {
- visibleRectF.moveTop(visibleRectF.top() - keyboardRect.height() / d->scaleFactor);
- }
- d->visibleRect = visibleRectF;
-
- qCDebug(lcQpaWindows) << __FUNCTION__ << d->visibleRect;
- QWindowSystemInterface::handleScreenGeometryChange(screen(), geometry(), availableGeometry());
- QPlatformScreen::resizeMaximizedWindows();
- handleExpose();
-}
-
-QWindow *QWinRTScreen::topWindow() const
-{
- Q_D(const QWinRTScreen);
- return d->visibleWindows.isEmpty() ? 0 : d->visibleWindows.first();
-}
-
-QWindow *QWinRTScreen::windowAt(const QPoint &pos)
-{
- Q_D(const QWinRTScreen);
- for (auto w : qAsConst(d->visibleWindows)) {
- if (w->geometry().contains(pos))
- return w;
- }
- qCDebug(lcQpaWindows) << __FUNCTION__ << ": No window found at:" << pos;
- return nullptr;
-}
-
-void QWinRTScreen::addWindow(QWindow *window)
-{
- Q_D(QWinRTScreen);
- qCDebug(lcQpaWindows) << __FUNCTION__ << window;
- if (window == topWindow() || window->surfaceClass() == QSurface::Offscreen)
- return;
-
- d->visibleWindows.prepend(window);
- const Qt::WindowType type = window->type();
- if (type != Qt::Popup && type != Qt::ToolTip && type != Qt::Tool) {
- updateWindowTitle(window->title());
- QWindowSystemInterface::handleWindowActivated(window, Qt::OtherFocusReason);
- }
-
- handleExpose();
- d->firstMouseMove = true;
- QWindowSystemInterface::flushWindowSystemEvents(QEventLoop::ExcludeUserInputEvents);
-
-#if QT_CONFIG(draganddrop)
- QWinRTDrag::instance()->setDropTarget(window);
-#endif
-}
-
-void QWinRTScreen::removeWindow(QWindow *window)
-{
- Q_D(QWinRTScreen);
- qCDebug(lcQpaWindows) << __FUNCTION__ << window;
-
- handleExpose();
-
- const bool wasTopWindow = window == topWindow();
- if (!d->visibleWindows.removeAll(window))
- return;
-
- const Qt::WindowType type = window->type();
- if (wasTopWindow && type != Qt::Popup && type != Qt::ToolTip && type != Qt::Tool)
- QWindowSystemInterface::handleWindowActivated(nullptr, Qt::OtherFocusReason);
- QWindowSystemInterface::flushWindowSystemEvents(QEventLoop::ExcludeUserInputEvents);
-#if QT_CONFIG(draganddrop)
- if (wasTopWindow)
- QWinRTDrag::instance()->setDropTarget(topWindow());
-#endif
-}
-
-void QWinRTScreen::raise(QWindow *window)
-{
- Q_D(QWinRTScreen);
- d->visibleWindows.removeAll(window);
- addWindow(window);
-}
-
-void QWinRTScreen::lower(QWindow *window)
-{
- Q_D(QWinRTScreen);
- const bool wasTopWindow = window == topWindow();
- if (wasTopWindow && d->visibleWindows.size() == 1)
- return;
- if (window->surfaceClass() == QSurface::Offscreen)
- return;
- d->visibleWindows.removeAll(window);
- d->visibleWindows.append(window);
- if (wasTopWindow)
- QWindowSystemInterface::handleWindowActivated(window, Qt::OtherFocusReason);
- handleExpose();
-}
-
-bool QWinRTScreen::setMouseGrabWindow(QWinRTWindow *window, bool grab)
-{
- Q_D(QWinRTScreen);
- qCDebug(lcQpaWindows) << __FUNCTION__ << window
- << "(" << window->window()->objectName() << "):" << grab;
-
- if (!grab || window == nullptr)
- d->mouseGrabWindow = nullptr;
- else if (d->mouseGrabWindow != window)
- d->mouseGrabWindow = window;
- return grab;
-}
-
-QWinRTWindow *QWinRTScreen::mouseGrabWindow() const
-{
- Q_D(const QWinRTScreen);
- return d->mouseGrabWindow;
-}
-
-bool QWinRTScreen::setKeyboardGrabWindow(QWinRTWindow *window, bool grab)
-{
- Q_D(QWinRTScreen);
- qCDebug(lcQpaWindows) << __FUNCTION__ << window
- << "(" << window->window()->objectName() << "):" << grab;
-
- if (!grab || window == nullptr)
- d->keyboardGrabWindow = nullptr;
- else if (d->keyboardGrabWindow != window)
- d->keyboardGrabWindow = window;
- return grab;
-}
-
-QWinRTWindow *QWinRTScreen::keyboardGrabWindow() const
-{
- Q_D(const QWinRTScreen);
- return d->keyboardGrabWindow;
-}
-
-void QWinRTScreen::updateWindowTitle(const QString &title)
-{
- Q_D(QWinRTScreen);
-
- HStringReference titleRef(reinterpret_cast<LPCWSTR>(title.utf16()), title.length());
- HRESULT hr = d->view->put_Title(titleRef.Get());
- RETURN_VOID_IF_FAILED("Unable to set window title");
-}
-
-void QWinRTScreen::handleExpose()
-{
- Q_D(QWinRTScreen);
- if (d->visibleWindows.isEmpty())
- return;
- QList<QWindow *>::const_iterator it = d->visibleWindows.constBegin();
- QWindowSystemInterface::handleExposeEvent(*it, geometry());
- while (++it != d->visibleWindows.constEnd())
- QWindowSystemInterface::handleExposeEvent(*it, QRegion());
-}
-
-HRESULT QWinRTScreen::onKeyDown(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IKeyEventArgs *args)
-{
- Q_D(QWinRTScreen);
- VirtualKey virtualKey;
- HRESULT hr = args->get_VirtualKey(&virtualKey);
- Q_ASSERT_SUCCEEDED(hr);
- CorePhysicalKeyStatus status;
- hr = args->get_KeyStatus(&status);
- Q_ASSERT_SUCCEEDED(hr);
-
- Qt::Key key = qKeyFromVirtual(virtualKey);
-
- const bool wasPressed = d->activeKeys.contains(key);
- if (wasPressed) {
- if (!shouldAutoRepeat(key))
- return S_OK;
-
- d->activeKeys[key].isAutoRepeat = true;
- // If the key was pressed before trigger a key release before the next key press
- QWindowSystemInterface::handleExtendedKeyEvent(
- topWindow(),
- QEvent::KeyRelease,
- key,
- keyboardModifiers(),
- !status.ScanCode ? -1 : status.ScanCode,
- virtualKey,
- 0,
- QString(),
- d->activeKeys.value(key).isAutoRepeat);
- } else {
- d->activeKeys.insert(key, KeyInfo(virtualKey));
- }
-
- // Defer character key presses to onCharacterReceived
- if (key == Qt::Key_unknown || (key >= Qt::Key_Space && key <= Qt::Key_ydiaeresis))
- return S_OK;
-
- Qt::KeyboardModifiers modifiers = keyboardModifiers();
- // If the key actually pressed is a modifier key, then we remove its modifier key from the
- // state, since a modifier-key can't have itself as a modifier (see qwindowskeymapper.cpp)
- if (key == Qt::Key_Control)
- modifiers = modifiers ^ Qt::ControlModifier;
- else if (key == Qt::Key_Shift)
- modifiers = modifiers ^ Qt::ShiftModifier;
- else if (key == Qt::Key_Alt)
- modifiers = modifiers ^ Qt::AltModifier;
-
- QWindowSystemInterface::handleExtendedKeyEvent(
- topWindow(),
- QEvent::KeyPress,
- key,
- modifiers,
- !status.ScanCode ? -1 : status.ScanCode,
- virtualKey,
- 0,
- QString(),
- d->activeKeys.value(key).isAutoRepeat);
- return S_OK;
-}
-
-HRESULT QWinRTScreen::onKeyUp(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IKeyEventArgs *args)
-{
- Q_D(QWinRTScreen);
- VirtualKey virtualKey;
- HRESULT hr = args->get_VirtualKey(&virtualKey);
- Q_ASSERT_SUCCEEDED(hr);
- CorePhysicalKeyStatus status;
- hr = args->get_KeyStatus(&status);
- Q_ASSERT_SUCCEEDED(hr);
-
- Qt::Key key = qKeyFromVirtual(virtualKey);
- const KeyInfo info = d->activeKeys.take(key);
- QWindowSystemInterface::handleExtendedKeyEvent(
- topWindow(),
- QEvent::KeyRelease,
- key,
- keyboardModifiers(),
- !status.ScanCode ? -1 : status.ScanCode,
- virtualKey,
- 0,
- info.text,
- false); // The final key release does not have autoRepeat set on Windows
- return S_OK;
-}
-
-HRESULT QWinRTScreen::onCharacterReceived(ICoreWindow *, ICharacterReceivedEventArgs *args)
-{
- Q_D(QWinRTScreen);
- quint32 keyCode;
- HRESULT hr = args->get_KeyCode(&keyCode);
- Q_ASSERT_SUCCEEDED(hr);
- CorePhysicalKeyStatus status;
- hr = args->get_KeyStatus(&status);
- Q_ASSERT_SUCCEEDED(hr);
-
- // Don't generate character events for non-printables; the meta key stage is enough
- if (qIsNonPrintable(keyCode))
- return S_OK;
-
- const Qt::KeyboardModifiers modifiers = keyboardModifiers();
- const Qt::Key key = qKeyFromCode(keyCode, modifiers);
- const QString text = QChar(keyCode);
- KeyInfo &info = d->activeKeys[key];
- info.text = text;
- QWindowSystemInterface::handleExtendedKeyEvent(
- topWindow(),
- QEvent::KeyPress,
- key,
- modifiers,
- !status.ScanCode ? -1 : status.ScanCode,
- info.virtualKey,
- 0,
- text,
- info.isAutoRepeat);
- return S_OK;
-}
-
-HRESULT QWinRTScreen::onPointerEntered(ICoreWindow *, IPointerEventArgs *args)
-{
- Q_D(QWinRTScreen);
- qCDebug(lcQpaEvents) << __FUNCTION__;
-
- ComPtr<IPointerPoint> pointerPoint;
- if (SUCCEEDED(args->get_CurrentPoint(&pointerPoint))) {
- // Assumes full-screen window
- Point point;
- pointerPoint->get_Position(&point);
- QPoint pos(point.X * d->scaleFactor, point.Y * d->scaleFactor);
-
- d->currentTargetWindow = topWindow();
- if (d->mouseGrabWindow)
- d->currentTargetWindow = d->mouseGrabWindow.loadRelaxed()->window();
-
- qCDebug(lcQpaEvents) << __FUNCTION__ << "handleEnterEvent" << d->currentTargetWindow << pos;
- QWindowSystemInterface::handleEnterEvent(d->currentTargetWindow, pos, pos);
- d->firstMouseMove = false;
- }
- return S_OK;
-}
-
-HRESULT QWinRTScreen::onPointerExited(ICoreWindow *, IPointerEventArgs *args)
-{
- Q_D(QWinRTScreen);
- qCDebug(lcQpaEvents) << __FUNCTION__;
- ComPtr<IPointerPoint> pointerPoint;
- if (FAILED(args->get_CurrentPoint(&pointerPoint)))
- return E_INVALIDARG;
-
- quint32 id;
- if (FAILED(pointerPoint->get_PointerId(&id)))
- return E_INVALIDARG;
-
- d->touchPoints.remove(id);
-
- if (d->mouseGrabWindow)
- d->currentTargetWindow = d->mouseGrabWindow.loadRelaxed()->window();
-
- qCDebug(lcQpaEvents) << __FUNCTION__ << "handleLeaveEvent" << d->currentTargetWindow;
- QWindowSystemInterface::handleLeaveEvent(d->currentTargetWindow);
- d->currentTargetWindow = nullptr;
- return S_OK;
-}
-
-// Required for qwinrtdrag.cpp
-ComPtr<IPointerPoint> qt_winrt_lastPointerPoint;
-
-HRESULT QWinRTScreen::onPointerUpdated(ICoreWindow *, IPointerEventArgs *args)
-{
- Q_D(QWinRTScreen);
- qCDebug(lcQpaEvents) << __FUNCTION__;
- ComPtr<IPointerPoint> pointerPoint;
- if (FAILED(args->get_CurrentPoint(&pointerPoint)))
- return E_INVALIDARG;
-
- qt_winrt_lastPointerPoint = pointerPoint;
- // Common traits - point, modifiers, properties
- Point point;
- pointerPoint->get_Position(&point);
- const QPointF pos(point.X * d->scaleFactor, point.Y * d->scaleFactor);
- QPointF localPos = pos;
-
- const QPoint posPoint = pos.toPoint();
- QWindow *windowUnderPointer = windowAt(QHighDpiScaling::mapPositionFromNative(posPoint, this));
- d->currentTargetWindow = windowUnderPointer;
-
- if (d->mouseGrabWindow)
- d->currentTargetWindow = d->mouseGrabWindow.loadRelaxed()->window();
-
- if (d->currentTargetWindow) {
- const QPointF globalPosDelta = pos - posPoint;
- localPos = d->currentTargetWindow->mapFromGlobal(posPoint) + globalPosDelta;
- }
-
- VirtualKeyModifiers modifiers;
- args->get_KeyModifiers(&modifiers);
- Qt::KeyboardModifiers mods;
- if (modifiers & VirtualKeyModifiers_Control)
- mods |= Qt::ControlModifier;
- if (modifiers & VirtualKeyModifiers_Menu)
- mods |= Qt::AltModifier;
- if (modifiers & VirtualKeyModifiers_Shift)
- mods |= Qt::ShiftModifier;
- if (modifiers & VirtualKeyModifiers_Windows)
- mods |= Qt::MetaModifier;
-
- ComPtr<IPointerPointProperties> properties;
- if (FAILED(pointerPoint->get_Properties(&properties)))
- return E_INVALIDARG;
-
- ComPtr<IPointerDevice> pointerDevice;
- HRESULT hr = pointerPoint->get_PointerDevice(&pointerDevice);
- RETURN_OK_IF_FAILED("Failed to get pointer device.");
-
- PointerDeviceType pointerDeviceType;
- hr = pointerDevice->get_PointerDeviceType(&pointerDeviceType);
- RETURN_OK_IF_FAILED("Failed to get pointer device type.");
-
- switch (pointerDeviceType) {
- case PointerDeviceType_Mouse: {
- qint32 delta;
- properties->get_MouseWheelDelta(&delta);
- if (delta) {
- boolean isHorizontal;
- properties->get_IsHorizontalMouseWheel(&isHorizontal);
- QPoint angleDelta(isHorizontal ? delta : 0, isHorizontal ? 0 : delta);
- qCDebug(lcQpaEvents) << __FUNCTION__ << "handleWheelEvent" << d->currentTargetWindow
- << localPos << pos << angleDelta << mods;
- QWindowSystemInterface::handleWheelEvent(d->currentTargetWindow, localPos, pos, QPoint(), angleDelta, mods);
- break;
- }
-
- boolean isPressed;
- Qt::MouseButtons buttons = Qt::NoButton;
- properties->get_IsLeftButtonPressed(&isPressed);
- if (isPressed)
- buttons |= Qt::LeftButton;
-
- properties->get_IsMiddleButtonPressed(&isPressed);
- if (isPressed)
- buttons |= Qt::MiddleButton;
-
- properties->get_IsRightButtonPressed(&isPressed);
- if (isPressed)
- buttons |= Qt::RightButton;
-
- properties->get_IsXButton1Pressed(&isPressed);
- if (isPressed)
- buttons |= Qt::XButton1;
-
- properties->get_IsXButton2Pressed(&isPressed);
- if (isPressed)
- buttons |= Qt::XButton2;
-
- // In case of a mouse grab we have to store the target of a press event
- // to be able to send one additional release event to this target when the mouse
- // button is released. This is a similar approach to AutoMouseCapture in the
- // windows qpa backend. Otherwise the release might not be propagated and the original
- // press event receiver considers a button to still be pressed, as in Qt Quick Controls 1
- // menus.
- if (buttons != Qt::NoButton && d->currentPressWindow == nullptr && !d->mouseGrabWindow)
- d->currentPressWindow = windowUnderPointer;
- if (buttons == Qt::NoButton && d->currentPressWindow && d->mouseGrabWindow) {
- const QPointF globalPosDelta = pos - posPoint;
- const QPointF localPressPos = d->currentPressWindow->mapFromGlobal(posPoint) + globalPosDelta;
-
- qCDebug(lcQpaEvents) << __FUNCTION__ << "handleMouseEvent" << d->currentPressWindow
- << localPressPos << pos << buttons << mods;
- QWindowSystemInterface::handleMouseEvent(d->currentPressWindow, localPressPos, pos, buttons, mods);
- d->currentPressWindow = nullptr;
- }
- // If the mouse button is released outside of a window, targetWindow is 0, but the event
- // has to be delivered to the window, that initially received the mouse press. Do not reset
- // d->currentTargetWindow though, as it is used (and reset) in onPointerExited.
- if (buttons == Qt::NoButton && d->currentPressWindow && !d->currentTargetWindow) {
- d->currentTargetWindow = d->currentPressWindow;
- d->currentPressWindow = nullptr;
- }
-
- qCDebug(lcQpaEvents) << __FUNCTION__ << "handleMouseEvent" << d->currentTargetWindow
- << localPos << pos << buttons << mods;
- QWindowSystemInterface::handleMouseEvent(d->currentTargetWindow, localPos, pos, buttons, mods);
-
- break;
- }
- case PointerDeviceType_Pen:
- case PointerDeviceType_Touch: {
- if (!d->touchDevice) {
- d->touchDevice = new QTouchDevice;
- d->touchDevice->setName(QStringLiteral("WinRTTouchScreen"));
- d->touchDevice->setType(QTouchDevice::TouchScreen);
- d->touchDevice->setCapabilities(QTouchDevice::Position | QTouchDevice::Area | QTouchDevice::Pressure | QTouchDevice::NormalizedPosition);
- QWindowSystemInterface::registerTouchDevice(d->touchDevice);
- }
-
- quint32 id;
- pointerPoint->get_PointerId(&id);
-
- Rect area;
- properties->get_ContactRect(&area);
-
- float pressure;
- properties->get_Pressure(&pressure);
-
- boolean isPressed;
- pointerPoint->get_IsInContact(&isPressed);
-
- // Devices like the Hololens set a static pressure of 0.0 or 0.5
- // (depending on the image) independent of the pressed state.
- // In those cases we need to synthesize the pressure value. To our
- // knowledge this does not apply to pens
- if (pointerDeviceType == PointerDeviceType_Touch && (pressure == 0.0f || pressure == 0.5f))
- pressure = isPressed ? 1. : 0.;
-
- const QRectF areaRect(area.X * d->scaleFactor, area.Y * d->scaleFactor,
- area.Width * d->scaleFactor, area.Height * d->scaleFactor);
-
- QHash<quint32, QWindowSystemInterface::TouchPoint>::iterator it = d->touchPoints.find(id);
- if (it == d->touchPoints.end()) {
- it = d->touchPoints.insert(id, QWindowSystemInterface::TouchPoint());
- it.value().id = id;
- }
-
- const bool wasPressEvent = isPressed && it.value().pressure == 0.;
- if (wasPressEvent)
- it.value().state = Qt::TouchPointPressed;
- else if (!isPressed && it.value().pressure > 0.)
- it.value().state = Qt::TouchPointReleased;
- else if (it.value().area == areaRect)
- it.value().state = Qt::TouchPointStationary;
- else
- it.value().state = Qt::TouchPointMoved;
-
- it.value().area = areaRect;
- it.value().normalPosition = QPointF(point.X/d->logicalRect.width(), point.Y/d->logicalRect.height());
- it.value().pressure = pressure;
-
- qCDebug(lcQpaEvents) << __FUNCTION__ << "handleTouchEvent" << d->currentTargetWindow
- << d->touchDevice << d->touchPoints.values() << mods;
- QWindowSystemInterface::handleTouchEvent(d->currentTargetWindow, d->touchDevice, d->touchPoints.values(), mods);
- if (wasPressEvent)
- it.value().state = Qt::TouchPointStationary;
-
- // Fall-through for pen to generate tablet event
- if (pointerDeviceType != PointerDeviceType_Pen)
- break;
-
- boolean isEraser;
- properties->get_IsEraser(&isEraser);
- int pointerType = isEraser ? 3 : 1;
-
- float xTilt;
- properties->get_XTilt(&xTilt);
-
- float yTilt;
- properties->get_YTilt(&yTilt);
-
- float rotation;
- properties->get_Twist(&rotation);
-
- qCDebug(lcQpaEvents) << __FUNCTION__ << "handleTabletEvent" << d->currentTargetWindow
- << isPressed << pos << pointerType << pressure << xTilt << yTilt
- << rotation << id << mods;
- QWindowSystemInterface::handleTabletEvent(d->currentTargetWindow, isPressed, pos, pos, 0,
- pointerType, pressure, xTilt, yTilt,
- 0, rotation, 0, id, mods);
-
- break;
- }
- }
-
- return S_OK;
-}
-
-void QWinRTScreen::emulateMouseMove(const QPointF &point, MousePositionTransition transition)
-{
- Q_D(QWinRTScreen);
- qCDebug(lcQpaEvents) << __FUNCTION__ << point << transition;
- if (transition == MousePositionTransition::StayedOut)
- return;
- qt_winrt_lastPointerPoint = nullptr;
- const QPointF pos(point.x() * d->scaleFactor, point.y() * d->scaleFactor);
- QPointF localPos = pos;
-
- const QPoint posPoint = pos.toPoint();
- QWindow *windowUnderPointer = windowAt(QHighDpiScaling::mapPositionFromNative(posPoint, this));
- d->currentTargetWindow = windowUnderPointer;
-
- if (d->mouseGrabWindow)
- d->currentTargetWindow = d->mouseGrabWindow.loadRelaxed()->window();
-
- if (d->currentTargetWindow) {
- const QPointF globalPosDelta = pos - posPoint;
- localPos = d->currentTargetWindow->mapFromGlobal(posPoint) + globalPosDelta;
- }
-
- // In case of a mouse grab we have to store the target of a press event
- // to be able to send one additional release event to this target when the mouse
- // button is released. This is a similar approach to AutoMouseCapture in the
- // windows qpa backend. Otherwise the release might not be propagated and the original
- // press event receiver considers a button to still be pressed, as in Qt Quick Controls 1
- // menus.
- if (d->currentPressWindow && d->mouseGrabWindow) {
- const QPointF globalPosDelta = pos - posPoint;
- const QPointF localPressPos = d->currentPressWindow->mapFromGlobal(posPoint) + globalPosDelta;
-
- qCDebug(lcQpaEvents) << __FUNCTION__ << "handleMouseEvent" << d->currentPressWindow
- << localPressPos << pos << Qt::NoButton << Qt::NoModifier;
- QWindowSystemInterface::handleMouseEvent(d->currentPressWindow, localPressPos, pos,
- Qt::NoButton, Qt::NoModifier);
- d->currentPressWindow = nullptr;
- }
- // If the mouse button is released outside of a window, targetWindow is 0, but the event
- // has to be delivered to the window, that initially received the mouse press. Do not reset
- // d->currentTargetWindow though, as it is used (and reset) in onPointerExited.
- if (d->currentPressWindow && !d->currentTargetWindow) {
- d->currentTargetWindow = d->currentPressWindow;
- d->currentPressWindow = nullptr;
- }
-
- if (transition == MousePositionTransition::MovedOut) {
- qCDebug(lcQpaEvents) << __FUNCTION__ << "handleLeaveEvent" << d->currentTargetWindow;
- QWindowSystemInterface::handleLeaveEvent(d->currentTargetWindow);
- return;
- }
-
- if (transition == MousePositionTransition::MovedIn || d->firstMouseMove) {
- qCDebug(lcQpaEvents) << __FUNCTION__ << "handleEnterEvent" << d->currentTargetWindow
- << localPos << pos;
- QWindowSystemInterface::handleEnterEvent(d->currentTargetWindow, localPos, pos);
- d->firstMouseMove = false;
- }
- qCDebug(lcQpaEvents) << __FUNCTION__ << "handleMouseEvent" << d->currentTargetWindow
- << localPos << pos << Qt::NoButton << Qt::NoModifier;
- QWindowSystemInterface::handleMouseEvent(d->currentTargetWindow, localPos, pos, Qt::NoButton,
- Qt::NoModifier);
-}
-
-void QWinRTScreen::setResizePending()
-{
- Q_D(QWinRTScreen);
- d->resizePending = true;
-}
-
-bool QWinRTScreen::resizePending() const
-{
- Q_D(const QWinRTScreen);
- return d->resizePending;
-}
-
-HRESULT QWinRTScreen::onActivated(ICoreWindow *, IWindowActivatedEventArgs *args)
-{
- Q_D(QWinRTScreen);
- qCDebug(lcQpaWindows) << __FUNCTION__;
-
- CoreWindowActivationState activationState;
- args->get_WindowActivationState(&activationState);
- if (activationState == CoreWindowActivationState_Deactivated) {
- QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationInactive);
- return S_OK;
- }
-
- QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationActive);
-
- // Activate topWindow
- if (!d->visibleWindows.isEmpty()) {
- Qt::FocusReason focusReason = activationState == CoreWindowActivationState_PointerActivated
- ? Qt::MouseFocusReason : Qt::ActiveWindowFocusReason;
- QWindowSystemInterface::handleWindowActivated(topWindow(), focusReason);
- }
- return S_OK;
-}
-
-HRESULT QWinRTScreen::onClosed(ICoreWindow *, ICoreWindowEventArgs *)
-{
- qCDebug(lcQpaWindows) << __FUNCTION__;
-
- foreach (QWindow *w, QGuiApplication::topLevelWindows())
- QWindowSystemInterface::handleCloseEvent(w);
- return S_OK;
-}
-
-HRESULT QWinRTScreen::onVisibilityChanged(ICoreWindow *, IVisibilityChangedEventArgs *args)
-{
- Q_D(QWinRTScreen);
- boolean visible;
- HRESULT hr = args ? args->get_Visible(&visible) : d->coreWindow->get_Visible(&visible);
- RETURN_OK_IF_FAILED("Failed to get visibility.");
- qCDebug(lcQpaWindows) << __FUNCTION__ << visible;
- QWindowSystemInterface::handleApplicationStateChanged(visible ? Qt::ApplicationActive : Qt::ApplicationHidden);
- if (visible) {
- handleExpose();
- onWindowSizeChanged(nullptr, nullptr);
- }
- return S_OK;
-}
-
-HRESULT QWinRTScreen::onOrientationChanged(IDisplayInformation *, IInspectable *)
-{
- Q_D(QWinRTScreen);
- qCDebug(lcQpaWindows) << __FUNCTION__;
- DisplayOrientations displayOrientation;
- HRESULT hr = d->displayInformation->get_CurrentOrientation(&displayOrientation);
- RETURN_OK_IF_FAILED("Failed to get current orientations.");
-
- Qt::ScreenOrientation newOrientation = static_cast<Qt::ScreenOrientation>(static_cast<int>(qtOrientationsFromNative(displayOrientation)));
- if (d->orientation != newOrientation) {
- d->orientation = newOrientation;
- qCDebug(lcQpaWindows) << " New orientation:" << newOrientation;
- onWindowSizeChanged(nullptr, nullptr);
- QWindowSystemInterface::handleScreenOrientationChange(screen(), d->orientation);
- handleExpose(); // Clean broken frames caused by race between Qt and ANGLE
- }
- return S_OK;
-}
-
-HRESULT QWinRTScreen::onDpiChanged(IDisplayInformation *, IInspectable *)
-{
- Q_D(QWinRTScreen);
-
- HRESULT hr;
- ResolutionScale resolutionScale;
- hr = d->displayInformation->get_ResolutionScale(&resolutionScale);
- d->scaleFactor = qreal(resolutionScale) / 100;
-
- qCDebug(lcQpaWindows) << __FUNCTION__ << "Scale Factor:" << d->scaleFactor;
-
- RETURN_OK_IF_FAILED("Failed to get scale factor");
-
- FLOAT dpi;
- hr = d->displayInformation->get_LogicalDpi(&dpi);
- RETURN_OK_IF_FAILED("Failed to get logical DPI.");
- d->logicalDpi = dpi;
-
- hr = d->displayInformation->get_RawDpiX(&dpi);
- RETURN_OK_IF_FAILED("Failed to get x raw DPI.");
- d->physicalDpi.first = dpi ? dpi : 96.0;
-
- hr = d->displayInformation->get_RawDpiY(&dpi);
- RETURN_OK_IF_FAILED("Failed to get y raw DPI.");
- d->physicalDpi.second = dpi ? dpi : 96.0;
- qCDebug(lcQpaWindows) << __FUNCTION__ << "Logical DPI:" << d->logicalDpi
- << "Physical DPI:" << d->physicalDpi;
-
- return S_OK;
-}
-
-HRESULT QWinRTScreen::onRedirectReleased(ICorePointerRedirector *, IPointerEventArgs *args)
-{
- // When dragging ends with a non-mouse input device then onRedirectRelease is invoked.
- // QTBUG-58781
- qCDebug(lcQpaEvents) << __FUNCTION__;
- return onPointerUpdated(nullptr, args);
-}
-
-HRESULT QWinRTScreen::onWindowSizeChanged(IApplicationView *w, IInspectable *)
-{
- Q_D(QWinRTScreen);
-
- HRESULT hr;
- Rect windowSize;
-
- hr = d->coreWindow->get_Bounds(&windowSize);
- RETURN_OK_IF_FAILED("Failed to get window bounds");
- d->logicalRect = QRectF(windowSize.X, windowSize.Y, windowSize.Width, windowSize.Height);
-
- Rect visibleRect;
- hr = d->view2->get_VisibleBounds(&visibleRect);
- RETURN_OK_IF_FAILED("Failed to get window visible bounds");
- d->visibleRect = QRectF(visibleRect.X, visibleRect.Y, visibleRect.Width, visibleRect.Height);
-
- qCDebug(lcQpaWindows) << __FUNCTION__ << d->logicalRect;
- QWindowSystemInterface::handleScreenGeometryChange(screen(), geometry(), availableGeometry());
- QPlatformScreen::resizeMaximizedWindows();
- handleExpose();
- // If we "emulate" a resize, w will be nullptr.Checking w shows whether it's a real resize
- if (w)
- d->resizePending = false;
- return S_OK;
-}
-
-QT_END_NAMESPACE
diff --git a/src/plugins/platforms/winrt/qwinrtscreen.h b/src/plugins/platforms/winrt/qwinrtscreen.h
deleted file mode 100644
index 6b57780fa1..0000000000
--- a/src/plugins/platforms/winrt/qwinrtscreen.h
+++ /dev/null
@@ -1,168 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 QWINRTSCREEN_H
-#define QWINRTSCREEN_H
-
-#include <qpa/qplatformscreen.h>
-#include <qpa/qwindowsysteminterface.h>
-
-namespace ABI {
- namespace Windows {
- namespace ApplicationModel {
- struct ISuspendingEventArgs;
- }
- namespace UI {
- namespace Core {
- struct IAutomationProviderRequestedEventArgs;
- struct ICharacterReceivedEventArgs;
- struct ICorePointerRedirector;
- struct ICoreWindow;
- struct ICoreWindowEventArgs;
- struct IKeyEventArgs;
- struct IPointerEventArgs;
- struct IVisibilityChangedEventArgs;
- struct IWindowActivatedEventArgs;
- }
- namespace Xaml {
- struct IDependencyObject;
- struct IWindow;
- }
- namespace ViewManagement {
- struct IApplicationView;
- }
- }
- namespace Graphics {
- namespace Display {
- struct IDisplayInformation;
- }
- }
- }
-}
-struct IInspectable;
-
-QT_BEGIN_NAMESPACE
-
-class QTouchDevice;
-class QWinRTCursor;
-class QWinRTInputContext;
-class QWinRTScreenPrivate;
-class QWinRTWindow;
-class QWinRTScreen : public QPlatformScreen
-{
-public:
- explicit QWinRTScreen();
- ~QWinRTScreen() override;
-
- QRect geometry() const override;
- QRect availableGeometry() const override;
- int depth() const override;
- QImage::Format format() const override;
- QSizeF physicalSize() const override;
- QDpi logicalDpi() const override;
- qreal scaleFactor() const;
- QPlatformCursor *cursor() const override;
- Qt::KeyboardModifiers keyboardModifiers() const;
-
- Qt::ScreenOrientation nativeOrientation() const override;
- Qt::ScreenOrientation orientation() const override;
-
- QWindow *topWindow() const;
- QWindow *windowAt(const QPoint &pos);
- void addWindow(QWindow *window);
- void removeWindow(QWindow *window);
- void raise(QWindow *window);
- void lower(QWindow *window);
-
- bool setMouseGrabWindow(QWinRTWindow *window, bool grab);
- QWinRTWindow* mouseGrabWindow() const;
-
- bool setKeyboardGrabWindow(QWinRTWindow *window, bool grab);
- QWinRTWindow* keyboardGrabWindow() const;
-
- void updateWindowTitle(const QString &title);
-
- ABI::Windows::UI::Core::ICoreWindow *coreWindow() const;
- ABI::Windows::UI::Xaml::IDependencyObject *canvas() const;
-
- void initialize();
-
- void setCursorRect(const QRectF &cursorRect);
- void setKeyboardRect(const QRectF &keyboardRect);
-
- enum class MousePositionTransition {
- MovedOut,
- MovedIn,
- StayedIn,
- StayedOut
- };
-
- void emulateMouseMove(const QPointF &point, MousePositionTransition transition);
-
- void setResizePending();
- bool resizePending() const;
-
-private:
- void handleExpose();
-
- HRESULT onKeyDown(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IKeyEventArgs *);
- HRESULT onKeyUp(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IKeyEventArgs *);
- HRESULT onCharacterReceived(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::ICharacterReceivedEventArgs *);
- HRESULT onPointerEntered(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IPointerEventArgs *);
- HRESULT onPointerExited(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IPointerEventArgs *);
- HRESULT onPointerUpdated(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IPointerEventArgs *);
-
- HRESULT onActivated(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IWindowActivatedEventArgs *);
-
- HRESULT onClosed(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::ICoreWindowEventArgs *);
- HRESULT onVisibilityChanged(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IVisibilityChangedEventArgs *);
-
- HRESULT onOrientationChanged(ABI::Windows::Graphics::Display::IDisplayInformation *, IInspectable *);
- HRESULT onDpiChanged(ABI::Windows::Graphics::Display::IDisplayInformation *, IInspectable *);
- HRESULT onWindowSizeChanged(ABI::Windows::UI::ViewManagement::IApplicationView *, IInspectable *);
- HRESULT onRedirectReleased(ABI::Windows::UI::Core::ICorePointerRedirector *, ABI::Windows::UI::Core::IPointerEventArgs *);
-
- QScopedPointer<QWinRTScreenPrivate> d_ptr;
- QRectF mCursorRect;
- Q_DECLARE_PRIVATE(QWinRTScreen)
-};
-
-QT_END_NAMESPACE
-
-#endif // QWINRTSCREEN_H
diff --git a/src/plugins/platforms/winrt/qwinrtservices.cpp b/src/plugins/platforms/winrt/qwinrtservices.cpp
deleted file mode 100644
index b27c408f40..0000000000
--- a/src/plugins/platforms/winrt/qwinrtservices.cpp
+++ /dev/null
@@ -1,145 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 "qwinrtservices.h"
-#include "qwinrtfileengine.h"
-#include <QtCore/QUrl>
-#include <QtCore/QDir>
-#include <QtCore/QCoreApplication>
-#include <QtCore/qfunctions_winrt.h>
-
-#include <wrl.h>
-#include <windows.foundation.h>
-#include <windows.storage.h>
-#include <windows.system.h>
-using namespace Microsoft::WRL;
-using namespace Microsoft::WRL::Wrappers;
-using namespace ABI::Windows::Foundation;
-using namespace ABI::Windows::Storage;
-using namespace ABI::Windows::System;
-
-QT_BEGIN_NAMESPACE
-
-class QWinRTServicesPrivate
-{
-public:
- ComPtr<IUriRuntimeClassFactory> uriFactory;
- ComPtr<IStorageFileStatics> fileFactory;
- ComPtr<ILauncherStatics> launcher;
-};
-
-QWinRTServices::QWinRTServices()
- : d_ptr(new QWinRTServicesPrivate)
-{
- Q_D(QWinRTServices);
-
- HRESULT hr;
- hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Foundation_Uri).Get(),
- IID_PPV_ARGS(&d->uriFactory));
- Q_ASSERT_X(SUCCEEDED(hr), Q_FUNC_INFO, qPrintable(qt_error_string(hr)));
-
- hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Storage_StorageFile).Get(),
- IID_PPV_ARGS(&d->fileFactory));
- Q_ASSERT_X(SUCCEEDED(hr), Q_FUNC_INFO, qPrintable(qt_error_string(hr)));
-
- hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_System_Launcher).Get(),
- IID_PPV_ARGS(&d->launcher));
- Q_ASSERT_X(SUCCEEDED(hr), Q_FUNC_INFO, qPrintable(qt_error_string(hr)));
-}
-
-bool QWinRTServices::openUrl(const QUrl &url)
-{
- Q_D(QWinRTServices);
-
- ComPtr<IUriRuntimeClass> uri;
- QString urlString = url.toString();
- HStringReference uriString(reinterpret_cast<LPCWSTR>(urlString.utf16()),
- uint(urlString.length()));
- HRESULT hr = d->uriFactory->CreateUri(uriString.Get(), &uri);
- RETURN_FALSE_IF_FAILED("Failed to create URI from QUrl.");
-
- ComPtr<IAsyncOperation<bool>> op;
- hr = d->launcher->LaunchUriAsync(uri.Get(), &op);
- RETURN_FALSE_IF_FAILED("Failed to start URI launch.");
-
- boolean result;
- hr = QWinRTFunctions::await(op, &result);
- RETURN_FALSE_IF_FAILED("Failed to launch URI.");
-
- return result;
-}
-
-bool QWinRTServices::openDocument(const QUrl &url)
-{
- Q_D(QWinRTServices);
-
- HRESULT hr;
- ComPtr<IStorageFile> file;
- ComPtr<IStorageItem> item = QWinRTFileEngineHandler::registeredFile(url.toLocalFile());
- if (item) {
- hr = item.As(&file);
- if (FAILED(hr))
- qErrnoWarning(hr, "Failed to cast picked item to a file");
- }
- if (!file) {
- const QString pathString = QDir::toNativeSeparators(url.toLocalFile());
- HStringReference path(reinterpret_cast<LPCWSTR>(pathString.utf16()),
- uint(pathString.length()));
- ComPtr<IAsyncOperation<StorageFile *>> op;
- hr = d->fileFactory->GetFileFromPathAsync(path.Get(), &op);
- RETURN_FALSE_IF_FAILED("Failed to initialize file URI.");
-
- hr = QWinRTFunctions::await(op, file.GetAddressOf());
- RETURN_FALSE_IF_FAILED("Failed to get file URI.");
- }
-
- boolean result;
- {
- ComPtr<IAsyncOperation<bool>> op;
- hr = d->launcher->LaunchFileAsync(file.Get(), &op);
- RETURN_FALSE_IF_FAILED("Failed to start file launch.");
-
- hr = QWinRTFunctions::await(op, &result);
- RETURN_FALSE_IF_FAILED("Failed to launch file.");
- }
-
- return result;
-}
-
-QT_END_NAMESPACE
diff --git a/src/plugins/platforms/winrt/qwinrtservices.h b/src/plugins/platforms/winrt/qwinrtservices.h
deleted file mode 100644
index 202ce722cf..0000000000
--- a/src/plugins/platforms/winrt/qwinrtservices.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 QWINRTSERVICES_H
-#define QWINRTSERVICES_H
-
-#include <qpa/qplatformservices.h>
-#include <QtCore/QScopedPointer>
-
-QT_BEGIN_NAMESPACE
-
-class QWinRTServicesPrivate;
-class QWinRTServices : public QPlatformServices
-{
-public:
- explicit QWinRTServices();
- ~QWinRTServices() override = default;
-
- bool openUrl(const QUrl &url) override;
- bool openDocument(const QUrl &url) override;
-
-private:
- QScopedPointer<QWinRTServicesPrivate> d_ptr;
- Q_DECLARE_PRIVATE(QWinRTServices)
-};
-
-QT_END_NAMESPACE
-
-#endif // QWINRTSERVICES_H
diff --git a/src/plugins/platforms/winrt/qwinrttheme.cpp b/src/plugins/platforms/winrt/qwinrttheme.cpp
deleted file mode 100644
index 0e1504b1c1..0000000000
--- a/src/plugins/platforms/winrt/qwinrttheme.cpp
+++ /dev/null
@@ -1,342 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 "qwinrttheme.h"
-#include "qwinrtmessagedialoghelper.h"
-#include "qwinrtfiledialoghelper.h"
-
-#include <QtCore/qfunctions_winrt.h>
-#include <QtGui/QPalette>
-
-#include <QtFontDatabaseSupport/private/qwinrtfontdatabase_p.h>
-
-#include <wrl.h>
-#include <windows.ui.h>
-#include <windows.ui.viewmanagement.h>
-#if _MSC_VER >= 1900
-#include <windows.foundation.metadata.h>
-using namespace ABI::Windows::Foundation::Metadata;
-#endif
-
-using namespace Microsoft::WRL;
-using namespace Microsoft::WRL::Wrappers;
-using namespace ABI::Windows::UI;
-using namespace ABI::Windows::UI::ViewManagement;
-
-QT_BEGIN_NAMESPACE
-
-Q_LOGGING_CATEGORY(lcQpaTheme, "qt.qpa.theme")
-
-class QWinRTApiInformationHandler {
-public:
- QWinRTApiInformationHandler()
- {
- HRESULT hr;
- hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Foundation_Metadata_ApiInformation).Get(),
- IID_PPV_ARGS(&m_apiInformationStatics));
- Q_ASSERT_SUCCEEDED(hr);
- }
-
- ComPtr<IApiInformationStatics> apiInformationStatics() const
- {
- return m_apiInformationStatics;
- }
-
-private:
- ComPtr<IApiInformationStatics> m_apiInformationStatics;
-};
-Q_GLOBAL_STATIC(QWinRTApiInformationHandler, gApiHandler);
-
-static IUISettings *uiSettings()
-{
- static ComPtr<IUISettings> settings;
- if (!settings) {
- HRESULT hr;
- hr = RoActivateInstance(Wrappers::HString::MakeReference(RuntimeClass_Windows_UI_ViewManagement_UISettings).Get(),
- &settings);
- Q_ASSERT_SUCCEEDED(hr);
- }
- return settings.Get();
-}
-
-class QWinRTThemePrivate
-{
-public:
- QWinRTThemePrivate()
- : monospaceFont(QWinRTFontDatabase::familyForStyleHint(QFont::Monospace))
- {
- }
-
- QPalette palette;
- QFont monospaceFont;
-};
-
-static inline QColor fromColor(const Color &color)
-{
- return QColor(color.R, color.G, color.B, color.A);
-}
-
-static bool uiColorSettings(const wchar_t *value, UIElementType type, Color *color)
-{
- ComPtr<IApiInformationStatics> apiInformationStatics = gApiHandler->apiInformationStatics();
- if (!apiInformationStatics) {
- qErrnoWarning("Could not get ApiInformationStatics");
- return false;
- }
-
- static const HStringReference enumRef(L"Windows.UI.ViewManagement.UIElementType");
- HStringReference valueRef(value);
-
- HRESULT hr;
- boolean exists;
- hr = apiInformationStatics->IsEnumNamedValuePresent(enumRef.Get(), valueRef.Get(), &exists);
-
- if (hr != S_OK || !exists)
- return false;
-
- return SUCCEEDED(uiSettings()->UIElementColor(type, color));
-}
-
-static void nativeColorSettings(QPalette &p)
-{
- Color color;
-
- if (uiColorSettings(L"ActiveCaption", UIElementType_ActiveCaption, &color))
- p.setColor(QPalette::ToolTipBase, fromColor(color));
-
- if (uiColorSettings(L"Background", UIElementType_Background, &color))
- p.setColor(QPalette::AlternateBase, fromColor(color));
-
- if (uiColorSettings(L"ButtonFace", UIElementType_ButtonFace, &color)) {
- p.setColor(QPalette::Button, fromColor(color));
- p.setColor(QPalette::Midlight, fromColor(color).lighter(110));
- p.setColor(QPalette::Light, fromColor(color).lighter(150));
- p.setColor(QPalette::Mid, fromColor(color).dark(130));
- p.setColor(QPalette::Dark, fromColor(color).dark(150));
- }
-
- if (uiColorSettings(L"ButtonText", UIElementType_ButtonText, &color)) {
- p.setColor(QPalette::ButtonText, fromColor(color));
- p.setColor(QPalette::Text, fromColor(color));
- }
-
- if (uiColorSettings(L"CaptionText", UIElementType_CaptionText, &color))
- p.setColor(QPalette::ToolTipText, fromColor(color));
-
- if (uiColorSettings(L"Highlight", UIElementType_Highlight, &color))
- p.setColor(QPalette::Highlight, fromColor(color));
-
- if (uiColorSettings(L"HighlightText", UIElementType_HighlightText, &color))
- p.setColor(QPalette::HighlightedText, fromColor(color));
-
- if (uiColorSettings(L"Window", UIElementType_Window, &color)) {
- p.setColor(QPalette::Window, fromColor(color));
- p.setColor(QPalette::Base, fromColor(color));
- }
-
- if (uiColorSettings(L"Hotlight", UIElementType_Hotlight, &color))
- p.setColor(QPalette::BrightText, fromColor(color));
-
- // Starting with SDK 15063 those have been removed.
-#ifndef QT_WINRT_DISABLE_PHONE_COLORS
- //Phone related
- ComPtr<IApiInformationStatics> apiInformationStatics = gApiHandler->apiInformationStatics();
- boolean phoneApiPresent = false;
- HRESULT hr;
- HStringReference phoneRef(L"Windows.Phone.PhoneContract");
- hr = apiInformationStatics.Get()->IsApiContractPresentByMajor(phoneRef.Get(), 1, &phoneApiPresent);
- if (FAILED(hr) || !phoneApiPresent)
- return;
-
- if (uiColorSettings(L"PopupBackground", UIElementType_PopupBackground, &color)) {
- p.setColor(QPalette::ToolTipBase, fromColor(color));
- p.setColor(QPalette::AlternateBase, fromColor(color));
- }
-
- if (uiColorSettings(L"NonTextMedium", UIElementType_NonTextMedium, &color))
- p.setColor(QPalette::Button, fromColor(color));
-
- if (uiColorSettings(L"NonTextMediumHigh", UIElementType_NonTextMediumHigh, &color))
- p.setColor(QPalette::Midlight, fromColor(color));
-
- if (uiColorSettings(L"NonTextHigh", UIElementType_NonTextHigh, &color))
- p.setColor(QPalette::Light, fromColor(color));
-
- if (uiColorSettings(L"NonTextMediumLow", UIElementType_NonTextMediumLow, &color))
- p.setColor(QPalette::Mid, fromColor(color));
-
- if (uiColorSettings(L"NonTextLow", UIElementType_NonTextLow, &color))
- p.setColor(QPalette::Dark, fromColor(color));
-
- if (uiColorSettings(L"TextHigh", UIElementType_TextHigh, &color)) {
- p.setColor(QPalette::ButtonText, fromColor(color));
- p.setColor(QPalette::Text, fromColor(color));
- p.setColor(QPalette::WindowText, fromColor(color));
- }
-
- if (uiColorSettings(L"TextMedium", UIElementType_TextMedium, &color))
- p.setColor(QPalette::ToolTipText, fromColor(color));
-
- if (uiColorSettings(L"AccentColor", UIElementType_AccentColor, &color))
- p.setColor(QPalette::Highlight, fromColor(color));
-
- if (uiColorSettings(L"PageBackground", UIElementType_PageBackground, &color)) {
- p.setColor(QPalette::Window, fromColor(color));
- p.setColor(QPalette::Base, fromColor(color));
- }
-
- if (uiColorSettings(L"TextContrastWithHigh", UIElementType_TextContrastWithHigh, &color))
- p.setColor(QPalette::BrightText, fromColor(color));
-#endif // QT_WINRT_DISABLE_PHONE_COLORS
-}
-
-QWinRTTheme::QWinRTTheme()
- : d_ptr(new QWinRTThemePrivate)
-{
- Q_D(QWinRTTheme);
- qCDebug(lcQpaTheme) << __FUNCTION__;
-
- nativeColorSettings(d->palette);
-}
-
-bool QWinRTTheme::usePlatformNativeDialog(DialogType type) const
-{
- qCDebug(lcQpaTheme) << __FUNCTION__ << type;
- static bool useNativeDialogs = qEnvironmentVariableIsSet("QT_USE_WINRT_NATIVE_DIALOGS")
- ? qEnvironmentVariableIntValue("QT_USE_WINRT_NATIVE_DIALOGS") : true;
-
- if (type == FileDialog || type == MessageDialog)
- return useNativeDialogs;
- return false;
-}
-
-QPlatformDialogHelper *QWinRTTheme::createPlatformDialogHelper(DialogType type) const
-{
- qCDebug(lcQpaTheme) << __FUNCTION__ << type;
- switch (type) {
- case FileDialog:
- return new QWinRTFileDialogHelper;
- case MessageDialog:
- return new QWinRTMessageDialogHelper(this);
- default:
- break;
- }
- return QPlatformTheme::createPlatformDialogHelper(type);
-}
-
-QVariant QWinRTTheme::styleHint(QPlatformIntegration::StyleHint hint)
-{
- qCDebug(lcQpaTheme) << __FUNCTION__ << hint;
- HRESULT hr;
- switch (hint) {
- case QPlatformIntegration::CursorFlashTime: {
- quint32 blinkRate;
- hr = uiSettings()->get_CaretBlinkRate(&blinkRate);
- RETURN_IF_FAILED("Failed to get caret blink rate", return defaultThemeHint(CursorFlashTime));
- return blinkRate;
- }
- case QPlatformIntegration::KeyboardInputInterval:
- return defaultThemeHint(KeyboardInputInterval);
- case QPlatformIntegration::MouseDoubleClickInterval: {
- quint32 doubleClickTime;
- hr = uiSettings()->get_DoubleClickTime(&doubleClickTime);
- RETURN_IF_FAILED("Failed to get double click time", return defaultThemeHint(MouseDoubleClickInterval));
- return doubleClickTime;
- }
- case QPlatformIntegration::StartDragDistance:
- return defaultThemeHint(StartDragDistance);
- case QPlatformIntegration::StartDragTime:
- return defaultThemeHint(StartDragTime);
- case QPlatformIntegration::KeyboardAutoRepeatRate:
- return defaultThemeHint(KeyboardAutoRepeatRate);
- case QPlatformIntegration::ShowIsFullScreen:
- return false;
- case QPlatformIntegration::PasswordMaskDelay:
- return defaultThemeHint(PasswordMaskDelay);
- case QPlatformIntegration::FontSmoothingGamma:
- return qreal(1.7);
- case QPlatformIntegration::StartDragVelocity:
- return defaultThemeHint(StartDragVelocity);
- case QPlatformIntegration::UseRtlExtensions:
- return false;
- case QPlatformIntegration::PasswordMaskCharacter:
- return defaultThemeHint(PasswordMaskCharacter);
- case QPlatformIntegration::SetFocusOnTouchRelease:
- return true;
- case QPlatformIntegration::ShowIsMaximized:
- return true;
- case QPlatformIntegration::MousePressAndHoldInterval:
- return defaultThemeHint(MousePressAndHoldInterval);
- default:
- break;
- }
- return QVariant();
-}
-
-QVariant QWinRTTheme::themeHint(ThemeHint hint) const
-{
- qCDebug(lcQpaTheme) << __FUNCTION__ << hint;
- switch (hint) {
- case StyleNames:
- return QStringList() << QStringLiteral("fusion") << QStringLiteral("windows");
- default:
- return QPlatformTheme::themeHint(hint);
- }
-}
-
-const QPalette *QWinRTTheme::palette(Palette type) const
-{
- Q_D(const QWinRTTheme);
- qCDebug(lcQpaTheme) << __FUNCTION__ << type;
- if (type == SystemPalette)
- return &d->palette;
- return QPlatformTheme::palette(type);
-}
-
-const QFont *QWinRTTheme::font(QPlatformTheme::Font type) const
-{
- Q_D(const QWinRTTheme);
- qCDebug(lcQpaTheme) << __FUNCTION__ << type;
- if (type == QPlatformTheme::FixedFont)
- return &d->monospaceFont;
-
- return QPlatformTheme::font(type);
-}
-
-QT_END_NAMESPACE
diff --git a/src/plugins/platforms/winrt/qwinrttheme.h b/src/plugins/platforms/winrt/qwinrttheme.h
deleted file mode 100644
index acf5a54a94..0000000000
--- a/src/plugins/platforms/winrt/qwinrttheme.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 QWINRTTHEME_H
-#define QWINRTTHEME_H
-
-#include <qpa/qplatformtheme.h>
-#include <qpa/qplatformintegration.h>
-#include <QtCore/QLoggingCategory>
-
-QT_BEGIN_NAMESPACE
-
-Q_DECLARE_LOGGING_CATEGORY(lcQpaTheme)
-
-class QWinRTThemePrivate;
-class QWinRTTheme : public QPlatformTheme
-{
-public:
- QWinRTTheme();
-
- bool usePlatformNativeDialog(DialogType type) const override;
- QPlatformDialogHelper *createPlatformDialogHelper(DialogType type) const override;
-
- const QPalette *palette(Palette type = SystemPalette) const override;
- const QFont *font(Font type = SystemFont) const override;
-
- static QVariant styleHint(QPlatformIntegration::StyleHint hint);
- QVariant themeHint(ThemeHint hint) const override;
-private:
- QScopedPointer<QWinRTThemePrivate> d_ptr;
- Q_DECLARE_PRIVATE(QWinRTTheme)
-};
-
-QT_END_NAMESPACE
-
-#endif // QWINRTTHEME_H
diff --git a/src/plugins/platforms/winrt/qwinrtwindow.cpp b/src/plugins/platforms/winrt/qwinrtwindow.cpp
deleted file mode 100644
index 73816b6512..0000000000
--- a/src/plugins/platforms/winrt/qwinrtwindow.cpp
+++ /dev/null
@@ -1,438 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 "qwinrtwindow.h"
-#include "qwinrtscreen.h"
-#include <private/qeventdispatcher_winrt_p.h>
-
-#include <EGL/egl.h>
-#include <EGL/eglext.h>
-
-#include <qfunctions_winrt.h>
-#include <qpa/qplatformscreen.h>
-#include <qpa/qwindowsysteminterface.h>
-#include <QtGui/QGuiApplication>
-#include <QtGui/QOpenGLContext>
-#include <QtGui/QWindow>
-#include <QtEglSupport/private/qeglconvenience_p.h>
-
-#include <functional>
-#include <wrl.h>
-#include <windows.foundation.h>
-#include <windows.foundation.collections.h>
-#include <windows.ui.xaml.h>
-#include <windows.ui.xaml.controls.h>
-#include <windows.ui.viewmanagement.h>
-
-using namespace ABI::Windows::UI::ViewManagement;
-using namespace Microsoft::WRL;
-using namespace Microsoft::WRL::Wrappers;
-using namespace ABI::Windows::Foundation;
-using namespace ABI::Windows::Foundation::Collections;
-using namespace ABI::Windows::UI;
-using namespace ABI::Windows::UI::Xaml;
-using namespace ABI::Windows::UI::Xaml::Controls;
-
-QT_BEGIN_NAMESPACE
-
-Q_LOGGING_CATEGORY(lcQpaWindows, "qt.qpa.windows");
-
-static void setUIElementVisibility(IUIElement *uiElement, bool visibility)
-{
- Q_ASSERT(uiElement);
- QEventDispatcherWinRT::runOnXamlThread([uiElement, visibility]() {
- HRESULT hr;
- hr = uiElement->put_Visibility(visibility ? Visibility_Visible : Visibility_Collapsed);
- Q_ASSERT_SUCCEEDED(hr);
- return S_OK;
- });
-}
-
-class QWinRTWindowPrivate
-{
-public:
- QWinRTScreen *screen;
-
- QSurfaceFormat surfaceFormat;
- QString windowTitle;
- Qt::WindowStates state;
- EGLDisplay display;
- EGLSurface surface;
-
- ComPtr<ISwapChainPanel> swapChainPanel;
- ComPtr<ICanvasStatics> canvas;
- ComPtr<IUIElement> uiElement;
-};
-
-QWinRTWindow::QWinRTWindow(QWindow *window)
- : QPlatformWindow(window)
- , d_ptr(new QWinRTWindowPrivate)
-{
- Q_D(QWinRTWindow);
- qCDebug(lcQpaWindows) << __FUNCTION__ << this;
-
- d->surface = EGL_NO_SURFACE;
- d->display = EGL_NO_DISPLAY;
- d->screen = static_cast<QWinRTScreen *>(screen());
- handleContentOrientationChange(window->contentOrientation());
-
- d->surfaceFormat.setMajorVersion(3);
- d->surfaceFormat.setMinorVersion(0);
- d->surfaceFormat.setAlphaBufferSize(0);
- d->surfaceFormat.setRedBufferSize(8);
- d->surfaceFormat.setGreenBufferSize(8);
- d->surfaceFormat.setBlueBufferSize(8);
- d->surfaceFormat.setDepthBufferSize(24);
- d->surfaceFormat.setStencilBufferSize(8);
- d->surfaceFormat.setRenderableType(QSurfaceFormat::OpenGLES);
- d->surfaceFormat.setSamples(1);
- d->surfaceFormat.setSwapBehavior(QSurfaceFormat::DoubleBuffer);
-
- HRESULT hr;
- hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_UI_Xaml_Controls_Canvas).Get(),
- IID_PPV_ARGS(&d->canvas));
- Q_ASSERT_SUCCEEDED(hr);
- hr = QEventDispatcherWinRT::runOnXamlThread([d]() {
- // Create a new swapchain and place it inside the canvas
- HRESULT hr;
- hr = RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_UI_Xaml_Controls_SwapChainPanel).Get(),
- &d->swapChainPanel);
- Q_ASSERT_SUCCEEDED(hr);
- hr = d->swapChainPanel.As(&d->uiElement);
- Q_ASSERT_SUCCEEDED(hr);
-
- ComPtr<Xaml::IFrameworkElement> frameworkElement;
- hr = d->swapChainPanel.As(&frameworkElement);
- Q_ASSERT_SUCCEEDED(hr);
- const QSizeF size = QSizeF(d->screen->geometry().size()) / d->screen->scaleFactor();
- hr = frameworkElement->put_Width(size.width());
- Q_ASSERT_SUCCEEDED(hr);
- hr = frameworkElement->put_Height(size.height());
- Q_ASSERT_SUCCEEDED(hr);
-
- ComPtr<IDependencyObject> canvas = d->screen->canvas();
- ComPtr<IPanel> panel;
- hr = canvas.As(&panel);
- Q_ASSERT_SUCCEEDED(hr);
- ComPtr<IVector<UIElement *>> children;
- hr = panel->get_Children(&children);
- Q_ASSERT_SUCCEEDED(hr);
- hr = children->Append(d->uiElement.Get());
- Q_ASSERT_SUCCEEDED(hr);
- return S_OK;
- });
- Q_ASSERT_SUCCEEDED(hr);
-
- setWindowFlags(window->flags());
- setWindowState(window->windowStates());
- setWindowTitle(window->title());
-
- setGeometry(window->geometry());
-}
-
-QWinRTWindow::~QWinRTWindow()
-{
- Q_D(QWinRTWindow);
- qCDebug(lcQpaWindows) << __FUNCTION__ << this;
-
- HRESULT hr;
- hr = QEventDispatcherWinRT::runOnXamlThread([d]() {
- HRESULT hr;
- ComPtr<IDependencyObject> canvas = d->screen->canvas();
- ComPtr<IPanel> panel;
- hr = canvas.As(&panel);
- Q_ASSERT_SUCCEEDED(hr);
- ComPtr<IVector<UIElement *>> children;
- hr = panel->get_Children(&children);
- Q_ASSERT_SUCCEEDED(hr);
- quint32 index;
- boolean found;
- hr = children->IndexOf(d->uiElement.Get(), &index, &found);
- Q_ASSERT_SUCCEEDED(hr);
- if (found) {
- hr = children->RemoveAt(index);
- Q_ASSERT_SUCCEEDED(hr);
- }
- return S_OK;
- });
- RETURN_VOID_IF_FAILED("Failed to completely destroy window resources, likely because the application is shutting down");
-
- if (d->screen->mouseGrabWindow() == this)
- d->screen->setMouseGrabWindow(this, false);
- if (d->screen->keyboardGrabWindow() == this)
- d->screen->setKeyboardGrabWindow(this, false);
-
- d->screen->removeWindow(window());
-
- if (!d->surface)
- return;
-
- qCDebug(lcQpaWindows) << __FUNCTION__ << ": Destroying surface";
-
- EGLBoolean value = eglDestroySurface(d->display, d->surface);
- d->surface = EGL_NO_SURFACE;
- if (Q_UNLIKELY(value == EGL_FALSE))
- qCritical("Failed to destroy EGL window surface: 0x%x", eglGetError());
-}
-
-QSurfaceFormat QWinRTWindow::format() const
-{
- Q_D(const QWinRTWindow);
- return d->surfaceFormat;
-}
-
-bool QWinRTWindow::isActive() const
-{
- Q_D(const QWinRTWindow);
- return d->screen->topWindow() == window();
-}
-
-bool QWinRTWindow::isExposed() const
-{
- Q_D(const QWinRTWindow);
- const bool exposed = isActive() && !d->screen->resizePending();
- return exposed;
-}
-
-void QWinRTWindow::setGeometry(const QRect &rect)
-{
- Q_D(QWinRTWindow);
- qCDebug(lcQpaWindows) << __FUNCTION__ << this << rect;
-
- const Qt::WindowFlags windowFlags = window()->flags();
- const Qt::WindowFlags windowType = windowFlags & Qt::WindowType_Mask;
- if (window()->isTopLevel() && (windowType == Qt::Window || windowType == Qt::Dialog)) {
- const QRect screenRect = windowFlags & Qt::MaximizeUsingFullscreenGeometryHint
- ? d->screen->geometry() : d->screen->availableGeometry();
- qCDebug(lcQpaWindows) << __FUNCTION__ << "top-level, overwrite" << screenRect;
- QPlatformWindow::setGeometry(screenRect);
- QWindowSystemInterface::handleGeometryChange(window(), geometry());
- } else {
- QPlatformWindow::setGeometry(rect);
- QWindowSystemInterface::handleGeometryChange(window(), rect);
- }
-
- HRESULT hr;
- hr = QEventDispatcherWinRT::runOnXamlThread([this, d]() {
- HRESULT hr;
- const QRect windowGeometry = geometry();
- const QPointF topLeft= QPointF(windowGeometry.topLeft()) / d->screen->scaleFactor();
- hr = d->canvas->SetTop(d->uiElement.Get(), topLeft.y());
- Q_ASSERT_SUCCEEDED(hr);
- hr = d->canvas->SetLeft(d->uiElement.Get(), topLeft.x());
- Q_ASSERT_SUCCEEDED(hr);
- ComPtr<Xaml::IFrameworkElement> frameworkElement;
- hr = d->swapChainPanel.As(&frameworkElement);
- Q_ASSERT_SUCCEEDED(hr);
- const QSizeF size = QSizeF(windowGeometry.size()) / d->screen->scaleFactor();
- hr = frameworkElement->put_Width(size.width());
- Q_ASSERT_SUCCEEDED(hr);
- hr = frameworkElement->put_Height(size.height());
- Q_ASSERT_SUCCEEDED(hr);
- qCDebug(lcQpaWindows) << __FUNCTION__ << "(setGeometry Xaml)" << this
- << topLeft << size;
- return S_OK;
- });
- Q_ASSERT_SUCCEEDED(hr);
-}
-
-void QWinRTWindow::setVisible(bool visible)
-{
- Q_D(QWinRTWindow);
- qCDebug(lcQpaWindows) << __FUNCTION__ << this << visible;
-
- if (!window()->isTopLevel())
- return;
- if (visible) {
- d->screen->addWindow(window());
- setUIElementVisibility(d->uiElement.Get(), d->state != Qt::WindowMinimized);
- } else {
- d->screen->removeWindow(window());
- setUIElementVisibility(d->uiElement.Get(), false);
- }
-}
-
-void QWinRTWindow::setWindowTitle(const QString &title)
-{
- Q_D(QWinRTWindow);
- d->windowTitle = title;
-
- if (d->screen->topWindow() == window())
- d->screen->updateWindowTitle(title);
-}
-
-void QWinRTWindow::raise()
-{
- Q_D(QWinRTWindow);
- qCDebug(lcQpaWindows) << __FUNCTION__ << this;
- if (!window()->isTopLevel())
- return;
- d->screen->raise(window());
-}
-
-void QWinRTWindow::lower()
-{
- Q_D(QWinRTWindow);
- qCDebug(lcQpaWindows) << __FUNCTION__ << this;
- if (!window()->isTopLevel())
- return;
- d->screen->lower(window());
-}
-
-WId QWinRTWindow::winId() const
-{
- Q_D(const QWinRTWindow);
- return WId(d->swapChainPanel.Get());
-}
-
-qreal QWinRTWindow::devicePixelRatio() const
-{
- return screen()->devicePixelRatio();
-}
-
-void QWinRTWindow::setWindowState(Qt::WindowStates state)
-{
- Q_D(QWinRTWindow);
- qCDebug(lcQpaWindows) << __FUNCTION__ << this << state;
-
- if (d->state == state)
- return;
-
- if (state & Qt::WindowMinimized) {
- setUIElementVisibility(d->uiElement.Get(), false);
- d->state = state;
- return;
- }
-
- if (state & Qt::WindowFullScreen) {
- HRESULT hr;
- boolean success;
- hr = QEventDispatcherWinRT::runOnXamlThread([&hr, &success]() {
- ComPtr<IApplicationViewStatics2> applicationViewStatics;
- hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_UI_ViewManagement_ApplicationView).Get(),
- IID_PPV_ARGS(&applicationViewStatics));
- RETURN_HR_IF_FAILED("Could not access application view statics.");
- ComPtr<IApplicationView> view;
- hr = applicationViewStatics->GetForCurrentView(&view);
- RETURN_HR_IF_FAILED("Could not access application view.");
- ComPtr<IApplicationView3> view3;
- hr = view.As(&view3);
- Q_ASSERT_SUCCEEDED(hr);
- hr = view3->TryEnterFullScreenMode(&success);
- return hr;
- });
- if (FAILED(hr) || !success) {
- qCDebug(lcQpaWindows) << "Failed to enter full screen mode.";
- return;
- }
- d->screen->setResizePending();
- d->state = state;
- return;
- }
-
- if (d->state & Qt::WindowFullScreen) {
- HRESULT hr;
- hr = QEventDispatcherWinRT::runOnXamlThread([&hr]() {
- ComPtr<IApplicationViewStatics2> applicationViewStatics;
- hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_UI_ViewManagement_ApplicationView).Get(),
- IID_PPV_ARGS(&applicationViewStatics));
- RETURN_HR_IF_FAILED("Could not access application view statics.");
- ComPtr<IApplicationView> view;
- hr = applicationViewStatics->GetForCurrentView(&view);
- RETURN_HR_IF_FAILED("Could not access application view.");
- ComPtr<IApplicationView3> view3;
- hr = view.As(&view3);
- Q_ASSERT_SUCCEEDED(hr);
- hr = view3->ExitFullScreenMode();
- return hr;
- });
- if (FAILED(hr)) {
- qCDebug(lcQpaWindows) << "Failed to exit full screen mode.";
- return;
- }
- d->screen->setResizePending();
- }
-
- if (d->state & Qt::WindowMinimized || state == Qt::WindowNoState || state == Qt::WindowActive)
- setUIElementVisibility(d->uiElement.Get(), true);
-
- d->state = state;
-}
-
-bool QWinRTWindow::setMouseGrabEnabled(bool grab)
-{
- Q_D(QWinRTWindow);
- if (!isActive() && grab) {
- qWarning("%s: Not setting mouse grab for invisible window %s/'%s'",
- __FUNCTION__, window()->metaObject()->className(),
- qPrintable(window()->objectName()));
- return false;
- }
- return d->screen->setMouseGrabWindow(this, grab);
-}
-
-bool QWinRTWindow::setKeyboardGrabEnabled(bool grab)
-{
- Q_D(QWinRTWindow);
- return d->screen->setKeyboardGrabWindow(this, grab);
-}
-
-EGLSurface QWinRTWindow::eglSurface() const
-{
- Q_D(const QWinRTWindow);
- return d->surface;
-}
-
-void QWinRTWindow::createEglSurface(EGLDisplay display, EGLConfig config)
-{
- Q_D(QWinRTWindow);
- if (d->surface == EGL_NO_SURFACE) {
- d->display = display;
- QEventDispatcherWinRT::runOnXamlThread([this, d, display, config]() {
- d->surface = eglCreateWindowSurface(display, config,
- reinterpret_cast<EGLNativeWindowType>(winId()),
- nullptr);
- if (Q_UNLIKELY(d->surface == EGL_NO_SURFACE))
- qCritical("Failed to create EGL window surface: 0x%x", eglGetError());
- return S_OK;
- });
- }
-}
-
-QT_END_NAMESPACE
diff --git a/src/plugins/platforms/winrt/qwinrtwindow.h b/src/plugins/platforms/winrt/qwinrtwindow.h
deleted file mode 100644
index 0445e6bf54..0000000000
--- a/src/plugins/platforms/winrt/qwinrtwindow.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 QWINRTWINDOW_H
-#define QWINRTWINDOW_H
-
-#include <QtCore/QLoggingCategory>
-#include <qpa/qplatformwindow.h>
-#include <qpa/qwindowsysteminterface.h>
-#include <EGL/egl.h>
-
-QT_BEGIN_NAMESPACE
-
-Q_DECLARE_LOGGING_CATEGORY(lcQpaWindows)
-
-class QWinRTWindowPrivate;
-class QWinRTWindow : public QPlatformWindow
-{
-public:
- QWinRTWindow(QWindow *window);
- ~QWinRTWindow() override;
-
- QSurfaceFormat format() const override;
- bool isActive() const override;
- bool isExposed() const override;
- void setGeometry(const QRect &rect) override;
- void setVisible(bool visible) override;
- void setWindowTitle(const QString &title) override;
- void raise() override;
- void lower() override;
-
- WId winId() const override;
-
- qreal devicePixelRatio() const override;
- void setWindowState(Qt::WindowStates state) override;
-
- bool setMouseGrabEnabled(bool grab) override;
- bool setKeyboardGrabEnabled(bool grab) override;
-
- EGLSurface eglSurface() const;
- void createEglSurface(EGLDisplay display, EGLConfig config);
-
-private:
- QScopedPointer<QWinRTWindowPrivate> d_ptr;
- Q_DECLARE_PRIVATE(QWinRTWindow)
-};
-
-QT_END_NAMESPACE
-
-#endif // QWINRTWINDOW_H
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiaaccessibility.cpp b/src/plugins/platforms/winrt/uiautomation/qwinrtuiaaccessibility.cpp
deleted file mode 100644
index 40274fb967..0000000000
--- a/src/plugins/platforms/winrt/uiautomation/qwinrtuiaaccessibility.cpp
+++ /dev/null
@@ -1,113 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 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 <QtGui/qtguiglobal.h>
-#if QT_CONFIG(accessibility)
-
-#include "qwinrtuiaaccessibility.h"
-#include "qwinrtuiamainprovider.h"
-
-#include <QtGui/QAccessible>
-#include <QtGui/QWindow>
-#include <QtGui/QGuiApplication>
-#include <QtGui/private/qguiapplication_p.h>
-#include <QtCore/qt_windows.h>
-#include <qpa/qplatformintegration.h>
-
-QT_BEGIN_NAMESPACE
-
-QWinRTUiaAccessibility::QWinRTUiaAccessibility()
-{
-}
-
-QWinRTUiaAccessibility::~QWinRTUiaAccessibility()
-{
-}
-
-// Handles UI Automation window messages.
-void QWinRTUiaAccessibility::activate()
-{
- // Start handling accessibility internally
- QGuiApplicationPrivate::platformIntegration()->accessibility()->setActive(true);
-}
-
-// Handles accessibility update notifications.
-void QWinRTUiaAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event)
-{
- if (!event)
- return;
-
- QAccessibleInterface *accessible = event->accessibleInterface();
- if (!isActive() || !accessible || !accessible->isValid())
- return;
-
- switch (event->type()) {
- case QAccessible::Focus:
- QWinRTUiaMainProvider::notifyFocusChange(event);
- break;
- case QAccessible::ObjectCreated:
- case QAccessible::ObjectDestroyed:
- case QAccessible::ObjectShow:
- case QAccessible::ObjectHide:
- case QAccessible::ObjectReorder:
- QWinRTUiaMainProvider::notifyVisibilityChange(event);
- break;
- case QAccessible::StateChanged:
- QWinRTUiaMainProvider::notifyStateChange(static_cast<QAccessibleStateChangeEvent *>(event));
- break;
- case QAccessible::ValueChanged:
- QWinRTUiaMainProvider::notifyValueChange(static_cast<QAccessibleValueChangeEvent *>(event));
- break;
- case QAccessible::TextAttributeChanged:
- case QAccessible::TextColumnChanged:
- case QAccessible::TextInserted:
- case QAccessible::TextRemoved:
- case QAccessible::TextUpdated:
- case QAccessible::TextSelectionChanged:
- case QAccessible::TextCaretMoved:
- QWinRTUiaMainProvider::notifyTextChange(event);
- break;
- default:
- break;
- }
-}
-
-QT_END_NAMESPACE
-
-#endif // QT_CONFIG(accessibility)
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiaaccessibility.h b/src/plugins/platforms/winrt/uiautomation/qwinrtuiaaccessibility.h
deleted file mode 100644
index b966271e21..0000000000
--- a/src/plugins/platforms/winrt/uiautomation/qwinrtuiaaccessibility.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 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 QWINRTUIAACCESSIBILITY_H
-#define QWINRTUIAACCESSIBILITY_H
-
-#include <QtGui/qtguiglobal.h>
-#if QT_CONFIG(accessibility)
-
-#include <qpa/qplatformaccessibility.h>
-
-QT_BEGIN_NAMESPACE
-
-// WinRT platform accessibility implemented over UI Automation.
-class QWinRTUiaAccessibility : public QPlatformAccessibility
-{
-public:
- explicit QWinRTUiaAccessibility();
- virtual ~QWinRTUiaAccessibility();
- static void activate();
- void notifyAccessibilityUpdate(QAccessibleEvent *event) override;
-};
-
-QT_END_NAMESPACE
-
-#endif // QT_CONFIG(accessibility)
-
-#endif // QWINRTUIAACCESSIBILITY_H
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiabaseprovider.cpp b/src/plugins/platforms/winrt/uiautomation/qwinrtuiabaseprovider.cpp
deleted file mode 100644
index ee53714caa..0000000000
--- a/src/plugins/platforms/winrt/uiautomation/qwinrtuiabaseprovider.cpp
+++ /dev/null
@@ -1,76 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 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 <QtGui/qtguiglobal.h>
-#if QT_CONFIG(accessibility)
-
-#include "qwinrtuiabaseprovider.h"
-
-#include <QtGui/QAccessible>
-#include <QtGui/QAccessibleInterface>
-#include <QtCore/QLoggingCategory>
-#include <QtCore/QString>
-
-QT_BEGIN_NAMESPACE
-
-QWinRTUiaBaseProvider::QWinRTUiaBaseProvider(QAccessible::Id id) :
- m_id(id)
-{
-}
-
-QWinRTUiaBaseProvider::~QWinRTUiaBaseProvider()
-{
-}
-
-QAccessibleInterface *QWinRTUiaBaseProvider::accessibleInterface() const
-{
- QAccessibleInterface *accessible = QAccessible::accessibleInterface(m_id);
- if (accessible && accessible->isValid())
- return accessible;
- return nullptr;
-}
-
-QAccessible::Id QWinRTUiaBaseProvider::id() const
-{
- return m_id;
-}
-
-QT_END_NAMESPACE
-
-#endif // QT_CONFIG(accessibility)
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiabaseprovider.h b/src/plugins/platforms/winrt/uiautomation/qwinrtuiabaseprovider.h
deleted file mode 100644
index d8837354dc..0000000000
--- a/src/plugins/platforms/winrt/uiautomation/qwinrtuiabaseprovider.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 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 QWINRTUIABASEPROVIDER_H
-#define QWINRTUIABASEPROVIDER_H
-
-#include <QtGui/qtguiglobal.h>
-#if QT_CONFIG(accessibility)
-
-#include <QtGui/QAccessible>
-#include <QtGui/QAccessibleInterface>
-#include <QtCore/QPointer>
-
-QT_BEGIN_NAMESPACE
-
-// Base class for UI Automation providers.
-class QWinRTUiaBaseProvider : public QObject
-{
- Q_OBJECT
- Q_DISABLE_COPY(QWinRTUiaBaseProvider)
-public:
- explicit QWinRTUiaBaseProvider(QAccessible::Id id);
- virtual ~QWinRTUiaBaseProvider();
-
- QAccessibleInterface *accessibleInterface() const;
- QAccessible::Id id() const;
-
-private:
- QAccessible::Id m_id;
-};
-
-QT_END_NAMESPACE
-
-#endif // QT_CONFIG(accessibility)
-
-#endif // QWINRTUIABASEPROVIDER_H
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiacontrolmetadata.cpp b/src/plugins/platforms/winrt/uiautomation/qwinrtuiacontrolmetadata.cpp
deleted file mode 100644
index 4e406a3545..0000000000
--- a/src/plugins/platforms/winrt/uiautomation/qwinrtuiacontrolmetadata.cpp
+++ /dev/null
@@ -1,182 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 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 <QtGui/qtguiglobal.h>
-#if QT_CONFIG(accessibility)
-
-#include "qwinrtuiacontrolmetadata.h"
-#include "qwinrtuiautils.h"
-
-#include <QtCore/QLoggingCategory>
-#include <QtCore/QString>
-
-QT_BEGIN_NAMESPACE
-
-using namespace QWinRTUiAutomation;
-
-QWinRTUiaControlMetadata::QWinRTUiaControlMetadata()
-{
-}
-
-QWinRTUiaControlMetadata::QWinRTUiaControlMetadata(QAccessible::Id id)
-{
- update(id);
-}
-
-void QWinRTUiaControlMetadata::update(QAccessible::Id id)
-{
- if (QAccessibleInterface *accessible = accessibleForId(id)) {
- m_automationId = generateAutomationId(accessible);
- m_className = generateClassName(accessible);
- m_controlName = generateControlName(accessible);
- m_role = generateRole(accessible);
- m_state = accessible->state();
- m_accelerator = accessible->text(QAccessible::Accelerator);
- m_access = accessible->text(QAccessible::Accelerator);
- m_help = accessible->text(QAccessible::Help);
- m_description = accessible->text(QAccessible::Description);
- m_value = accessible->text(QAccessible::Value);
- m_boundingRect = accessible->rect();
- updateValueData(accessible);
- updateTableData(accessible);
- updateTextData(accessible);
- }
-}
-
-QString QWinRTUiaControlMetadata::generateControlName(QAccessibleInterface *accessible)
-{
- const bool clientTopLevel = (accessible->role() == QAccessible::Client)
- && accessible->parent() && (accessible->parent()->role() == QAccessible::Application);
-
- QString name = accessible->text(QAccessible::Name);
- if (name.isEmpty() && clientTopLevel)
- name = QCoreApplication::applicationName();
- return name;
-}
-
-QString QWinRTUiaControlMetadata::generateClassName(QAccessibleInterface *accessible)
-{
- QString name;
-
- if (QObject *obj = accessible->object())
- name = QLatin1String(obj->metaObject()->className());
- return name;
-}
-
-// Generates an ID based on the name of the controls and their parents.
-QString QWinRTUiaControlMetadata::generateAutomationId(QAccessibleInterface *accessible)
-{
- QString autid;
- QObject *obj = accessible->object();
- while (obj) {
- QString name = obj->objectName();
- if (name.isEmpty()) {
- autid = QStringLiteral("");
- break;
- }
- if (!autid.isEmpty())
- autid.prepend(QLatin1Char('.'));
- autid.prepend(name);
- obj = obj->parent();
- }
- return autid;
-}
-
-QAccessible::Role QWinRTUiaControlMetadata::generateRole(QAccessibleInterface *accessible)
-{
- const bool clientTopLevel = (accessible->role() == QAccessible::Client)
- && accessible->parent() && (accessible->parent()->role() == QAccessible::Application);
-
- if (clientTopLevel) {
- // Reports a top-level widget as a window.
- return QAccessible::Window;
- } else {
- return accessible->role();
- }
-}
-
-void QWinRTUiaControlMetadata::updateValueData(QAccessibleInterface *accessible)
-{
- if (QAccessibleValueInterface *valueInterface = accessible->valueInterface()) {
- m_minimumValue = valueInterface->minimumValue().toDouble();
- m_maximumValue = valueInterface->maximumValue().toDouble();
- m_currentValue = valueInterface->currentValue().toDouble();
- m_minimumStepSize = valueInterface->minimumStepSize().toDouble();
- } else {
- m_minimumValue = 0.0;
- m_maximumValue = 0.0;
- m_currentValue = 0.0;
- m_minimumStepSize = 0.0;
- }
-}
-
-void QWinRTUiaControlMetadata::updateTableData(QAccessibleInterface *accessible)
-{
- if (QAccessibleTableInterface *tableInterface = accessible->tableInterface()) {
- m_rowIndex = 0;
- m_columnIndex = 0;
- m_rowCount = tableInterface->rowCount();
- m_columnCount = tableInterface->columnCount();
- } else if (QAccessibleTableCellInterface *tableCellInterface = accessible->tableCellInterface()) {
- m_rowIndex = tableCellInterface->rowIndex();
- m_columnIndex = tableCellInterface->columnIndex();
- m_rowCount = tableCellInterface->rowExtent();
- m_columnCount = tableCellInterface->columnExtent();
- } else {
- m_rowIndex = 0;
- m_columnIndex = 0;
- m_rowCount = 0;
- m_columnCount = 0;
- }
-}
-
-void QWinRTUiaControlMetadata::updateTextData(QAccessibleInterface *accessible)
-{
- if (QAccessibleTextInterface *textInterface = accessible->textInterface()) {
- m_cursorPosition = textInterface->cursorPosition();
- m_text = textInterface->text(0, textInterface->characterCount());
- } else {
- m_cursorPosition = 0;
- m_text = QStringLiteral("");
- }
-}
-
-QT_END_NAMESPACE
-
-#endif // QT_CONFIG(accessibility)
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiacontrolmetadata.h b/src/plugins/platforms/winrt/uiautomation/qwinrtuiacontrolmetadata.h
deleted file mode 100644
index 769f073a1b..0000000000
--- a/src/plugins/platforms/winrt/uiautomation/qwinrtuiacontrolmetadata.h
+++ /dev/null
@@ -1,117 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 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 QWINRTUIACONTROLMETADATA_H
-#define QWINRTUIACONTROLMETADATA_H
-
-#include <QtGui/qtguiglobal.h>
-#if QT_CONFIG(accessibility)
-
-#include <QString>
-#include <QtGui/QAccessible>
-#include <QtGui/QAccessibleInterface>
-
-QT_BEGIN_NAMESPACE
-
-// Cacheable control metadata
-class QWinRTUiaControlMetadata
-{
-public:
- QWinRTUiaControlMetadata();
- QWinRTUiaControlMetadata(QAccessible::Id id);
- void update(QAccessible::Id id);
- QString automationId() const { return m_automationId; }
- QString className() const { return m_className; }
- QString controlName() const { return m_controlName; }
- QString accelerator() const { return m_accelerator; }
- QString access() const { return m_access; }
- QString help() const { return m_help; }
- QString description() const { return m_description; }
- QString value() const { return m_value; }
- QString text() const { return m_text; }
- QAccessible::Role role() const { return m_role; }
- QAccessible::State state() const { return m_state; }
- QRect boundingRect() const { return m_boundingRect; }
- double minimumValue() const { return m_minimumValue; }
- double maximumValue() const { return m_maximumValue; }
- double currentValue() const { return m_currentValue; }
- double minimumStepSize() const { return m_minimumStepSize; }
- int rowIndex() const { return m_rowIndex; }
- int columnIndex() const { return m_columnIndex; }
- int rowCount() const { return m_rowCount; }
- int columnCount() const { return m_columnCount; }
- int characterCount() const { return m_text.length(); }
- int cursorPosition() const { return m_cursorPosition; }
-
-private:
- QString generateControlName(QAccessibleInterface *accessible);
- QString generateClassName(QAccessibleInterface *accessible);
- QString generateAutomationId(QAccessibleInterface *accessible);
- QAccessible::Role generateRole(QAccessibleInterface *accessible);
- void updateValueData(QAccessibleInterface *accessible);
- void updateTableData(QAccessibleInterface *accessible);
- void updateTextData(QAccessibleInterface *accessible);
- QString m_automationId;
- QString m_className;
- QString m_controlName;
- QString m_accelerator;
- QString m_access;
- QString m_help;
- QString m_description;
- QString m_value;
- QString m_text;
- QAccessible::Role m_role = QAccessible::NoRole;
- QAccessible::State m_state;
- QRect m_boundingRect;
- double m_minimumValue = 0.0;
- double m_maximumValue = 0.0;
- double m_currentValue = 0.0;
- double m_minimumStepSize = 0.0;
- int m_rowIndex = 0;
- int m_columnIndex = 0;
- int m_rowCount = 0;
- int m_columnCount = 0;
- int m_cursorPosition = 0;
-};
-
-QT_END_NAMESPACE
-
-#endif // QT_CONFIG(accessibility)
-
-#endif // QWINRTUIACONTROLMETADATA_H
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiaemptypropertyvalue.h b/src/plugins/platforms/winrt/uiautomation/qwinrtuiaemptypropertyvalue.h
deleted file mode 100644
index 35e4df75fc..0000000000
--- a/src/plugins/platforms/winrt/uiautomation/qwinrtuiaemptypropertyvalue.h
+++ /dev/null
@@ -1,108 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 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 QWINRTUIAEMPTYPROPERTYVALUE_H
-#define QWINRTUIAEMPTYPROPERTYVALUE_H
-
-#include <QtGui/qtguiglobal.h>
-#if QT_CONFIG(accessibility)
-
-#include <wrl.h>
-#include <windows.ui.xaml.h>
-
-QT_BEGIN_NAMESPACE
-
-// Implements an empty property value.
-class QWinRTUiaEmptyPropertyValue :
- public Microsoft::WRL::RuntimeClass<ABI::Windows::Foundation::IPropertyValue>
-{
- InspectableClass(L"QWinRTUiaEmptyPropertyValue", BaseTrust);
-public:
-
- HRESULT STDMETHODCALLTYPE get_Type(ABI::Windows::Foundation::PropertyType *value)
- {
- *value = ABI::Windows::Foundation::PropertyType_Empty;
- return S_OK;
- }
-
- HRESULT STDMETHODCALLTYPE get_IsNumericScalar(boolean*) { return E_FAIL; }
- HRESULT STDMETHODCALLTYPE GetUInt8(BYTE*) { return E_FAIL; }
- HRESULT STDMETHODCALLTYPE GetInt16(INT16*) { return E_FAIL; }
- HRESULT STDMETHODCALLTYPE GetUInt16(UINT16*) { return E_FAIL; }
- HRESULT STDMETHODCALLTYPE GetInt32(INT32*) { return E_FAIL; }
- HRESULT STDMETHODCALLTYPE GetUInt32(UINT32*) { return E_FAIL; }
- HRESULT STDMETHODCALLTYPE GetInt64(INT64*) { return E_FAIL; }
- HRESULT STDMETHODCALLTYPE GetUInt64(UINT64*) { return E_FAIL; }
- HRESULT STDMETHODCALLTYPE GetSingle(FLOAT*) { return E_FAIL; }
- HRESULT STDMETHODCALLTYPE GetDouble(DOUBLE*) { return E_FAIL; }
- HRESULT STDMETHODCALLTYPE GetChar16(WCHAR*) { return E_FAIL; }
- HRESULT STDMETHODCALLTYPE GetBoolean(boolean*) { return E_FAIL; }
- HRESULT STDMETHODCALLTYPE GetString(HSTRING*) { return E_FAIL; }
- HRESULT STDMETHODCALLTYPE GetGuid(GUID*) { return E_FAIL; }
- HRESULT STDMETHODCALLTYPE GetDateTime(ABI::Windows::Foundation::DateTime*) { return E_FAIL; }
- HRESULT STDMETHODCALLTYPE GetTimeSpan(ABI::Windows::Foundation::TimeSpan*) { return E_FAIL; }
- HRESULT STDMETHODCALLTYPE GetPoint(ABI::Windows::Foundation::Point*) { return E_FAIL; }
- HRESULT STDMETHODCALLTYPE GetSize(ABI::Windows::Foundation::Size*) { return E_FAIL; }
- HRESULT STDMETHODCALLTYPE GetRect(ABI::Windows::Foundation::Rect*) { return E_FAIL; }
- HRESULT STDMETHODCALLTYPE GetUInt8Array(UINT32*, BYTE**) { return E_FAIL; }
- HRESULT STDMETHODCALLTYPE GetInt16Array(UINT32*, INT16**) { return E_FAIL; }
- HRESULT STDMETHODCALLTYPE GetUInt16Array(UINT32*, UINT16**) { return E_FAIL; }
- HRESULT STDMETHODCALLTYPE GetInt32Array(UINT32*, INT32**) { return E_FAIL; }
- HRESULT STDMETHODCALLTYPE GetUInt32Array(UINT32*, UINT32**) { return E_FAIL; }
- HRESULT STDMETHODCALLTYPE GetInt64Array(UINT32*, INT64**) { return E_FAIL; }
- HRESULT STDMETHODCALLTYPE GetUInt64Array(UINT32*, UINT64**) { return E_FAIL; }
- HRESULT STDMETHODCALLTYPE GetSingleArray(UINT32*, FLOAT**) { return E_FAIL; }
- HRESULT STDMETHODCALLTYPE GetDoubleArray(UINT32*, DOUBLE**) { return E_FAIL; }
- HRESULT STDMETHODCALLTYPE GetChar16Array(UINT32*, WCHAR**) { return E_FAIL; }
- HRESULT STDMETHODCALLTYPE GetBooleanArray(UINT32*, boolean**) { return E_FAIL; }
- HRESULT STDMETHODCALLTYPE GetStringArray(UINT32*, HSTRING**) { return E_FAIL; }
- HRESULT STDMETHODCALLTYPE GetInspectableArray(UINT32*, IInspectable***) { return E_FAIL; }
- HRESULT STDMETHODCALLTYPE GetGuidArray(UINT32*, GUID**) { return E_FAIL; }
- HRESULT STDMETHODCALLTYPE GetDateTimeArray(UINT32*, ABI::Windows::Foundation::DateTime**) { return E_FAIL; }
- HRESULT STDMETHODCALLTYPE GetTimeSpanArray(UINT32*, ABI::Windows::Foundation::TimeSpan**) { return E_FAIL; }
- HRESULT STDMETHODCALLTYPE GetPointArray(UINT32*, ABI::Windows::Foundation::Point**) { return E_FAIL; }
- HRESULT STDMETHODCALLTYPE GetSizeArray(UINT32*, ABI::Windows::Foundation::Size**) { return E_FAIL; }
- HRESULT STDMETHODCALLTYPE GetRectArray(UINT32*, ABI::Windows::Foundation::Rect**) { return E_FAIL; }
-};
-
-QT_END_NAMESPACE
-
-#endif // QT_CONFIG(accessibility)
-
-#endif // QWINRTUIAEMPTYPROPERTYVALUE_H
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiagriditemprovider.cpp b/src/plugins/platforms/winrt/uiautomation/qwinrtuiagriditemprovider.cpp
deleted file mode 100644
index 355dbf7d20..0000000000
--- a/src/plugins/platforms/winrt/uiautomation/qwinrtuiagriditemprovider.cpp
+++ /dev/null
@@ -1,160 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 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 <QtGui/qtguiglobal.h>
-#if QT_CONFIG(accessibility)
-
-#include "qwinrtuiagriditemprovider.h"
-#include "qwinrtuiamainprovider.h"
-#include "qwinrtuiametadatacache.h"
-#include "qwinrtuiautils.h"
-
-#include <QtGui/QAccessible>
-#include <QtGui/QAccessibleInterface>
-#include <QtCore/QLoggingCategory>
-#include <QtCore/QString>
-#include <QtCore/private/qeventdispatcher_winrt_p.h>
-
-#include <memory>
-
-QT_BEGIN_NAMESPACE
-
-using namespace QWinRTUiAutomation;
-using namespace ABI::Windows::UI::Xaml::Automation;
-using namespace ABI::Windows::UI::Xaml::Automation::Provider;
-using namespace ABI::Windows::UI::Xaml::Automation::Peers;
-
-QWinRTUiaGridItemProvider::QWinRTUiaGridItemProvider(QAccessible::Id id) :
- QWinRTUiaBaseProvider(id)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-}
-
-QWinRTUiaGridItemProvider::~QWinRTUiaGridItemProvider()
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-}
-
-// Returns the column index of the item.
-HRESULT STDMETHODCALLTYPE QWinRTUiaGridItemProvider::get_Column(INT32 *value)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-
- if (!value)
- return E_INVALIDARG;
-
- QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
- *value = metadata->columnIndex();
- return S_OK;
-}
-
-// Returns the number of columns occupied by the item.
-HRESULT STDMETHODCALLTYPE QWinRTUiaGridItemProvider::get_ColumnSpan(INT32 *value)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-
- if (!value)
- return E_INVALIDARG;
-
- QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
- *value = metadata->columnCount();
- return S_OK;
-}
-
-// Returns the provider for the containing table/tree.
-HRESULT STDMETHODCALLTYPE QWinRTUiaGridItemProvider::get_ContainingGrid(IIRawElementProviderSimple **value)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-
- if (!value)
- return E_INVALIDARG;
- *value = nullptr;
-
- auto accid = id();
- auto elementId = std::make_shared<QAccessible::Id>(0);
-
- if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, elementId]() {
- if (QAccessibleInterface *accessible = accessibleForId(accid)) {
- if (QAccessibleTableCellInterface *tableCellInterface = accessible->tableCellInterface()) {
- if (QAccessibleInterface *table = tableCellInterface->table()) {
- *elementId = idForAccessible(table);
- QWinRTUiaMetadataCache::instance()->load(*elementId);
- }
- }
- }
- return S_OK;
- }))) {
- return E_FAIL;
- }
-
- if (!*elementId)
- return S_OK;
-
- return QWinRTUiaMainProvider::rawProviderForAccessibleId(*elementId, value);
-}
-
-// Returns the row index of the item.
-HRESULT STDMETHODCALLTYPE QWinRTUiaGridItemProvider::get_Row(INT32 *value)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-
- if (!value)
- return E_INVALIDARG;
-
- QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
- *value = metadata->rowIndex();
- return S_OK;
-}
-
-// Returns the number of rows occupied by the item.
-HRESULT STDMETHODCALLTYPE QWinRTUiaGridItemProvider::get_RowSpan(INT32 *value)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-
- if (!value)
- return E_INVALIDARG;
-
- QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
- *value = metadata->rowCount();
- return S_OK;
-}
-
-QT_END_NAMESPACE
-
-#endif // QT_CONFIG(accessibility)
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiagriditemprovider.h b/src/plugins/platforms/winrt/uiautomation/qwinrtuiagriditemprovider.h
deleted file mode 100644
index 70504fc555..0000000000
--- a/src/plugins/platforms/winrt/uiautomation/qwinrtuiagriditemprovider.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 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 QWINRTUIAGRIDITEMPROVIDER_H
-#define QWINRTUIAGRIDITEMPROVIDER_H
-
-#include <QtGui/qtguiglobal.h>
-#if QT_CONFIG(accessibility)
-
-#include "qwinrtuiabaseprovider.h"
-
-#include <wrl.h>
-#include <windows.ui.xaml.h>
-
-QT_BEGIN_NAMESPACE
-
-// Implements the Grid Item control pattern provider. Used by items within a table/tree.
-class QWinRTUiaGridItemProvider :
- public QWinRTUiaBaseProvider,
- public Microsoft::WRL::RuntimeClass<ABI::Windows::UI::Xaml::Automation::Provider::IGridItemProvider>
-{
- Q_OBJECT
- Q_DISABLE_COPY(QWinRTUiaGridItemProvider)
- InspectableClass(L"QWinRTUiaGridItemProvider", BaseTrust);
-
-public:
- explicit QWinRTUiaGridItemProvider(QAccessible::Id id);
- virtual ~QWinRTUiaGridItemProvider();
-
- // IGridItemProvider
- HRESULT STDMETHODCALLTYPE get_Column(INT32 *value) override;
- HRESULT STDMETHODCALLTYPE get_ColumnSpan(INT32 *value) override;
- HRESULT STDMETHODCALLTYPE get_ContainingGrid(ABI::Windows::UI::Xaml::Automation::Provider::IIRawElementProviderSimple **value) override;
- HRESULT STDMETHODCALLTYPE get_Row(INT32 *value) override;
- HRESULT STDMETHODCALLTYPE get_RowSpan(INT32 *value) override;
-};
-
-QT_END_NAMESPACE
-
-#endif // QT_CONFIG(accessibility)
-
-#endif // QWINRTUIAGRIDITEMPROVIDER_H
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiagridprovider.cpp b/src/plugins/platforms/winrt/uiautomation/qwinrtuiagridprovider.cpp
deleted file mode 100644
index 3bd90f6850..0000000000
--- a/src/plugins/platforms/winrt/uiautomation/qwinrtuiagridprovider.cpp
+++ /dev/null
@@ -1,135 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 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 <QtGui/qtguiglobal.h>
-#if QT_CONFIG(accessibility)
-
-#include "qwinrtuiagridprovider.h"
-#include "qwinrtuiamainprovider.h"
-#include "qwinrtuiametadatacache.h"
-#include "qwinrtuiautils.h"
-
-#include <QtGui/QAccessible>
-#include <QtGui/QAccessibleInterface>
-#include <QtCore/QLoggingCategory>
-#include <QtCore/QString>
-#include <QtCore/private/qeventdispatcher_winrt_p.h>
-
-#include <memory>
-
-QT_BEGIN_NAMESPACE
-
-using namespace QWinRTUiAutomation;
-using namespace ABI::Windows::UI::Xaml::Automation;
-using namespace ABI::Windows::UI::Xaml::Automation::Provider;
-using namespace ABI::Windows::UI::Xaml::Automation::Peers;
-
-QWinRTUiaGridProvider::QWinRTUiaGridProvider(QAccessible::Id id) :
- QWinRTUiaBaseProvider(id)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-}
-
-QWinRTUiaGridProvider::~QWinRTUiaGridProvider()
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-}
-
-// Returns the number of columns.
-HRESULT STDMETHODCALLTYPE QWinRTUiaGridProvider::get_ColumnCount(INT32 *value)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-
- if (!value)
- return E_INVALIDARG;
-
- QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
- *value = metadata->columnCount();
- return S_OK;
-}
-
-// Returns the number of rows.
-HRESULT STDMETHODCALLTYPE QWinRTUiaGridProvider::get_RowCount(INT32 *value)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-
- if (!value)
- return E_INVALIDARG;
-
- QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
- *value = metadata->rowCount();
- return S_OK;
-}
-
-HRESULT STDMETHODCALLTYPE QWinRTUiaGridProvider::GetItem(INT32 row, INT32 column, IIRawElementProviderSimple **returnValue)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-
- if (!returnValue)
- return E_INVALIDARG;
- *returnValue = nullptr;
-
- auto accid = id();
- auto elementId = std::make_shared<QAccessible::Id>(0);
-
- if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, row, column, elementId]() {
- if (QAccessibleInterface *accessible = accessibleForId(accid)) {
- if (QAccessibleTableInterface *tableInterface = accessible->tableInterface()) {
- if ((row >= 0) && (row < tableInterface->rowCount()) && (column >= 0) && (column < tableInterface->columnCount())) {
- if (QAccessibleInterface *cell = tableInterface->cellAt(row, column)) {
- *elementId = idForAccessible(cell);
- QWinRTUiaMetadataCache::instance()->load(*elementId);
- }
- }
- }
- }
- return S_OK;
- }))) {
- return E_FAIL;
- }
-
- if (!*elementId)
- return E_FAIL;
-
- return QWinRTUiaMainProvider::rawProviderForAccessibleId(*elementId, returnValue);
-}
-
-QT_END_NAMESPACE
-
-#endif // QT_CONFIG(accessibility)
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiagridprovider.h b/src/plugins/platforms/winrt/uiautomation/qwinrtuiagridprovider.h
deleted file mode 100644
index d6dfaed315..0000000000
--- a/src/plugins/platforms/winrt/uiautomation/qwinrtuiagridprovider.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 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 QWINRTUIAGRIDPROVIDER_H
-#define QWINRTUIAGRIDPROVIDER_H
-
-#include <QtGui/qtguiglobal.h>
-#if QT_CONFIG(accessibility)
-
-#include "qwinrtuiabaseprovider.h"
-
-#include <wrl.h>
-#include <windows.ui.xaml.h>
-
-QT_BEGIN_NAMESPACE
-
-// Implements the Grid control pattern provider. Used by tables/trees.
-class QWinRTUiaGridProvider :
- public QWinRTUiaBaseProvider,
- public Microsoft::WRL::RuntimeClass<ABI::Windows::UI::Xaml::Automation::Provider::IGridProvider>
-{
- Q_OBJECT
- Q_DISABLE_COPY(QWinRTUiaGridProvider)
- InspectableClass(L"QWinRTUiaGridProvider", BaseTrust);
-
-public:
- explicit QWinRTUiaGridProvider(QAccessible::Id id);
- virtual ~QWinRTUiaGridProvider();
-
- // IGridProvider
- HRESULT STDMETHODCALLTYPE get_ColumnCount(INT32 *value) override;
- HRESULT STDMETHODCALLTYPE get_RowCount(INT32 *value) override;
- HRESULT STDMETHODCALLTYPE GetItem(INT32 row, INT32 column, ABI::Windows::UI::Xaml::Automation::Provider::IIRawElementProviderSimple **returnValue) override;
-};
-
-QT_END_NAMESPACE
-
-#endif // QT_CONFIG(accessibility)
-
-#endif // QWINRTUIAGRIDPROVIDER_H
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiainvokeprovider.cpp b/src/plugins/platforms/winrt/uiautomation/qwinrtuiainvokeprovider.cpp
deleted file mode 100644
index e2cf7bc107..0000000000
--- a/src/plugins/platforms/winrt/uiautomation/qwinrtuiainvokeprovider.cpp
+++ /dev/null
@@ -1,88 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 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 <QtGui/qtguiglobal.h>
-#if QT_CONFIG(accessibility)
-
-#include "qwinrtuiainvokeprovider.h"
-#include "qwinrtuiametadatacache.h"
-#include "qwinrtuiautils.h"
-
-#include <QtGui/QAccessible>
-#include <QtGui/QAccessibleInterface>
-#include <QtCore/QLoggingCategory>
-#include <QtCore/QString>
-#include <QtCore/private/qeventdispatcher_winrt_p.h>
-
-QT_BEGIN_NAMESPACE
-
-using namespace QWinRTUiAutomation;
-using namespace ABI::Windows::UI::Xaml::Automation;
-using namespace ABI::Windows::UI::Xaml::Automation::Provider;
-
-QWinRTUiaInvokeProvider::QWinRTUiaInvokeProvider(QAccessible::Id id) :
- QWinRTUiaBaseProvider(id)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-}
-
-QWinRTUiaInvokeProvider::~QWinRTUiaInvokeProvider()
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-}
-
-HRESULT STDMETHODCALLTYPE QWinRTUiaInvokeProvider::Invoke()
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-
- auto accid = id();
-
- QEventDispatcherWinRT::runOnMainThread([accid]() {
- if (QAccessibleInterface *accessible = accessibleForId(accid))
- if (QAccessibleActionInterface *actionInterface = accessible->actionInterface())
- actionInterface->doAction(QAccessibleActionInterface::pressAction());
- QWinRTUiaMetadataCache::instance()->load(accid);
- return S_OK;
- }, 0);
- return S_OK;
-}
-
-QT_END_NAMESPACE
-
-#endif // QT_CONFIG(accessibility)
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiainvokeprovider.h b/src/plugins/platforms/winrt/uiautomation/qwinrtuiainvokeprovider.h
deleted file mode 100644
index dfe7917a16..0000000000
--- a/src/plugins/platforms/winrt/uiautomation/qwinrtuiainvokeprovider.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 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 QWINRTUIAINVOKEPROVIDER_H
-#define QWINRTUIAINVOKEPROVIDER_H
-
-#include <QtGui/qtguiglobal.h>
-#if QT_CONFIG(accessibility)
-
-#include "qwinrtuiabaseprovider.h"
-
-#include <wrl.h>
-#include <windows.ui.xaml.h>
-
-QT_BEGIN_NAMESPACE
-
-// Implements the Invoke control pattern provider.
-class QWinRTUiaInvokeProvider :
- public QWinRTUiaBaseProvider,
- public Microsoft::WRL::RuntimeClass<ABI::Windows::UI::Xaml::Automation::Provider::IInvokeProvider>
-{
- Q_OBJECT
- Q_DISABLE_COPY(QWinRTUiaInvokeProvider)
- InspectableClass(L"QWinRTUiaInvokeProvider", BaseTrust);
-
-public:
- explicit QWinRTUiaInvokeProvider(QAccessible::Id id);
- virtual ~QWinRTUiaInvokeProvider();
-
- // IInvokeProvider
- HRESULT STDMETHODCALLTYPE Invoke() override;
-};
-
-QT_END_NAMESPACE
-
-#endif // QT_CONFIG(accessibility)
-
-#endif // QWINRTUIAINVOKEPROVIDER_H
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiamainprovider.cpp b/src/plugins/platforms/winrt/uiautomation/qwinrtuiamainprovider.cpp
deleted file mode 100644
index 0b1db306bd..0000000000
--- a/src/plugins/platforms/winrt/uiautomation/qwinrtuiamainprovider.cpp
+++ /dev/null
@@ -1,787 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 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 <QtGui/qtguiglobal.h>
-#if QT_CONFIG(accessibility)
-
-#include "qwinrtuiamainprovider.h"
-#include "qwinrtuiaprovidercache.h"
-#include "qwinrtuiavalueprovider.h"
-#include "qwinrtuiarangevalueprovider.h"
-#include "qwinrtuiatextprovider.h"
-#include "qwinrtuiatoggleprovider.h"
-#include "qwinrtuiainvokeprovider.h"
-#include "qwinrtuiaselectionprovider.h"
-#include "qwinrtuiaselectionitemprovider.h"
-#include "qwinrtuiatableprovider.h"
-#include "qwinrtuiatableitemprovider.h"
-#include "qwinrtuiagridprovider.h"
-#include "qwinrtuiagriditemprovider.h"
-#include "qwinrtuiapeervector.h"
-#include "qwinrtuiametadatacache.h"
-#include "qwinrtuiaemptypropertyvalue.h"
-#include "qwinrtuiautils.h"
-
-#include <QCoreApplication>
-#include <QSemaphore>
-#include <QtCore/QLoggingCategory>
-#include <QtCore/qfunctions_winrt.h>
-#include <QtCore/private/qeventdispatcher_winrt_p.h>
-
-#include <memory>
-
-using namespace QWinRTUiAutomation;
-using namespace Microsoft::WRL;
-using namespace Microsoft::WRL::Wrappers;
-using namespace ABI::Windows::System;
-using namespace ABI::Windows::UI;
-using namespace ABI::Windows::UI::Core;
-using namespace ABI::Windows::UI::Xaml;
-using namespace ABI::Windows::UI::Xaml::Automation;
-using namespace ABI::Windows::UI::Xaml::Automation::Provider;
-using namespace ABI::Windows::UI::Xaml::Automation::Peers;
-using namespace ABI::Windows::Foundation;
-using namespace ABI::Windows::Foundation::Collections;
-
-QT_BEGIN_NAMESPACE
-
-QWinRTUiaMainProvider::QWinRTUiaMainProvider(QAccessible::Id id)
- : QWinRTUiaBaseProvider(id)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-
- ComPtr<IAutomationPeerFactory> factory;
- HRESULT hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_UI_Xaml_Automation_Peers_AutomationPeer).Get(), IID_PPV_ARGS(&factory));
- Q_ASSERT_SUCCEEDED(hr);
-
- hr = factory->CreateInstance(this, &m_base, &m_core);
- Q_ASSERT_SUCCEEDED(hr);
-}
-
-QWinRTUiaMainProvider::~QWinRTUiaMainProvider()
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-}
-
-HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::QueryInterface(REFIID iid, LPVOID *iface)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-
- if (!iface)
- return E_POINTER;
- *iface = nullptr;
-
- if (iid == IID_IUnknown) {
- *iface = static_cast<IAutomationPeerOverrides *>(this);
- AddRef();
- return S_OK;
- } else if (iid == IID_IAutomationPeerOverrides) {
- *iface = static_cast<IAutomationPeerOverrides *>(this);
- AddRef();
- return S_OK;
- } else {
- return m_base.CopyTo(iid, iface);
- }
-}
-
-HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetIids(ULONG *iidCount, IID **iids)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
- *iidCount = 0;
- *iids = nullptr;
- return S_OK;
-}
-
-HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetRuntimeClassName(HSTRING *className)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
- return qHString(QStringLiteral("QWinRTUiaMainProvider"), className);
-}
-
-HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetTrustLevel(TrustLevel *trustLevel)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
- *trustLevel = TrustLevel::BaseTrust;
- return S_OK;
-}
-
-// Returns a cached instance of the provider for a specific accessible interface.
-QWinRTUiaMainProvider *QWinRTUiaMainProvider::providerForAccessibleId(QAccessible::Id id)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-
- QWinRTUiaProviderCache *providerCache = QWinRTUiaProviderCache::instance();
- QWinRTUiaMainProvider *provider = qobject_cast<QWinRTUiaMainProvider *>(providerCache->providerForId(id));
-
- if (provider) {
- provider->AddRef();
- } else {
- ComPtr<QWinRTUiaMainProvider> p = Make<QWinRTUiaMainProvider>(id);
- provider = p.Get();
- provider->AddRef();
- providerCache->insert(id, provider);
- }
- return provider;
-}
-
-// Returns an IIRawElementProviderSimple for a specific accessible interface.
-HRESULT QWinRTUiaMainProvider::rawProviderForAccessibleId(QAccessible::Id elementId,
- IIRawElementProviderSimple **returnValue)
-{
- if (!returnValue)
- return E_INVALIDARG;
- *returnValue = nullptr;
-
- if (ComPtr<QWinRTUiaMainProvider> provider = providerForAccessibleId(elementId)) {
- ComPtr<IAutomationPeer> automationPeer;
- if (SUCCEEDED(provider.As(&automationPeer))) {
- ComPtr<IAutomationPeerProtected> automationPeerProtected;
- if (SUCCEEDED(provider.As(&automationPeerProtected))) {
- return automationPeerProtected->ProviderFromPeer(automationPeer.Get(), returnValue);
- }
- }
- }
- return E_FAIL;
-}
-
-// Returns an array of IIRawElementProviderSimple instances for a list of accessible interface ids.
-HRESULT QWinRTUiaMainProvider::rawProviderArrayForAccessibleIdList(const QVarLengthArray<QAccessible::Id> &elementIds,
- UINT32 *returnValueSize,
- IIRawElementProviderSimple ***returnValue)
-{
- if (!returnValueSize || !returnValue)
- return E_INVALIDARG;
- *returnValueSize = 0;
- *returnValue = nullptr;
-
- QList<IIRawElementProviderSimple *> rawProviderList;
-
- for (auto elementId : elementIds) {
- IIRawElementProviderSimple *rawProvider;
- if (SUCCEEDED(rawProviderForAccessibleId(elementId, &rawProvider)))
- rawProviderList.append(rawProvider);
- }
-
- if (rawProviderList.size() == 0)
- return S_OK;
-
- *returnValue = static_cast<IIRawElementProviderSimple **>(CoTaskMemAlloc(rawProviderList.size() * sizeof(IIRawElementProviderSimple *)));
- if (!*returnValue) {
- for (auto rawProvider : qAsConst(rawProviderList))
- rawProvider->Release();
- return E_OUTOFMEMORY;
- }
-
- int index = 0;
- for (auto rawProvider : qAsConst(rawProviderList))
- (*returnValue)[index++] = rawProvider;
- *returnValueSize = rawProviderList.size();
- return S_OK;
-}
-
-void QWinRTUiaMainProvider::notifyFocusChange(QAccessibleEvent *event)
-{
- if (QAccessibleInterface *accessible = event->accessibleInterface()) {
- QAccessible::Id accid = idForAccessible(accessible);
- QWinRTUiaMetadataCache::instance()->load(accid);
- QEventDispatcherWinRT::runOnXamlThread([accid]() {
- if (ComPtr<QWinRTUiaMainProvider> provider = providerForAccessibleId(accid)) {
- ComPtr<IAutomationPeer> automationPeer;
- if (SUCCEEDED(provider->QueryInterface(IID_PPV_ARGS(&automationPeer)))) {
- automationPeer->RaiseAutomationEvent(AutomationEvents_AutomationFocusChanged);
- }
- }
- return S_OK;
- }, false);
- }
-}
-
-void QWinRTUiaMainProvider::notifyVisibilityChange(QAccessibleEvent *event)
-{
- if (QAccessibleInterface *accessible = event->accessibleInterface()) {
- QAccessible::Id accid = idForAccessible(accessible);
- QWinRTUiaMetadataCache::instance()->load(accid);
- }
-}
-
-void QWinRTUiaMainProvider::notifyStateChange(QAccessibleStateChangeEvent *event)
-{
- if (QAccessibleInterface *accessible = event->accessibleInterface()) {
- QAccessible::Id accid = idForAccessible(accessible);
- QWinRTUiaMetadataCache::instance()->load(accid);
-
- if (event->changedStates().checked || event->changedStates().checkStateMixed) {
- // Notifies states changes in checkboxes.
- if (accessible->role() == QAccessible::CheckBox) {
- QEventDispatcherWinRT::runOnXamlThread([accid]() {
- if (ComPtr<QWinRTUiaMainProvider> provider = providerForAccessibleId(accid)) {
- ComPtr<IAutomationPeer> automationPeer;
- if (SUCCEEDED(provider->QueryInterface(IID_PPV_ARGS(&automationPeer)))) {
- ComPtr<ITogglePatternIdentifiersStatics> toggleStatics;
- if (SUCCEEDED(RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_UI_Xaml_Automation_TogglePatternIdentifiers).Get(), IID_PPV_ARGS(&toggleStatics)))) {
- ComPtr<IAutomationProperty> toggleStateProperty;
- if (SUCCEEDED(toggleStatics->get_ToggleStateProperty(&toggleStateProperty))) {
- ComPtr<QWinRTUiaEmptyPropertyValue> emptyValue = Make<QWinRTUiaEmptyPropertyValue>();
- // by sending an event with an empty value we force ui automation to refresh its state
- automationPeer->RaisePropertyChangedEvent(toggleStateProperty.Get(), emptyValue.Get(), emptyValue.Get());
- }
- }
- }
- }
- return S_OK;
- }, false);
- }
- }
- if (event->changedStates().active) {
- if (accessible->role() == QAccessible::Window) {
- // Notifies window opened/closed.
- bool active = accessible->state().active;
- QEventDispatcherWinRT::runOnXamlThread([accid, active]() {
- if (ComPtr<QWinRTUiaMainProvider> provider = providerForAccessibleId(accid)) {
- ComPtr<IAutomationPeer> automationPeer;
- if (SUCCEEDED(provider->QueryInterface(IID_PPV_ARGS(&automationPeer)))) {
- if (active) {
- automationPeer->RaiseAutomationEvent(AutomationEvents_WindowOpened);
- } else {
- automationPeer->RaiseAutomationEvent(AutomationEvents_WindowClosed);
- }
- }
- }
- return S_OK;
- }, false);
- }
- }
- }
-}
-
-void QWinRTUiaMainProvider::notifyValueChange(QAccessibleValueChangeEvent *event)
-{
- if (QAccessibleInterface *accessible = event->accessibleInterface()) {
- QAccessible::Id accid = idForAccessible(accessible);
- QWinRTUiaMetadataCache::instance()->load(accid);
- if (QAccessibleValueInterface *valueInterface = accessible->valueInterface()) {
- // Notifies changes in values of controls supporting the value interface.
- double value = valueInterface->currentValue().toDouble();
- QEventDispatcherWinRT::runOnXamlThread([accid, value]() {
- // For some reason RaisePropertyChangedEvent() does not seem to be
- // forwarding notifications for any property types except empty,
- // which would do nothing here. ToDo: find a workaround.
- return S_OK;
- }, false);
- }
- }
-}
-
-// Notifies changes in text content and selection state of text controls.
-void QWinRTUiaMainProvider::notifyTextChange(QAccessibleEvent *event)
-{
- if (QAccessibleInterface *accessible = event->accessibleInterface()) {
- QAccessible::Id accid = idForAccessible(accessible);
- QWinRTUiaMetadataCache::instance()->load(accid);
- bool readOnly = accessible->state().readOnly;
- QAccessible::Event eventType = event->type();
- if (accessible->textInterface()) {
- QEventDispatcherWinRT::runOnXamlThread([accid, eventType, readOnly]() {
- if (ComPtr<QWinRTUiaMainProvider> provider = providerForAccessibleId(accid)) {
- ComPtr<IAutomationPeer> automationPeer;
- if (SUCCEEDED(provider->QueryInterface(IID_PPV_ARGS(&automationPeer)))) {
- if (eventType == QAccessible::TextSelectionChanged) {
- automationPeer->RaiseAutomationEvent(AutomationEvents_TextPatternOnTextSelectionChanged);
- } else if (eventType == QAccessible::TextCaretMoved) {
- if (!readOnly) {
- automationPeer->RaiseAutomationEvent(AutomationEvents_TextPatternOnTextSelectionChanged);
- }
- } else {
- automationPeer->RaiseAutomationEvent(AutomationEvents_TextPatternOnTextChanged);
- }
- }
- }
- return S_OK;
- }, false);
- }
- }
-}
-
-// Return providers for specific control patterns
-HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetPatternCore(PatternInterface patternInterface, IInspectable **returnValue)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__ << patternInterface;
-
- if (!returnValue)
- return E_INVALIDARG;
- *returnValue = nullptr;
-
- QAccessibleInterface *accessible = accessibleInterface();
- if (!accessible)
- return E_FAIL;
-
- switch (patternInterface) {
- case PatternInterface_Text:
- case PatternInterface_Text2: {
- // All text controls.
- if (accessible->textInterface()) {
- ComPtr<QWinRTUiaTextProvider> provider = Make<QWinRTUiaTextProvider>(id());
- return provider.CopyTo(returnValue);
- }
- break;
- }
- case PatternInterface_Value: {
- // All accessible controls return text(QAccessible::Value) (which may be empty).
- ComPtr<QWinRTUiaValueProvider> provider = Make<QWinRTUiaValueProvider>(id());
- return provider.CopyTo(returnValue);
- }
- case PatternInterface_RangeValue: {
- // Controls providing a numeric value within a range (e.g., sliders, scroll bars, dials).
- if (accessible->valueInterface()) {
- ComPtr<QWinRTUiaRangeValueProvider> provider = Make<QWinRTUiaRangeValueProvider>(id());
- return provider.CopyTo(returnValue);
- }
- break;
- }
- case PatternInterface_Toggle: {
- // Checkbox controls.
- if (accessible->role() == QAccessible::CheckBox) {
- ComPtr<QWinRTUiaToggleProvider> provider = Make<QWinRTUiaToggleProvider>(id());
- return provider.CopyTo(returnValue);
- }
- break;
- }
- case PatternInterface_Selection: {
- // Lists of items.
- if (accessible->role() == QAccessible::List) {
- ComPtr<QWinRTUiaSelectionProvider> provider = Make<QWinRTUiaSelectionProvider>(id());
- return provider.CopyTo(returnValue);
- }
- break;
- }
- case PatternInterface_SelectionItem: {
- // Items within a list and radio buttons.
- if ((accessible->role() == QAccessible::RadioButton)
- || (accessible->role() == QAccessible::ListItem)) {
- ComPtr<QWinRTUiaSelectionItemProvider> provider = Make<QWinRTUiaSelectionItemProvider>(id());
- return provider.CopyTo(returnValue);
- }
- break;
- }
- case PatternInterface_Table: {
- // Table/tree.
- if (accessible->tableInterface()
- && ((accessible->role() == QAccessible::Table) || (accessible->role() == QAccessible::Tree))) {
- ComPtr<QWinRTUiaTableProvider> provider = Make<QWinRTUiaTableProvider>(id());
- return provider.CopyTo(returnValue);
- }
- break;
- }
- case PatternInterface_TableItem: {
- // Item within a table/tree.
- if (accessible->tableCellInterface()
- && ((accessible->role() == QAccessible::Cell) || (accessible->role() == QAccessible::TreeItem))) {
- ComPtr<QWinRTUiaTableItemProvider> provider = Make<QWinRTUiaTableItemProvider>(id());
- return provider.CopyTo(returnValue);
- }
- break;
- }
- case PatternInterface_Grid: {
- // Table/tree.
- if (accessible->tableInterface()
- && ((accessible->role() == QAccessible::Table) || (accessible->role() == QAccessible::Tree))) {
- ComPtr<QWinRTUiaGridProvider> provider = Make<QWinRTUiaGridProvider>(id());
- return provider.CopyTo(returnValue);
- }
- break;
- }
- case PatternInterface_GridItem: {
- // Item within a table/tree.
- if (accessible->tableCellInterface()
- && ((accessible->role() == QAccessible::Cell) || (accessible->role() == QAccessible::TreeItem))) {
- ComPtr<QWinRTUiaGridItemProvider> provider = Make<QWinRTUiaGridItemProvider>(id());
- return provider.CopyTo(returnValue);
- }
- break;
- }
- case PatternInterface_Invoke: {
- // Things that have an invokable action (e.g., simple buttons).
- if (accessible->actionInterface()) {
- ComPtr<QWinRTUiaInvokeProvider> provider = Make<QWinRTUiaInvokeProvider>(id());
- return provider.CopyTo(returnValue);
- }
- break;
- }
- default:
- break;
- }
- return S_OK;
-}
-
-HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetAcceleratorKeyCore(HSTRING *returnValue)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-
- if (!returnValue)
- return E_INVALIDARG;
- QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
- return qHString(metadata->accelerator(), returnValue);
-}
-
-HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetAccessKeyCore(HSTRING *returnValue)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-
- if (!returnValue)
- return E_INVALIDARG;
- QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
- return qHString(metadata->access(), returnValue);
-}
-
-HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetAutomationControlTypeCore(AutomationControlType *returnValue)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-
- if (!returnValue)
- return E_INVALIDARG;
- QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
- *returnValue = roleToControlType(metadata->role());
- return S_OK;
-}
-
-HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetAutomationIdCore(HSTRING *returnValue)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-
- if (!returnValue)
- return E_INVALIDARG;
- QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
- return qHString(metadata->automationId(), returnValue);
-}
-
-// Returns the bounding rectangle for the accessible control.
-HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetBoundingRectangleCore(ABI::Windows::Foundation::Rect *returnValue)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-
- if (!returnValue)
- return E_INVALIDARG;
-
- QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
-
- QRect rect = metadata->boundingRect();
- returnValue->X = rect.x();
- returnValue->Y = rect.y();
- returnValue->Width = rect.width();
- returnValue->Height = rect.height();
- return S_OK;
-}
-
-HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetChildrenCore(IVector<AutomationPeer *> **returnValue)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-
- if (!returnValue)
- return E_INVALIDARG;
- *returnValue = nullptr;
-
- auto accid = id();
- auto children = std::make_shared<QVarLengthArray<QAccessible::Id>>();
-
- if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, children]() {
- if (QAccessibleInterface *accessible = accessibleForId(accid)) {
- int childCount = accessible->childCount();
- for (int i = 0; i < childCount; ++i) {
- if (QAccessibleInterface *childAcc = accessible->child(i)) {
- QAccessible::Id childId = idForAccessible(childAcc);
- QWinRTUiaMetadataCache::instance()->load(childId);
- if (!childAcc->state().invisible)
- children->append(childId);
- }
- }
- }
- return S_OK;
- }))) {
- return E_FAIL;
- }
-
- ComPtr<IVector<AutomationPeer *>> peerVector = Make<QWinRTUiaPeerVector>();
-
- for (auto childId : *children) {
- if (ComPtr<QWinRTUiaMainProvider> provider = providerForAccessibleId(childId)) {
- IAutomationPeer *peer;
- if (SUCCEEDED(provider.CopyTo(&peer)))
- peerVector->Append(peer);
- }
- }
- return peerVector.CopyTo(returnValue);
-}
-
-HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetClassNameCore(HSTRING *returnValue)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-
- if (!returnValue)
- return E_INVALIDARG;
- QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
- return qHString(metadata->className(), returnValue);
-}
-
-HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetClickablePointCore(ABI::Windows::Foundation::Point *returnValue)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-
- if (!returnValue)
- return E_INVALIDARG;
- return E_NOTIMPL;
-}
-
-HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetHelpTextCore(HSTRING *returnValue)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-
- if (!returnValue)
- return E_INVALIDARG;
- QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
- return qHString(metadata->help(), returnValue);
-}
-
-HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetItemStatusCore(HSTRING *returnValue)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-
- if (!returnValue)
- return E_INVALIDARG;
- return E_NOTIMPL;
-}
-
-HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetItemTypeCore(HSTRING *returnValue)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-
- if (!returnValue)
- return E_INVALIDARG;
- return E_NOTIMPL;
-}
-
-HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetLabeledByCore(IAutomationPeer **returnValue)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-
- if (!returnValue)
- return E_INVALIDARG;
- return E_NOTIMPL;
-}
-
-HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetLocalizedControlTypeCore(HSTRING *returnValue)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-
- if (!returnValue)
- return E_INVALIDARG;
- return E_NOTIMPL;
-}
-
-HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetNameCore(HSTRING *returnValue)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-
- if (!returnValue)
- return E_INVALIDARG;
- QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
- return qHString(metadata->controlName(), returnValue);
-}
-
-HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetOrientationCore(AutomationOrientation *returnValue)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-
- if (!returnValue)
- return E_INVALIDARG;
- *returnValue = AutomationOrientation_None;
- return S_OK;
-}
-
-HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::HasKeyboardFocusCore(boolean *returnValue)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-
- if (!returnValue)
- return E_INVALIDARG;
- QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
- *returnValue = (metadata->state().focused != 0);
- return S_OK;
-}
-
-HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::IsContentElementCore(boolean *returnValue)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-
- if (!returnValue)
- return E_INVALIDARG;
- *returnValue = true;
- return S_OK;
-}
-
-HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::IsControlElementCore(boolean *returnValue)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-
- if (!returnValue)
- return E_INVALIDARG;
- *returnValue = true;
- return S_OK;
-}
-
-HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::IsEnabledCore(boolean *returnValue)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-
- if (!returnValue)
- return E_INVALIDARG;
- QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
- *returnValue = (metadata->state().disabled == 0);
- return S_OK;
-}
-
-HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::IsKeyboardFocusableCore(boolean *returnValue)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-
- if (!returnValue)
- return E_INVALIDARG;
- QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
- *returnValue = (metadata->state().focusable != 0);
- return S_OK;
-}
-
-HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::IsOffscreenCore(boolean *returnValue)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-
- if (!returnValue)
- return E_INVALIDARG;
- QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
- *returnValue = (metadata->state().offscreen != 0);
- return S_OK;
-}
-
-HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::IsPasswordCore(boolean *returnValue)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-
- if (!returnValue)
- return E_INVALIDARG;
- QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
- *returnValue = (metadata->role() == QAccessible::EditableText) && (metadata->state().passwordEdit != 0);
- return S_OK;
-}
-
-HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::IsRequiredForFormCore(boolean *returnValue)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-
- if (!returnValue)
- return E_INVALIDARG;
- *returnValue = false;
- return S_OK;
-}
-
-// Sets focus to the control.
-HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::SetFocusCore()
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-
- QAccessibleInterface *accessible = accessibleInterface();
- if (!accessible)
- return E_FAIL;
-
- QAccessibleActionInterface *actionInterface = accessible->actionInterface();
- if (!actionInterface)
- return E_FAIL;
-
- QEventDispatcherWinRT::runOnMainThread([actionInterface]() {
- actionInterface->doAction(QAccessibleActionInterface::setFocusAction());
- return S_OK;
- });
- return S_OK;
-}
-
-// Returns a provider for the UI element present at the specified screen coordinates.
-HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetPeerFromPointCore(ABI::Windows::Foundation::Point point, IAutomationPeer **returnValue)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-
- if (!returnValue)
- return E_INVALIDARG;
- *returnValue = nullptr;
-
- // Scale coordinates from High DPI screens?
-
- auto accid = id();
- auto elementId = std::make_shared<QAccessible::Id>(0);
-
- if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, elementId, point]() {
- // Controls can be embedded within grouping elements. By default returns the innermost control.
- QAccessibleInterface *target = accessibleForId(accid);
- while (QAccessibleInterface *tmpacc = target->childAt(point.X, point.Y)) {
- target = tmpacc;
- // For accessibility tools it may be better to return the text element instead of its subcomponents.
- if (target->textInterface()) break;
- }
- *elementId = idForAccessible(target);
- QWinRTUiaMetadataCache::instance()->load(*elementId);
- return S_OK;
- }))) {
- return E_FAIL;
- }
-
- if (ComPtr<QWinRTUiaMainProvider> provider = providerForAccessibleId(*elementId))
- return provider.CopyTo(returnValue);
- return E_FAIL;
-}
-
-HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetLiveSettingCore(AutomationLiveSetting *returnValue)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-
- if (!returnValue)
- return E_INVALIDARG;
- return E_NOTIMPL;
-}
-
-QT_END_NAMESPACE
-
-#endif // QT_CONFIG(accessibility)
-
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiamainprovider.h b/src/plugins/platforms/winrt/uiautomation/qwinrtuiamainprovider.h
deleted file mode 100644
index 23a6e56ae7..0000000000
--- a/src/plugins/platforms/winrt/uiautomation/qwinrtuiamainprovider.h
+++ /dev/null
@@ -1,125 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 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 QWINRTUIAMAINPROVIDER_H
-#define QWINRTUIAMAINPROVIDER_H
-
-#include <QtGui/qtguiglobal.h>
-#if QT_CONFIG(accessibility)
-
-#include "qwinrtuiabaseprovider.h"
-
-#include <QtCore/qglobal.h>
-#include <QtCore/QPointer>
-#include <QtCore/QSharedPointer>
-#include <QtGui/QAccessible>
-#include <QtGui/QAccessibleInterface>
-
-#include <wrl.h>
-#include <windows.ui.xaml.h>
-
-QT_BEGIN_NAMESPACE
-
-// The main WinRT UI Automation class.
-class QWinRTUiaMainProvider:
- public QWinRTUiaBaseProvider,
- public Microsoft::WRL::RuntimeClass<ABI::Windows::UI::Xaml::Automation::Peers::IAutomationPeerOverrides>
-{
- Q_OBJECT
- Q_DISABLE_COPY(QWinRTUiaMainProvider)
-
-public:
- explicit QWinRTUiaMainProvider(QAccessible::Id id);
- virtual ~QWinRTUiaMainProvider();
- static QWinRTUiaMainProvider *providerForAccessibleId(QAccessible::Id id);
- static HRESULT rawProviderForAccessibleId(QAccessible::Id elementId, ABI::Windows::UI::Xaml::Automation::Provider::IIRawElementProviderSimple **returnValue);
- static HRESULT rawProviderArrayForAccessibleIdList(const QVarLengthArray<QAccessible::Id> &elementIds, UINT32 *returnValueSize, ABI::Windows::UI::Xaml::Automation::Provider::IIRawElementProviderSimple ***returnValue);
- static void notifyFocusChange(QAccessibleEvent *event);
- static void notifyVisibilityChange(QAccessibleEvent *event);
- static void notifyStateChange(QAccessibleStateChangeEvent *event);
- static void notifyValueChange(QAccessibleValueChangeEvent *event);
- static void notifyTextChange(QAccessibleEvent *event);
-
- // IUnknown
- HRESULT STDMETHODCALLTYPE QueryInterface(REFIID id, LPVOID *iface) override;
-
- // IInspectable
- HRESULT STDMETHODCALLTYPE GetIids(ULONG *iidCount, IID **iids) override;
- HRESULT STDMETHODCALLTYPE GetRuntimeClassName(HSTRING *className) override;
- HRESULT STDMETHODCALLTYPE GetTrustLevel(TrustLevel *trustLevel) override;
-
- // IAutomationPeerOverrides
- HRESULT STDMETHODCALLTYPE GetPatternCore(ABI::Windows::UI::Xaml::Automation::Peers::PatternInterface patternInterface, IInspectable **returnValue) override;
- HRESULT STDMETHODCALLTYPE GetAcceleratorKeyCore(HSTRING *returnValue) override;
- HRESULT STDMETHODCALLTYPE GetAccessKeyCore(HSTRING *returnValue) override;
- HRESULT STDMETHODCALLTYPE GetAutomationControlTypeCore(ABI::Windows::UI::Xaml::Automation::Peers::AutomationControlType *returnValue) override;
- HRESULT STDMETHODCALLTYPE GetAutomationIdCore(HSTRING *returnValue) override;
- HRESULT STDMETHODCALLTYPE GetBoundingRectangleCore(ABI::Windows::Foundation::Rect *returnValue) override;
- HRESULT STDMETHODCALLTYPE GetChildrenCore(ABI::Windows::Foundation::Collections::IVector<ABI::Windows::UI::Xaml::Automation::Peers::AutomationPeer*> **returnValue) override;
- HRESULT STDMETHODCALLTYPE GetClassNameCore(HSTRING *returnValue) override;
- HRESULT STDMETHODCALLTYPE GetClickablePointCore(ABI::Windows::Foundation::Point *returnValue) override;
- HRESULT STDMETHODCALLTYPE GetHelpTextCore(HSTRING *returnValue) override;
- HRESULT STDMETHODCALLTYPE GetItemStatusCore(HSTRING *returnValue) override;
- HRESULT STDMETHODCALLTYPE GetItemTypeCore(HSTRING *returnValue) override;
- HRESULT STDMETHODCALLTYPE GetLabeledByCore(ABI::Windows::UI::Xaml::Automation::Peers::IAutomationPeer **returnValue) override;
- HRESULT STDMETHODCALLTYPE GetLocalizedControlTypeCore(HSTRING *returnValue) override;
- HRESULT STDMETHODCALLTYPE GetNameCore(HSTRING *returnValue) override;
- HRESULT STDMETHODCALLTYPE GetOrientationCore(ABI::Windows::UI::Xaml::Automation::Peers::AutomationOrientation *returnValue) override;
- HRESULT STDMETHODCALLTYPE HasKeyboardFocusCore(boolean *returnValue) override;
- HRESULT STDMETHODCALLTYPE IsContentElementCore(boolean *returnValue) override;
- HRESULT STDMETHODCALLTYPE IsControlElementCore(boolean *returnValue) override;
- HRESULT STDMETHODCALLTYPE IsEnabledCore(boolean *returnValue) override;
- HRESULT STDMETHODCALLTYPE IsKeyboardFocusableCore(boolean *returnValue) override;
- HRESULT STDMETHODCALLTYPE IsOffscreenCore(boolean *returnValue) override;
- HRESULT STDMETHODCALLTYPE IsPasswordCore(boolean *returnValue) override;
- HRESULT STDMETHODCALLTYPE IsRequiredForFormCore(boolean *returnValue) override;
- HRESULT STDMETHODCALLTYPE SetFocusCore() override;
- HRESULT STDMETHODCALLTYPE GetPeerFromPointCore(ABI::Windows::Foundation::Point point, ABI::Windows::UI::Xaml::Automation::Peers::IAutomationPeer **returnValue) override;
- HRESULT STDMETHODCALLTYPE GetLiveSettingCore(ABI::Windows::UI::Xaml::Automation::Peers::AutomationLiveSetting *returnValue) override;
-
-private:
- Microsoft::WRL::ComPtr<ABI::Windows::UI::Xaml::Automation::Peers::IAutomationPeerOverrides> m_base;
- Microsoft::WRL::ComPtr<ABI::Windows::UI::Xaml::Automation::Peers::IAutomationPeer> m_core;
-};
-
-QT_END_NAMESPACE
-
-#endif // QT_CONFIG(accessibility)
-
-#endif // QWINRTUIAMAINPROVIDER_H
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiametadatacache.cpp b/src/plugins/platforms/winrt/uiautomation/qwinrtuiametadatacache.cpp
deleted file mode 100644
index 442ff184a8..0000000000
--- a/src/plugins/platforms/winrt/uiautomation/qwinrtuiametadatacache.cpp
+++ /dev/null
@@ -1,112 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 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 <QtGui/qtguiglobal.h>
-#if QT_CONFIG(accessibility)
-
-#include "qwinrtuiametadatacache.h"
-#include "qwinrtuiautils.h"
-
-#include <QtCore/QLoggingCategory>
-#include <QtCore/private/qeventdispatcher_winrt_p.h>
-
-QT_BEGIN_NAMESPACE
-
-using namespace QWinRTUiAutomation;
-
-// Private constructor
-QWinRTUiaMetadataCache::QWinRTUiaMetadataCache()
-{
-}
-
-// shared instance
-QWinRTUiaMetadataCache *QWinRTUiaMetadataCache::instance()
-{
- static QWinRTUiaMetadataCache metadataCache;
- return &metadataCache;
-}
-
-// Returns the cached metadata associated with the ID, or an instance with default values.
-QSharedPointer<QWinRTUiaControlMetadata> QWinRTUiaMetadataCache::metadataForId(QAccessible::Id id)
-{
- QSharedPointer<QWinRTUiaControlMetadata> metadata;
-
- m_mutex.lock();
- if (m_metadataTable.contains(id))
- metadata = m_metadataTable[id];
- else
- metadata = QSharedPointer<QWinRTUiaControlMetadata>(new QWinRTUiaControlMetadata);
- m_mutex.unlock();
- return metadata;
-}
-
-// Caches metadata from the accessibility framework within the main thread.
-bool QWinRTUiaMetadataCache::load(QAccessible::Id id)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-
- if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([id]() {
- QWinRTUiaMetadataCache::instance()->insert(id, QSharedPointer<QWinRTUiaControlMetadata>(new QWinRTUiaControlMetadata(id)));
- return S_OK;
- }))) {
- return false;
- }
- return true;
-}
-
-// Inserts metadata in the cache and associates it with an accessibility ID.
-void QWinRTUiaMetadataCache::insert(QAccessible::Id id, const QSharedPointer<QWinRTUiaControlMetadata> &metadata)
-{
- m_mutex.lock();
- m_metadataTable[id] = metadata;
- m_mutex.unlock();
-}
-
-// Removes metadata with a given id from the cache.
-void QWinRTUiaMetadataCache::remove(QAccessible::Id id)
-{
- m_mutex.lock();
- m_metadataTable.remove(id);
- m_mutex.unlock();
-}
-
-QT_END_NAMESPACE
-
-#endif // QT_CONFIG(accessibility)
-
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiametadatacache.h b/src/plugins/platforms/winrt/uiautomation/qwinrtuiametadatacache.h
deleted file mode 100644
index 2d68d1b654..0000000000
--- a/src/plugins/platforms/winrt/uiautomation/qwinrtuiametadatacache.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 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 QWINRTUIAMETADATACACHE_H
-#define QWINRTUIAMETADATACACHE_H
-
-#include <QtGui/qtguiglobal.h>
-#if QT_CONFIG(accessibility)
-
-#include "qwinrtuiacontrolmetadata.h"
-
-#include <QtCore/QHash>
-#include <QtCore/QMutex>
-#include <QtGui/QAccessible>
-#include <QtGui/QAccessibleInterface>
-
-QT_BEGIN_NAMESPACE
-
-// Singleton used to cache metadata using the accessibility ID as the key.
-class QWinRTUiaMetadataCache : public QObject
-{
- QWinRTUiaMetadataCache();
- Q_OBJECT
-public:
- static QWinRTUiaMetadataCache *instance();
- QSharedPointer<QWinRTUiaControlMetadata> metadataForId(QAccessible::Id id);
- void insert(QAccessible::Id id, const QSharedPointer<QWinRTUiaControlMetadata> &metadata);
- void remove(QAccessible::Id id);
- bool load(QAccessible::Id id);
-
-private:
- QHash<QAccessible::Id, QSharedPointer<QWinRTUiaControlMetadata>> m_metadataTable;
- QMutex m_mutex;
-};
-
-QT_END_NAMESPACE
-
-#endif // QT_CONFIG(accessibility)
-
-#endif // QWINRTUIAMETADATACACHE_H
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiapeervector.cpp b/src/plugins/platforms/winrt/uiautomation/qwinrtuiapeervector.cpp
deleted file mode 100644
index e3d6bcae4b..0000000000
--- a/src/plugins/platforms/winrt/uiautomation/qwinrtuiapeervector.cpp
+++ /dev/null
@@ -1,149 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 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 <QtGui/qtguiglobal.h>
-#if QT_CONFIG(accessibility)
-
-#include "qwinrtuiapeervector.h"
-#include "qwinrtuiautils.h"
-
-using namespace ABI::Windows::UI::Xaml::Automation::Peers;
-using namespace ABI::Windows::Foundation::Collections;
-
-QT_BEGIN_NAMESPACE
-
-HRESULT QWinRTUiaPeerVector::GetAt(quint32 index, IAutomationPeer **item)
-{
- if (index >= quint32(m_impl.size()))
- return E_FAIL;
- if ((*item = m_impl.at(index)))
- (*item)->AddRef();
- return S_OK;
-}
-
-HRESULT QWinRTUiaPeerVector::get_Size(quint32 *size)
-{
- *size = m_impl.size();
- return S_OK;
-}
-
-HRESULT QWinRTUiaPeerVector::GetView(IVectorView<AutomationPeer *> **view)
-{
- *view = nullptr;
- return E_NOTIMPL;
-}
-
-HRESULT QWinRTUiaPeerVector::IndexOf(IAutomationPeer *value, quint32 *index, boolean *found)
-{
- int idx = m_impl.indexOf(value);
- if (idx > -1) {
- *index = quint32(idx);
- *found = true;
- } else {
- *found = false;
- }
- return S_OK;
-}
-
-HRESULT QWinRTUiaPeerVector::SetAt(quint32 index, IAutomationPeer *item)
-{
- if (index >= quint32(m_impl.size()))
- return E_FAIL;
- if (IAutomationPeer *elem = m_impl.at(index)) {
- if (elem == item)
- return S_OK;
- else
- elem->Release();
- }
- if (item)
- item->AddRef();
- m_impl[index] = item;
- return S_OK;
-}
-
-HRESULT QWinRTUiaPeerVector::InsertAt(quint32 index, IAutomationPeer *item)
-{
- if (index >= quint32(m_impl.size()))
- return E_FAIL;
- if (item)
- item->AddRef();
- m_impl.insert(index, item);
- return S_OK;
-}
-
-HRESULT QWinRTUiaPeerVector::RemoveAt(quint32 index)
-{
- if (index >= quint32(m_impl.size()))
- return E_FAIL;
- if (IAutomationPeer *elem = m_impl.at(index))
- elem->Release();
- m_impl.remove(index);
- return S_OK;
-}
-
-HRESULT QWinRTUiaPeerVector::Append(IAutomationPeer *item)
-{
- if (item)
- item->AddRef();
- m_impl.append(item);
- return S_OK;
-}
-
-HRESULT QWinRTUiaPeerVector::RemoveAtEnd()
-{
- if (m_impl.size() == 0)
- return E_FAIL;
- if (IAutomationPeer *elem = m_impl.last())
- elem->Release();
- m_impl.removeLast();
- return S_OK;
-}
-
-HRESULT QWinRTUiaPeerVector::Clear()
-{
- for (auto elem : qAsConst(m_impl))
- if (elem)
- elem->Release();
- m_impl.clear();
- return S_OK;
-}
-
-QT_END_NAMESPACE
-
-#endif // QT_CONFIG(accessibility)
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiapeervector.h b/src/plugins/platforms/winrt/uiautomation/qwinrtuiapeervector.h
deleted file mode 100644
index 265526de09..0000000000
--- a/src/plugins/platforms/winrt/uiautomation/qwinrtuiapeervector.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 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 QWINRTUIAPEERVECTOR_H
-#define QWINRTUIAPEERVECTOR_H
-
-#include <QtGui/qtguiglobal.h>
-#if QT_CONFIG(accessibility)
-
-#include <QtCore/QString>
-#include <QtCore/qt_windows.h>
-#include <QtGui/QAccessible>
-#include <QtGui/QAccessibleInterface>
-#include <QtGui/QWindow>
-#include <QVector>
-
-#include <wrl.h>
-#include <windows.ui.xaml.h>
-
-QT_BEGIN_NAMESPACE
-
-// Implements IVector<AutomationPeer *>
-class QWinRTUiaPeerVector : public Microsoft::WRL::RuntimeClass<ABI::Windows::Foundation::Collections::IVector<ABI::Windows::UI::Xaml::Automation::Peers::AutomationPeer *>>
-{
-public:
- HRESULT STDMETHODCALLTYPE GetAt(quint32 index, ABI::Windows::UI::Xaml::Automation::Peers::IAutomationPeer **item) override;
- HRESULT STDMETHODCALLTYPE get_Size(quint32 *size) override;
- HRESULT STDMETHODCALLTYPE GetView(ABI::Windows::Foundation::Collections::IVectorView<ABI::Windows::UI::Xaml::Automation::Peers::AutomationPeer *> **view) override;
- HRESULT STDMETHODCALLTYPE IndexOf(ABI::Windows::UI::Xaml::Automation::Peers::IAutomationPeer *value, quint32 *index, boolean *found) override;
- HRESULT STDMETHODCALLTYPE SetAt(quint32 index, ABI::Windows::UI::Xaml::Automation::Peers::IAutomationPeer *item) override;
- HRESULT STDMETHODCALLTYPE InsertAt(quint32 index, ABI::Windows::UI::Xaml::Automation::Peers::IAutomationPeer *item) override;
- HRESULT STDMETHODCALLTYPE RemoveAt(quint32 index) override;
- HRESULT STDMETHODCALLTYPE Append(ABI::Windows::UI::Xaml::Automation::Peers::IAutomationPeer *item) override;
- HRESULT STDMETHODCALLTYPE RemoveAtEnd() override;
- HRESULT STDMETHODCALLTYPE Clear() override;
-private:
- QVector<ABI::Windows::UI::Xaml::Automation::Peers::IAutomationPeer *> m_impl;
-};
-
-QT_END_NAMESPACE
-
-#endif // QT_CONFIG(accessibility)
-
-#endif // QWINRTUIAPEERVECTOR_H
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiaprovidercache.cpp b/src/plugins/platforms/winrt/uiautomation/qwinrtuiaprovidercache.cpp
deleted file mode 100644
index 06ff094c45..0000000000
--- a/src/plugins/platforms/winrt/uiautomation/qwinrtuiaprovidercache.cpp
+++ /dev/null
@@ -1,99 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 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 <QtGui/qtguiglobal.h>
-#if QT_CONFIG(accessibility)
-
-#include "qwinrtuiaprovidercache.h"
-
-QT_BEGIN_NAMESPACE
-
-// Private constructor
-QWinRTUiaProviderCache::QWinRTUiaProviderCache()
-{
-}
-
-// shared instance
-QWinRTUiaProviderCache *QWinRTUiaProviderCache::instance()
-{
- static QWinRTUiaProviderCache providerCache;
- return &providerCache;
-}
-
-// Returns the provider instance associated with the ID, or nullptr.
-QWinRTUiaBaseProvider *QWinRTUiaProviderCache::providerForId(QAccessible::Id id) const
-{
- return m_providerTable.value(id);
-}
-
-// Inserts a provider in the cache and associates it with an accessibility ID.
-void QWinRTUiaProviderCache::insert(QAccessible::Id id, QWinRTUiaBaseProvider *provider)
-{
- remove(id);
- if (provider) {
- m_providerTable[id] = provider;
- m_inverseTable[provider] = id;
- // Connects the destroyed signal to our slot, to remove deleted objects from the cache.
- QObject::connect(provider, &QObject::destroyed, this, &QWinRTUiaProviderCache::objectDestroyed);
- }
-}
-
-// Removes deleted provider objects from the cache.
-void QWinRTUiaProviderCache::objectDestroyed(QObject *obj)
-{
- // We have to use the inverse table to map the object address back to its ID,
- // since at this point (called from QObject destructor), it has already been
- // partially destroyed and we cannot treat it as a provider.
- auto it = m_inverseTable.find(obj);
- if (it != m_inverseTable.end()) {
- m_providerTable.remove(*it);
- m_inverseTable.remove(obj);
- }
-}
-
-// Removes a provider with a given id from the cache.
-void QWinRTUiaProviderCache::remove(QAccessible::Id id)
-{
- m_inverseTable.remove(m_providerTable.value(id));
- m_providerTable.remove(id);
-}
-
-QT_END_NAMESPACE
-
-#endif // QT_CONFIG(accessibility)
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiaprovidercache.h b/src/plugins/platforms/winrt/uiautomation/qwinrtuiaprovidercache.h
deleted file mode 100644
index 393ef7d562..0000000000
--- a/src/plugins/platforms/winrt/uiautomation/qwinrtuiaprovidercache.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 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 QWINRTUIAPROVIDERCACHE_H
-#define QWINRTUIAPROVIDERCACHE_H
-
-#include <QtGui/qtguiglobal.h>
-#if QT_CONFIG(accessibility)
-
-#include "qwinrtuiabaseprovider.h"
-
-#include <QtCore/QHash>
-#include <QtGui/QAccessible>
-#include <QtGui/QAccessibleInterface>
-
-QT_BEGIN_NAMESPACE
-
-// Singleton used to cache provider instances using the accessibility ID as the key.
-class QWinRTUiaProviderCache : public QObject
-{
- QWinRTUiaProviderCache();
- Q_OBJECT
-public:
- static QWinRTUiaProviderCache *instance();
- QWinRTUiaBaseProvider *providerForId(QAccessible::Id id) const;
- void insert(QAccessible::Id id, QWinRTUiaBaseProvider *provider);
- void remove(QAccessible::Id id);
-
-private Q_SLOTS:
- void objectDestroyed(QObject *obj);
-
-private:
- QHash<QAccessible::Id, QWinRTUiaBaseProvider *> m_providerTable;
- QHash<QObject *, QAccessible::Id> m_inverseTable;
-};
-
-QT_END_NAMESPACE
-
-#endif // QT_CONFIG(accessibility)
-
-#endif // QWINRTUIAPROVIDERCACHE_H
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiarangevalueprovider.cpp b/src/plugins/platforms/winrt/uiautomation/qwinrtuiarangevalueprovider.cpp
deleted file mode 100644
index 4ac59c890a..0000000000
--- a/src/plugins/platforms/winrt/uiautomation/qwinrtuiarangevalueprovider.cpp
+++ /dev/null
@@ -1,167 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 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 <QtGui/qtguiglobal.h>
-#if QT_CONFIG(accessibility)
-
-#include "qwinrtuiarangevalueprovider.h"
-#include "qwinrtuiametadatacache.h"
-#include "qwinrtuiautils.h"
-
-#include <QtGui/QAccessible>
-#include <QtGui/QAccessibleInterface>
-#include <QtCore/QLoggingCategory>
-#include <QtCore/QString>
-#include <QtCore/private/qeventdispatcher_winrt_p.h>
-
-QT_BEGIN_NAMESPACE
-
-using namespace QWinRTUiAutomation;
-using namespace ABI::Windows::UI::Xaml::Automation;
-using namespace ABI::Windows::UI::Xaml::Automation::Provider;
-
-QWinRTUiaRangeValueProvider::QWinRTUiaRangeValueProvider(QAccessible::Id id) :
- QWinRTUiaBaseProvider(id)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-}
-
-QWinRTUiaRangeValueProvider::~QWinRTUiaRangeValueProvider()
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-}
-
-HRESULT STDMETHODCALLTYPE QWinRTUiaRangeValueProvider::get_IsReadOnly(boolean *value)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-
- if (!value)
- return E_INVALIDARG;
-
- QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
- *value = (metadata->state().readOnly != 0);
- return S_OK;
-}
-
-HRESULT STDMETHODCALLTYPE QWinRTUiaRangeValueProvider::get_LargeChange(DOUBLE *value)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-
- if (!value)
- return E_INVALIDARG;
-
- QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
- *value = metadata->minimumStepSize();
- return S_OK;
-}
-
-HRESULT STDMETHODCALLTYPE QWinRTUiaRangeValueProvider::get_Maximum(DOUBLE *value)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-
- if (!value)
- return E_INVALIDARG;
-
- QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
- *value = metadata->maximumValue();
- return S_OK;
-}
-
-HRESULT STDMETHODCALLTYPE QWinRTUiaRangeValueProvider::get_Minimum(DOUBLE *value)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-
- if (!value)
- return E_INVALIDARG;
-
- QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
- *value = metadata->minimumValue();
- return S_OK;
-}
-
-HRESULT STDMETHODCALLTYPE QWinRTUiaRangeValueProvider::get_SmallChange(DOUBLE *value)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-
- if (!value)
- return E_INVALIDARG;
-
- QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
- *value = metadata->minimumStepSize();
- return S_OK;
-}
-
-HRESULT STDMETHODCALLTYPE QWinRTUiaRangeValueProvider::get_Value(DOUBLE *value)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-
- if (!value)
- return E_INVALIDARG;
-
- QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
- *value = metadata->currentValue();
- return S_OK;
-}
-
-HRESULT STDMETHODCALLTYPE QWinRTUiaRangeValueProvider::SetValue(DOUBLE value)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-
- auto accid = id();
-
- QEventDispatcherWinRT::runOnMainThread([accid, value]() {
- if (QAccessibleInterface *accessible = accessibleForId(accid)) {
- if (QAccessibleValueInterface *valueInterface = accessible->valueInterface()) {
- double minimum = valueInterface->minimumValue().toDouble();
- double maximum = valueInterface->maximumValue().toDouble();
- if ((value >= minimum) && (value <= maximum)) {
- valueInterface->setCurrentValue(QVariant(value));
- }
- }
- }
- QWinRTUiaMetadataCache::instance()->load(accid);
- return S_OK;
- }, 0);
-
- return S_OK;
-}
-
-QT_END_NAMESPACE
-
-#endif // QT_CONFIG(accessibility)
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiarangevalueprovider.h b/src/plugins/platforms/winrt/uiautomation/qwinrtuiarangevalueprovider.h
deleted file mode 100644
index 4e98959526..0000000000
--- a/src/plugins/platforms/winrt/uiautomation/qwinrtuiarangevalueprovider.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 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 QWINRTUIARANGEVALUEPROVIDER_H
-#define QWINRTUIARANGEVALUEPROVIDER_H
-
-#include <QtGui/qtguiglobal.h>
-#if QT_CONFIG(accessibility)
-
-#include "qwinrtuiabaseprovider.h"
-
-#include <wrl.h>
-#include <windows.ui.xaml.h>
-
-QT_BEGIN_NAMESPACE
-
-// Implements the Range Value control pattern provider.
-class QWinRTUiaRangeValueProvider :
- public QWinRTUiaBaseProvider,
- public Microsoft::WRL::RuntimeClass<ABI::Windows::UI::Xaml::Automation::Provider::IRangeValueProvider>
-{
- Q_OBJECT
- Q_DISABLE_COPY(QWinRTUiaRangeValueProvider)
- InspectableClass(L"QWinRTUiaRangeValueProvider", BaseTrust);
-
-public:
- explicit QWinRTUiaRangeValueProvider(QAccessible::Id id);
- virtual ~QWinRTUiaRangeValueProvider();
-
- // IRangeValueProvider
- HRESULT STDMETHODCALLTYPE get_IsReadOnly(boolean *value) override;
- HRESULT STDMETHODCALLTYPE get_LargeChange(DOUBLE *value) override;
- HRESULT STDMETHODCALLTYPE get_Maximum(DOUBLE *value) override;
- HRESULT STDMETHODCALLTYPE get_Minimum(DOUBLE *value) override;
- HRESULT STDMETHODCALLTYPE get_SmallChange(DOUBLE *value) override;
- HRESULT STDMETHODCALLTYPE get_Value(DOUBLE *value) override;
- HRESULT STDMETHODCALLTYPE SetValue(DOUBLE value) override;
-};
-
-QT_END_NAMESPACE
-
-#endif // QT_CONFIG(accessibility)
-
-#endif // QWINRTUIARANGEVALUEPROVIDER_H
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiaselectionitemprovider.cpp b/src/plugins/platforms/winrt/uiautomation/qwinrtuiaselectionitemprovider.cpp
deleted file mode 100644
index 2cb5aa685c..0000000000
--- a/src/plugins/platforms/winrt/uiautomation/qwinrtuiaselectionitemprovider.cpp
+++ /dev/null
@@ -1,214 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 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 <QtGui/qtguiglobal.h>
-#if QT_CONFIG(accessibility)
-
-#include "qwinrtuiaselectionitemprovider.h"
-#include "qwinrtuiamainprovider.h"
-#include "qwinrtuiametadatacache.h"
-#include "qwinrtuiautils.h"
-
-#include <QtGui/QAccessible>
-#include <QtGui/QAccessibleInterface>
-#include <QtCore/QLoggingCategory>
-#include <QtCore/QString>
-#include <QtCore/private/qeventdispatcher_winrt_p.h>
-
-#include <memory>
-
-QT_BEGIN_NAMESPACE
-
-using namespace QWinRTUiAutomation;
-using namespace ABI::Windows::UI::Xaml::Automation;
-using namespace ABI::Windows::UI::Xaml::Automation::Provider;
-using namespace ABI::Windows::UI::Xaml::Automation::Peers;
-
-QWinRTUiaSelectionItemProvider::QWinRTUiaSelectionItemProvider(QAccessible::Id id) :
- QWinRTUiaBaseProvider(id)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-}
-
-QWinRTUiaSelectionItemProvider::~QWinRTUiaSelectionItemProvider()
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-}
-
-// Returns true if element is currently selected.
-HRESULT STDMETHODCALLTYPE QWinRTUiaSelectionItemProvider::get_IsSelected(boolean *value)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-
- if (!value)
- return E_INVALIDARG;
- QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
- if (metadata->role() == QAccessible::RadioButton)
- *value = metadata->state().checked;
- else
- *value = metadata->state().selected;
- return S_OK;
-}
-
-// Returns the provider for the container element (e.g., the list for the list item).
-HRESULT STDMETHODCALLTYPE QWinRTUiaSelectionItemProvider::get_SelectionContainer(IIRawElementProviderSimple **value)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-
- if (!value)
- return E_INVALIDARG;
- *value = nullptr;
-
- auto accid = id();
- auto elementId = std::make_shared<QAccessible::Id>(0);
-
- if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, elementId]() {
- if (QAccessibleInterface *accessible = accessibleForId(accid)) {
- // Radio buttons do not require a container.
- if (accessible->role() == QAccessible::ListItem) {
- if (QAccessibleInterface *parent = accessible->parent()) {
- if (parent->role() == QAccessible::List) {
- *elementId = idForAccessible(parent);
- }
- }
- }
- }
- return S_OK;
- }))) {
- return E_FAIL;
- }
-
- if (!*elementId)
- return S_OK;
-
- return QWinRTUiaMainProvider::rawProviderForAccessibleId(*elementId, value);
-}
-
-// Adds the element to the list of selected elements.
-HRESULT STDMETHODCALLTYPE QWinRTUiaSelectionItemProvider::AddToSelection()
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-
- auto accid = id();
-
- QEventDispatcherWinRT::runOnMainThread([accid]() {
- if (QAccessibleInterface *accessible = accessibleForId(accid)) {
- if (QAccessibleActionInterface *actionInterface = accessible->actionInterface()) {
- if (accessible->role() == QAccessible::RadioButton) {
- // For radio buttons we invoke the selection action.
- actionInterface->doAction(QAccessibleActionInterface::pressAction());
- } else {
- // Toggle list item if not already selected.
- if (!accessible->state().selected) {
- actionInterface->doAction(QAccessibleActionInterface::toggleAction());
- }
- }
- }
- }
- QWinRTUiaMetadataCache::instance()->load(accid);
- return S_OK;
- }, 0);
- return S_OK;
-}
-
-// Removes a list item from selection.
-HRESULT STDMETHODCALLTYPE QWinRTUiaSelectionItemProvider::RemoveFromSelection()
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-
- auto accid = id();
-
- QEventDispatcherWinRT::runOnMainThread([accid]() {
- if (QAccessibleInterface *accessible = accessibleForId(accid)) {
- if (QAccessibleActionInterface *actionInterface = accessible->actionInterface()) {
- if (accessible->role() != QAccessible::RadioButton) {
- if (accessible->state().selected) {
- actionInterface->doAction(QAccessibleActionInterface::toggleAction());
- }
- }
- }
- }
- QWinRTUiaMetadataCache::instance()->load(accid);
- return S_OK;
- }, 0);
- return S_OK;
-}
-
-// Selects the element (deselecting all others).
-HRESULT STDMETHODCALLTYPE QWinRTUiaSelectionItemProvider::Select()
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-
- auto accid = id();
-
- QEventDispatcherWinRT::runOnMainThread([accid]() {
- if (QAccessibleInterface *accessible = accessibleForId(accid)) {
- if (QAccessibleActionInterface *actionInterface = accessible->actionInterface()) {
- if (accessible->role() == QAccessible::RadioButton) {
- // For radio buttons we just invoke the selection action; others are automatically deselected.
- actionInterface->doAction(QAccessibleActionInterface::pressAction());
- } else {
- // Toggle list item if not already selected. It must be done first to support all selection modes.
- if (!accessible->state().selected) {
- actionInterface->doAction(QAccessibleActionInterface::toggleAction());
- }
- // Toggle selected siblings.
- if (QAccessibleInterface *parent = accessible->parent()) {
- for (int i = 0; i < parent->childCount(); ++i) {
- if (QAccessibleInterface *sibling = parent->child(i)) {
- if ((sibling != accessible) && (sibling->state().selected)) {
- if (QAccessibleActionInterface *siblingAction = sibling->actionInterface()) {
- siblingAction->doAction(QAccessibleActionInterface::toggleAction());
- }
- }
- }
- }
- }
- }
- }
- }
- QWinRTUiaMetadataCache::instance()->load(accid);
- return S_OK;
- }, 0);
- return S_OK;
-}
-
-QT_END_NAMESPACE
-
-#endif // QT_CONFIG(accessibility)
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiaselectionitemprovider.h b/src/plugins/platforms/winrt/uiautomation/qwinrtuiaselectionitemprovider.h
deleted file mode 100644
index 1b3cce7495..0000000000
--- a/src/plugins/platforms/winrt/uiautomation/qwinrtuiaselectionitemprovider.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 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 QWINRTUIASELECTIONITEMPROVIDER_H
-#define QWINRTUIASELECTIONITEMPROVIDER_H
-
-#include <QtGui/qtguiglobal.h>
-#if QT_CONFIG(accessibility)
-
-#include "qwinrtuiabaseprovider.h"
-
-#include <wrl.h>
-#include <windows.ui.xaml.h>
-
-QT_BEGIN_NAMESPACE
-
-// Implements the Selection Item control pattern provider. Used for List items and radio buttons.
-class QWinRTUiaSelectionItemProvider :
- public QWinRTUiaBaseProvider,
- public Microsoft::WRL::RuntimeClass<ABI::Windows::UI::Xaml::Automation::Provider::ISelectionItemProvider>
-{
- Q_OBJECT
- Q_DISABLE_COPY(QWinRTUiaSelectionItemProvider)
- InspectableClass(L"QWinRTUiaSelectionItemProvider", BaseTrust);
-
-public:
- explicit QWinRTUiaSelectionItemProvider(QAccessible::Id id);
- virtual ~QWinRTUiaSelectionItemProvider();
-
- // ISelectionItemProvider
- HRESULT STDMETHODCALLTYPE get_IsSelected(boolean *value) override;
- HRESULT STDMETHODCALLTYPE get_SelectionContainer(ABI::Windows::UI::Xaml::Automation::Provider::IIRawElementProviderSimple **value) override;
- HRESULT STDMETHODCALLTYPE AddToSelection() override;
- HRESULT STDMETHODCALLTYPE RemoveFromSelection() override;
- HRESULT STDMETHODCALLTYPE Select() override;
-};
-
-QT_END_NAMESPACE
-
-#endif // QT_CONFIG(accessibility)
-
-#endif // QWINRTUIASELECTIONITEMPROVIDER_H
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiaselectionprovider.cpp b/src/plugins/platforms/winrt/uiautomation/qwinrtuiaselectionprovider.cpp
deleted file mode 100644
index 4d825351c8..0000000000
--- a/src/plugins/platforms/winrt/uiautomation/qwinrtuiaselectionprovider.cpp
+++ /dev/null
@@ -1,156 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 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 <QtGui/qtguiglobal.h>
-#if QT_CONFIG(accessibility)
-
-#include "qwinrtuiaselectionprovider.h"
-#include "qwinrtuiametadatacache.h"
-#include "qwinrtuiamainprovider.h"
-#include "qwinrtuiautils.h"
-
-#include <QtGui/QAccessible>
-#include <QtGui/QAccessibleInterface>
-#include <QtCore/QLoggingCategory>
-#include <QtCore/QString>
-#include <QtCore/private/qeventdispatcher_winrt_p.h>
-
-#include <memory>
-
-QT_BEGIN_NAMESPACE
-
-using namespace QWinRTUiAutomation;
-using namespace ABI::Windows::UI::Xaml::Automation;
-using namespace ABI::Windows::UI::Xaml::Automation::Provider;
-using namespace ABI::Windows::UI::Xaml::Automation::Peers;
-
-QWinRTUiaSelectionProvider::QWinRTUiaSelectionProvider(QAccessible::Id id) :
- QWinRTUiaBaseProvider(id)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-}
-
-QWinRTUiaSelectionProvider::~QWinRTUiaSelectionProvider()
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-}
-
-HRESULT STDMETHODCALLTYPE QWinRTUiaSelectionProvider::get_CanSelectMultiple(boolean *value)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-
- if (!value)
- return E_INVALIDARG;
- QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
- *value = (metadata->state().multiSelectable != 0);
- return S_OK;
-}
-
-HRESULT STDMETHODCALLTYPE QWinRTUiaSelectionProvider::get_IsSelectionRequired(boolean *value)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-
- if (!value)
- return E_INVALIDARG;
- *value = false;
-
- auto accid = id();
- auto selectionRequired = std::make_shared<bool>(false);
-
- if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, selectionRequired]() {
- // Initially returns false if none are selected. After the first selection, it may be required.
- bool anySelected = false;
- if (QAccessibleInterface *accessible = accessibleForId(accid)) {
- int childCount = accessible->childCount();
- for (int i = 0; i < childCount; ++i) {
- if (QAccessibleInterface *childAcc = accessible->child(i)) {
- if (childAcc->state().selected) {
- anySelected = true;
- break;
- }
- }
- }
- *selectionRequired = anySelected && !accessible->state().multiSelectable && !accessible->state().extSelectable;
- }
- return S_OK;
- }))) {
- return E_FAIL;
- }
-
- *value = *selectionRequired;
- return S_OK;
-}
-
-// Returns an array of providers with the selected items.
-HRESULT STDMETHODCALLTYPE QWinRTUiaSelectionProvider::GetSelection(UINT32 *returnValueSize, IIRawElementProviderSimple ***returnValue)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-
- if (!returnValueSize || !returnValue)
- return E_INVALIDARG;
- *returnValueSize = 0;
- *returnValue = nullptr;
-
- auto accid = id();
- auto elementIds = std::make_shared<QVarLengthArray<QAccessible::Id>>();
-
- if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, elementIds]() {
- if (QAccessibleInterface *accessible = accessibleForId(accid)) {
- int childCount = accessible->childCount();
- for (int i = 0; i < childCount; ++i) {
- if (QAccessibleInterface *childAcc = accessible->child(i)) {
- if (childAcc->state().selected) {
- QAccessible::Id childId = idForAccessible(childAcc);
- QWinRTUiaMetadataCache::instance()->load(childId);
- elementIds->append(childId);
- }
- }
- }
- }
- return S_OK;
- }))) {
- return E_FAIL;
- }
-
- return QWinRTUiaMainProvider::rawProviderArrayForAccessibleIdList(*elementIds, returnValueSize, returnValue);
-}
-
-QT_END_NAMESPACE
-
-#endif // QT_CONFIG(accessibility)
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiaselectionprovider.h b/src/plugins/platforms/winrt/uiautomation/qwinrtuiaselectionprovider.h
deleted file mode 100644
index dcd286800f..0000000000
--- a/src/plugins/platforms/winrt/uiautomation/qwinrtuiaselectionprovider.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 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 QWINRTUIASELECTIONPROVIDER_H
-#define QWINRTUIASELECTIONPROVIDER_H
-
-#include <QtGui/qtguiglobal.h>
-#if QT_CONFIG(accessibility)
-
-#include "qwinrtuiabaseprovider.h"
-
-#include <wrl.h>
-#include <windows.ui.xaml.h>
-
-QT_BEGIN_NAMESPACE
-
-// Implements the Selection control pattern provider. Used for Lists.
-class QWinRTUiaSelectionProvider :
- public QWinRTUiaBaseProvider,
- public Microsoft::WRL::RuntimeClass<ABI::Windows::UI::Xaml::Automation::Provider::ISelectionProvider>
-{
- Q_OBJECT
- Q_DISABLE_COPY(QWinRTUiaSelectionProvider)
- InspectableClass(L"QWinRTUiaSelectionProvider", BaseTrust);
-
-public:
- explicit QWinRTUiaSelectionProvider(QAccessible::Id id);
- virtual ~QWinRTUiaSelectionProvider();
-
- // ISelectionProvider
- HRESULT STDMETHODCALLTYPE get_CanSelectMultiple(boolean *value) override;
- HRESULT STDMETHODCALLTYPE get_IsSelectionRequired(boolean *value) override;
- HRESULT STDMETHODCALLTYPE GetSelection(UINT32 *returnValueSize, ABI::Windows::UI::Xaml::Automation::Provider::IIRawElementProviderSimple ***returnValue) override;
-};
-
-QT_END_NAMESPACE
-
-#endif // QT_CONFIG(accessibility)
-
-#endif // QWINRTUIASELECTIONPROVIDER_H
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiatableitemprovider.cpp b/src/plugins/platforms/winrt/uiautomation/qwinrtuiatableitemprovider.cpp
deleted file mode 100644
index 7cd953de87..0000000000
--- a/src/plugins/platforms/winrt/uiautomation/qwinrtuiatableitemprovider.cpp
+++ /dev/null
@@ -1,139 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 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 <QtGui/qtguiglobal.h>
-#if QT_CONFIG(accessibility)
-
-#include "qwinrtuiatableitemprovider.h"
-#include "qwinrtuiamainprovider.h"
-#include "qwinrtuiametadatacache.h"
-#include "qwinrtuiautils.h"
-
-#include <QtGui/QAccessible>
-#include <QtGui/QAccessibleInterface>
-#include <QtCore/QLoggingCategory>
-#include <QtCore/QString>
-#include <QtCore/private/qeventdispatcher_winrt_p.h>
-
-#include <memory>
-
-QT_BEGIN_NAMESPACE
-
-using namespace QWinRTUiAutomation;
-using namespace ABI::Windows::UI::Xaml::Automation;
-using namespace ABI::Windows::UI::Xaml::Automation::Provider;
-
-QWinRTUiaTableItemProvider::QWinRTUiaTableItemProvider(QAccessible::Id id) :
- QWinRTUiaBaseProvider(id)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-}
-
-QWinRTUiaTableItemProvider::~QWinRTUiaTableItemProvider()
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-}
-
-// Returns the providers for the column headers associated with the item.
-HRESULT STDMETHODCALLTYPE QWinRTUiaTableItemProvider::GetColumnHeaderItems(UINT32 *returnValueSize, IIRawElementProviderSimple ***returnValue)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-
- if (!returnValueSize || !returnValue)
- return E_INVALIDARG;
- *returnValueSize = 0;
- *returnValue = nullptr;
-
- auto accid = id();
- auto elementIds = std::make_shared<QVarLengthArray<QAccessible::Id>>();
-
- if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, elementIds]() {
- if (QAccessibleInterface *accessible = accessibleForId(accid)) {
- if (QAccessibleTableCellInterface *tableCellInterface = accessible->tableCellInterface()) {
- QList<QAccessibleInterface *> headers = tableCellInterface->columnHeaderCells();
- for (auto header : qAsConst(headers)) {
- QAccessible::Id headerId = idForAccessible(header);
- QWinRTUiaMetadataCache::instance()->load(headerId);
- elementIds->append(headerId);
- }
- }
- }
- return S_OK;
- }))) {
- return E_FAIL;
- }
-
- return QWinRTUiaMainProvider::rawProviderArrayForAccessibleIdList(*elementIds, returnValueSize, returnValue);
-}
-
-// Returns the providers for the row headers associated with the item.
-HRESULT STDMETHODCALLTYPE QWinRTUiaTableItemProvider::GetRowHeaderItems(UINT32 *returnValueSize, IIRawElementProviderSimple ***returnValue)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-
- if (!returnValueSize || !returnValue)
- return E_INVALIDARG;
- *returnValueSize = 0;
- *returnValue = nullptr;
-
- auto accid = id();
- auto elementIds = std::make_shared<QVarLengthArray<QAccessible::Id>>();
-
- if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, elementIds]() {
- if (QAccessibleInterface *accessible = accessibleForId(accid)) {
- if (QAccessibleTableCellInterface *tableCellInterface = accessible->tableCellInterface()) {
- QList<QAccessibleInterface *> headers = tableCellInterface->rowHeaderCells();
- for (auto header : qAsConst(headers)) {
- QAccessible::Id headerId = idForAccessible(header);
- QWinRTUiaMetadataCache::instance()->load(headerId);
- elementIds->append(headerId);
- }
- }
- }
- return S_OK;
- }))) {
- return E_FAIL;
- }
-
- return QWinRTUiaMainProvider::rawProviderArrayForAccessibleIdList(*elementIds, returnValueSize, returnValue);
-}
-
-QT_END_NAMESPACE
-
-#endif // QT_CONFIG(accessibility)
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiatableitemprovider.h b/src/plugins/platforms/winrt/uiautomation/qwinrtuiatableitemprovider.h
deleted file mode 100644
index cb759864ae..0000000000
--- a/src/plugins/platforms/winrt/uiautomation/qwinrtuiatableitemprovider.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 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 QWINRTUIATABLEITEMPROVIDER_H
-#define QWINRTUIATABLEITEMPROVIDER_H
-
-#include <QtGui/qtguiglobal.h>
-#if QT_CONFIG(accessibility)
-
-#include "qwinrtuiabaseprovider.h"
-
-#include <wrl.h>
-#include <windows.ui.xaml.h>
-
-QT_BEGIN_NAMESPACE
-
-// Implements the Table Item control pattern provider. Used by items within a table/tree.
-class QWinRTUiaTableItemProvider :
- public QWinRTUiaBaseProvider,
- public Microsoft::WRL::RuntimeClass<ABI::Windows::UI::Xaml::Automation::Provider::ITableItemProvider>
-{
- Q_OBJECT
- Q_DISABLE_COPY(QWinRTUiaTableItemProvider)
- InspectableClass(L"QWinRTUiaTableItemProvider", BaseTrust);
-
-public:
- explicit QWinRTUiaTableItemProvider(QAccessible::Id id);
- virtual ~QWinRTUiaTableItemProvider();
-
- // ITableItemProvider
- HRESULT STDMETHODCALLTYPE GetColumnHeaderItems(UINT32 *returnValueSize, ABI::Windows::UI::Xaml::Automation::Provider::IIRawElementProviderSimple ***returnValue) override;
- HRESULT STDMETHODCALLTYPE GetRowHeaderItems(UINT32 *returnValueSize, ABI::Windows::UI::Xaml::Automation::Provider::IIRawElementProviderSimple ***returnValue) override;
-};
-
-QT_END_NAMESPACE
-
-#endif // QT_CONFIG(accessibility)
-
-#endif // QWINRTUIATABLEITEMPROVIDER_H
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiatableprovider.cpp b/src/plugins/platforms/winrt/uiautomation/qwinrtuiatableprovider.cpp
deleted file mode 100644
index d763b320b1..0000000000
--- a/src/plugins/platforms/winrt/uiautomation/qwinrtuiatableprovider.cpp
+++ /dev/null
@@ -1,165 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 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 <QtGui/qtguiglobal.h>
-#if QT_CONFIG(accessibility)
-
-#include "qwinrtuiatableprovider.h"
-#include "qwinrtuiamainprovider.h"
-#include "qwinrtuiametadatacache.h"
-#include "qwinrtuiautils.h"
-
-#include <QtGui/QAccessible>
-#include <QtGui/QAccessibleInterface>
-#include <QtCore/QLoggingCategory>
-#include <QtCore/QString>
-#include <QtCore/private/qeventdispatcher_winrt_p.h>
-
-#include <memory>
-
-QT_BEGIN_NAMESPACE
-
-using namespace QWinRTUiAutomation;
-using namespace ABI::Windows::UI::Xaml::Automation;
-using namespace ABI::Windows::UI::Xaml::Automation::Provider;
-using namespace ABI::Windows::UI::Xaml::Automation::Peers;
-
-QWinRTUiaTableProvider::QWinRTUiaTableProvider(QAccessible::Id id) :
- QWinRTUiaBaseProvider(id)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-}
-
-QWinRTUiaTableProvider::~QWinRTUiaTableProvider()
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-}
-
-// Returns the primary direction of traversal for the table.
-HRESULT STDMETHODCALLTYPE QWinRTUiaTableProvider::get_RowOrColumnMajor(RowOrColumnMajor *value)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-
- if (!value)
- return E_INVALIDARG;
- *value = RowOrColumnMajor_Indeterminate;
- return S_OK;
-}
-
-// Gets the providers for all the column headers in the table.
-HRESULT STDMETHODCALLTYPE QWinRTUiaTableProvider::GetColumnHeaders(UINT32 *returnValueSize, IIRawElementProviderSimple ***returnValue)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-
- if (!returnValueSize || !returnValue)
- return E_INVALIDARG;
- *returnValueSize = 0;
- *returnValue = nullptr;
-
- auto accid = id();
- auto elementIds = std::make_shared<QVarLengthArray<QAccessible::Id>>();
-
- if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, elementIds]() {
- if (QAccessibleInterface *accessible = accessibleForId(accid)) {
- if (QAccessibleTableInterface *tableInterface = accessible->tableInterface()) {
- for (int i = 0; i < tableInterface->columnCount(); ++i) {
- if (QAccessibleInterface *cell = tableInterface->cellAt(0, i)) {
- QWinRTUiaMetadataCache::instance()->load(idForAccessible(cell));
- if (QAccessibleTableCellInterface *tableCellInterface = cell->tableCellInterface()) {
- QList<QAccessibleInterface *> headers = tableCellInterface->columnHeaderCells();
- for (auto header : qAsConst(headers)) {
- QAccessible::Id headerId = idForAccessible(header);
- QWinRTUiaMetadataCache::instance()->load(headerId);
- elementIds->append(headerId);
- }
- }
- }
- }
- }
- }
- return S_OK;
- }))) {
- return E_FAIL;
- }
-
- return QWinRTUiaMainProvider::rawProviderArrayForAccessibleIdList(*elementIds, returnValueSize, returnValue);
-}
-
-// Gets the providers for all the row headers in the table.
-HRESULT STDMETHODCALLTYPE QWinRTUiaTableProvider::GetRowHeaders(UINT32 *returnValueSize, IIRawElementProviderSimple ***returnValue)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-
- if (!returnValueSize || !returnValue)
- return E_INVALIDARG;
- *returnValueSize = 0;
- *returnValue = nullptr;
-
- auto accid = id();
- auto elementIds = std::make_shared<QVarLengthArray<QAccessible::Id>>();
-
- if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, elementIds]() {
- if (QAccessibleInterface *accessible = accessibleForId(accid)) {
- if (QAccessibleTableInterface *tableInterface = accessible->tableInterface()) {
- for (int i = 0; i < tableInterface->rowCount(); ++i) {
- if (QAccessibleInterface *cell = tableInterface->cellAt(i, 0)) {
- QWinRTUiaMetadataCache::instance()->load(idForAccessible(cell));
- if (QAccessibleTableCellInterface *tableCellInterface = cell->tableCellInterface()) {
- QList<QAccessibleInterface *> headers = tableCellInterface->rowHeaderCells();
- for (auto header : qAsConst(headers)) {
- QAccessible::Id headerId = idForAccessible(header);
- QWinRTUiaMetadataCache::instance()->load(headerId);
- elementIds->append(headerId);
- }
- }
- }
- }
- }
- }
- return S_OK;
- }))) {
- return E_FAIL;
- }
-
- return QWinRTUiaMainProvider::rawProviderArrayForAccessibleIdList(*elementIds, returnValueSize, returnValue);
-}
-
-QT_END_NAMESPACE
-
-#endif // QT_CONFIG(accessibility)
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiatableprovider.h b/src/plugins/platforms/winrt/uiautomation/qwinrtuiatableprovider.h
deleted file mode 100644
index 0cd174e401..0000000000
--- a/src/plugins/platforms/winrt/uiautomation/qwinrtuiatableprovider.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 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 QWINRTUIATABLEPROVIDER_H
-#define QWINRTUIATABLEPROVIDER_H
-
-#include <QtGui/qtguiglobal.h>
-#if QT_CONFIG(accessibility)
-
-#include "qwinrtuiabaseprovider.h"
-
-#include <wrl.h>
-#include <windows.ui.xaml.h>
-
-QT_BEGIN_NAMESPACE
-
-// Implements the Table control pattern provider. Used by tables/trees.
-class QWinRTUiaTableProvider :
- public QWinRTUiaBaseProvider,
- public Microsoft::WRL::RuntimeClass<ABI::Windows::UI::Xaml::Automation::Provider::ITableProvider>
-{
- Q_OBJECT
- Q_DISABLE_COPY(QWinRTUiaTableProvider)
- InspectableClass(L"QWinRTUiaTableProvider", BaseTrust);
-
-public:
- explicit QWinRTUiaTableProvider(QAccessible::Id id);
- virtual ~QWinRTUiaTableProvider();
-
- // ITableProvider
- HRESULT STDMETHODCALLTYPE get_RowOrColumnMajor(ABI::Windows::UI::Xaml::Automation::RowOrColumnMajor *value) override;
- HRESULT STDMETHODCALLTYPE GetColumnHeaders(UINT32 *returnValueSize, ABI::Windows::UI::Xaml::Automation::Provider::IIRawElementProviderSimple ***returnValue) override;
- HRESULT STDMETHODCALLTYPE GetRowHeaders(UINT32 *returnValueSize, ABI::Windows::UI::Xaml::Automation::Provider::IIRawElementProviderSimple ***returnValue) override;
-};
-
-QT_END_NAMESPACE
-
-#endif // QT_CONFIG(accessibility)
-
-#endif // QWINRTUIATABLEPROVIDER_H
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiatextprovider.cpp b/src/plugins/platforms/winrt/uiautomation/qwinrtuiatextprovider.cpp
deleted file mode 100644
index cd7420f360..0000000000
--- a/src/plugins/platforms/winrt/uiautomation/qwinrtuiatextprovider.cpp
+++ /dev/null
@@ -1,234 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 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 <QtGui/qtguiglobal.h>
-#if QT_CONFIG(accessibility)
-
-#include "qwinrtuiatextprovider.h"
-#include "qwinrtuiametadatacache.h"
-#include "qwinrtuiatextrangeprovider.h"
-#include "qwinrtuiautils.h"
-
-#include <QtGui/QAccessible>
-#include <QtGui/QAccessibleInterface>
-#include <QtCore/QLoggingCategory>
-#include <QtCore/QString>
-#include <QtCore/private/qeventdispatcher_winrt_p.h>
-
-#include <memory>
-
-QT_BEGIN_NAMESPACE
-
-using namespace QWinRTUiAutomation;
-using namespace Microsoft::WRL;
-using namespace Microsoft::WRL::Wrappers;
-using namespace ABI::Windows::UI::Xaml::Automation;
-using namespace ABI::Windows::UI::Xaml::Automation::Provider;
-
-QWinRTUiaTextProvider::QWinRTUiaTextProvider(QAccessible::Id id) :
- QWinRTUiaBaseProvider(id)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-}
-
-QWinRTUiaTextProvider::~QWinRTUiaTextProvider()
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-}
-
-// Returns a text range provider for the entire text.
-HRESULT STDMETHODCALLTYPE QWinRTUiaTextProvider::get_DocumentRange(ITextRangeProvider **value)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-
- if (!value)
- return E_INVALIDARG;
-
- QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
- ComPtr<QWinRTUiaTextRangeProvider> textRangeProvider = Make<QWinRTUiaTextRangeProvider>(id(), 0, metadata->characterCount());
- return textRangeProvider.CopyTo(value);
-}
-
-// Currently supporting single selection.
-HRESULT STDMETHODCALLTYPE QWinRTUiaTextProvider::get_SupportedTextSelection(SupportedTextSelection *value)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
- if (!value)
- return E_INVALIDARG;
- *value = SupportedTextSelection_Single;
- return S_OK;
-
-}
-
-// Returns an array of providers for the selected text ranges.
-HRESULT STDMETHODCALLTYPE QWinRTUiaTextProvider::GetSelection(UINT32 *returnValueSize, ITextRangeProvider ***returnValue)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-
- if (!returnValueSize || !returnValue)
- return E_INVALIDARG;
- *returnValueSize = 0;
- *returnValue = nullptr;
-
- struct Selection { int startOffset, endOffset; };
-
- auto accid = id();
- auto selections = std::make_shared<QVarLengthArray<Selection>>();
-
- if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, selections]() {
- if (QAccessibleInterface *accessible = accessibleForId(accid)) {
- if (QAccessibleTextInterface *textInterface = accessible->textInterface()) {
- for (int i = 0; i < textInterface->selectionCount(); ++i) {
- int startOffset, endOffset;
- textInterface->selection(i, &startOffset, &endOffset);
- selections->append({startOffset, endOffset});
- }
- if (selections->size() == 0) {
- // If there is no selection, we return an array with a single degenerate (empty) text range at the cursor position.
- auto cur = textInterface->cursorPosition();
- selections->append({cur, cur});
- }
- }
- }
- return S_OK;
- }))) {
- return E_FAIL;
- }
-
- int selCount = selections->size();
- if (selCount < 1)
- return E_FAIL;
-
- ITextRangeProvider **providerArray = static_cast<ITextRangeProvider **>(CoTaskMemAlloc(selCount * sizeof(ITextRangeProvider *)));
- if (!providerArray)
- return E_OUTOFMEMORY;
-
- auto dst = providerArray;
- for (auto sel : *selections) {
- ComPtr<QWinRTUiaTextRangeProvider> textRangeProvider
- = Make<QWinRTUiaTextRangeProvider>(id(), sel.startOffset, sel.endOffset);
- textRangeProvider.CopyTo(dst++);
- }
- *returnValueSize = selCount;
- *returnValue = providerArray;
- return S_OK;
-}
-
-// Returns an array of providers for the visible text ranges.
-HRESULT STDMETHODCALLTYPE QWinRTUiaTextProvider::GetVisibleRanges(UINT32 *returnValueSize, ITextRangeProvider ***returnValue)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-
- if (!returnValueSize || !returnValue)
- return E_INVALIDARG;
-
- QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
-
- // Considering the entire text as visible.
- ComPtr<QWinRTUiaTextRangeProvider> textRangeProvider = Make<QWinRTUiaTextRangeProvider>(id(), 0, metadata->characterCount());
- textRangeProvider.CopyTo(*returnValue);
- *returnValueSize = 1;
- return S_OK;
-}
-
-HRESULT STDMETHODCALLTYPE QWinRTUiaTextProvider::RangeFromChild(IIRawElementProviderSimple *childElement, ITextRangeProvider **returnValue)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
- if (!childElement || !returnValue)
- return E_INVALIDARG;
- *returnValue = nullptr;
- // No children supported.
- return S_OK;
-}
-
-// Returns a degenerate text range at the specified point.
-HRESULT STDMETHODCALLTYPE QWinRTUiaTextProvider::RangeFromPoint(ABI::Windows::Foundation::Point screenLocation, ITextRangeProvider **returnValue)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-
- if (!returnValue)
- return E_INVALIDARG;
- *returnValue = nullptr;
-
- const QPoint pt(screenLocation.X, screenLocation.Y);
- auto accid = id();
- auto offset = std::make_shared<int>();
-
- if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, pt, offset]() {
- if (QAccessibleInterface *accessible = accessibleForId(accid))
- if (QAccessibleTextInterface *textInterface = accessible->textInterface())
- *offset = qBound(0, textInterface->offsetAtPoint(pt), textInterface->characterCount() - 1);
- return S_OK;
- }))) {
- return E_FAIL;
- }
-
- ComPtr<QWinRTUiaTextRangeProvider> textRangeProvider = Make<QWinRTUiaTextRangeProvider>(id(), *offset, *offset);
- textRangeProvider.CopyTo(returnValue);
- return S_OK;
-}
-
-// Not supporting annotations.
-HRESULT STDMETHODCALLTYPE QWinRTUiaTextProvider::RangeFromAnnotation(IIRawElementProviderSimple *annotationElement, ITextRangeProvider **returnValue)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
- if (!annotationElement || !returnValue)
- return E_INVALIDARG;
- *returnValue = nullptr;
- return S_OK;
-}
-
-HRESULT STDMETHODCALLTYPE QWinRTUiaTextProvider::GetCaretRange(boolean *isActive, ITextRangeProvider **returnValue)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-
- if (!isActive || !returnValue)
- return E_INVALIDARG;
-
- QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
- *isActive = metadata->state().focused;
-
- ComPtr<QWinRTUiaTextRangeProvider> textRangeProvider = Make<QWinRTUiaTextRangeProvider>(id(), metadata->cursorPosition(), metadata->cursorPosition());
- return textRangeProvider.CopyTo(returnValue);
-}
-
-
-QT_END_NAMESPACE
-
-#endif // QT_CONFIG(accessibility)
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiatextprovider.h b/src/plugins/platforms/winrt/uiautomation/qwinrtuiatextprovider.h
deleted file mode 100644
index 80d88e4115..0000000000
--- a/src/plugins/platforms/winrt/uiautomation/qwinrtuiatextprovider.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 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 QWINRTUIATEXTPROVIDER_H
-#define QWINRTUIATEXTPROVIDER_H
-
-#include <QtGui/qtguiglobal.h>
-#if QT_CONFIG(accessibility)
-
-#include "qwinrtuiabaseprovider.h"
-
-#include <wrl.h>
-#include <windows.ui.xaml.h>
-
-QT_BEGIN_NAMESPACE
-
-// Implements the Text control pattern provider. Used for text controls.
-class QWinRTUiaTextProvider :
- public QWinRTUiaBaseProvider,
- public Microsoft::WRL::RuntimeClass<ABI::Windows::UI::Xaml::Automation::Provider::ITextProvider, ABI::Windows::UI::Xaml::Automation::Provider::ITextProvider2>
-{
- Q_OBJECT
- Q_DISABLE_COPY(QWinRTUiaTextProvider)
- InspectableClass(L"QWinRTUiaTextProvider", BaseTrust);
-
-public:
- explicit QWinRTUiaTextProvider(QAccessible::Id id);
- virtual ~QWinRTUiaTextProvider();
-
- // ITextProvider
- HRESULT STDMETHODCALLTYPE get_DocumentRange(ABI::Windows::UI::Xaml::Automation::Provider::ITextRangeProvider **value) override;
- HRESULT STDMETHODCALLTYPE get_SupportedTextSelection(ABI::Windows::UI::Xaml::Automation::SupportedTextSelection *value) override;
- HRESULT STDMETHODCALLTYPE GetSelection(UINT32 *returnValueSize, ABI::Windows::UI::Xaml::Automation::Provider::ITextRangeProvider ***returnValue) override;
- HRESULT STDMETHODCALLTYPE GetVisibleRanges(UINT32 *returnValueSize, ABI::Windows::UI::Xaml::Automation::Provider::ITextRangeProvider ***returnValue) override;
- HRESULT STDMETHODCALLTYPE RangeFromChild(ABI::Windows::UI::Xaml::Automation::Provider::IIRawElementProviderSimple *childElement, ABI::Windows::UI::Xaml::Automation::Provider::ITextRangeProvider **returnValue) override;
- HRESULT STDMETHODCALLTYPE RangeFromPoint(ABI::Windows::Foundation::Point screenLocation, ABI::Windows::UI::Xaml::Automation::Provider::ITextRangeProvider **returnValue) override;
-
- // ITextProvider2
- HRESULT STDMETHODCALLTYPE RangeFromAnnotation(ABI::Windows::UI::Xaml::Automation::Provider::IIRawElementProviderSimple *annotationElement, ABI::Windows::UI::Xaml::Automation::Provider::ITextRangeProvider **returnValue) override;
- HRESULT STDMETHODCALLTYPE GetCaretRange(boolean *isActive, ABI::Windows::UI::Xaml::Automation::Provider::ITextRangeProvider **returnValue) override;
-};
-
-QT_END_NAMESPACE
-
-#endif // QT_CONFIG(accessibility)
-
-#endif // QWINRTUIATEXTPROVIDER_H
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiatextrangeprovider.cpp b/src/plugins/platforms/winrt/uiautomation/qwinrtuiatextrangeprovider.cpp
deleted file mode 100644
index ca15feaff9..0000000000
--- a/src/plugins/platforms/winrt/uiautomation/qwinrtuiatextrangeprovider.cpp
+++ /dev/null
@@ -1,498 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 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 <QtGui/qtguiglobal.h>
-#if QT_CONFIG(accessibility)
-
-#include "qwinrtuiatextrangeprovider.h"
-#include "qwinrtuiametadatacache.h"
-#include "qwinrtuiamainprovider.h"
-#include "qwinrtuiautils.h"
-
-#include <QtGui/QAccessible>
-#include <QtGui/QAccessibleInterface>
-#include <QtCore/QLoggingCategory>
-#include <QtCore/QString>
-#include <QtCore/private/qeventdispatcher_winrt_p.h>
-
-#include <memory>
-
-QT_BEGIN_NAMESPACE
-
-using namespace QWinRTUiAutomation;
-using namespace Microsoft::WRL;
-using namespace Microsoft::WRL::Wrappers;
-using namespace ABI::Windows::Foundation;
-using namespace ABI::Windows::UI::Xaml;
-using namespace ABI::Windows::UI::Xaml::Automation;
-using namespace ABI::Windows::UI::Xaml::Automation::Provider;
-using namespace ABI::Windows::UI::Xaml::Automation::Text;
-
-QWinRTUiaTextRangeProvider::QWinRTUiaTextRangeProvider(QAccessible::Id id, int startOffset, int endOffset) :
- QWinRTUiaBaseProvider(id),
- m_startOffset(startOffset),
- m_endOffset(endOffset)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__ << startOffset << endOffset;
-}
-
-QWinRTUiaTextRangeProvider::~QWinRTUiaTextRangeProvider()
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-}
-
-HRESULT STDMETHODCALLTYPE QWinRTUiaTextRangeProvider::Clone(ITextRangeProvider **returnValue)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
- if (!returnValue)
- return E_INVALIDARG;
-
- ComPtr<QWinRTUiaTextRangeProvider> textRangeProvider = Make<QWinRTUiaTextRangeProvider>(id(), m_startOffset, m_endOffset);
- textRangeProvider.CopyTo(returnValue);
- return S_OK;
-}
-
-// Two ranges are considered equal if their start/end points are the same.
-HRESULT STDMETHODCALLTYPE QWinRTUiaTextRangeProvider::Compare(ITextRangeProvider *textRangeProvider, boolean *returnValue)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
- if (!textRangeProvider || !returnValue)
- return E_INVALIDARG;
-
- QWinRTUiaTextRangeProvider *targetProvider = static_cast<QWinRTUiaTextRangeProvider *>(textRangeProvider);
- *returnValue = ((targetProvider->m_startOffset == m_startOffset) && (targetProvider->m_endOffset == m_endOffset));
- return S_OK;
-}
-
-// Compare different endpoinds between two providers.
-HRESULT STDMETHODCALLTYPE QWinRTUiaTextRangeProvider::CompareEndpoints(TextPatternRangeEndpoint endpoint, ITextRangeProvider *textRangeProvider, TextPatternRangeEndpoint targetEndpoint, INT32 *returnValue)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-
- if (!textRangeProvider || !returnValue)
- return E_INVALIDARG;
-
- QWinRTUiaTextRangeProvider *targetProvider = static_cast<QWinRTUiaTextRangeProvider *>(textRangeProvider);
-
- int point = (endpoint == TextPatternRangeEndpoint_Start) ? m_startOffset : m_endOffset;
- int targetPoint = (targetEndpoint == TextPatternRangeEndpoint_Start) ?
- targetProvider->m_startOffset : targetProvider->m_endOffset;
- *returnValue = point - targetPoint;
- return S_OK;
-}
-
-// Expands/normalizes the range for a given text unit.
-HRESULT STDMETHODCALLTYPE QWinRTUiaTextRangeProvider::ExpandToEnclosingUnit(TextUnit unit)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__ << "unit=" << unit << "this: " << this;
-
- QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
-
- int len = metadata->characterCount();
- if (len < 1) {
- m_startOffset = 0;
- m_endOffset = 0;
- } else {
- if (unit == TextUnit_Character) {
- m_startOffset = qBound(0, m_startOffset, len - 1);
- m_endOffset = m_startOffset + 1;
- } else {
- QString text = metadata->text();
- for (int t = m_startOffset; t >= 0; --t) {
- if (!isTextUnitSeparator(unit, text[t]) && ((t == 0) || isTextUnitSeparator(unit, text[t - 1]))) {
- m_startOffset = t;
- break;
- }
- }
- for (int t = m_startOffset; t < len; ++t) {
- if ((t == len - 1) || (isTextUnitSeparator(unit, text[t]) && ((unit == TextUnit_Word) || !isTextUnitSeparator(unit, text[t + 1])))) {
- m_endOffset = t + 1;
- break;
- }
- }
- }
- }
- return S_OK;
-}
-
-// Not supported.
-HRESULT STDMETHODCALLTYPE QWinRTUiaTextRangeProvider::FindAttribute(INT32 /*attributeId*/, IInspectable * /*value*/, boolean /*backward*/, ITextRangeProvider **returnValue)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
- if (!returnValue)
- return E_INVALIDARG;
- *returnValue = nullptr;
- return S_OK;
-}
-
-HRESULT STDMETHODCALLTYPE QWinRTUiaTextRangeProvider::FindText(HSTRING /*text*/, boolean /*backward*/, boolean /*ignoreCase*/, ITextRangeProvider **returnValue)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
- if (!returnValue)
- return E_INVALIDARG;
- *returnValue = nullptr;
- return S_OK;
-}
-
-// Returns the value of a given attribute.
-HRESULT STDMETHODCALLTYPE QWinRTUiaTextRangeProvider::GetAttributeValue(INT32 attributeId, IInspectable **returnValue)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__ << "attributeId=" << attributeId;
-
- if (!returnValue)
- return E_INVALIDARG;
- *returnValue = nullptr;
-
- ComPtr<IPropertyValueStatics> propertyValueStatics;
- if (FAILED(RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Foundation_PropertyValue).Get(), IID_PPV_ARGS(&propertyValueStatics))))
- return E_FAIL;
-
- QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
-
- switch (attributeId) {
- case AutomationTextAttributesEnum_IsReadOnlyAttribute:
- return propertyValueStatics->CreateBoolean(metadata->state().readOnly, returnValue);
- case AutomationTextAttributesEnum_CaretPositionAttribute:
- if (metadata->cursorPosition() == 0)
- return propertyValueStatics->CreateInt32(AutomationCaretPosition_BeginningOfLine, returnValue);
- else if (metadata->cursorPosition() == metadata->characterCount())
- return propertyValueStatics->CreateInt32(AutomationCaretPosition_EndOfLine, returnValue);
- else
- return propertyValueStatics->CreateInt32(AutomationCaretPosition_Unknown, returnValue);
- default:
- break;
- }
- return E_FAIL;
-}
-
-// Returns an array of bounding rectangles for text lines within the range.
-HRESULT STDMETHODCALLTYPE QWinRTUiaTextRangeProvider::GetBoundingRectangles(UINT32 *returnValueSize, DOUBLE **returnValue)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-
- if (!returnValueSize || !returnValue)
- return E_INVALIDARG;
- *returnValueSize = 0;
- *returnValue = nullptr;
-
- auto accid = id();
- auto startOffset = m_startOffset;
- auto endOffset = m_endOffset;
- auto rects = std::make_shared<QVarLengthArray<QRect>>();
-
- if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, startOffset, endOffset, rects]() {
- if (QAccessibleInterface *accessible = accessibleForId(accid)) {
- if (QAccessibleTextInterface *textInterface = accessible->textInterface()) {
- int len = textInterface->characterCount();
- if ((startOffset >= 0) && (endOffset <= len) && (startOffset < endOffset)) {
- int start, end;
- textInterface->textAtOffset(startOffset, QAccessible::LineBoundary, &start, &end);
- while ((start >= 0) && (end >= 0)) {
- int startRange = qMax(start, startOffset);
- int endRange = qMin(end, endOffset);
- if (startRange < endRange) {
- // Calculates a bounding rectangle for the line and adds it to the list.
- const QRect startRect = textInterface->characterRect(startRange);
- const QRect endRect = textInterface->characterRect(endRange - 1);
- const QRect lineRect(qMin(startRect.x(), endRect.x()),
- qMin(startRect.y(), endRect.y()),
- qMax(startRect.x() + startRect.width(), endRect.x() + endRect.width()) - qMin(startRect.x(), endRect.x()),
- qMax(startRect.y() + startRect.height(), endRect.y() + endRect.height()) - qMin(startRect.y(), endRect.y()));
- rects->append(lineRect);
- }
- if (end >= len) break;
- textInterface->textAfterOffset(end + 1, QAccessible::LineBoundary, &start, &end);
- }
- }
- }
- }
- return S_OK;
- }))) {
- return E_FAIL;
- }
-
- DOUBLE *doubleArray = static_cast<DOUBLE *>(CoTaskMemAlloc(4 * rects->size() * sizeof(DOUBLE)));
- if (!doubleArray)
- return E_OUTOFMEMORY;
-
- DOUBLE *dst = doubleArray;
- for (auto rect : *rects) {
- *dst++ = rect.left();
- *dst++ = rect.top();
- *dst++ = rect.width();
- *dst++ = rect.height();
- }
- *returnValue = doubleArray;
- *returnValueSize = 4 * rects->size();
- return S_OK;
-}
-
-HRESULT STDMETHODCALLTYPE QWinRTUiaTextRangeProvider::GetEnclosingElement(IIRawElementProviderSimple **returnValue)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
- if (!returnValue)
- return E_INVALIDARG;
- return QWinRTUiaMainProvider::rawProviderForAccessibleId(id(), returnValue);
-}
-
-HRESULT STDMETHODCALLTYPE QWinRTUiaTextRangeProvider::GetText(INT32 maxLength, HSTRING *returnValue)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
- if (!returnValue)
- return E_INVALIDARG;
- *returnValue = nullptr;
-
- QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
-
- QString rangeText = metadata->text().mid(m_startOffset, m_endOffset - m_startOffset);
-
- if ((maxLength > -1) && (rangeText.size() > maxLength))
- rangeText.truncate(maxLength);
- return qHString(rangeText, returnValue);
-}
-
-HRESULT STDMETHODCALLTYPE QWinRTUiaTextRangeProvider::Move(TextUnit unit, INT32 count, INT32 *returnValue)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
- if (!returnValue)
- return E_INVALIDARG;
- *returnValue = 0;
-
- QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
-
- int len = metadata->characterCount();
- if (len < 1)
- return S_OK;
-
- if (unit == TextUnit_Character) {
- // Moves the start point, ensuring it lies within the bounds.
- int start = qBound(0, m_startOffset + count, len - 1);
- // If range was initially empty, leaves it as is; otherwise, normalizes it to one char.
- m_endOffset = (m_endOffset > m_startOffset) ? start + 1 : start;
- *returnValue = start - m_startOffset; // Returns the actually moved distance.
- m_startOffset = start;
- } else {
- if (count > 0) {
- MoveEndpointByUnit(TextPatternRangeEndpoint_End, unit, count, returnValue);
- MoveEndpointByUnit(TextPatternRangeEndpoint_Start, unit, count, returnValue);
- } else {
- MoveEndpointByUnit(TextPatternRangeEndpoint_Start, unit, count, returnValue);
- MoveEndpointByUnit(TextPatternRangeEndpoint_End, unit, count, returnValue);
- }
- }
- return S_OK;
-}
-
-HRESULT STDMETHODCALLTYPE QWinRTUiaTextRangeProvider::MoveEndpointByUnit(TextPatternRangeEndpoint endpoint, TextUnit unit, INT32 count, INT32 *returnValue)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
- if (!returnValue)
- return E_INVALIDARG;
- *returnValue = 0;
-
- QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
-
- int len = metadata->characterCount();
- if (len < 1)
- return S_OK;
-
- if (unit == TextUnit_Character) {
- if (endpoint == TextPatternRangeEndpoint_Start) {
- int boundedValue = qBound(0, m_startOffset + count, len - 1);
- *returnValue = boundedValue - m_startOffset;
- m_startOffset = boundedValue;
- m_endOffset = qBound(m_startOffset, m_endOffset, len);
- } else {
- int boundedValue = qBound(0, m_endOffset + count, len);
- *returnValue = boundedValue - m_endOffset;
- m_endOffset = boundedValue;
- m_startOffset = qBound(0, m_startOffset, m_endOffset);
- }
- } else {
- QString text = metadata->text();
- int moved = 0;
-
- if (endpoint == TextPatternRangeEndpoint_Start) {
- if (count > 0) {
- for (int t = m_startOffset; (t < len - 1) && (moved < count); ++t) {
- if (isTextUnitSeparator(unit, text[t]) && !isTextUnitSeparator(unit, text[t + 1])) {
- m_startOffset = t + 1;
- ++moved;
- }
- }
- m_endOffset = qBound(m_startOffset, m_endOffset, len);
- } else {
- for (int t = m_startOffset - 1; (t >= 0) && (moved > count); --t) {
- if (!isTextUnitSeparator(unit, text[t]) && ((t == 0) || isTextUnitSeparator(unit, text[t - 1]))) {
- m_startOffset = t;
- --moved;
- }
- }
- }
- } else {
- if (count > 0) {
- for (int t = m_endOffset; (t < len) && (moved < count); ++t) {
- if ((t == len - 1) || (isTextUnitSeparator(unit, text[t]) && ((unit == TextUnit_Word) || !isTextUnitSeparator(unit, text[t + 1])))) {
- m_endOffset = t + 1;
- ++moved;
- }
- }
- } else {
- int end = 0;
- for (int t = m_endOffset - 2; (t > 0) && (moved > count); --t) {
- if (isTextUnitSeparator(unit, text[t]) && ((unit == TextUnit_Word) || !isTextUnitSeparator(unit, text[t + 1]))) {
- end = t + 1;
- --moved;
- }
- }
- m_endOffset = end;
- m_startOffset = qBound(0, m_startOffset, m_endOffset);
- }
- }
- *returnValue = moved;
- }
- return S_OK;
-}
-
-HRESULT STDMETHODCALLTYPE QWinRTUiaTextRangeProvider::MoveEndpointByRange(TextPatternRangeEndpoint endpoint, ITextRangeProvider *textRangeProvider, TextPatternRangeEndpoint targetEndpoint)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
- if (!textRangeProvider)
- return E_INVALIDARG;
-
- QWinRTUiaTextRangeProvider *targetProvider = static_cast<QWinRTUiaTextRangeProvider *>(textRangeProvider);
-
- int targetPoint = (targetEndpoint == TextPatternRangeEndpoint_Start) ?
- targetProvider->m_startOffset : targetProvider->m_endOffset;
-
- // If the moved endpoint crosses the other endpoint, that one is moved too.
- if (endpoint == TextPatternRangeEndpoint_Start) {
- m_startOffset = targetPoint;
- if (m_endOffset < m_startOffset)
- m_endOffset = m_startOffset;
- } else {
- m_endOffset = targetPoint;
- if (m_endOffset < m_startOffset)
- m_startOffset = m_endOffset;
- }
- return S_OK;
-}
-
-HRESULT STDMETHODCALLTYPE QWinRTUiaTextRangeProvider::Select()
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-
- auto accid = id();
- auto startOffset = m_startOffset;
- auto endOffset = m_endOffset;
-
- QEventDispatcherWinRT::runOnMainThread([accid, startOffset, endOffset]() {
- if (QAccessibleInterface *accessible = accessibleForId(accid))
- if (QAccessibleTextInterface *textInterface = accessible->textInterface()) {
- // unselects all and adds a new selection
- for (int i = textInterface->selectionCount() - 1; i >= 0; --i)
- textInterface->removeSelection(i);
- textInterface->addSelection(startOffset, endOffset);
- }
- QWinRTUiaMetadataCache::instance()->load(accid);
- return S_OK;
- }, 0);
- return S_OK;
-}
-
-HRESULT STDMETHODCALLTYPE QWinRTUiaTextRangeProvider::AddToSelection()
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
- return Select();
-}
-
-HRESULT STDMETHODCALLTYPE QWinRTUiaTextRangeProvider::RemoveFromSelection()
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-
- auto accid = id();
-
- QEventDispatcherWinRT::runOnMainThread([accid]() {
- if (QAccessibleInterface *accessible = accessibleForId(accid))
- if (QAccessibleTextInterface *textInterface = accessible->textInterface()) {
- // unselects all
- for (int i = textInterface->selectionCount() - 1; i >= 0; --i)
- textInterface->removeSelection(i);
- }
- QWinRTUiaMetadataCache::instance()->load(accid);
- return S_OK;
- }, 0);
- return S_OK;
-}
-
-HRESULT STDMETHODCALLTYPE QWinRTUiaTextRangeProvider::ScrollIntoView(boolean /*alignToTop*/)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-
- auto accid = id();
- auto startOffset = m_startOffset;
- auto endOffset = m_endOffset;
-
- QEventDispatcherWinRT::runOnMainThread([accid, startOffset, endOffset]() {
- if (QAccessibleInterface *accessible = accessibleForId(accid))
- if (QAccessibleTextInterface *textInterface = accessible->textInterface()) {
- textInterface->scrollToSubstring(startOffset, endOffset);
- }
- QWinRTUiaMetadataCache::instance()->load(accid);
- return S_OK;
- }, 0);
- return S_OK;
-}
-
-// Returns an array of children elements embedded within the range.
-HRESULT STDMETHODCALLTYPE QWinRTUiaTextRangeProvider::GetChildren(UINT32 *returnValueSize, IIRawElementProviderSimple ***returnValue)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-
- if (!returnValue)
- return E_INVALIDARG;
- // Not supporting any children.
- returnValueSize = 0;
- *returnValue = nullptr;
- return S_OK;
-}
-
-QT_END_NAMESPACE
-
-#endif // QT_CONFIG(accessibility)
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiatextrangeprovider.h b/src/plugins/platforms/winrt/uiautomation/qwinrtuiatextrangeprovider.h
deleted file mode 100644
index 81b5f0d400..0000000000
--- a/src/plugins/platforms/winrt/uiautomation/qwinrtuiatextrangeprovider.h
+++ /dev/null
@@ -1,95 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 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 QWINRTUIATEXTRANGEPROVIDER_H
-#define QWINRTUIATEXTRANGEPROVIDER_H
-
-#include <QtGui/qtguiglobal.h>
-#if QT_CONFIG(accessibility)
-
-#include "qwinrtuiabaseprovider.h"
-
-#include <wrl.h>
-#include <windows.ui.xaml.h>
-
-QT_BEGIN_NAMESPACE
-
-// Implements the Text Range control pattern provider. Used for text controls.
-class QWinRTUiaTextRangeProvider :
- public QWinRTUiaBaseProvider,
- public Microsoft::WRL::RuntimeClass<ABI::Windows::UI::Xaml::Automation::Provider::ITextRangeProvider>
-{
- Q_OBJECT
- Q_DISABLE_COPY(QWinRTUiaTextRangeProvider)
- InspectableClass(L"QWinRTUiaTextRangeProvider", BaseTrust);
-
-public:
- explicit QWinRTUiaTextRangeProvider(QAccessible::Id id, int startOffset, int endOffset);
- virtual ~QWinRTUiaTextRangeProvider();
-
- // ITextRangeProvider
- HRESULT STDMETHODCALLTYPE Clone(ABI::Windows::UI::Xaml::Automation::Provider::ITextRangeProvider **returnValue) override;
- HRESULT STDMETHODCALLTYPE Compare(ABI::Windows::UI::Xaml::Automation::Provider::ITextRangeProvider *textRangeProvider, boolean *returnValue) override;
- HRESULT STDMETHODCALLTYPE CompareEndpoints(ABI::Windows::UI::Xaml::Automation::Text::TextPatternRangeEndpoint endpoint, ABI::Windows::UI::Xaml::Automation::Provider::ITextRangeProvider *textRangeProvider, ABI::Windows::UI::Xaml::Automation::Text::TextPatternRangeEndpoint targetEndpoint, INT32 *returnValue) override;
- HRESULT STDMETHODCALLTYPE ExpandToEnclosingUnit(ABI::Windows::UI::Xaml::Automation::Text::TextUnit unit) override;
- HRESULT STDMETHODCALLTYPE FindAttribute(INT32 attributeId, IInspectable *value, boolean backward, ABI::Windows::UI::Xaml::Automation::Provider::ITextRangeProvider **returnValue) override;
- HRESULT STDMETHODCALLTYPE FindText(HSTRING text, boolean backward, boolean ignoreCase, ABI::Windows::UI::Xaml::Automation::Provider::ITextRangeProvider **returnValue) override;
- HRESULT STDMETHODCALLTYPE GetAttributeValue(INT32 attributeId, IInspectable **returnValue) override;
- HRESULT STDMETHODCALLTYPE GetBoundingRectangles(UINT32 *returnValueSize, DOUBLE **returnValue) override;
- HRESULT STDMETHODCALLTYPE GetEnclosingElement(ABI::Windows::UI::Xaml::Automation::Provider::IIRawElementProviderSimple **returnValue) override;
- HRESULT STDMETHODCALLTYPE GetText(INT32 maxLength, HSTRING *returnValue) override;
- HRESULT STDMETHODCALLTYPE Move(ABI::Windows::UI::Xaml::Automation::Text::TextUnit unit, INT32 count, INT32 *returnValue) override;
- HRESULT STDMETHODCALLTYPE MoveEndpointByUnit(ABI::Windows::UI::Xaml::Automation::Text::TextPatternRangeEndpoint endpoint, ABI::Windows::UI::Xaml::Automation::Text::TextUnit unit, INT32 count, INT32 *returnValue) override;
- HRESULT STDMETHODCALLTYPE MoveEndpointByRange(ABI::Windows::UI::Xaml::Automation::Text::TextPatternRangeEndpoint endpoint, ABI::Windows::UI::Xaml::Automation::Provider::ITextRangeProvider *textRangeProvider, ABI::Windows::UI::Xaml::Automation::Text::TextPatternRangeEndpoint targetEndpoint) override;
- HRESULT STDMETHODCALLTYPE Select() override;
- HRESULT STDMETHODCALLTYPE AddToSelection() override;
- HRESULT STDMETHODCALLTYPE RemoveFromSelection() override;
- HRESULT STDMETHODCALLTYPE ScrollIntoView(boolean alignToTop) override;
- HRESULT STDMETHODCALLTYPE GetChildren(UINT32 *returnValueSize, ABI::Windows::UI::Xaml::Automation::Provider::IIRawElementProviderSimple ***returnValue) override;
-
-private:
- int m_startOffset;
- int m_endOffset;
-};
-
-QT_END_NAMESPACE
-
-#endif // QT_CONFIG(accessibility)
-
-#endif // QWINRTUIATEXTRANGEPROVIDER_H
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiatoggleprovider.cpp b/src/plugins/platforms/winrt/uiautomation/qwinrtuiatoggleprovider.cpp
deleted file mode 100644
index 59f55eb422..0000000000
--- a/src/plugins/platforms/winrt/uiautomation/qwinrtuiatoggleprovider.cpp
+++ /dev/null
@@ -1,104 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 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 <QtGui/qtguiglobal.h>
-#if QT_CONFIG(accessibility)
-
-#include "qwinrtuiatoggleprovider.h"
-#include "qwinrtuiametadatacache.h"
-#include "qwinrtuiautils.h"
-
-#include <QtGui/QAccessible>
-#include <QtGui/QAccessibleInterface>
-#include <QtCore/QLoggingCategory>
-#include <QtCore/QString>
-#include <QtCore/private/qeventdispatcher_winrt_p.h>
-
-QT_BEGIN_NAMESPACE
-
-using namespace QWinRTUiAutomation;
-using namespace ABI::Windows::UI::Xaml::Automation;
-using namespace ABI::Windows::UI::Xaml::Automation::Provider;
-
-QWinRTUiaToggleProvider::QWinRTUiaToggleProvider(QAccessible::Id id) :
- QWinRTUiaBaseProvider(id)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-}
-
-QWinRTUiaToggleProvider::~QWinRTUiaToggleProvider()
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-}
-
-// Gets the current toggle state.
-HRESULT STDMETHODCALLTYPE QWinRTUiaToggleProvider::get_ToggleState(ToggleState *value)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-
- if (!value)
- return E_INVALIDARG;
- QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
- if (metadata->state().checked)
- *value = metadata->state().checkStateMixed ? ToggleState_Indeterminate : ToggleState_On;
- else
- *value = ToggleState_Off;
- return S_OK;
-}
-
-// Toggles the state by invoking the toggle action.
-HRESULT STDMETHODCALLTYPE QWinRTUiaToggleProvider::Toggle()
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-
- auto accid = id();
-
- QEventDispatcherWinRT::runOnMainThread([accid]() {
- if (QAccessibleInterface *accessible = accessibleForId(accid))
- if (QAccessibleActionInterface *actionInterface = accessible->actionInterface())
- actionInterface->doAction(QAccessibleActionInterface::toggleAction());
- QWinRTUiaMetadataCache::instance()->load(accid);
- return S_OK;
- }, 0);
- return S_OK;
-}
-
-QT_END_NAMESPACE
-
-#endif // QT_CONFIG(accessibility)
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiatoggleprovider.h b/src/plugins/platforms/winrt/uiautomation/qwinrtuiatoggleprovider.h
deleted file mode 100644
index 3d1740c0a1..0000000000
--- a/src/plugins/platforms/winrt/uiautomation/qwinrtuiatoggleprovider.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 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 QWINRTUIATOGGLEPROVIDER_H
-#define QWINRTUIATOGGLEPROVIDER_H
-
-#include <QtGui/qtguiglobal.h>
-#if QT_CONFIG(accessibility)
-
-#include "qwinrtuiabaseprovider.h"
-
-#include <wrl.h>
-#include <windows.ui.xaml.h>
-
-QT_BEGIN_NAMESPACE
-
-// Implements the Toggle control pattern provider. Used for checkboxes.
-class QWinRTUiaToggleProvider :
- public QWinRTUiaBaseProvider,
- public Microsoft::WRL::RuntimeClass<ABI::Windows::UI::Xaml::Automation::Provider::IToggleProvider>
-{
- Q_OBJECT
- Q_DISABLE_COPY(QWinRTUiaToggleProvider)
- InspectableClass(L"QWinRTUiaToggleProvider", BaseTrust);
-
-public:
- explicit QWinRTUiaToggleProvider(QAccessible::Id id);
- virtual ~QWinRTUiaToggleProvider();
-
- // IToggleProvider
- HRESULT STDMETHODCALLTYPE get_ToggleState(ABI::Windows::UI::Xaml::Automation::ToggleState *value) override;
- HRESULT STDMETHODCALLTYPE Toggle() override;
-};
-
-QT_END_NAMESPACE
-
-#endif // QT_CONFIG(accessibility)
-
-#endif // QWINRTUIATOGGLEPROVIDER_H
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiautils.cpp b/src/plugins/platforms/winrt/uiautomation/qwinrtuiautils.cpp
deleted file mode 100644
index 16197c99b9..0000000000
--- a/src/plugins/platforms/winrt/uiautomation/qwinrtuiautils.cpp
+++ /dev/null
@@ -1,182 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 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 <QtGui/qtguiglobal.h>
-#if QT_CONFIG(accessibility)
-
-#include "qwinrtuiautils.h"
-
-using namespace ABI::Windows::UI::Xaml::Automation::Peers;
-using namespace ABI::Windows::UI::Xaml::Automation::Text;
-using namespace ABI::Windows::Foundation::Collections;
-
-QT_BEGIN_NAMESPACE
-
-Q_LOGGING_CATEGORY(lcQpaUiAutomation, "qt.qpa.uiautomation")
-
-namespace QWinRTUiAutomation {
-
-// Returns the window containing the element (usually the top window),
-QWindow *windowForAccessible(const QAccessibleInterface *accessible)
-{
- QWindow *window = accessible->window();
- if (!window) {
- QAccessibleInterface *acc = accessible->parent();
- while (acc && acc->isValid() && !window) {
- window = acc->window();
- QAccessibleInterface *par = acc->parent();
- acc = par;
- }
- }
- return window;
-}
-
-QAccessibleInterface *accessibleForId(QAccessible::Id id)
-{
- QAccessibleInterface *accessible = QAccessible::accessibleInterface(id);
- if (!accessible || !accessible->isValid())
- return nullptr;
- return accessible;
-}
-
-QAccessible::Id idForAccessible(QAccessibleInterface *accessible)
-{
- if (!accessible)
- return QAccessible::Id(0);
- return QAccessible::uniqueId(accessible);
-}
-
-// Maps an accessibility role ID to an UI Automation control type ID.
-AutomationControlType roleToControlType(QAccessible::Role role)
-{
- static const QHash<QAccessible::Role, AutomationControlType> mapping {
- {QAccessible::TitleBar, AutomationControlType::AutomationControlType_TitleBar},
- {QAccessible::MenuBar, AutomationControlType::AutomationControlType_MenuBar},
- {QAccessible::ScrollBar, AutomationControlType::AutomationControlType_ScrollBar},
- {QAccessible::Grip, AutomationControlType::AutomationControlType_Thumb},
- {QAccessible::Sound, AutomationControlType::AutomationControlType_Custom},
- {QAccessible::Cursor, AutomationControlType::AutomationControlType_Custom},
- {QAccessible::Caret, AutomationControlType::AutomationControlType_Custom},
- {QAccessible::AlertMessage, AutomationControlType::AutomationControlType_Custom},
- {QAccessible::Window, AutomationControlType::AutomationControlType_Window},
- {QAccessible::Client, AutomationControlType::AutomationControlType_Custom},
- {QAccessible::PopupMenu, AutomationControlType::AutomationControlType_Menu},
- {QAccessible::MenuItem, AutomationControlType::AutomationControlType_MenuItem},
- {QAccessible::ToolTip, AutomationControlType::AutomationControlType_ToolTip},
- {QAccessible::Application, AutomationControlType::AutomationControlType_Custom},
- {QAccessible::Document, AutomationControlType::AutomationControlType_Document},
- {QAccessible::Pane, AutomationControlType::AutomationControlType_Pane},
- {QAccessible::Chart, AutomationControlType::AutomationControlType_Custom},
- {QAccessible::Dialog, AutomationControlType::AutomationControlType_Window},
- {QAccessible::Border, AutomationControlType::AutomationControlType_Custom},
- {QAccessible::Grouping, AutomationControlType::AutomationControlType_Group},
- {QAccessible::Separator, AutomationControlType::AutomationControlType_Separator},
- {QAccessible::ToolBar, AutomationControlType::AutomationControlType_ToolBar},
- {QAccessible::StatusBar, AutomationControlType::AutomationControlType_StatusBar},
- {QAccessible::Table, AutomationControlType::AutomationControlType_Table},
- {QAccessible::ColumnHeader, AutomationControlType::AutomationControlType_Header},
- {QAccessible::RowHeader, AutomationControlType::AutomationControlType_Header},
- {QAccessible::Column, AutomationControlType::AutomationControlType_HeaderItem},
- {QAccessible::Row, AutomationControlType::AutomationControlType_HeaderItem},
- {QAccessible::Cell, AutomationControlType::AutomationControlType_DataItem},
- {QAccessible::Link, AutomationControlType::AutomationControlType_Hyperlink},
- {QAccessible::HelpBalloon, AutomationControlType::AutomationControlType_ToolTip},
- {QAccessible::Assistant, AutomationControlType::AutomationControlType_Custom},
- {QAccessible::List, AutomationControlType::AutomationControlType_List},
- {QAccessible::ListItem, AutomationControlType::AutomationControlType_ListItem},
- {QAccessible::Tree, AutomationControlType::AutomationControlType_Tree},
- {QAccessible::TreeItem, AutomationControlType::AutomationControlType_TreeItem},
- {QAccessible::PageTab, AutomationControlType::AutomationControlType_TabItem},
- {QAccessible::PropertyPage, AutomationControlType::AutomationControlType_Custom},
- {QAccessible::Indicator, AutomationControlType::AutomationControlType_Custom},
- {QAccessible::Graphic, AutomationControlType::AutomationControlType_Image},
- {QAccessible::StaticText, AutomationControlType::AutomationControlType_Text},
- {QAccessible::EditableText, AutomationControlType::AutomationControlType_Edit},
- {QAccessible::Button, AutomationControlType::AutomationControlType_Button},
- {QAccessible::CheckBox, AutomationControlType::AutomationControlType_CheckBox},
- {QAccessible::RadioButton, AutomationControlType::AutomationControlType_RadioButton},
- {QAccessible::ComboBox, AutomationControlType::AutomationControlType_ComboBox},
- {QAccessible::ProgressBar, AutomationControlType::AutomationControlType_ProgressBar},
- {QAccessible::Dial, AutomationControlType::AutomationControlType_Custom},
- {QAccessible::HotkeyField, AutomationControlType::AutomationControlType_Custom},
- {QAccessible::Slider, AutomationControlType::AutomationControlType_Slider},
- {QAccessible::SpinBox, AutomationControlType::AutomationControlType_Spinner},
- {QAccessible::Canvas, AutomationControlType::AutomationControlType_Custom},
- {QAccessible::Animation, AutomationControlType::AutomationControlType_Custom},
- {QAccessible::Equation, AutomationControlType::AutomationControlType_Custom},
- {QAccessible::ButtonDropDown, AutomationControlType::AutomationControlType_Button},
- {QAccessible::ButtonMenu, AutomationControlType::AutomationControlType_Button},
- {QAccessible::ButtonDropGrid, AutomationControlType::AutomationControlType_Button},
- {QAccessible::Whitespace, AutomationControlType::AutomationControlType_Custom},
- {QAccessible::PageTabList, AutomationControlType::AutomationControlType_Tab},
- {QAccessible::Clock, AutomationControlType::AutomationControlType_Custom},
- {QAccessible::Splitter, AutomationControlType::AutomationControlType_Custom},
- };
-
- return mapping.value(role, AutomationControlType::AutomationControlType_Custom);
-}
-
-// True if a character can be a separator for a text unit.
-bool isTextUnitSeparator(TextUnit unit, const QChar &ch)
-{
- return (((unit == TextUnit_Word) || (unit == TextUnit_Format)) && ch.isSpace())
- || ((unit == TextUnit_Line) && (ch.toLatin1() == '\n'));
-}
-
-HRESULT qHString(const QString &str, HSTRING *returnValue)
-{
- if (!returnValue)
- return E_INVALIDARG;
-
- const wchar_t *wstr = reinterpret_cast<const wchar_t *>(str.utf16());
- return ::WindowsCreateString(wstr, static_cast<UINT32>(::wcslen(wstr)), returnValue);
-}
-
-QString hStrToQStr(const HSTRING &hStr)
-{
- quint32 len;
- const wchar_t *wstr = ::WindowsGetStringRawBuffer(hStr, &len);
- return QString::fromWCharArray(wstr, len);
-}
-
-} // namespace QWinRTUiAutomation
-
-QT_END_NAMESPACE
-
-#endif // QT_CONFIG(accessibility)
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiautils.h b/src/plugins/platforms/winrt/uiautomation/qwinrtuiautils.h
deleted file mode 100644
index 9519cb4eb5..0000000000
--- a/src/plugins/platforms/winrt/uiautomation/qwinrtuiautils.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 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 QWINRTUIAUTILS_H
-#define QWINRTUIAUTILS_H
-
-#include <QtGui/qtguiglobal.h>
-#if QT_CONFIG(accessibility)
-
-#include <QtCore/QString>
-#include <QtCore/qt_windows.h>
-#include <QtGui/QAccessible>
-#include <QtGui/QAccessibleInterface>
-#include <QtGui/QWindow>
-#include <QtCore/QLoggingCategory>
-
-#include <wrl.h>
-#include <windows.ui.xaml.h>
-#include <functional>
-
-QT_BEGIN_NAMESPACE
-
-Q_DECLARE_LOGGING_CATEGORY(lcQpaUiAutomation)
-
-namespace QWinRTUiAutomation {
-
-QWindow *windowForAccessible(const QAccessibleInterface *accessible);
-
-QAccessibleInterface *accessibleForId(QAccessible::Id id);
-
-QAccessible::Id idForAccessible(QAccessibleInterface *accessible);
-
-ABI::Windows::UI::Xaml::Automation::Peers::AutomationControlType roleToControlType(QAccessible::Role role);
-
-bool isTextUnitSeparator(ABI::Windows::UI::Xaml::Automation::Text::TextUnit unit, const QChar &ch);
-
-HRESULT qHString(const QString &str, HSTRING *returnValue);
-
-QString hStrToQStr(const HSTRING &hStr);
-
-} // namespace QWinRTUiAutomation
-
-QT_END_NAMESPACE
-
-#endif // QT_CONFIG(accessibility)
-
-#endif // QWINRTUIAUTILS_H
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiavalueprovider.cpp b/src/plugins/platforms/winrt/uiautomation/qwinrtuiavalueprovider.cpp
deleted file mode 100644
index 255d8ee49e..0000000000
--- a/src/plugins/platforms/winrt/uiautomation/qwinrtuiavalueprovider.cpp
+++ /dev/null
@@ -1,133 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 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 <QtGui/qtguiglobal.h>
-#if QT_CONFIG(accessibility)
-
-#include "qwinrtuiavalueprovider.h"
-#include "qwinrtuiametadatacache.h"
-#include "qwinrtuiautils.h"
-
-#include <QtGui/QAccessible>
-#include <QtGui/QAccessibleInterface>
-#include <QtCore/QLoggingCategory>
-#include <QtCore/QString>
-#include <QtCore/private/qeventdispatcher_winrt_p.h>
-
-QT_BEGIN_NAMESPACE
-
-using namespace QWinRTUiAutomation;
-using namespace ABI::Windows::UI::Xaml::Automation;
-using namespace ABI::Windows::UI::Xaml::Automation::Provider;
-
-QWinRTUiaValueProvider::QWinRTUiaValueProvider(QAccessible::Id id) :
- QWinRTUiaBaseProvider(id)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-}
-
-QWinRTUiaValueProvider::~QWinRTUiaValueProvider()
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-}
-
-// True for read-only controls.
-HRESULT STDMETHODCALLTYPE QWinRTUiaValueProvider::get_IsReadOnly(boolean *value)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-
- if (!value)
- return E_INVALIDARG;
- QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
- *value = (metadata->state().readOnly != 0);
- return S_OK;
-}
-
-// Returns the value in text form.
-HRESULT STDMETHODCALLTYPE QWinRTUiaValueProvider::get_Value(HSTRING *value)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-
- if (!value)
- return E_INVALIDARG;
- QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
- return qHString(metadata->value(), value);
-}
-
-// Sets the value associated with the control.
-HRESULT STDMETHODCALLTYPE QWinRTUiaValueProvider::SetValue(HSTRING value)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__;
-
- auto accid = id();
-
- QString tmpValue = hStrToQStr(value);
-
- QEventDispatcherWinRT::runOnMainThread([accid, tmpValue]() {
-
- if (QAccessibleInterface *accessible = accessibleForId(accid)) {
-
- // First sets the value as a text.
- accessible->setText(QAccessible::Value, tmpValue);
-
- // Then, if the control supports the value interface (range value)
- // and the supplied text can be converted to a number, and that number
- // lies within the min/max limits, sets it as the control's current (numeric) value.
- if (QAccessibleValueInterface *valueInterface = accessible->valueInterface()) {
- bool ok = false;
- double numval = tmpValue.toDouble(&ok);
- if (ok) {
- double minimum = valueInterface->minimumValue().toDouble();
- double maximum = valueInterface->maximumValue().toDouble();
- if ((numval >= minimum) && (numval <= maximum)) {
- valueInterface->setCurrentValue(QVariant(numval));
- }
- }
- }
- }
- QWinRTUiaMetadataCache::instance()->load(accid);
- return S_OK;
- }, 0);
-
- return S_OK;
-}
-
-QT_END_NAMESPACE
-
-#endif // QT_CONFIG(accessibility)
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiavalueprovider.h b/src/plugins/platforms/winrt/uiautomation/qwinrtuiavalueprovider.h
deleted file mode 100644
index d9cd5d200d..0000000000
--- a/src/plugins/platforms/winrt/uiautomation/qwinrtuiavalueprovider.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 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 QWINRTUIAVALUEPROVIDER_H
-#define QWINRTUIAVALUEPROVIDER_H
-
-#include <QtGui/qtguiglobal.h>
-#if QT_CONFIG(accessibility)
-
-#include "qwinrtuiabaseprovider.h"
-
-#include <wrl.h>
-#include <windows.ui.xaml.h>
-
-QT_BEGIN_NAMESPACE
-
-// Implements the Value control pattern provider.
-// Supported for all controls that can return text(QAccessible::Value).
-class QWinRTUiaValueProvider :
- public QWinRTUiaBaseProvider,
- public Microsoft::WRL::RuntimeClass<ABI::Windows::UI::Xaml::Automation::Provider::IValueProvider>
-{
- Q_OBJECT
- Q_DISABLE_COPY(QWinRTUiaValueProvider)
- InspectableClass(L"QWinRTUiaValueProvider", BaseTrust);
-
-public:
- explicit QWinRTUiaValueProvider(QAccessible::Id id);
- virtual ~QWinRTUiaValueProvider();
-
- // IValueProvider
- HRESULT STDMETHODCALLTYPE get_IsReadOnly(boolean *value) override;
- HRESULT STDMETHODCALLTYPE get_Value(HSTRING *value) override;
- HRESULT STDMETHODCALLTYPE SetValue(HSTRING value) override;
-};
-
-QT_END_NAMESPACE
-
-#endif // QT_CONFIG(accessibility)
-
-#endif // QWINRTUIAVALUEPROVIDER_H
diff --git a/src/plugins/platforms/winrt/uiautomation/uiautomation.pri b/src/plugins/platforms/winrt/uiautomation/uiautomation.pri
deleted file mode 100644
index ca0dfae53f..0000000000
--- a/src/plugins/platforms/winrt/uiautomation/uiautomation.pri
+++ /dev/null
@@ -1,45 +0,0 @@
-
-SOURCES += \
- $$PWD/qwinrtuiaaccessibility.cpp \
- $$PWD/qwinrtuiabaseprovider.cpp \
- $$PWD/qwinrtuiacontrolmetadata.cpp \
- $$PWD/qwinrtuiagriditemprovider.cpp \
- $$PWD/qwinrtuiagridprovider.cpp \
- $$PWD/qwinrtuiainvokeprovider.cpp \
- $$PWD/qwinrtuiamainprovider.cpp \
- $$PWD/qwinrtuiametadatacache.cpp \
- $$PWD/qwinrtuiapeervector.cpp \
- $$PWD/qwinrtuiaprovidercache.cpp \
- $$PWD/qwinrtuiarangevalueprovider.cpp \
- $$PWD/qwinrtuiaselectionitemprovider.cpp \
- $$PWD/qwinrtuiaselectionprovider.cpp \
- $$PWD/qwinrtuiatableitemprovider.cpp \
- $$PWD/qwinrtuiatableprovider.cpp \
- $$PWD/qwinrtuiatextprovider.cpp \
- $$PWD/qwinrtuiatextrangeprovider.cpp \
- $$PWD/qwinrtuiatoggleprovider.cpp \
- $$PWD/qwinrtuiautils.cpp \
- $$PWD/qwinrtuiavalueprovider.cpp
-
-HEADERS += \
- $$PWD/qwinrtuiaaccessibility.h \
- $$PWD/qwinrtuiabaseprovider.h \
- $$PWD/qwinrtuiacontrolmetadata.h \
- $$PWD/qwinrtuiaemptypropertyvalue.h \
- $$PWD/qwinrtuiagriditemprovider.h \
- $$PWD/qwinrtuiagridprovider.h \
- $$PWD/qwinrtuiainvokeprovider.h \
- $$PWD/qwinrtuiamainprovider.h \
- $$PWD/qwinrtuiametadatacache.h \
- $$PWD/qwinrtuiapeervector.h \
- $$PWD/qwinrtuiaprovidercache.h \
- $$PWD/qwinrtuiarangevalueprovider.h \
- $$PWD/qwinrtuiaselectionitemprovider.h \
- $$PWD/qwinrtuiaselectionprovider.h \
- $$PWD/qwinrtuiatableitemprovider.h \
- $$PWD/qwinrtuiatableprovider.h \
- $$PWD/qwinrtuiatextprovider.h \
- $$PWD/qwinrtuiatextrangeprovider.h \
- $$PWD/qwinrtuiatoggleprovider.h \
- $$PWD/qwinrtuiautils.h \
- $$PWD/qwinrtuiavalueprovider.h
diff --git a/src/plugins/platforms/winrt/winrt.json b/src/plugins/platforms/winrt/winrt.json
deleted file mode 100644
index 962747b697..0000000000
--- a/src/plugins/platforms/winrt/winrt.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "Keys": [ "winrt" ]
-}
diff --git a/src/plugins/platforms/winrt/winrt.pro b/src/plugins/platforms/winrt/winrt.pro
deleted file mode 100644
index 7ac49f73c4..0000000000
--- a/src/plugins/platforms/winrt/winrt.pro
+++ /dev/null
@@ -1,68 +0,0 @@
-TARGET = qwinrt
-
-CONFIG -= precompile_header
-
-QT += \
- core-private gui-private \
- fontdatabase_support-private egl_support-private
-
-qtHaveModule(platformcompositor_support-private): QT += platformcompositor_support-private
-
-DEFINES *= QT_NO_CAST_FROM_ASCII __WRL_NO_DEFAULT_LIB__
-
-QMAKE_USE_PRIVATE += d3d11 ws2_32
-
-SOURCES = \
- main.cpp \
- qwinrtbackingstore.cpp \
- qwinrtcanvas.cpp \
- qwinrtclipboard.cpp \
- qwinrtcursor.cpp \
- qwinrteglcontext.cpp \
- qwinrteventdispatcher.cpp \
- qwinrtfiledialoghelper.cpp \
- qwinrtfileengine.cpp \
- qwinrtinputcontext.cpp \
- qwinrtintegration.cpp \
- qwinrtmessagedialoghelper.cpp \
- qwinrtscreen.cpp \
- qwinrtservices.cpp \
- qwinrttheme.cpp \
- qwinrtwindow.cpp
-
-
-HEADERS = \
- qwinrtbackingstore.h \
- qwinrtcanvas.h \
- qwinrtclipboard.h \
- qwinrtcursor.h \
- qwinrteglcontext.h \
- qwinrteventdispatcher.h \
- qwinrtfiledialoghelper.h \
- qwinrtfileengine.h \
- qwinrtinputcontext.h \
- qwinrtintegration.h \
- qwinrtmessagedialoghelper.h \
- qwinrtscreen.h \
- qwinrtservices.h \
- qwinrttheme.h \
- qwinrtwindow.h
-
-OTHER_FILES += winrt.json
-
-WINRT_SDK_VERSION_STRING = $$(UCRTVersion)
-WINRT_SDK_VERSION = $$member($$list($$split(WINRT_SDK_VERSION_STRING, .)), 2)
-lessThan(WINRT_SDK_VERSION, 14322): DEFINES += QT_WINRT_LIMITED_DRAGANDDROP
-greaterThan(WINRT_SDK_VERSION, 14393): DEFINES += QT_WINRT_DISABLE_PHONE_COLORS
-
-qtConfig(draganddrop) {
- SOURCES += qwinrtdrag.cpp
- HEADERS += qwinrtdrag.h
-}
-
-qtConfig(accessibility): include($$PWD/uiautomation/uiautomation.pri)
-
-PLUGIN_TYPE = platforms
-PLUGIN_CLASS_NAME = QWinRTIntegrationPlugin
-!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = -
-load(qt_plugin)
diff --git a/src/plugins/platforms/xcb/.prev_CMakeLists.txt b/src/plugins/platforms/xcb/.prev_CMakeLists.txt
deleted file mode 100644
index 427997fc66..0000000000
--- a/src/plugins/platforms/xcb/.prev_CMakeLists.txt
+++ /dev/null
@@ -1,166 +0,0 @@
-# Generated from xcb.pro.
-
-#####################################################################
-## XcbQpa Module:
-#####################################################################
-
-qt_add_module(XcbQpa
- INTERNAL_MODULE
- NO_MODULE_HEADERS
- SOURCES
- gl_integrations/qxcbglintegration.cpp gl_integrations/qxcbglintegration.h
- gl_integrations/qxcbglintegrationfactory.cpp gl_integrations/qxcbglintegrationfactory.h
- gl_integrations/qxcbglintegrationplugin.h
- gl_integrations/qxcbnativeinterfacehandler.cpp gl_integrations/qxcbnativeinterfacehandler.h
- qxcbatom.cpp qxcbatom.h
- qxcbbackingstore.cpp qxcbbackingstore.h
- qxcbclipboard.cpp qxcbclipboard.h
- qxcbconnection.cpp qxcbconnection.h
- qxcbconnection_basic.cpp qxcbconnection_basic.h
- qxcbconnection_screens.cpp
- qxcbconnection_xi2.cpp
- qxcbcursor.cpp qxcbcursor.h
- qxcbeventdispatcher.cpp qxcbeventdispatcher.h
- qxcbeventqueue.cpp qxcbeventqueue.h
- qxcbimage.cpp qxcbimage.h
- qxcbintegration.cpp qxcbintegration.h
- qxcbkeyboard.cpp qxcbkeyboard.h
- qxcbmime.cpp qxcbmime.h
- qxcbnativeinterface.cpp qxcbnativeinterface.h
- qxcbobject.h
- qxcbscreen.cpp qxcbscreen.h
- qxcbsystemtraytracker.cpp qxcbsystemtraytracker.h
- qxcbwindow.cpp qxcbwindow.h
- qxcbwmsupport.cpp qxcbwmsupport.h
- qxcbxsettings.cpp qxcbxsettings.h
- DEFINES
- QT_BUILD_XCB_PLUGIN
- QT_NO_FOREACH
- INCLUDE_DIRECTORIES
- gl_integrations
- PUBLIC_LIBRARIES
- Qt::CorePrivate
- Qt::EdidSupportPrivate
- Qt::FontDatabaseSupportPrivate
- Qt::GuiPrivate
- Qt::ServiceSupportPrivate
- Qt::ThemeSupportPrivate
- Qt::XkbCommonSupportPrivate
- XCB::ICCCM
- XCB::IMAGE
- XCB::KEYSYMS
- XCB::RANDR
- XCB::RENDER
- XCB::RENDERUTIL
- XCB::SHAPE
- XCB::SHM
- XCB::SYNC
- XCB::XCB
- XCB::XFIXES
- XCB::XINERAMA
- XCB::XINPUT
- XCB::XKB
- XKB::XKB
-)
-
-## Scopes:
-#####################################################################
-
-qt_extend_target(XcbQpa CONDITION TARGET Qt::PlatformCompositorSupportPrivate
- PUBLIC_LIBRARIES
- Qt::PlatformCompositorSupportPrivate
-)
-
-qt_extend_target(XcbQpa CONDITION TARGET Qt::LinuxAccessibilitySupportPrivate
- PUBLIC_LIBRARIES
- Qt::LinuxAccessibilitySupportPrivate
-)
-
-qt_extend_target(XcbQpa CONDITION QT_FEATURE_vulkan
- SOURCES
- qxcbvulkaninstance.cpp qxcbvulkaninstance.h
- qxcbvulkanwindow.cpp qxcbvulkanwindow.h
- PUBLIC_LIBRARIES
- Qt::VulkanSupportPrivate
-)
-
-qt_extend_target(XcbQpa CONDITION QT_FEATURE_glib
- LIBRARIES
- GLIB2::GLIB2
-)
-
-qt_extend_target(XcbQpa CONDITION QT_FEATURE_draganddrop
- SOURCES
- qxcbdrag.cpp qxcbdrag.h
-)
-
-qt_extend_target(XcbQpa CONDITION QT_FEATURE_xcb_xlib
- PUBLIC_LIBRARIES
- X11::XCB
-)
-
-qt_extend_target(XcbQpa CONDITION QT_FEATURE_xcb_sm
- SOURCES
- qxcbsessionmanager.cpp qxcbsessionmanager.h
- PUBLIC_LIBRARIES
- ${X11_SM_LIB} ${X11_ICE_LIB}
-)
-
-qt_extend_target(XcbQpa CONDITION QT_FEATURE_dlopen
- PUBLIC_LIBRARIES
- ${CMAKE_DL_LIBS}
-)
-
-qt_extend_target(XcbQpa CONDITION CLANG AND NOT ICC
- COMPILE_OPTIONS
- -ftemplate-depth=1024
-)
-
-qt_extend_target(XcbQpa CONDITION QT_FEATURE_xcb_native_painting
- SOURCES
- nativepainting/qbackingstore_x11.cpp nativepainting/qbackingstore_x11_p.h
- nativepainting/qcolormap_x11.cpp nativepainting/qcolormap_x11_p.h
- nativepainting/qpaintengine_x11.cpp nativepainting/qpaintengine_x11_p.h
- nativepainting/qpixmap_x11.cpp nativepainting/qpixmap_x11_p.h
- nativepainting/qt_x11_p.h
- nativepainting/qtessellator.cpp nativepainting/qtessellator_p.h
- nativepainting/qxcbnativepainting.cpp nativepainting/qxcbnativepainting.h
- INCLUDE_DIRECTORIES
- nativepainting
-)
-
-qt_extend_target(XcbQpa CONDITION QT_FEATURE_xcb_native_painting AND QT_FEATURE_xrender
- PUBLIC_LIBRARIES
- PkgConfig::XRender
-)
-
-qt_extend_target(XcbQpa CONDITION QT_FEATURE_fontconfig AND QT_FEATURE_xcb_native_painting
- LIBRARIES
- WrapFreetype::WrapFreetype
-)
-#####################################################################
-## QXcbIntegrationPlugin Plugin:
-#####################################################################
-
-qt_add_plugin(QXcbIntegrationPlugin
- OUTPUT_NAME qxcb
- TYPE platforms
- SOURCES
- qxcbmain.cpp
- DEFINES
- QT_NO_FOREACH
- PUBLIC_LIBRARIES
- Qt::CorePrivate
- Qt::GuiPrivate
- Qt::XcbQpaPrivate
-)
-
-#### Keys ignored in scope 20:.:.:xcb-plugin.pro:<TRUE>:
-# OTHER_FILES = "xcb.json" "README"
-
-## Scopes:
-#####################################################################
-
-#### Keys ignored in scope 22:.:.:xcb-plugin.pro:NOT TARGET___equals____ss_QT_DEFAULT_QPA_PLUGIN:
-# PLUGIN_EXTENDS = "-"
-add_subdirectory(gl_integrations)
diff --git a/src/plugins/platforms/xcb/CMakeLists.txt b/src/plugins/platforms/xcb/CMakeLists.txt
index d422d69891..e8fb442dd4 100644
--- a/src/plugins/platforms/xcb/CMakeLists.txt
+++ b/src/plugins/platforms/xcb/CMakeLists.txt
@@ -1,32 +1,17 @@
-# Generated from xcb.pro.
-
-# begin special case:
-qt_find_package(X11_XCB
- PROVIDED_TARGETS
- X11::XCB
-)
-qt_find_package(X11
- PROVIDED_TARGETS
- X11::X11
-)
-qt_find_package(XCB)
-qt_find_package(XKB)
-qt_find_package(PkgConfig)
-qt_find_package(WrapFreetype)
-qt_find_package(GLIB2
- PROVIDED_TARGETS
- GLIB2::GLIB2
-)
-qt_find_package(XRender PROVIDED_TARGETS PkgConfig::XRender)
-qt_find_package(XKB_COMMON_X11 PROVIDED_TARGETS PkgConfig::XKB_COMMON_X11)
-
-# end special case:
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
-## XcbQpa Module:
+## XcbQpaPrivate Module:
#####################################################################
-qt_add_module(XcbQpa
+if(GCC)
+ # Work around GCC ABI issues
+ add_compile_options(-Wno-psabi)
+endif()
+
+qt_internal_add_module(XcbQpaPrivate
+ CONFIG_MODULE_NAME xcb_qpa_lib
INTERNAL_MODULE
NO_MODULE_HEADERS
SOURCES
@@ -47,6 +32,7 @@ qt_add_module(XcbQpa
qxcbimage.cpp qxcbimage.h
qxcbintegration.cpp qxcbintegration.h
qxcbkeyboard.cpp qxcbkeyboard.h
+ qxcbscrollingdevice.cpp qxcbscrollingdevice_p.h
qxcbmime.cpp qxcbmime.h
qxcbnativeinterface.cpp qxcbnativeinterface.h
qxcbobject.h
@@ -61,14 +47,10 @@ qt_add_module(XcbQpa
INCLUDE_DIRECTORIES
gl_integrations
PUBLIC_LIBRARIES
+ PkgConfig::XKB_COMMON_X11
Qt::CorePrivate
- Qt::EdidSupportPrivate
- Qt::FontDatabaseSupportPrivate
Qt::GuiPrivate
- Qt::ServiceSupportPrivate
- Qt::ThemeSupportPrivate
- Qt::XkbCommonSupportPrivate
- PkgConfig::XKB_COMMON_X11 # special case
+ XCB::CURSOR
XCB::ICCCM
XCB::IMAGE
XCB::KEYSYMS
@@ -80,72 +62,70 @@ qt_add_module(XcbQpa
XCB::SYNC
XCB::XCB
XCB::XFIXES
- XCB::XINERAMA
- $<$<TARGET_EXISTS:XCB::XINPUT>:XCB::XINPUT> # special case
XCB::XKB
XKB::XKB
+ NO_UNITY_BUILD # X11 define clashes
)
+qt_disable_apple_app_extension_api_only(XcbQpaPrivate)
+
## Scopes:
#####################################################################
-qt_extend_target(XcbQpa CONDITION TARGET Qt::PlatformCompositorSupportPrivate
- PUBLIC_LIBRARIES
- Qt::PlatformCompositorSupportPrivate
-)
-
-qt_extend_target(XcbQpa CONDITION TARGET Qt::LinuxAccessibilitySupportPrivate
- PUBLIC_LIBRARIES
- Qt::LinuxAccessibilitySupportPrivate
-)
-
-qt_extend_target(XcbQpa CONDITION QT_FEATURE_vulkan
- SOURCES
- qxcbvulkaninstance.cpp qxcbvulkaninstance.h
- qxcbvulkanwindow.cpp qxcbvulkanwindow.h
- PUBLIC_LIBRARIES
- Qt::VulkanSupportPrivate
-)
-
-qt_extend_target(XcbQpa CONDITION QT_FEATURE_glib
+qt_internal_extend_target(XcbQpaPrivate CONDITION QT_FEATURE_glib
LIBRARIES
GLIB2::GLIB2
)
-qt_extend_target(XcbQpa CONDITION QT_FEATURE_draganddrop
+qt_internal_extend_target(XcbQpaPrivate CONDITION QT_FEATURE_draganddrop
SOURCES
qxcbdrag.cpp qxcbdrag.h
)
-qt_extend_target(XcbQpa CONDITION QT_FEATURE_xcb_xlib
+qt_internal_extend_target(XcbQpaPrivate CONDITION QT_FEATURE_xcb_xlib
+ SOURCES
+ qt_xlib_wrapper.c qt_xlib_wrapper.h
PUBLIC_LIBRARIES
X11::XCB
- X11::X11 # special case
+ X11::X11
)
-qt_extend_target(XcbQpa CONDITION QT_FEATURE_xcb_sm
+qt_internal_extend_target(XcbQpaPrivate CONDITION NOT QT_FEATURE_xcb_xlib
+ SOURCES
+ qxcbcursorfont.h
+)
+
+qt_internal_extend_target(XcbQpaPrivate CONDITION QT_FEATURE_xcb_sm
SOURCES
qxcbsessionmanager.cpp qxcbsessionmanager.h
PUBLIC_LIBRARIES
- ${X11_SM_LIB} ${X11_ICE_LIB}
+ X11::SM
+ X11::ICE
+)
+
+qt_internal_extend_target(XcbQpaPrivate CONDITION QT_FEATURE_vulkan
+ SOURCES
+ qxcbvulkaninstance.cpp qxcbvulkaninstance.h
+ qxcbvulkanwindow.cpp qxcbvulkanwindow.h
)
-qt_extend_target(XcbQpa CONDITION QT_FEATURE_dlopen
+qt_internal_extend_target(XcbQpaPrivate CONDITION QT_FEATURE_dlopen
PUBLIC_LIBRARIES
${CMAKE_DL_LIBS}
)
-qt_extend_target(XcbQpa CONDITION CLANG AND NOT ICC
+qt_internal_extend_target(XcbQpaPrivate CONDITION CLANG
COMPILE_OPTIONS
-ftemplate-depth=1024
)
-qt_extend_target(XcbQpa CONDITION QT_FEATURE_xcb_native_painting
+qt_internal_extend_target(XcbQpaPrivate CONDITION QT_FEATURE_xcb_native_painting
SOURCES
nativepainting/qbackingstore_x11.cpp nativepainting/qbackingstore_x11_p.h
nativepainting/qcolormap_x11.cpp nativepainting/qcolormap_x11_p.h
nativepainting/qpaintengine_x11.cpp nativepainting/qpaintengine_x11_p.h
nativepainting/qpixmap_x11.cpp nativepainting/qpixmap_x11_p.h
+ nativepainting/qpolygonclipper_p.h
nativepainting/qt_x11_p.h
nativepainting/qtessellator.cpp nativepainting/qtessellator_p.h
nativepainting/qxcbnativepainting.cpp nativepainting/qxcbnativepainting.h
@@ -153,58 +133,49 @@ qt_extend_target(XcbQpa CONDITION QT_FEATURE_xcb_native_painting
nativepainting
)
-qt_extend_target(XcbQpa CONDITION QT_FEATURE_xcb_native_painting AND QT_FEATURE_xrender
+qt_internal_extend_target(XcbQpaPrivate CONDITION QT_FEATURE_xcb_native_painting AND QT_FEATURE_xrender
PUBLIC_LIBRARIES
PkgConfig::XRender
)
-qt_extend_target(XcbQpa CONDITION QT_FEATURE_fontconfig AND QT_FEATURE_xcb_native_painting
+qt_internal_extend_target(XcbQpaPrivate CONDITION QT_FEATURE_fontconfig AND QT_FEATURE_xcb_native_painting
LIBRARIES
WrapFreetype::WrapFreetype
)
-# special case begin
-if (NOT QT_FEATURE_system_xcb_input)
+if(QT_FEATURE_system_xcb_xinput)
+ qt_internal_extend_target(XcbQpaPrivate LIBRARIES XCB::XINPUT)
+else()
set(xinput_source "${PROJECT_SOURCE_DIR}/src/3rdparty/xcb/libxcb/xinput.c")
set_source_files_properties(
"${xinput_source}"
PROPERTIES COMPILE_OPTIONS "-w"
)
- target_sources(XcbQpa PRIVATE "${xinput_source}")
- target_include_directories(XcbQpa PRIVATE
+ target_sources(XcbQpaPrivate PRIVATE "${xinput_source}")
+ target_include_directories(XcbQpaPrivate PRIVATE
"${PROJECT_SOURCE_DIR}/src/3rdparty/xcb/include"
)
endif()
-# special case end
#####################################################################
## QXcbIntegrationPlugin Plugin:
#####################################################################
-qt_add_plugin(QXcbIntegrationPlugin
+qt_internal_add_plugin(QXcbIntegrationPlugin
OUTPUT_NAME qxcb
- TYPE platforms
- DEFAULT_IF ${QT_QPA_DEFAULT_PLATFORM} MATCHES xcb # special case
+ PLUGIN_TYPE platforms
+ DEFAULT_IF ${QT_QPA_DEFAULT_PLATFORM} MATCHES xcb
SOURCES
qxcbmain.cpp
DEFINES
QT_NO_FOREACH
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::GuiPrivate
Qt::XcbQpaPrivate
)
-#### Keys ignored in scope 20:.:.:xcb-plugin.pro:<TRUE>:
-# OTHER_FILES = "xcb.json" "README"
-
-## Scopes:
-#####################################################################
-
-#### Keys ignored in scope 22:.:.:xcb-plugin.pro:NOT TARGET___equals____ss_QT_DEFAULT_QPA_PLUGIN:
-# PLUGIN_EXTENDS = "-"
add_subdirectory(gl_integrations)
if(OFF)
- add_subdirectory(xcb-static) # special case TODO: xcb-static sub folder
+ add_subdirectory(xcb-static)
endif()
-
diff --git a/src/plugins/platforms/xcb/README b/src/plugins/platforms/xcb/README
index 5f238ab261..1fb3264cf1 100644
--- a/src/plugins/platforms/xcb/README
+++ b/src/plugins/platforms/xcb/README
@@ -1,7 +1 @@
Requires libxcb >= 1.9.1.
-
-REDUCING RUNTIME DEPENDENCIES
-
-The '-qt-xcb' configure option can be used to get rid of most xcb- dependencies. Only libxcb will
-still be linked dynamically, since it will be most likely be pulled in via other dependencies anyway.
-This should allow for binaries that are portable across most modern Linux distributions.
diff --git a/src/plugins/platforms/xcb/gl_integrations/CMakeLists.txt b/src/plugins/platforms/xcb/gl_integrations/CMakeLists.txt
index 210a924550..957beb9ed4 100644
--- a/src/plugins/platforms/xcb/gl_integrations/CMakeLists.txt
+++ b/src/plugins/platforms/xcb/gl_integrations/CMakeLists.txt
@@ -1,4 +1,5 @@
-# Generated from gl_integrations.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
if(QT_FEATURE_xcb_egl_plugin)
add_subdirectory(xcb_egl)
diff --git a/src/plugins/platforms/xcb/gl_integrations/gl_integrations.pri b/src/plugins/platforms/xcb/gl_integrations/gl_integrations.pri
deleted file mode 100644
index 56bc126652..0000000000
--- a/src/plugins/platforms/xcb/gl_integrations/gl_integrations.pri
+++ /dev/null
@@ -1,13 +0,0 @@
-INCLUDEPATH += $$PWD
-
-HEADERS += \
- $$PWD/qxcbglintegration.h \
- $$PWD/qxcbglintegrationfactory.h \
- $$PWD/qxcbglintegrationplugin.h \
- $$PWD/qxcbnativeinterfacehandler.h
-
-SOURCES += \
- $$PWD/qxcbglintegrationfactory.cpp \
- $$PWD/qxcbglintegration.cpp \
- $$PWD/qxcbnativeinterfacehandler.cpp
-
diff --git a/src/plugins/platforms/xcb/gl_integrations/gl_integrations.pro b/src/plugins/platforms/xcb/gl_integrations/gl_integrations.pro
deleted file mode 100644
index dde176433c..0000000000
--- a/src/plugins/platforms/xcb/gl_integrations/gl_integrations.pro
+++ /dev/null
@@ -1,10 +0,0 @@
-TEMPLATE = subdirs
-QT_FOR_CONFIG += gui-private
-
-qtConfig(xcb-egl-plugin) {
- SUBDIRS += xcb_egl
-}
-
-qtConfig(xcb-glx-plugin) {
- SUBDIRS += xcb_glx
-}
diff --git a/src/plugins/platforms/xcb/gl_integrations/gl_integrations_plugin_base.pri b/src/plugins/platforms/xcb/gl_integrations/gl_integrations_plugin_base.pri
deleted file mode 100644
index 98e48b706f..0000000000
--- a/src/plugins/platforms/xcb/gl_integrations/gl_integrations_plugin_base.pri
+++ /dev/null
@@ -1,7 +0,0 @@
-QT += core-private gui-private xcb_qpa_lib-private
-
-INCLUDEPATH += $$PWD
-INCLUDEPATH += $$PWD/../
-
-load(qt_build_paths)
-
diff --git a/src/plugins/platforms/xcb/gl_integrations/qxcbglintegration.cpp b/src/plugins/platforms/xcb/gl_integrations/qxcbglintegration.cpp
index 59401d2ce7..48010b9013 100644
--- a/src/plugins/platforms/xcb/gl_integrations/qxcbglintegration.cpp
+++ b/src/plugins/platforms/xcb/gl_integrations/qxcbglintegration.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qxcbglintegration.h"
diff --git a/src/plugins/platforms/xcb/gl_integrations/qxcbglintegration.h b/src/plugins/platforms/xcb/gl_integrations/qxcbglintegration.h
index 07e983a499..c6492f02ae 100644
--- a/src/plugins/platforms/xcb/gl_integrations/qxcbglintegration.h
+++ b/src/plugins/platforms/xcb/gl_integrations/qxcbglintegration.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QXCBGLINTEGRATION_H
@@ -50,7 +14,7 @@ class QPlatformOffscreenSurface;
class QOffscreenSurface;
class QXcbNativeInterfaceHandler;
-Q_XCB_EXPORT Q_DECLARE_LOGGING_CATEGORY(lcQpaGl)
+Q_DECLARE_EXPORTED_LOGGING_CATEGORY(lcQpaGl, Q_XCB_EXPORT)
class Q_XCB_EXPORT QXcbGlIntegration
{
diff --git a/src/plugins/platforms/xcb/gl_integrations/qxcbglintegrationfactory.cpp b/src/plugins/platforms/xcb/gl_integrations/qxcbglintegrationfactory.cpp
index d69d969783..593441de6d 100644
--- a/src/plugins/platforms/xcb/gl_integrations/qxcbglintegrationfactory.cpp
+++ b/src/plugins/platforms/xcb/gl_integrations/qxcbglintegrationfactory.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qxcbglintegrationfactory.h"
#include "qxcbglintegrationplugin.h"
@@ -47,26 +11,13 @@
QT_BEGIN_NAMESPACE
-Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader,
- (QXcbGlIntegrationFactoryInterface_iid, QLatin1String("/xcbglintegrations"), Qt::CaseInsensitive))
+using namespace Qt::StringLiterals;
-#if QT_CONFIG(library)
-Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, directLoader,
- (QXcbGlIntegrationFactoryInterface_iid, QLatin1String(""), Qt::CaseInsensitive))
-#endif // QT_CONFIG(library)
+Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader,
+ (QXcbGlIntegrationFactoryInterface_iid, "/xcbglintegrations"_L1, Qt::CaseInsensitive))
-QXcbGlIntegration *QXcbGlIntegrationFactory::create(const QString &platform, const QString &pluginPath)
+QXcbGlIntegration *QXcbGlIntegrationFactory::create(const QString &platform)
{
-#if QT_CONFIG(library)
- // Try loading the plugin from pluginPath first:
- if (!pluginPath.isEmpty()) {
- QCoreApplication::addLibraryPath(pluginPath);
- if (QXcbGlIntegration *ret = qLoadPlugin<QXcbGlIntegration, QXcbGlIntegrationPlugin>(directLoader(), platform))
- return ret;
- }
-#else
- Q_UNUSED(pluginPath);
-#endif
return qLoadPlugin<QXcbGlIntegration, QXcbGlIntegrationPlugin>(loader(), platform);
}
diff --git a/src/plugins/platforms/xcb/gl_integrations/qxcbglintegrationfactory.h b/src/plugins/platforms/xcb/gl_integrations/qxcbglintegrationfactory.h
index c4aa0a3d8d..bb169aee4a 100644
--- a/src/plugins/platforms/xcb/gl_integrations/qxcbglintegrationfactory.h
+++ b/src/plugins/platforms/xcb/gl_integrations/qxcbglintegrationfactory.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QXCBGLINTEGRATIONFACTORY_H
#define QXCBGLINTEGRATIONFACTORY_H
@@ -49,7 +13,7 @@ class QXcbGlIntegration;
class QXcbGlIntegrationFactory
{
public:
- static QXcbGlIntegration *create(const QString &name, const QString &platformPluginPath = QString());
+ static QXcbGlIntegration *create(const QString &name);
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/xcb/gl_integrations/qxcbglintegrationplugin.h b/src/plugins/platforms/xcb/gl_integrations/qxcbglintegrationplugin.h
index b18248570f..3de9d3f408 100644
--- a/src/plugins/platforms/xcb/gl_integrations/qxcbglintegrationplugin.h
+++ b/src/plugins/platforms/xcb/gl_integrations/qxcbglintegrationplugin.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QXCBGLINTEGRATIONPLUGIN_H
#define QXCBGLINTEGRATIONPLUGIN_H
diff --git a/src/plugins/platforms/xcb/gl_integrations/qxcbnativeinterfacehandler.cpp b/src/plugins/platforms/xcb/gl_integrations/qxcbnativeinterfacehandler.cpp
index e18656c6ec..f557a35b8e 100644
--- a/src/plugins/platforms/xcb/gl_integrations/qxcbnativeinterfacehandler.cpp
+++ b/src/plugins/platforms/xcb/gl_integrations/qxcbnativeinterfacehandler.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qxcbnativeinterfacehandler.h"
diff --git a/src/plugins/platforms/xcb/gl_integrations/qxcbnativeinterfacehandler.h b/src/plugins/platforms/xcb/gl_integrations/qxcbnativeinterfacehandler.h
index 94102e7764..58c28c85b0 100644
--- a/src/plugins/platforms/xcb/gl_integrations/qxcbnativeinterfacehandler.h
+++ b/src/plugins/platforms/xcb/gl_integrations/qxcbnativeinterfacehandler.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QXCBNATIVEINTERFACEHANDLER_H
#define QXCBNATIVEINTERFACEHANDLER_H
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 a78d01ec87..12938c159a 100644
--- a/src/plugins/platforms/xcb/gl_integrations/xcb_egl/CMakeLists.txt
+++ b/src/plugins/platforms/xcb/gl_integrations/xcb_egl/CMakeLists.txt
@@ -1,12 +1,15 @@
-# Generated from xcb_egl.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## QXcbEglIntegrationPlugin Plugin:
#####################################################################
-qt_add_plugin(QXcbEglIntegrationPlugin
+qt_find_package(EGL)
+
+qt_internal_add_plugin(QXcbEglIntegrationPlugin
OUTPUT_NAME qxcb-egl-integration
- TYPE xcbglintegrations
+ PLUGIN_TYPE xcbglintegrations
SOURCES
qxcbeglcontext.h
qxcbeglintegration.cpp qxcbeglintegration.h
@@ -18,11 +21,12 @@ qt_add_plugin(QXcbEglIntegrationPlugin
INCLUDE_DIRECTORIES
..
../..
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Core
Qt::CorePrivate
- Qt::EglSupportPrivate
Qt::Gui
Qt::GuiPrivate
Qt::XcbQpaPrivate
+ EGL::EGL
+ NO_UNITY_BUILD # X11 define clashes
)
diff --git a/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglcontext.h b/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglcontext.h
index fda53f17a1..3044493291 100644
--- a/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglcontext.h
+++ b/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglcontext.h
@@ -1,62 +1,25 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QXCBEGLCONTEXT_H
#define QXCBEGLCONTEXT_H
#include "qxcbeglwindow.h"
-#include <QtEglSupport/private/qeglplatformcontext_p.h>
-#include <QtEglSupport/private/qeglpbuffer_p.h>
-#include <QtPlatformHeaders/QEGLNativeContext>
+#include <QtGui/private/qeglplatformcontext_p.h>
+#include <QtGui/private/qeglpbuffer_p.h>
QT_BEGIN_NAMESPACE
class QXcbEglContext : public QEGLPlatformContext
{
public:
- QXcbEglContext(const QSurfaceFormat &glFormat, QPlatformOpenGLContext *share,
- EGLDisplay display, const QVariant &nativeHandle)
- : QEGLPlatformContext(glFormat, share, display, nullptr, nativeHandle)
+ using QEGLPlatformContext::QEGLPlatformContext;
+ QXcbEglContext(const QSurfaceFormat &glFormat, QPlatformOpenGLContext *share, EGLDisplay display)
+ : QEGLPlatformContext(glFormat, share, display, nullptr)
{
}
- void swapBuffers(QPlatformSurface *surface)
+ void swapBuffers(QPlatformSurface *surface) override
{
QEGLPlatformContext::swapBuffers(surface);
if (surface->surface()->surfaceClass() == QSurface::Window) {
@@ -69,27 +32,23 @@ public:
}
}
- bool makeCurrent(QPlatformSurface *surface)
+ bool makeCurrent(QPlatformSurface *surface) override
{
return QEGLPlatformContext::makeCurrent(surface);
}
- void doneCurrent()
+ void doneCurrent() override
{
QEGLPlatformContext::doneCurrent();
}
- EGLSurface eglSurfaceForPlatformSurface(QPlatformSurface *surface)
+ EGLSurface eglSurfaceForPlatformSurface(QPlatformSurface *surface) override
{
if (surface->surface()->surfaceClass() == QSurface::Window)
return static_cast<QXcbEglWindow *>(surface)->eglSurface();
else
return static_cast<QEGLPbuffer *>(surface)->pbuffer();
}
-
- QVariant nativeHandle() const {
- return QVariant::fromValue<QEGLNativeContext>(QEGLNativeContext(eglContext(), eglDisplay()));
- }
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglinclude.h b/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglinclude.h
index a5a47dd0bb..d12501bd90 100644
--- a/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglinclude.h
+++ b/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglinclude.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QXCBINCLUDE_H
#define QXCBINCLUDE_H
@@ -43,10 +7,9 @@
#include <QtGui/QPalette>
#include <QtCore/QTextStream>
#include <QtGui/private/qmath_p.h>
-#include <QtGui/private/qcssparser_p.h>
#include <QtGui/private/qtextengine_p.h>
-#include <QtEglSupport/private/qt_egl_p.h>
+#include <QtGui/private/qt_egl_p.h>
QT_BEGIN_NAMESPACE
diff --git a/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglintegration.cpp b/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglintegration.cpp
index fe18bc24db..133b992cd9 100644
--- a/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglintegration.cpp
+++ b/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglintegration.cpp
@@ -1,56 +1,64 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qxcbeglintegration.h"
#include "qxcbeglcontext.h"
#include <QtGui/QOffscreenSurface>
-#include <QtEglSupport/private/qeglstreamconvenience_p.h>
+#include <QtGui/private/qeglconvenience_p.h>
+#include <QtGui/private/qeglstreamconvenience_p.h>
+#include <optional>
#include "qxcbeglnativeinterfacehandler.h"
QT_BEGIN_NAMESPACE
+namespace {
+
+struct VisualInfo
+{
+ xcb_visualtype_t visualType;
+ uint8_t depth;
+};
+
+std::optional<VisualInfo> getVisualInfo(xcb_screen_t *screen,
+ std::optional<xcb_visualid_t> requestedVisualId,
+ std::optional<uint8_t> requestedDepth = std::nullopt)
+{
+ xcb_depth_iterator_t depthIterator = xcb_screen_allowed_depths_iterator(screen);
+
+ while (depthIterator.rem) {
+ xcb_depth_t *depth = depthIterator.data;
+ xcb_visualtype_iterator_t visualTypeIterator = xcb_depth_visuals_iterator(depth);
+
+ while (visualTypeIterator.rem) {
+ xcb_visualtype_t *visualType = visualTypeIterator.data;
+ if (requestedVisualId && visualType->visual_id != *requestedVisualId) {
+ xcb_visualtype_next(&visualTypeIterator);
+ continue;
+ }
+
+ if (requestedDepth && depth->depth != *requestedDepth) {
+ xcb_visualtype_next(&visualTypeIterator);
+ continue;
+ }
+
+ return VisualInfo{ *visualType, depth->depth };
+ }
+
+ xcb_depth_next(&depthIterator);
+ }
+
+ return std::nullopt;
+}
+
+} // namespace
+
QXcbEglIntegration::QXcbEglIntegration()
: m_connection(nullptr)
, m_egl_display(EGL_NO_DISPLAY)
+ , m_using_platform_display(false)
{
qCDebug(lcQpaGl) << "Xcb EGL gl-integration created";
}
@@ -67,27 +75,46 @@ bool QXcbEglIntegration::initialize(QXcbConnection *connection)
const char *extensions = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
+#if QT_CONFIG(xcb_xlib)
if (extensions && strstr(extensions, "EGL_EXT_platform_x11")) {
QEGLStreamConvenience streamFuncs;
m_egl_display = streamFuncs.get_platform_display(EGL_PLATFORM_X11_KHR,
- xlib_display(),
+ m_connection->xlib_display(),
nullptr);
+ m_using_platform_display = true;
}
+#if QT_CONFIG(egl_x11)
if (!m_egl_display)
- m_egl_display = eglGetDisplay(reinterpret_cast<EGLNativeDisplayType>(xlib_display()));
+ m_egl_display = eglGetDisplay(reinterpret_cast<EGLNativeDisplayType>(m_connection->xlib_display()));
+#endif
+#else
+ if (extensions && (strstr(extensions, "EGL_EXT_platform_xcb") || strstr(extensions, "EGL_MESA_platform_xcb"))) {
+ QEGLStreamConvenience streamFuncs;
+ m_egl_display = streamFuncs.get_platform_display(EGL_PLATFORM_XCB_KHR,
+ reinterpret_cast<void *>(connection->xcb_connection()),
+ nullptr);
+ m_using_platform_display = true;
+ }
+#endif
EGLint major, minor;
bool success = eglInitialize(m_egl_display, &major, &minor);
+#if QT_CONFIG(egl_x11)
if (!success) {
m_egl_display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
qCDebug(lcQpaGl) << "Xcb EGL gl-integration retrying with display" << m_egl_display;
success = eglInitialize(m_egl_display, &major, &minor);
}
+#endif
m_native_interface_handler.reset(new QXcbEglNativeInterfaceHandler(connection->nativeInterface()));
- qCDebug(lcQpaGl) << "Xcb EGL gl-integration successfully initialized";
+ if (success)
+ qCDebug(lcQpaGl) << "Xcb EGL gl-integration successfully initialized";
+ else
+ qCWarning(lcQpaGl) << "Xcb EGL gl-integration initialize failed";
+
return success;
}
@@ -101,25 +128,114 @@ QPlatformOpenGLContext *QXcbEglIntegration::createPlatformOpenGLContext(QOpenGLC
QXcbScreen *screen = static_cast<QXcbScreen *>(context->screen()->handle());
QXcbEglContext *platformContext = new QXcbEglContext(screen->surfaceFormatFor(context->format()),
context->shareHandle(),
- eglDisplay(),
- context->nativeHandle());
- context->setNativeHandle(platformContext->nativeHandle());
+ eglDisplay());
return platformContext;
}
+QOpenGLContext *QXcbEglIntegration::createOpenGLContext(EGLContext context, EGLDisplay display, QOpenGLContext *shareContext) const
+{
+ return QEGLPlatformContext::createFrom<QXcbEglContext>(context, display, eglDisplay(), shareContext);
+}
+
QPlatformOffscreenSurface *QXcbEglIntegration::createPlatformOffscreenSurface(QOffscreenSurface *surface) const
{
QXcbScreen *screen = static_cast<QXcbScreen *>(surface->screen()->handle());
return new QEGLPbuffer(eglDisplay(), screen->surfaceFormatFor(surface->requestedFormat()), surface);
}
-void *QXcbEglIntegration::xlib_display() const
+xcb_visualid_t QXcbEglIntegration::getCompatibleVisualId(xcb_screen_t *screen, EGLConfig config) const
{
-#if QT_CONFIG(xcb_xlib)
- return m_connection->xlib_display();
-#else
- return EGL_DEFAULT_DISPLAY;
-#endif
+ xcb_visualid_t visualId = 0;
+ EGLint eglValue = 0;
+
+ EGLint configRedSize = 0;
+ eglGetConfigAttrib(eglDisplay(), config, EGL_RED_SIZE, &configRedSize);
+
+ EGLint configGreenSize = 0;
+ eglGetConfigAttrib(eglDisplay(), config, EGL_GREEN_SIZE, &configGreenSize);
+
+ EGLint configBlueSize = 0;
+ eglGetConfigAttrib(eglDisplay(), config, EGL_BLUE_SIZE, &configBlueSize);
+
+ EGLint configAlphaSize = 0;
+ eglGetConfigAttrib(eglDisplay(), config, EGL_ALPHA_SIZE, &configAlphaSize);
+
+ eglGetConfigAttrib(eglDisplay(), config, EGL_CONFIG_ID, &eglValue);
+ int configId = eglValue;
+
+ // See if EGL provided a valid VisualID:
+ eglGetConfigAttrib(eglDisplay(), config, EGL_NATIVE_VISUAL_ID, &eglValue);
+ visualId = eglValue;
+ if (visualId) {
+ // EGL has suggested a visual id, so get the rest of the visual info for that id:
+ std::optional<VisualInfo> chosenVisualInfo = getVisualInfo(screen, visualId);
+ if (chosenVisualInfo) {
+ // Skip size checks if implementation supports non-matching visual
+ // and config (QTBUG-9444).
+ if (q_hasEglExtension(eglDisplay(), "EGL_NV_post_convert_rounding"))
+ return visualId;
+ // Skip also for i.MX6 where 565 visuals are suggested for the default 444 configs and it works just fine.
+ const char *vendor = eglQueryString(eglDisplay(), EGL_VENDOR);
+ if (vendor && strstr(vendor, "Vivante"))
+ return visualId;
+
+ int visualRedSize = qPopulationCount(chosenVisualInfo->visualType.red_mask);
+ int visualGreenSize = qPopulationCount(chosenVisualInfo->visualType.green_mask);
+ int visualBlueSize = qPopulationCount(chosenVisualInfo->visualType.blue_mask);
+ int visualAlphaSize = chosenVisualInfo->depth - visualRedSize - visualBlueSize - visualGreenSize;
+
+ const bool visualMatchesConfig = visualRedSize >= configRedSize
+ && visualGreenSize >= configGreenSize
+ && visualBlueSize >= configBlueSize
+ && visualAlphaSize >= configAlphaSize;
+
+ // In some cases EGL tends to suggest a 24-bit visual for 8888
+ // configs. In such a case we have to fall back to getVisualInfo.
+ if (!visualMatchesConfig) {
+ visualId = 0;
+ qCDebug(lcQpaGl,
+ "EGL suggested using X Visual ID %d (%d %d %d %d depth %d) for EGL config %d"
+ "(%d %d %d %d), but this is incompatible",
+ visualId, visualRedSize, visualGreenSize, visualBlueSize, visualAlphaSize, chosenVisualInfo->depth,
+ configId, configRedSize, configGreenSize, configBlueSize, configAlphaSize);
+ }
+ } else {
+ qCDebug(lcQpaGl, "EGL suggested using X Visual ID %d for EGL config %d, but that isn't a valid ID",
+ visualId, configId);
+ visualId = 0;
+ }
+ }
+ else
+ qCDebug(lcQpaGl, "EGL did not suggest a VisualID (EGL_NATIVE_VISUAL_ID was zero) for EGLConfig %d", configId);
+
+ if (visualId) {
+ qCDebug(lcQpaGl, configAlphaSize > 0
+ ? "Using ARGB Visual ID %d provided by EGL for config %d"
+ : "Using Opaque Visual ID %d provided by EGL for config %d", visualId, configId);
+ return visualId;
+ }
+
+ // Finally, try to use getVisualInfo and only use the bit depths to match on:
+ if (!visualId) {
+ uint8_t depth = configRedSize + configGreenSize + configBlueSize + configAlphaSize;
+ std::optional<VisualInfo> matchingVisual = getVisualInfo(screen, std::nullopt, depth);
+ if (!matchingVisual) {
+ // Try again without taking the alpha channel into account:
+ depth = configRedSize + configGreenSize + configBlueSize;
+ matchingVisual = getVisualInfo(screen, std::nullopt, depth);
+ }
+
+ if (matchingVisual)
+ visualId = matchingVisual->visualType.visual_id;
+ }
+
+ if (visualId) {
+ qCDebug(lcQpaGl, "Using Visual ID %d provided by getVisualInfo for EGL config %d", visualId, configId);
+ return visualId;
+ }
+
+ qWarning("Unable to find an X11 visual which matches EGL config %d", configId);
+ return 0;
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglintegration.h b/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglintegration.h
index 54a9f5cd83..7caf4304bc 100644
--- a/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglintegration.h
+++ b/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglintegration.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QXCBEGLINTEGRATION_H
#define QXCBEGLINTEGRATION_H
@@ -45,6 +9,7 @@
#include "qxcbeglwindow.h"
#include <QtGui/QOpenGLContext>
+#include <qpa/qplatformopenglcontext.h>
#include <QtGui/qpa/qplatformscreen.h>
#include <QtGui/QScreen>
@@ -57,6 +22,7 @@ QT_BEGIN_NAMESPACE
class QXcbEglNativeInterfaceHandler;
class QXcbEglIntegration : public QXcbGlIntegration
+ , public QNativeInterface::Private::QEGLIntegration
{
public:
QXcbEglIntegration();
@@ -66,15 +32,20 @@ public:
QXcbWindow *createWindow(QWindow *window) const override;
QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const override;
+ QOpenGLContext *createOpenGLContext(EGLContext context, EGLDisplay display, QOpenGLContext *shareContext) const override;
QPlatformOffscreenSurface *createPlatformOffscreenSurface(QOffscreenSurface *surface) const override;
bool supportsThreadedOpenGL() const override { return true; }
EGLDisplay eglDisplay() const { return m_egl_display; }
- void *xlib_display() const;
+
+ bool usingPlatformDisplay() const { return m_using_platform_display; }
+
+ xcb_visualid_t getCompatibleVisualId(xcb_screen_t *screen, EGLConfig config) const;
private:
QXcbConnection *m_connection;
EGLDisplay m_egl_display;
+ bool m_using_platform_display;
QScopedPointer<QXcbEglNativeInterfaceHandler> m_native_interface_handler;
};
diff --git a/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglmain.cpp b/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglmain.cpp
index 2de6d800e4..44539dd2e1 100644
--- a/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglmain.cpp
+++ b/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglmain.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qxcbglintegrationplugin.h"
@@ -48,7 +12,7 @@ class QXcbEglIntegrationPlugin : public QXcbGlIntegrationPlugin
Q_OBJECT
Q_PLUGIN_METADATA(IID QXcbGlIntegrationFactoryInterface_iid FILE "xcb_egl.json")
public:
- QXcbGlIntegration *create()
+ QXcbGlIntegration *create() override
{
return new QXcbEglIntegration();
}
diff --git a/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglnativeinterfacehandler.cpp b/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglnativeinterfacehandler.cpp
index c0e3f820fe..47a95d6876 100644
--- a/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglnativeinterfacehandler.cpp
+++ b/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglnativeinterfacehandler.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qxcbeglnativeinterfacehandler.h"
@@ -107,7 +71,7 @@ QPlatformNativeInterface::NativeResourceForWindowFunction QXcbEglNativeInterface
void *QXcbEglNativeInterfaceHandler::eglDisplay()
{
QXcbIntegration *integration = QXcbIntegration::instance();
- QXcbEglIntegration *eglIntegration = static_cast<QXcbEglIntegration *>(integration->defaultConnection()->glIntegration());
+ QXcbEglIntegration *eglIntegration = static_cast<QXcbEglIntegration *>(integration->connection()->glIntegration());
return eglIntegration->eglDisplay();
}
diff --git a/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglnativeinterfacehandler.h b/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglnativeinterfacehandler.h
index 7c83d0e240..fdd48fc842 100644
--- a/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglnativeinterfacehandler.h
+++ b/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglnativeinterfacehandler.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QXCBEGLNATIVEINTERFACEHANDLER_H
#define QXCBEGLNATIVEINTERFACEHANDLER_H
diff --git a/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglwindow.cpp b/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglwindow.cpp
index 30e3381993..bf2ceb96f4 100644
--- a/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglwindow.cpp
+++ b/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglwindow.cpp
@@ -1,48 +1,15 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qxcbeglwindow.h"
#include "qxcbeglintegration.h"
-#include <QtEglSupport/private/qeglconvenience_p.h>
-#include <QtEglSupport/private/qxlibeglintegration_p.h>
+#include <QtGui/private/qeglconvenience_p.h>
+
+#ifndef EGL_EXT_platform_base
+typedef EGLSurface (EGLAPIENTRYP PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC) (EGLDisplay dpy, EGLConfig config, void *native_window, const EGLint *attrib_list);
+#endif
QT_BEGIN_NAMESPACE
@@ -65,35 +32,34 @@ void QXcbEglWindow::resolveFormat(const QSurfaceFormat &format)
m_format = q_glFormatFromConfig(m_glIntegration->eglDisplay(), m_config, format);
}
-#if QT_CONFIG(xcb_xlib)
const xcb_visualtype_t *QXcbEglWindow::createVisual()
{
QXcbScreen *scr = xcbScreen();
if (!scr)
return QXcbWindow::createVisual();
- Display *xdpy = static_cast<Display *>(m_glIntegration->xlib_display());
- VisualID id = QXlibEglIntegration::getCompatibleVisualId(xdpy, m_glIntegration->eglDisplay(), m_config);
-
- XVisualInfo visualInfoTemplate;
- memset(&visualInfoTemplate, 0, sizeof(XVisualInfo));
- visualInfoTemplate.visualid = id;
-
- XVisualInfo *visualInfo;
- int matchingCount = 0;
- visualInfo = XGetVisualInfo(xdpy, VisualIDMask, &visualInfoTemplate, &matchingCount);
- const xcb_visualtype_t *xcb_visualtype = scr->visualForId(visualInfo->visualid);
- XFree(visualInfo);
-
- return xcb_visualtype;
+ xcb_visualid_t id = m_glIntegration->getCompatibleVisualId(scr->screen(), m_config);
+ return scr->visualForId(id);
}
-#endif
void QXcbEglWindow::create()
{
QXcbWindow::create();
+ // this is always true without egl_x11
+ if (m_glIntegration->usingPlatformDisplay()) {
+ auto createPlatformWindowSurface = reinterpret_cast<PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC>(
+ eglGetProcAddress("eglCreatePlatformWindowSurfaceEXT"));
+ m_surface = createPlatformWindowSurface(m_glIntegration->eglDisplay(),
+ m_config,
+ reinterpret_cast<void *>(&m_window),
+ nullptr);
+ return;
+ }
+
+#if QT_CONFIG(egl_x11)
m_surface = eglCreateWindowSurface(m_glIntegration->eglDisplay(), m_config, m_window, nullptr);
+#endif
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglwindow.h b/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglwindow.h
index e49a3fe2ac..935a0c6d43 100644
--- a/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglwindow.h
+++ b/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglwindow.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QXCBEGLWINDOW_H
#define QXCBEGLWINDOW_H
@@ -61,10 +25,7 @@ public:
protected:
void create() override;
void resolveFormat(const QSurfaceFormat &format) override;
-
-#if QT_CONFIG(xcb_xlib)
const xcb_visualtype_t *createVisual() override;
-#endif
private:
QXcbEglIntegration *m_glIntegration;
diff --git a/src/plugins/platforms/xcb/gl_integrations/xcb_egl/xcb_egl.pro b/src/plugins/platforms/xcb/gl_integrations/xcb_egl/xcb_egl.pro
deleted file mode 100644
index a39e00ec59..0000000000
--- a/src/plugins/platforms/xcb/gl_integrations/xcb_egl/xcb_egl.pro
+++ /dev/null
@@ -1,24 +0,0 @@
-TARGET = qxcb-egl-integration
-
-include(../gl_integrations_plugin_base.pri)
-QT += egl_support-private
-
-CONFIG += egl
-
-DEFINES += QT_NO_FOREACH
-
-HEADERS += \
- qxcbeglcontext.h \
- qxcbeglintegration.h \
- qxcbeglwindow.h \
- qxcbeglnativeinterfacehandler.h
-
-SOURCES += \
- qxcbeglintegration.cpp \
- qxcbeglwindow.cpp \
- qxcbeglmain.cpp \
- qxcbeglnativeinterfacehandler.cpp
-
-PLUGIN_CLASS_NAME = QXcbEglIntegrationPlugin
-PLUGIN_TYPE = xcbglintegrations
-load(qt_plugin)
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 b3361dbd99..f9f78ad1eb 100644
--- a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/CMakeLists.txt
+++ b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/CMakeLists.txt
@@ -1,12 +1,13 @@
-# Generated from xcb_glx.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## QXcbGlxIntegrationPlugin Plugin:
#####################################################################
-qt_add_plugin(QXcbGlxIntegrationPlugin
+qt_internal_add_plugin(QXcbGlxIntegrationPlugin
OUTPUT_NAME qxcb-glx-integration
- TYPE xcbglintegrations
+ PLUGIN_TYPE xcbglintegrations
SOURCES
qglxintegration.cpp qglxintegration.h
qxcbglxintegration.cpp qxcbglxintegration.h
@@ -18,24 +19,25 @@ qt_add_plugin(QXcbGlxIntegrationPlugin
INCLUDE_DIRECTORIES
..
../..
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Core
Qt::CorePrivate
- Qt::GlxSupportPrivate
Qt::Gui
Qt::GuiPrivate
Qt::XcbQpaPrivate
+ NO_UNITY_BUILD # X11 define clashes
)
## Scopes:
#####################################################################
-qt_extend_target(QXcbGlxIntegrationPlugin CONDITION QT_FEATURE_xcb_glx
- PUBLIC_LIBRARIES
+qt_internal_extend_target(QXcbGlxIntegrationPlugin CONDITION QT_FEATURE_xcb_glx
+ LIBRARIES
XCB::GLX
)
-qt_extend_target(QXcbGlxIntegrationPlugin CONDITION QT_FEATURE_dlopen AND NOT static
- PUBLIC_LIBRARIES
+qt_internal_extend_target(QXcbGlxIntegrationPlugin
+ CONDITION QT_FEATURE_dlopen AND QT_BUILD_SHARED_LIBS
+ LIBRARIES
${CMAKE_DL_LIBS}
)
diff --git a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp
index 75189a9c80..04eac027cd 100644
--- a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp
+++ b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QDebug>
@@ -51,12 +15,12 @@
#if QT_CONFIG(regularexpression)
# include <QtCore/QRegularExpression>
#endif
+#include <QtGui/qguiapplication.h>
#include <QtGui/QOpenGLContext>
#include <QtGui/QOffscreenSurface>
#include "qglxintegration.h"
-#include <QtGlxSupport/private/qglxconvenience_p.h>
-#include <QtPlatformHeaders/QGLXNativeContext>
+#include <QtGui/private/qglxconvenience_p.h>
#include "qxcbglintegration.h"
@@ -219,33 +183,15 @@ static void updateFormatFromContext(QSurfaceFormat &format)
}
}
-QGLXContext::QGLXContext(QXcbScreen *screen, const QSurfaceFormat &format, QPlatformOpenGLContext *share,
- const QVariant &nativeHandle)
+QGLXContext::QGLXContext(Display *display, QXcbScreen *screen, const QSurfaceFormat &format, QPlatformOpenGLContext *share)
: QPlatformOpenGLContext()
- , m_display(static_cast<Display *>(screen->connection()->xlib_display()))
- , m_config(nullptr)
- , m_context(nullptr)
- , m_shareContext(nullptr)
+ , m_display(display)
, m_format(format)
- , m_isPBufferCurrent(false)
- , m_ownsContext(nativeHandle.isNull())
- , m_getGraphicsResetStatus(nullptr)
- , m_lost(false)
-{
- if (nativeHandle.isNull())
- init(screen, share);
- else
- init(screen, share, nativeHandle);
-}
-
-void QGLXContext::init(QXcbScreen *screen, QPlatformOpenGLContext *share)
+ , m_ownsContext(true)
{
if (m_format.renderableType() == QSurfaceFormat::DefaultRenderableType)
-#if defined(QT_OPENGL_ES_2)
- m_format.setRenderableType(QSurfaceFormat::OpenGLES);
-#else
- m_format.setRenderableType(QSurfaceFormat::OpenGL);
-#endif
+ m_format.setRenderableType(QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGL
+ ? QSurfaceFormat::OpenGL : QSurfaceFormat::OpenGLES);
if (m_format.renderableType() != QSurfaceFormat::OpenGL && m_format.renderableType() != QSurfaceFormat::OpenGLES)
return;
@@ -277,7 +223,7 @@ void QGLXContext::init(QXcbScreen *screen, QPlatformOpenGLContext *share)
// order from the requested version.
const int requestedVersion = m_format.majorVersion() * 10 + qMin(m_format.minorVersion(), 9);
- QVector<int> glVersions;
+ QList<int> glVersions;
if (m_format.renderableType() == QSurfaceFormat::OpenGL) {
if (requestedVersion > 46)
glVersions << requestedVersion;
@@ -296,9 +242,9 @@ void QGLXContext::init(QXcbScreen *screen, QPlatformOpenGLContext *share)
// Robustness must match that of the shared context.
if (share && share->format().testOption(QSurfaceFormat::ResetNotification))
m_format.setOption(QSurfaceFormat::ResetNotification);
- Q_ASSERT(glVersions.count() > 0);
+ Q_ASSERT(glVersions.size() > 0);
- for (int i = 0; !m_context && i < glVersions.count(); i++) {
+ for (int i = 0; !m_context && i < glVersions.size(); i++) {
const int version = glVersions[i];
if (version > requestedVersion)
continue;
@@ -306,7 +252,7 @@ void QGLXContext::init(QXcbScreen *screen, QPlatformOpenGLContext *share)
const int majorVersion = version / 10;
const int minorVersion = version % 10;
- QVector<int> contextAttributes;
+ QList<int> contextAttributes;
contextAttributes << GLX_CONTEXT_MAJOR_VERSION_ARB << majorVersion
<< GLX_CONTEXT_MINOR_VERSION_ARB << minorVersion;
@@ -339,7 +285,7 @@ void QGLXContext::init(QXcbScreen *screen, QPlatformOpenGLContext *share)
}
if (supportsRobustness && m_format.testOption(QSurfaceFormat::ResetNotification)) {
- QVector<int> contextAttributesWithRobustness = contextAttributes;
+ QList<int> contextAttributesWithRobustness = contextAttributes;
contextAttributesWithRobustness << GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB << GLX_LOSE_CONTEXT_ON_RESET_ARB;
if (supportsVideoMemoryPurge)
contextAttributesWithRobustness << GLX_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV << GL_TRUE;
@@ -423,85 +369,55 @@ void QGLXContext::init(QXcbScreen *screen, QPlatformOpenGLContext *share)
XDestroyWindow(m_display, window);
}
-void QGLXContext::init(QXcbScreen *screen, QPlatformOpenGLContext *share, const QVariant &nativeHandle)
+QGLXContext::QGLXContext(Display *display, GLXContext context, void *visualInfo, QPlatformOpenGLContext *share)
+ : QPlatformOpenGLContext()
+ , m_display(display)
{
- if (!nativeHandle.canConvert<QGLXNativeContext>()) {
- qWarning("QGLXContext: Requires a QGLXNativeContext");
- return;
- }
- QGLXNativeContext handle = qvariant_cast<QGLXNativeContext>(nativeHandle);
- GLXContext context = handle.context();
- if (!context) {
- qWarning("QGLXContext: No GLXContext given");
- return;
- }
-
- // Use the provided Display, if available. If not, use our own. It may still work.
- Display *dpy = handle.display();
- if (!dpy)
- dpy = m_display;
-
- // Legacy contexts created using glXCreateContext are created using a visual
- // and the FBConfig cannot be queried. The only way to adapt these contexts
- // is to figure out the visual id.
- XVisualInfo *vinfo = nullptr;
- // If the VisualID is provided use it.
- VisualID vid = handle.visualId();
- if (!vid) {
- // In the absence of the VisualID figure it out from the window.
- Window wnd = handle.window();
- if (wnd) {
- XWindowAttributes attrs;
- XGetWindowAttributes(dpy, wnd, &attrs);
- vid = XVisualIDFromVisual(attrs.visual);
- }
- }
- if (vid) {
- XVisualInfo v;
- v.screen = screen->screenNumber();
- v.visualid = vid;
- int n = 0;
- vinfo = XGetVisualInfo(dpy, VisualScreenMask | VisualIDMask, &v, &n);
- if (n < 1) {
- XFree(vinfo);
- vinfo = nullptr;
- }
- }
+ // Legacy contexts created using glXCreateContext are created using a
+ // XVisualInfo. If the user passed one we should use that.
+ XVisualInfo *vinfo = static_cast<XVisualInfo*>(visualInfo);
- // For contexts created with an FBConfig using the modern functions providing the
- // visual or window is not mandatory. Just query the config from the context.
- GLXFBConfig config = nullptr;
+ // Otherwise assume the context was created with an FBConfig using the modern functions
if (!vinfo) {
int configId = 0;
- if (glXQueryContext(dpy, context, GLX_FBCONFIG_ID, &configId) != Success) {
+ if (glXQueryContext(m_display, context, GLX_FBCONFIG_ID, &configId) != Success) {
qWarning("QGLXContext: Failed to query config from the provided context");
return;
}
+ int screenNumber = 0;
+ if (glXQueryContext(m_display, context, GLX_SCREEN, &screenNumber) != Success) {
+ qWarning("QGLXContext: Failed to query screen from the provided context");
+ screenNumber = DefaultScreen(m_display);
+ }
+
GLXFBConfig *configs;
int numConfigs = 0;
static const int attribs[] = { GLX_FBCONFIG_ID, configId, None };
- configs = glXChooseFBConfig(dpy, screen->screenNumber(), attribs, &numConfigs);
- if (!configs || numConfigs < 1) {
+ configs = glXChooseFBConfig(m_display, screenNumber, attribs, &numConfigs);
+ if (!configs) {
+ qWarning("QGLXContext: Failed to find config(invalid arguments for glXChooseFBConfig)");
+ return;
+ } else if (numConfigs < 1) {
qWarning("QGLXContext: Failed to find config");
+ XFree(configs);
return;
}
if (configs && numConfigs > 1) // this is suspicious so warn but let it continue
qWarning("QGLXContext: Multiple configs for FBConfig ID %d", configId);
- config = configs[0];
- // Store the config.
- m_config = config;
+ m_config = configs[0];
+ XFree(configs);
}
- Q_ASSERT(vinfo || config);
+ Q_ASSERT(vinfo || m_config);
- int screenNumber = DefaultScreen(dpy);
+ int screenNumber = DefaultScreen(m_display);
Window window;
if (vinfo)
- window = createDummyWindow(dpy, vinfo, screenNumber, RootWindow(dpy, screenNumber));
+ window = createDummyWindow(m_display, vinfo, screenNumber, RootWindow(m_display, screenNumber));
else
- window = createDummyWindow(dpy, config, screenNumber, RootWindow(dpy, screenNumber));
+ window = createDummyWindow(m_display, m_config, screenNumber, RootWindow(m_display, screenNumber));
if (!window) {
qWarning("QGLXContext: Failed to create dummy window");
return;
@@ -510,7 +426,7 @@ void QGLXContext::init(QXcbScreen *screen, QPlatformOpenGLContext *share, const
// Update OpenGL version and buffer sizes in our format.
GLXContext prevContext = glXGetCurrentContext();
GLXDrawable prevDrawable = glXGetCurrentDrawable();
- if (!glXMakeCurrent(dpy, window, context)) {
+ if (!glXMakeCurrent(m_display, window, context)) {
qWarning("QGLXContext: Failed to make provided context current");
return;
}
@@ -519,11 +435,11 @@ void QGLXContext::init(QXcbScreen *screen, QPlatformOpenGLContext *share, const
? QSurfaceFormat::OpenGL : QSurfaceFormat::OpenGLES);
updateFormatFromContext(m_format);
if (vinfo)
- qglx_surfaceFormatFromVisualInfo(&m_format, dpy, vinfo);
+ qglx_surfaceFormatFromVisualInfo(&m_format, m_display, vinfo);
else
- qglx_surfaceFormatFromGLXFBConfig(&m_format, dpy, config);
- glXMakeCurrent(dpy, prevDrawable, prevContext);
- XDestroyWindow(dpy, window);
+ qglx_surfaceFormatFromGLXFBConfig(&m_format, m_display, m_config);
+ glXMakeCurrent(m_display, prevDrawable, prevContext);
+ XDestroyWindow(m_display, window);
if (vinfo)
XFree(vinfo);
@@ -552,11 +468,6 @@ static QXcbScreen *screenForPlatformSurface(QPlatformSurface *surface)
return nullptr;
}
-QVariant QGLXContext::nativeHandle() const
-{
- return QVariant::fromValue<QGLXNativeContext>(QGLXNativeContext(m_context));
-}
-
bool QGLXContext::makeCurrent(QPlatformSurface *surface)
{
bool success = false;
@@ -786,6 +697,10 @@ void QGLXContext::queryDummyContext()
}
}
+ static bool nomultithread = qEnvironmentVariableIsSet("QT_XCB_NO_THREADED_OPENGL");
+ if (nomultithread)
+ m_supportsThreading = false;
+
context.doneCurrent();
if (oldContext && oldSurface)
oldContext->makeCurrent(oldSurface);
diff --git a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.h b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.h
index 2a88fd6e59..f46ae46b31 100644
--- a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.h
+++ b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QGLXINTEGRATION_H
#define QGLXINTEGRATION_H
@@ -53,11 +17,12 @@
QT_BEGIN_NAMESPACE
-class QGLXContext : public QPlatformOpenGLContext
+class QGLXContext : public QPlatformOpenGLContext,
+ public QNativeInterface::QGLXContext
{
public:
- QGLXContext(QXcbScreen *screen, const QSurfaceFormat &format, QPlatformOpenGLContext *share,
- const QVariant &nativeHandle);
+ QGLXContext(Display *display, QXcbScreen *screen, const QSurfaceFormat &format, QPlatformOpenGLContext *share);
+ QGLXContext(Display *display, GLXContext context, void *visualInfo, QPlatformOpenGLContext *share);
~QGLXContext();
bool makeCurrent(QPlatformSurface *surface) override;
@@ -69,27 +34,24 @@ public:
bool isSharing() const override;
bool isValid() const override;
+ GLXContext nativeContext() const override { return glxContext(); }
+
GLXContext glxContext() const { return m_context; }
GLXFBConfig glxConfig() const { return m_config; }
- QVariant nativeHandle() const;
-
static bool supportsThreading();
static void queryDummyContext();
private:
- void init(QXcbScreen *screen, QPlatformOpenGLContext *share);
- void init(QXcbScreen *screen, QPlatformOpenGLContext *share, const QVariant &nativeHandle);
-
- Display *m_display;
- GLXFBConfig m_config;
- GLXContext m_context;
- GLXContext m_shareContext;
+ Display *m_display = nullptr;
+ GLXFBConfig m_config = nullptr;
+ GLXContext m_context = nullptr;
+ GLXContext m_shareContext = nullptr;
QSurfaceFormat m_format;
- bool m_isPBufferCurrent;
- bool m_ownsContext;
- GLenum (APIENTRY * m_getGraphicsResetStatus)();
- bool m_lost;
+ bool m_isPBufferCurrent = false;
+ bool m_ownsContext = false;
+ GLenum (APIENTRY * m_getGraphicsResetStatus)() = nullptr;
+ bool m_lost = false;
static bool m_queriedDummyContext;
static bool m_supportsThreading;
};
diff --git a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxintegration.cpp b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxintegration.cpp
index 6814dbd844..db0de187be 100644
--- a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxintegration.cpp
+++ b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxintegration.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qxcbglxintegration.h"
@@ -48,7 +12,9 @@
#include "qxcbscreen.h"
#include "qglxintegration.h"
+#include <QtCore/QVersionNumber>
#include <QtGui/QOpenGLContext>
+#include <QtGui/private/qopenglcontext_p.h>
#include "qxcbglxnativeinterfacehandler.h"
@@ -59,6 +25,9 @@
QT_BEGIN_NAMESPACE
#if QT_CONFIG(xcb_glx)
+ #define QT_XCB_GLX_REQUIRED_MAJOR 1
+ #define QT_XCB_GLX_REQUIRED_MINOR 3
+
#if XCB_GLX_MAJOR_VERSION == 1 && XCB_GLX_MINOR_VERSION < 4
#define XCB_GLX_BUFFER_SWAP_COMPLETE 1
typedef struct xcb_glx_buffer_swap_complete_event_t {
@@ -113,7 +82,9 @@ bool QXcbGlxIntegration::initialize(QXcbConnection *connection)
auto xglx_query = Q_XCB_REPLY(xcb_glx_query_version, m_connection->xcb_connection(),
XCB_GLX_MAJOR_VERSION,
XCB_GLX_MINOR_VERSION);
- if (!xglx_query) {
+ if ((!xglx_query)
+ || (QVersionNumber(xglx_query->major_version, xglx_query->minor_version)
+ < QVersionNumber(QT_XCB_GLX_REQUIRED_MAJOR, QT_XCB_GLX_REQUIRED_MINOR))) {
qCWarning(lcQpaGl) << "QXcbConnection: Failed to initialize GLX";
return false;
}
@@ -164,11 +135,7 @@ bool QXcbGlxIntegration::handleXcbEvent(xcb_generic_event_t *event, uint respons
XUnlockDisplay(xdisplay);
locked = false;
auto eventType = m_connection->nativeInterface()->nativeEventType();
-# if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
qintptr result = 0;
-# else
- long result = 0;
-# endif
handled = dispatcher->filterNativeEvent(eventType, &ev, &result);
}
#endif
@@ -187,10 +154,22 @@ QXcbWindow *QXcbGlxIntegration::createWindow(QWindow *window) const
QPlatformOpenGLContext *QXcbGlxIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const
{
QXcbScreen *screen = static_cast<QXcbScreen *>(context->screen()->handle());
- QGLXContext *platformContext = new QGLXContext(screen, screen->surfaceFormatFor(context->format()),
- context->shareHandle(), context->nativeHandle());
- context->setNativeHandle(platformContext->nativeHandle());
- return platformContext;
+ return new QGLXContext(static_cast<Display *>(m_connection->xlib_display()),
+ screen, screen->surfaceFormatFor(context->format()), context->shareHandle());
+}
+
+QOpenGLContext *QXcbGlxIntegration::createOpenGLContext(GLXContext glxContext, void *visualInfo, QOpenGLContext *shareContext) const
+{
+ if (!glxContext)
+ return nullptr;
+
+ QPlatformOpenGLContext *shareHandle = shareContext ? shareContext->handle() : nullptr;
+
+ auto *context = new QOpenGLContext;
+ auto *contextPrivate = QOpenGLContextPrivate::get(context);
+ auto *display = static_cast<Display *>(m_connection->xlib_display());
+ contextPrivate->adopt(new QGLXContext(display, glxContext, visualInfo, shareHandle));
+ return context;
}
QPlatformOffscreenSurface *QXcbGlxIntegration::createPlatformOffscreenSurface(QOffscreenSurface *surface) const
diff --git a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxintegration.h b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxintegration.h
index 26cb233a59..797f6c4b3f 100644
--- a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxintegration.h
+++ b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxintegration.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QXCBGLXINTEGRATION_H
#define QXCBGLXINTEGRATION_H
@@ -46,7 +10,8 @@ QT_BEGIN_NAMESPACE
class QXcbNativeInterfaceHandler;
-class QXcbGlxIntegration : public QXcbGlIntegration
+class QXcbGlxIntegration : public QXcbGlIntegration,
+ public QNativeInterface::Private::QGLXIntegration
{
public:
QXcbGlxIntegration();
@@ -58,6 +23,7 @@ public:
QXcbWindow *createWindow(QWindow *window) const override;
QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const override;
QPlatformOffscreenSurface *createPlatformOffscreenSurface(QOffscreenSurface *surface) const override;
+ QOpenGLContext *createOpenGLContext(GLXContext context, void *visualInfo, QOpenGLContext *shareContext) const override;
bool supportsThreadedOpenGL() const override;
bool supportsSwitchableWidgetComposition() const override;
diff --git a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxmain.cpp b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxmain.cpp
index 1883d1bc52..63ecaac0be 100644
--- a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxmain.cpp
+++ b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxmain.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qxcbglintegrationplugin.h"
@@ -48,7 +12,7 @@ class QXcbGlxIntegrationPlugin : public QXcbGlIntegrationPlugin
Q_OBJECT
Q_PLUGIN_METADATA(IID QXcbGlIntegrationFactoryInterface_iid FILE "xcb_glx.json")
public:
- QXcbGlIntegration *create()
+ QXcbGlIntegration *create() override
{
return new QXcbGlxIntegration();
}
diff --git a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxnativeinterfacehandler.cpp b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxnativeinterfacehandler.cpp
index e9bb4460ff..e363dc077f 100644
--- a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxnativeinterfacehandler.cpp
+++ b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxnativeinterfacehandler.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qxcbglxnativeinterfacehandler.h"
diff --git a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxnativeinterfacehandler.h b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxnativeinterfacehandler.h
index d877732725..5ca329a368 100644
--- a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxnativeinterfacehandler.h
+++ b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxnativeinterfacehandler.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QXCBGLXNATIVEINTERFACEHANDLER_H
#define QXCBGLXNATIVEINTERFACEHANDLER_H
diff --git a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxwindow.cpp b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxwindow.cpp
index 5e406017ca..31bf39e400 100644
--- a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxwindow.cpp
+++ b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxwindow.cpp
@@ -1,46 +1,10 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qxcbglxwindow.h"
#include "qxcbscreen.h"
-#include <QtGlxSupport/private/qglxconvenience_p.h>
+#include <QtGui/private/qglxconvenience_p.h>
#include <QDebug>
QT_BEGIN_NAMESPACE
@@ -58,7 +22,7 @@ const xcb_visualtype_t *QXcbGlxWindow::createVisual()
{
QXcbScreen *scr = xcbScreen();
if (!scr)
- return nullptr;
+ return QXcbWindow::createVisual();
qCDebug(lcQpaGl) << "Requested format before FBConfig/Visual selection:" << m_format;
@@ -71,10 +35,13 @@ const xcb_visualtype_t *QXcbGlxWindow::createVisual()
flags |= QGLX_SUPPORTS_SRGB;
}
+ const auto formatBackup = m_format;
XVisualInfo *visualInfo = qglx_findVisualInfo(dpy, scr->screenNumber(), &m_format, GLX_WINDOW_BIT, flags);
if (!visualInfo) {
- qWarning() << "No XVisualInfo for format" << m_format;
- return nullptr;
+ qCDebug(lcQpaGl) << "No XVisualInfo for format" << m_format;
+ // restore initial format before requesting it again
+ m_format = formatBackup;
+ return QXcbWindow::createVisual();
}
const xcb_visualtype_t *xcb_visualtype = scr->visualForId(visualInfo->visualid);
XFree(visualInfo);
diff --git a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxwindow.h b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxwindow.h
index 14b2d5e6eb..3b39dc1ba0 100644
--- a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxwindow.h
+++ b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxwindow.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QXCBGLXWINDOW_H
#define QXCBGLXWINDOW_H
diff --git a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/xcb_glx.pro b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/xcb_glx.pro
deleted file mode 100644
index 9d537b18f3..0000000000
--- a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/xcb_glx.pro
+++ /dev/null
@@ -1,27 +0,0 @@
-TARGET = qxcb-glx-integration
-
-include(../gl_integrations_plugin_base.pri)
-QT += glx_support-private
-
-DEFINES += QT_NO_FOREACH
-
-qtConfig(xcb-glx): QMAKE_USE += xcb_glx
-
-!static:qtConfig(dlopen): QMAKE_USE += libdl
-
-HEADERS += \
- qxcbglxintegration.h \
- qxcbglxwindow.h \
- qglxintegration.h \
- qxcbglxnativeinterfacehandler.h
-
-SOURCES += \
- qxcbglxmain.cpp \
- qxcbglxintegration.cpp \
- qxcbglxwindow.cpp \
- qglxintegration.cpp \
- qxcbglxnativeinterfacehandler.cpp
-
-PLUGIN_CLASS_NAME = QXcbGlxIntegrationPlugin
-PLUGIN_TYPE = xcbglintegrations
-load(qt_plugin)
diff --git a/src/plugins/platforms/xcb/nativepainting/nativepainting.pri b/src/plugins/platforms/xcb/nativepainting/nativepainting.pri
deleted file mode 100644
index 78ed00843f..0000000000
--- a/src/plugins/platforms/xcb/nativepainting/nativepainting.pri
+++ /dev/null
@@ -1,22 +0,0 @@
-qtConfig(xcb-native-painting) {
- qtConfig(xrender): QMAKE_USE += xrender
- qtConfig(fontconfig): QMAKE_USE_PRIVATE += freetype
-
- INCLUDEPATH += $$PWD
- HEADERS += \
- $$PWD/qtessellator_p.h \
- $$PWD/qpixmap_x11_p.h \
- $$PWD/qpaintengine_x11_p.h \
- $$PWD/qt_x11_p.h \
- $$PWD/qcolormap_x11_p.h \
- $$PWD/qbackingstore_x11_p.h \
- $$PWD/qxcbnativepainting.h
-
- SOURCES += \
- $$PWD/qtessellator.cpp \
- $$PWD/qpixmap_x11.cpp \
- $$PWD/qpaintengine_x11.cpp \
- $$PWD/qcolormap_x11.cpp \
- $$PWD/qbackingstore_x11.cpp \
- $$PWD/qxcbnativepainting.cpp
-}
diff --git a/src/plugins/platforms/xcb/nativepainting/qbackingstore_x11.cpp b/src/plugins/platforms/xcb/nativepainting/qbackingstore_x11.cpp
index bbc156fc53..d523eecc5a 100644
--- a/src/plugins/platforms/xcb/nativepainting/qbackingstore_x11.cpp
+++ b/src/plugins/platforms/xcb/nativepainting/qbackingstore_x11.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 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$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qbackingstore_x11_p.h"
#include "qxcbwindow.h"
@@ -52,10 +16,6 @@
#include <X11/Xlib.h>
#undef register
-#ifndef None
-#define None 0L
-#endif
-
QT_BEGIN_NAMESPACE
QXcbNativeBackingStore::QXcbNativeBackingStore(QWindow *window)
@@ -100,7 +60,7 @@ void QXcbNativeBackingStore::flush(QWindow *window, const QRegion &region, const
Window wid = platformWindow->xcb_window();
Pixmap pid = qt_x11PixmapHandle(m_pixmap);
- QVector<XRectangle> clipRects = qt_region_to_xrectangles(clipped);
+ QList<XRectangle> clipRects = qt_region_to_xrectangles(clipped);
#if QT_CONFIG(xrender)
if (m_translucentBackground)
@@ -114,11 +74,8 @@ void QXcbNativeBackingStore::flush(QWindow *window, const QRegion &region, const
XRenderSetPictureClipRectangles(display(), dstPic, 0, 0, clipRects.constData(), clipRects.size());
- XRenderComposite(display(), PictOpSrc, srcPic, None, dstPic,
- br.x() + offset.x(), br.y() + offset.y(),
- 0, 0,
- br.x(), br.y(),
- br.width(), br.height());
+ XRenderComposite(display(), PictOpSrc, srcPic, 0L /*None*/, dstPic, br.x() + offset.x(),
+ br.y() + offset.y(), 0, 0, br.x(), br.y(), br.width(), br.height());
XRenderFreePicture(display(), dstPic);
}
@@ -198,7 +155,7 @@ void QXcbNativeBackingStore::beginPaint(const QRegion &region)
#if QT_CONFIG(xrender)
if (m_translucentBackground) {
- const QVector<XRectangle> xrects = qt_region_to_xrectangles(region);
+ const QList<XRectangle> xrects = qt_region_to_xrectangles(region);
const XRenderColor color = { 0, 0, 0, 0 };
XRenderFillRectangles(display(), PictOpSrc,
qt_x11PictureHandle(m_pixmap), &color,
diff --git a/src/plugins/platforms/xcb/nativepainting/qbackingstore_x11_p.h b/src/plugins/platforms/xcb/nativepainting/qbackingstore_x11_p.h
index f3653a9438..f57a5be9a6 100644
--- a/src/plugins/platforms/xcb/nativepainting/qbackingstore_x11_p.h
+++ b/src/plugins/platforms/xcb/nativepainting/qbackingstore_x11_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 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$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QBACKINGSTORE_X11_H
#define QBACKINGSTORE_X11_H
diff --git a/src/plugins/platforms/xcb/nativepainting/qcolormap_x11.cpp b/src/plugins/platforms/xcb/nativepainting/qcolormap_x11.cpp
index fe9d1fcde9..fffb154040 100644
--- a/src/plugins/platforms/xcb/nativepainting/qcolormap_x11.cpp
+++ b/src/plugins/platforms/xcb/nativepainting/qcolormap_x11.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 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$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QVarLengthArray>
@@ -77,8 +41,8 @@ public:
uint g_shift;
uint b_shift;
- QVector<QColor> colors;
- QVector<int> pixels;
+ QList<QColor> colors;
+ QList<int> pixels;
};
static uint right_align(uint v)
@@ -320,7 +284,7 @@ static void init_direct(QXcbColormapPrivate *d, bool ownColormap)
XStoreColors(X11->display, d->colormap, colorTable.data(), colorTable.count());
}
-static QXcbColormap **cmaps = 0;
+static QXcbColormap **cmaps = nullptr;
void QXcbColormap::initialize()
{
@@ -343,7 +307,7 @@ void QXcbColormap::initialize()
d->visual = DefaultVisual(display, i);
d->defaultVisual = true;
- Visual *argbVisual = 0;
+ Visual *argbVisual = nullptr;
if (X11->visual && i == DefaultScreen(display)) {
// only use the outside colormap on the default screen
@@ -356,7 +320,7 @@ void QXcbColormap::initialize()
d->visual = find_visual(display, i, X11->visual_class, X11->visual_id,
&d->depth, &d->defaultVisual);
} else if (!X11->custom_cmap) {
- XStandardColormap *stdcmap = 0;
+ XStandardColormap *stdcmap = nullptr;
int ncmaps = 0;
#if QT_CONFIG(xrender)
@@ -638,7 +602,7 @@ const QColor QXcbColormap::colorAt(uint pixel) const
return QColor(r, g, b);
}
-const QVector<QColor> QXcbColormap::colormap() const
+const QList<QColor> QXcbColormap::colormap() const
{ return d->colors; }
QXcbColormap &QXcbColormap::operator=(const QXcbColormap &colormap)
diff --git a/src/plugins/platforms/xcb/nativepainting/qcolormap_x11_p.h b/src/plugins/platforms/xcb/nativepainting/qcolormap_x11_p.h
index 573a0f28ea..eedf798e00 100644
--- a/src/plugins/platforms/xcb/nativepainting/qcolormap_x11_p.h
+++ b/src/plugins/platforms/xcb/nativepainting/qcolormap_x11_p.h
@@ -1,47 +1,11 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 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$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QCOLORMAP_X11_H
#define QCOLORMAP_X11_H
#include <QColor>
-#include <QVector>
+#include <QList>
QT_BEGIN_NAMESPACE
@@ -69,7 +33,7 @@ public:
uint pixel(const QColor &color) const;
const QColor colorAt(uint pixel) const;
- const QVector<QColor> colormap() const;
+ const QList<QColor> colormap() const;
private:
QXcbColormap();
diff --git a/src/plugins/platforms/xcb/nativepainting/qpaintengine_x11.cpp b/src/plugins/platforms/xcb/nativepainting/qpaintengine_x11.cpp
index 82b6d60bcd..743ff92654 100644
--- a/src/plugins/platforms/xcb/nativepainting/qpaintengine_x11.cpp
+++ b/src/plugins/platforms/xcb/nativepainting/qpaintengine_x11.cpp
@@ -1,45 +1,10 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 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$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <QtCore/qrandom.h>
#include <private/qpixmapcache_p.h>
#include <private/qpaintengine_p.h>
-#include <private/qpolygonclipper_p.h>
#include <private/qpainterpath_p.h>
#include <private/qdrawhelper_p.h>
#include <private/qfontengineglyphcache_p.h>
@@ -49,6 +14,7 @@
#endif
#include "qpaintengine_x11_p.h"
+#include "qpolygonclipper_p.h"
#include "qtessellator_p.h"
#include "qpixmap_x11_p.h"
#include "qcolormap_x11_p.h"
@@ -58,6 +24,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
#if QT_CONFIG(xrender)
class QXRenderTessellator : public QTessellator
@@ -68,7 +36,7 @@ public:
XTrapezoid *traps;
int allocated;
int size;
- void addTrap(const Trapezoid &trap);
+ void addTrap(const Trapezoid &trap) override;
QRect tessellate(const QPointF *points, int nPoints, bool winding) {
size = 0;
setWinding(winding);
@@ -148,17 +116,11 @@ public:
|| (render_hints & QPainter::Antialiasing);
}
void decideCoordAdjust() {
- adjust_coords = !(render_hints & QPainter::Antialiasing)
- && (render_hints & QPainter::Qt4CompatiblePainting)
- && (has_alpha_pen
- || (has_alpha_brush && has_pen && !has_alpha_pen)
- || (cpen.style() > Qt::SolidLine));
+ adjust_coords = false;
}
void clipPolygon_dev(const QPolygonF &poly, QPolygonF *clipped_poly);
void systemStateChanged() override;
inline bool isCosmeticPen() const {
- if ((render_hints & QPainter::Qt4CompatiblePainting) && cpen == QPen())
- return true;
return cpen.isCosmetic();
}
@@ -390,7 +352,7 @@ static inline void x11SetClipRegion(Display *dpy, GC gc, GC gc2,
{
// int num;
// XRectangle *rects = (XRectangle *)qt_getClipRects(r, num);
- QVector<XRectangle> rects = qt_region_to_xrectangles(r);
+ QList<XRectangle> rects = qt_region_to_xrectangles(r);
int num = rects.size();
if (gc)
@@ -455,7 +417,7 @@ static const uchar base_dither_matrix[DITHER_SIZE][DITHER_SIZE] = {
static QPixmap qt_patternForAlpha(uchar alpha, int screen)
{
QPixmap pm;
- QString key = QLatin1String("$qt-alpha-brush$")
+ QString key = "$qt-alpha-brush$"_L1
% HexString<uchar>(alpha)
% HexString<int>(screen);
@@ -504,7 +466,7 @@ static Picture getPatternFill(int screen, const QBrush &b)
return X11->pattern_fills[i].picture;
}
// none found, replace one
- int i = qrand() % 16;
+ int i = QRandomGenerator::global()->generate() % 16;
if (X11->pattern_fills[i].screen != screen && X11->pattern_fills[i].picture) {
XRenderFreePicture (QXcbX11Info::display(), X11->pattern_fills[i].picture);
@@ -2016,7 +1978,7 @@ Q_GUI_EXPORT void qt_x11_drawImage(const QRect &rect, const QPoint &pos, const Q
|| (image_byte_order == LSBFirst && bgr_layout))
{
im = image.copy(rect);
- const int iw = im.bytesPerLine() / 4;
+ const qsizetype iw = im.bytesPerLine() / 4;
uint *data = (uint *)im.bits();
for (int i=0; i < h; i++) {
uint *p = data;
@@ -2127,7 +2089,7 @@ void QX11PaintEngine::drawPixmap(const QRectF &r, const QPixmap &px, const QRect
XSetBackground(d->dpy, cgc, 0);
XSetForeground(d->dpy, cgc, 1);
if (!d->crgn.isEmpty()) {
- QVector<XRectangle> rects = qt_region_to_xrectangles(d->crgn);
+ QList<XRectangle> rects = qt_region_to_xrectangles(d->crgn);
XSetClipRectangles(d->dpy, cgc, -x, -y, rects.data(), rects.size(), Unsorted);
} else if (d->has_clipping) {
XSetClipRectangles(d->dpy, cgc, 0, 0, 0, 0, Unsorted);
@@ -2150,7 +2112,7 @@ void QX11PaintEngine::drawPixmap(const QRectF &r, const QPixmap &px, const QRect
GC cgc = XCreateGC(d->dpy, comb, 0, 0);
XSetForeground(d->dpy, cgc, 0);
XFillRectangle(d->dpy, comb, cgc, 0, 0, sw, sh);
- QVector<XRectangle> rects = qt_region_to_xrectangles(d->crgn);
+ QList<XRectangle> rects = qt_region_to_xrectangles(d->crgn);
XSetClipRectangles(d->dpy, cgc, -x, -y, rects.data(), rects.size(), Unsorted);
XCopyArea(d->dpy, qt_x11PixmapHandle(pixmap), comb, cgc, sx, sy, sw, sh, 0, 0);
XFreeGC(d->dpy, cgc);
@@ -2172,7 +2134,7 @@ void QX11PaintEngine::drawPixmap(const QRectF &r, const QPixmap &px, const QRect
XFillRectangle(d->dpy, d->hd, d->gc, x, y, sw, sh);
restore_clip = true;
} else if (mono_dst && !mono_src) {
- QBitmap bitmap(pixmap);
+ QBitmap bitmap = QBitmap::fromPixmap(pixmap);
XCopyArea(d->dpy, qt_x11PixmapHandle(bitmap), d->hd, d->gc, sx, sy, sw, sh, x, y);
} else {
XCopyArea(d->dpy, qt_x11PixmapHandle(pixmap), d->hd, d->gc, sx, sy, sw, sh, x, y);
@@ -2199,7 +2161,7 @@ void QX11PaintEngine::drawPixmap(const QRectF &r, const QPixmap &px, const QRect
if (restore_clip) {
XSetClipOrigin(d->dpy, d->gc, 0, 0);
- QVector<XRectangle> rects = qt_region_to_xrectangles(d->crgn);
+ QList<XRectangle> rects = qt_region_to_xrectangles(d->crgn);
if (rects.isEmpty())
XSetClipMask(d->dpy, d->gc, XNone);
else
@@ -2301,21 +2263,6 @@ void QX11PaintEngine::drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, co
#if QT_CONFIG(xrender)
if (X11->use_xrender && d->picture && qt_x11PictureHandle(pixmap)) {
-#if 0
- // ### Qt 5: enable this
- XRenderPictureAttributes attrs;
- attrs.repeat = true;
- XRenderChangePicture(d->dpy, pixmap.x11PictureHandle(), CPRepeat, &attrs);
-
- if (mono_src) {
- qt_render_bitmap(d->dpy, d->scrn, pixmap.x11PictureHandle(), d->picture,
- sx, sy, x, y, w, h, d->cpen);
- } else {
- XRenderComposite(d->dpy, d->composition_mode,
- pixmap.x11PictureHandle(), XNone, d->picture,
- sx, sy, 0, 0, x, y, w, h);
- }
-#else
const int numTiles = (w / pixmap.width()) * (h / pixmap.height());
if (numTiles < 100) {
// this is essentially qt_draw_tile(), inlined for
@@ -2398,7 +2345,6 @@ void QX11PaintEngine::drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, co
pmPicture, XNone, d->picture,
sx, sy, 0, 0, x, y, w, h);
}
-#endif
} else
#endif // QT_CONFIG(xrender)
if (pixmap.depth() > 1 && !static_cast<QX11PlatformPixmap*>(pixmap.handle())->x11_mask) {
@@ -2474,7 +2420,7 @@ static bool path_for_glyphs(QPainterPath *path,
ft->lockFace();
int i = 0;
while (i < glyphs.size()) {
- QFontEngineFT::Glyph *glyph = ft->loadGlyph(glyphs[i], 0, QFontEngineFT::Format_Mono);
+ QFontEngineFT::Glyph *glyph = ft->loadGlyph(glyphs[i], QFixedPoint(), QFontEngineFT::Format_Mono);
// #### fix case where we don't get a glyph
if (!glyph || glyph->format != QFontEngineFT::Format_Mono) {
result = false;
@@ -2626,7 +2572,8 @@ bool QXRenderGlyphCache::addGlyphs(const QTextItemInt &ti,
XGlyphInfo xglyphinfo;
for (int i = 0; i < glyphs.size(); ++i) {
- const QFixed spp = ft->subPixelPositionForX(positions[i].x);
+ const QFixed sppx = ft->subPixelPositionForX(positions[i].x);
+ const QFixedPoint spp(sppx, 0);
QFontEngineFT::Glyph *glyph = set->getGlyph(glyphs[i], spp);
Glyph xglyphid = qHash(QFontEngineFT::GlyphAndSubPixelPosition(glyphs[i], spp));
@@ -2718,7 +2665,8 @@ bool QXRenderGlyphCache::draw(Drawable src, Drawable dst, const QTransform &matr
if (!isValidCoordinate(positions[i]))
break;
- const QFixed spp = ft->subPixelPositionForX(positions[i].x);
+ const QFixed sppx = ft->subPixelPositionForX(positions[i].x);
+ const QFixedPoint spp(sppx, 0);
QFontEngineFT::Glyph *g = set->getGlyph(glyphs[i], spp);
if (g
@@ -2845,7 +2793,7 @@ QFontEngine::GlyphFormat QXRenderGlyphCache::glyphFormatForDepth(QFontEngine *fo
Glyph QXRenderGlyphCache::glyphId(glyph_t glyph, QFixed subPixelPosition)
{
- return qHash(QFontEngineFT::GlyphAndSubPixelPosition(glyph, subPixelPosition));
+ return qHash(QFontEngineFT::GlyphAndSubPixelPosition(glyph, QFixedPoint(subPixelPosition, 0)));
}
bool QXRenderGlyphCache::isValidCoordinate(const QFixedPoint &fp)
diff --git a/src/plugins/platforms/xcb/nativepainting/qpaintengine_x11_p.h b/src/plugins/platforms/xcb/nativepainting/qpaintengine_x11_p.h
index bc82351283..f799fdd900 100644
--- a/src/plugins/platforms/xcb/nativepainting/qpaintengine_x11_p.h
+++ b/src/plugins/platforms/xcb/nativepainting/qpaintengine_x11_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 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$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QPAINTENGINE_X11_H
#define QPAINTENGINE_X11_H
diff --git a/src/plugins/platforms/xcb/nativepainting/qpixmap_x11.cpp b/src/plugins/platforms/xcb/nativepainting/qpixmap_x11.cpp
index f86bedbdcd..a4e820ea92 100644
--- a/src/plugins/platforms/xcb/nativepainting/qpixmap_x11.cpp
+++ b/src/plugins/platforms/xcb/nativepainting/qpixmap_x11.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 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$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QGuiApplication>
@@ -282,9 +246,9 @@ static uint n_bits(uint v)
return i;
}
-static uint *red_scale_table = 0;
-static uint *green_scale_table = 0;
-static uint *blue_scale_table = 0;
+static uint *red_scale_table = nullptr;
+static uint *green_scale_table = nullptr;
+static uint *blue_scale_table = nullptr;
static void cleanup_scale_tables()
{
@@ -546,10 +510,10 @@ void QX11PlatformPixmap::fromImage(const QImage &img, Qt::ImageConversionFlags f
Display *dpy = xinfo.display();
Visual *visual = (Visual *)xinfo.visual();
- XImage *xi = 0;
+ XImage *xi = nullptr;
bool trucol = (visual->c_class >= TrueColor);
size_t nbytes = image.sizeInBytes();
- uchar *newbits= 0;
+ uchar *newbits= nullptr;
#if QT_CONFIG(xrender)
if (alphaCheck.hasXRenderAndAlpha()) {
@@ -573,7 +537,7 @@ void QX11PlatformPixmap::fromImage(const QImage &img, Qt::ImageConversionFlags f
switch (cimage.format()) {
case QImage::Format_Indexed8: {
- QVector<QRgb> colorTable = cimage.colorTable();
+ QList<QRgb> colorTable = cimage.colorTable();
uint *xidata = (uint *)xi->data;
for (int y = 0; y < h; ++y) {
const uchar *p = cimage.scanLine(y);
@@ -676,7 +640,7 @@ void QX11PlatformPixmap::fromImage(const QImage &img, Qt::ImageConversionFlags f
const uint bbits = highest_bit(blue_mask) - lowest_bit(blue_mask) + 1;
if (d8) { // setup pixel translation
- QVector<QRgb> ctable = cimage.colorTable();
+ QList<QRgb> ctable = cimage.colorTable();
for (int i=0; i < cimage.colorCount(); i++) {
int r = qRed (ctable[i]);
int g = qGreen(ctable[i]);
@@ -1061,7 +1025,7 @@ void QX11PlatformPixmap::fromImage(const QImage &img, Qt::ImageConversionFlags f
int maxpop = 0;
int maxpix = 0;
uint j = 0;
- QVector<QRgb> ctable = cimage.colorTable();
+ QList<QRgb> ctable = cimage.colorTable();
for (int i = 0; i < 256; i++) { // init pixel array
if (pop[i] > 0) {
px->r = qRed (ctable[i]);
@@ -1350,7 +1314,7 @@ QBitmap QX11PlatformPixmap::mask() const
#endif
if (d == 1) {
QX11PlatformPixmap *that = const_cast<QX11PlatformPixmap*>(this);
- mask = QPixmap(that);
+ mask = QBitmap::fromPixmap(QPixmap(that));
} else {
mask = mask_to_bitmap(xinfo.screen());
}
@@ -1473,22 +1437,16 @@ QPixmap QX11PlatformPixmap::transformed(const QTransform &transform, Qt::Transfo
transform.m21(), transform.m22(), transform.m23(),
0., 0., 1);
bool complex_xform = false;
- qreal scaledWidth;
- qreal scaledHeight;
if (mat.type() <= QTransform::TxScale) {
- scaledHeight = qAbs(mat.m22()) * hs + 0.9999;
- scaledWidth = qAbs(mat.m11()) * ws + 0.9999;
- h = qAbs(int(scaledHeight));
- w = qAbs(int(scaledWidth));
+ h = qRound(qAbs(mat.m22()) * hs);
+ w = qRound(qAbs(mat.m11()) * ws);
} else { // rotation or shearing
QPolygonF a(QRectF(0, 0, ws, hs));
a = mat.map(a);
QRect r = a.boundingRect().toAlignedRect();
w = r.width();
h = r.height();
- scaledWidth = w;
- scaledHeight = h;
complex_xform = true;
}
mat = QPixmap::trueMatrix(mat, ws, hs); // true matrix
@@ -1497,7 +1455,7 @@ QPixmap QX11PlatformPixmap::transformed(const QTransform &transform, Qt::Transfo
mat = mat.inverted(&invertible); // invert matrix
if (h == 0 || w == 0 || !invertible
- || qAbs(scaledWidth) >= 32768 || qAbs(scaledHeight) >= 32768 )
+ || qAbs(h) >= 32768 || qAbs(w) >= 32768 )
// error, return null pixmap
return QPixmap();
@@ -1747,7 +1705,7 @@ XID QX11PlatformPixmap::createBitmapFromImage(const QImage &image)
int w = img.width();
int h = img.height();
int bpl = (w + 7) / 8;
- int ibpl = img.bytesPerLine();
+ qsizetype ibpl = img.bytesPerLine();
if (bpl != ibpl) {
tmp_bits = new uchar[bpl*h];
bits = (char *)tmp_bits;
@@ -2017,7 +1975,7 @@ QImage QX11PlatformPixmap::toImage(const QXImageWrapper &xiWrapper, const QRect
}
} else if (xi->bits_per_pixel == d) { // compatible depth
char *xidata = xi->data; // copy each scanline
- int bpl = qMin(int(image.bytesPerLine()),xi->bytes_per_line);
+ qsizetype bpl = qMin(image.bytesPerLine(),xi->bytes_per_line);
for (int y=0; y<xi->height; y++) {
memcpy(image.scanLine(y), xidata, bpl);
xidata += xi->bytes_per_line;
@@ -2038,10 +1996,10 @@ QImage QX11PlatformPixmap::toImage(const QXImageWrapper &xiWrapper, const QRect
uchar *end;
uchar use[256]; // pixel-in-use table
uchar pix[256]; // pixel translation table
- int ncols, bpl;
+ int ncols;
memset(use, 0, 256);
memset(pix, 0, 256);
- bpl = image.bytesPerLine();
+ qsizetype bpl = image.bytesPerLine();
if (x11_mask) { // which pixels are used?
for (int i = 0; i < xi->height; i++) {
@@ -2114,7 +2072,7 @@ QImage QX11PlatformPixmap::toImage(const QXImageWrapper &xiWrapper, const QRect
} else {
image.setColorCount(ncols); // create color table
}
- QVector<QColor> colors = QXcbColormap::instance(xinfo.screen()).colormap();
+ QList<QColor> colors = QXcbColormap::instance(xinfo.screen()).colormap();
int j = 0;
for (int i=0; i<colors.size(); i++) { // translate pixels
if (use[i])
diff --git a/src/plugins/platforms/xcb/nativepainting/qpixmap_x11_p.h b/src/plugins/platforms/xcb/nativepainting/qpixmap_x11_p.h
index 9c0ba98300..7d830baaa7 100644
--- a/src/plugins/platforms/xcb/nativepainting/qpixmap_x11_p.h
+++ b/src/plugins/platforms/xcb/nativepainting/qpixmap_x11_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 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$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QX11PLATFORMPIXMAP_H
#define QX11PLATFORMPIXMAP_H
diff --git a/src/plugins/platforms/xcb/nativepainting/qpolygonclipper_p.h b/src/plugins/platforms/xcb/nativepainting/qpolygonclipper_p.h
new file mode 100644
index 0000000000..e640fc11a0
--- /dev/null
+++ b/src/plugins/platforms/xcb/nativepainting/qpolygonclipper_p.h
@@ -0,0 +1,280 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QPOLYGONCLIPPER_P_H
+#define QPOLYGONCLIPPER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qrect.h>
+#include <QtGui/private/qdatabuffer_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/* based on sutherland-hodgman line-by-line clipping, as described in
+ Computer Graphics and Principles */
+template <typename InType, typename OutType, typename CastType> class QPolygonClipper
+{
+public:
+ QPolygonClipper() :
+ buffer1(0), buffer2(0)
+ {
+ x1 = y1 = x2 = y2 = 0;
+ }
+
+ ~QPolygonClipper()
+ {
+ }
+
+ void setBoundingRect(const QRect bounds)
+ {
+ x1 = bounds.x();
+ x2 = bounds.x() + bounds.width();
+ y1 = bounds.y();
+ y2 = bounds.y() + bounds.height();
+ }
+
+ QRect boundingRect()
+ {
+ return QRect(QPoint(x1, y1), QPoint(x2, y2));
+ }
+
+ inline OutType intersectLeft(const OutType &p1, const OutType &p2)
+ {
+ OutType t;
+ qreal dy = (p1.y - p2.y) / qreal(p1.x - p2.x);
+ t.x = x1;
+ t.y = static_cast<CastType>(p2.y + (x1 - p2.x) * dy);
+ return t;
+ }
+
+
+ inline OutType intersectRight(const OutType &p1, const OutType &p2)
+ {
+ OutType t;
+ qreal dy = (p1.y - p2.y) / qreal(p1.x - p2.x);
+ t.x = x2;
+ t.y = static_cast<CastType>(p2.y + (x2 - p2.x) * dy);
+ return t;
+ }
+
+
+ inline OutType intersectTop(const OutType &p1, const OutType &p2)
+ {
+ OutType t;
+ qreal dx = (p1.x - p2.x) / qreal(p1.y - p2.y);
+ t.x = static_cast<CastType>(p2.x + (y1 - p2.y) * dx);
+ t.y = y1;
+ return t;
+ }
+
+
+ inline OutType intersectBottom(const OutType &p1, const OutType &p2)
+ {
+ OutType t;
+ qreal dx = (p1.x - p2.x) / qreal(p1.y - p2.y);
+ t.x = static_cast<CastType>(p2.x + (y2 - p2.y) * dx);
+ t.y = y2;
+ return t;
+ }
+
+
+ void clipPolygon(const InType *inPoints, int inCount, OutType **outPoints, int *outCount,
+ bool closePolygon = true)
+ {
+ Q_ASSERT(outPoints);
+ Q_ASSERT(outCount);
+
+ if (inCount < 2) {
+ *outCount = 0;
+ return;
+ }
+
+ buffer1.reset();
+ buffer2.reset();
+
+ QDataBuffer<OutType> *source = &buffer1;
+ QDataBuffer<OutType> *clipped = &buffer2;
+
+ // Gather some info since we are iterating through the points anyway..
+ bool doLeft = false, doRight = false, doTop = false, doBottom = false;
+ OutType ot;
+ for (int i=0; i<inCount; ++i) {
+ ot = inPoints[i];
+ clipped->add(ot);
+
+ if (ot.x < x1)
+ doLeft = true;
+ else if (ot.x > x2)
+ doRight = true;
+ if (ot.y < y1)
+ doTop = true;
+ else if (ot.y > y2)
+ doBottom = true;
+ }
+
+ if (doLeft && clipped->size() > 1) {
+ QDataBuffer<OutType> *tmp = source;
+ source = clipped;
+ clipped = tmp;
+ clipped->reset();
+ int lastPos, start;
+ if (closePolygon) {
+ lastPos = source->size() - 1;
+ start = 0;
+ } else {
+ lastPos = 0;
+ start = 1;
+ if (source->at(0).x >= x1)
+ clipped->add(source->at(0));
+ }
+ for (int i=start; i<inCount; ++i) {
+ const OutType &cpt = source->at(i);
+ const OutType &ppt = source->at(lastPos);
+
+ if (cpt.x >= x1) {
+ if (ppt.x >= x1) {
+ clipped->add(cpt);
+ } else {
+ clipped->add(intersectLeft(cpt, ppt));
+ clipped->add(cpt);
+ }
+ } else if (ppt.x >= x1) {
+ clipped->add(intersectLeft(cpt, ppt));
+ }
+ lastPos = i;
+ }
+ }
+
+ if (doRight && clipped->size() > 1) {
+ QDataBuffer<OutType> *tmp = source;
+ source = clipped;
+ clipped = tmp;
+ clipped->reset();
+ int lastPos, start;
+ if (closePolygon) {
+ lastPos = source->size() - 1;
+ start = 0;
+ } else {
+ lastPos = 0;
+ start = 1;
+ if (source->at(0).x <= x2)
+ clipped->add(source->at(0));
+ }
+ for (int i=start; i<source->size(); ++i) {
+ const OutType &cpt = source->at(i);
+ const OutType &ppt = source->at(lastPos);
+
+ if (cpt.x <= x2) {
+ if (ppt.x <= x2) {
+ clipped->add(cpt);
+ } else {
+ clipped->add(intersectRight(cpt, ppt));
+ clipped->add(cpt);
+ }
+ } else if (ppt.x <= x2) {
+ clipped->add(intersectRight(cpt, ppt));
+ }
+
+ lastPos = i;
+ }
+
+ }
+
+ if (doTop && clipped->size() > 1) {
+ QDataBuffer<OutType> *tmp = source;
+ source = clipped;
+ clipped = tmp;
+ clipped->reset();
+ int lastPos, start;
+ if (closePolygon) {
+ lastPos = source->size() - 1;
+ start = 0;
+ } else {
+ lastPos = 0;
+ start = 1;
+ if (source->at(0).y >= y1)
+ clipped->add(source->at(0));
+ }
+ for (int i=start; i<source->size(); ++i) {
+ const OutType &cpt = source->at(i);
+ const OutType &ppt = source->at(lastPos);
+
+ if (cpt.y >= y1) {
+ if (ppt.y >= y1) {
+ clipped->add(cpt);
+ } else {
+ clipped->add(intersectTop(cpt, ppt));
+ clipped->add(cpt);
+ }
+ } else if (ppt.y >= y1) {
+ clipped->add(intersectTop(cpt, ppt));
+ }
+
+ lastPos = i;
+ }
+ }
+
+ if (doBottom && clipped->size() > 1) {
+ QDataBuffer<OutType> *tmp = source;
+ source = clipped;
+ clipped = tmp;
+ clipped->reset();
+ int lastPos, start;
+ if (closePolygon) {
+ lastPos = source->size() - 1;
+ start = 0;
+ } else {
+ lastPos = 0;
+ start = 1;
+ if (source->at(0).y <= y2)
+ clipped->add(source->at(0));
+ }
+ for (int i=start; i<source->size(); ++i) {
+ const OutType &cpt = source->at(i);
+ const OutType &ppt = source->at(lastPos);
+
+ if (cpt.y <= y2) {
+ if (ppt.y <= y2) {
+ clipped->add(cpt);
+ } else {
+ clipped->add(intersectBottom(cpt, ppt));
+ clipped->add(cpt);
+ }
+ } else if (ppt.y <= y2) {
+ clipped->add(intersectBottom(cpt, ppt));
+ }
+ lastPos = i;
+ }
+ }
+
+ if (closePolygon && clipped->size() > 0) {
+ // close clipped polygon
+ if (clipped->at(0).x != clipped->at(clipped->size()-1).x ||
+ clipped->at(0).y != clipped->at(clipped->size()-1).y) {
+ OutType ot = clipped->at(0);
+ clipped->add(ot);
+ }
+ }
+ *outCount = clipped->size();
+ *outPoints = clipped->data();
+ }
+
+private:
+ int x1, x2, y1, y2;
+ QDataBuffer<OutType> buffer1;
+ QDataBuffer<OutType> buffer2;
+};
+
+QT_END_NAMESPACE
+
+#endif // QPOLYGONCLIPPER_P_H
diff --git a/src/plugins/platforms/xcb/nativepainting/qt_x11_p.h b/src/plugins/platforms/xcb/nativepainting/qt_x11_p.h
index 1f7e7cf49b..66e0aa2cf8 100644
--- a/src/plugins/platforms/xcb/nativepainting/qt_x11_p.h
+++ b/src/plugins/platforms/xcb/nativepainting/qt_x11_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 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$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QT_X11_P_H
#define QT_X11_P_H
@@ -190,7 +154,7 @@ struct QX11InfoData {
};
template <class T>
-Q_DECL_RELAXED_CONSTEXPR inline int lowest_bit(T v) noexcept
+constexpr inline int lowest_bit(T v) noexcept
{
int result = qCountTrailingZeroBits(v);
return ((result >> 3) == sizeof(T)) ? -1 : result;
diff --git a/src/plugins/platforms/xcb/nativepainting/qtessellator.cpp b/src/plugins/platforms/xcb/nativepainting/qtessellator.cpp
index 1afa00cfc9..7b0094044b 100644
--- a/src/plugins/platforms/xcb/nativepainting/qtessellator.cpp
+++ b/src/plugins/platforms/xcb/nativepainting/qtessellator.cpp
@@ -1,46 +1,11 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 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$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qtessellator_p.h"
#include <QRect>
#include <QList>
+#include <QMap>
#include <QDebug>
#include <qmath.h>
@@ -268,7 +233,7 @@ QTessellatorPrivate::Edge::Edge(const QTessellatorPrivate::Vertices &vertices, i
//
// WARNING: It's absolutely critical that the intersect() and isLeftOf() methods use
-// exactly the same algorithm to calulate yi. It's also important to be sure the algorithms
+// exactly the same algorithm to calculate yi. It's also important to be sure the algorithms
// are transitive (ie. the conditions below are true for all input data):
//
// a.intersect(b) == b.intersect(a)
@@ -725,7 +690,7 @@ void QTessellatorPrivate::cancelCoincidingEdges()
{
Vertex **vv = vertices.sorted;
- QCoincidingEdge *tl = 0;
+ QCoincidingEdge *tl = nullptr;
int tlSize = 0;
for (int i = 0; i < vertices.nPoints - 1; ++i) {
diff --git a/src/plugins/platforms/xcb/nativepainting/qtessellator_p.h b/src/plugins/platforms/xcb/nativepainting/qtessellator_p.h
index 7181a1ecc9..70379c9e55 100644
--- a/src/plugins/platforms/xcb/nativepainting/qtessellator_p.h
+++ b/src/plugins/platforms/xcb/nativepainting/qtessellator_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 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$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QTESSELATOR_P_H
#define QTESSELATOR_P_H
diff --git a/src/plugins/platforms/xcb/nativepainting/qxcbnativepainting.cpp b/src/plugins/platforms/xcb/nativepainting/qxcbnativepainting.cpp
index 57b1882e4b..06eea93ff5 100644
--- a/src/plugins/platforms/xcb/nativepainting/qxcbnativepainting.cpp
+++ b/src/plugins/platforms/xcb/nativepainting/qxcbnativepainting.cpp
@@ -1,41 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 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$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <QtCore/qrandom.h>
#include "qxcbconnection.h"
#include "qcolormap_x11_p.h"
@@ -108,11 +74,11 @@ void qt_xcb_native_x11_info_init(QXcbConnection *conn)
#endif // QT_CONFIG(xrender)
}
-QVector<XRectangle> qt_region_to_xrectangles(const QRegion &r)
+QList<XRectangle> qt_region_to_xrectangles(const QRegion &r)
{
const int numRects = r.rectCount();
const auto input = r.begin();
- QVector<XRectangle> output(numRects);
+ QList<XRectangle> output(numRects);
for (int i = 0; i < numRects; ++i) {
const QRect &in = input[i];
XRectangle &out = output[i];
@@ -279,7 +245,7 @@ Picture QXcbX11Data::getSolidFill(int screen, const QColor &c)
return X11->solid_fills[i].picture;
}
// none found, replace one
- int i = qrand() % 16;
+ int i = QRandomGenerator::global()->generate() % 16;
if (X11->solid_fills[i].screen != screen && X11->solid_fills[i].picture) {
XRenderFreePicture (X11->display, X11->solid_fills[i].picture);
diff --git a/src/plugins/platforms/xcb/nativepainting/qxcbnativepainting.h b/src/plugins/platforms/xcb/nativepainting/qxcbnativepainting.h
index b00ccfcdff..5ee4298645 100644
--- a/src/plugins/platforms/xcb/nativepainting/qxcbnativepainting.h
+++ b/src/plugins/platforms/xcb/nativepainting/qxcbnativepainting.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 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$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QXCBNATIVEPAINTING_H
#define QXCBNATIVEPAINTING_H
@@ -55,7 +19,7 @@ class QXcbConnection;
class QPixmap;
void qt_xcb_native_x11_info_init(QXcbConnection *conn);
-QVector<XRectangle> qt_region_to_xrectangles(const QRegion &r);
+QList<XRectangle> qt_region_to_xrectangles(const QRegion &r);
class QXcbX11InfoData;
class QXcbX11Info
diff --git a/src/plugins/platforms/xcb/qt_xlib_wrapper.c b/src/plugins/platforms/xcb/qt_xlib_wrapper.c
new file mode 100644
index 0000000000..f4614e5504
--- /dev/null
+++ b/src/plugins/platforms/xcb/qt_xlib_wrapper.c
@@ -0,0 +1,7 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+#include "qt_xlib_wrapper.h"
+
+#include <X11/Xlib.h>
+
+void qt_XFlush(Display *dpy) { XFlush(dpy); }
diff --git a/src/plugins/platforms/xcb/qt_xlib_wrapper.h b/src/plugins/platforms/xcb/qt_xlib_wrapper.h
new file mode 100644
index 0000000000..642dbdeadd
--- /dev/null
+++ b/src/plugins/platforms/xcb/qt_xlib_wrapper.h
@@ -0,0 +1,17 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+#ifndef QT_XLIB_WRAPPER_H
+#define QT_XLIB_WRAPPER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ typedef struct _XDisplay Display;
+ void qt_XFlush(Display *dpy);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // QT_XLIB_WRAPPER_H
diff --git a/src/plugins/platforms/xcb/qxcbatom.cpp b/src/plugins/platforms/xcb/qxcbatom.cpp
index 79b5ba06e6..dd5596653c 100644
--- a/src/plugins/platforms/xcb/qxcbatom.cpp
+++ b/src/plugins/platforms/xcb/qxcbatom.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and 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$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qxcbatom.h"
#include <QtCore/qglobal.h>
@@ -90,6 +54,8 @@ static const char *xcb_atomnames = {
"_QT_CLOSE_CONNECTION\0"
+ "_QT_GET_TIMESTAMP\0"
+
"_MOTIF_WM_HINTS\0"
"DTWM_IS_RUNNING\0"
@@ -122,6 +88,7 @@ static const char *xcb_atomnames = {
"_NET_WM_STATE_MODAL\0"
"_NET_WM_STATE_STAYS_ON_TOP\0"
"_NET_WM_STATE_DEMANDS_ATTENTION\0"
+ "_NET_WM_STATE_HIDDEN\0"
"_NET_WM_USER_TIME\0"
"_NET_WM_USER_TIME_WINDOW\0"
@@ -144,11 +111,13 @@ static const char *xcb_atomnames = {
"_NET_WM_WINDOW_TYPE_NORMAL\0"
"_KDE_NET_WM_WINDOW_TYPE_OVERRIDE\0"
+ "_KDE_NET_WM_DESKTOP_FILE\0"
"_KDE_NET_WM_FRAME_STRUT\0"
"_NET_FRAME_EXTENTS\0"
"_NET_STARTUP_INFO\0"
"_NET_STARTUP_INFO_BEGIN\0"
+ "_NET_STARTUP_ID\0"
"_NET_SUPPORTING_WM_CHECK\0"
@@ -181,6 +150,7 @@ static const char *xcb_atomnames = {
"XdndActionCopy\0"
"XdndActionLink\0"
"XdndActionMove\0"
+ "XdndActionAsk\0"
"XdndActionPrivate\0"
// Xkb
@@ -227,11 +197,13 @@ static const char *xcb_atomnames = {
"_COMPIZ_DECOR_REQUEST\0"
"_COMPIZ_DECOR_DELETE_PIXMAP\0"
"_COMPIZ_TOOLKIT_ACTION\0"
+ "_GTK_APPLICATION_ID\0"
"_GTK_LOAD_ICONTHEMES\0"
"AT_SPI_BUS\0"
"EDID\0"
"EDID_DATA\0"
"XFree86_DDC_EDID1_RAWDATA\0"
+ "_ICC_PROFILE\0"
// \0\0 terminates loop.
};
@@ -245,29 +217,25 @@ void QXcbAtom::initialize(xcb_connection_t *connection)
}
void QXcbAtom::initializeAllAtoms(xcb_connection_t *connection) {
- const char *names[QXcbAtom::NAtoms];
- const char *ptr = xcb_atomnames;
-
+ const char *name = xcb_atomnames;
+ size_t name_len;
int i = 0;
- while (*ptr) {
- names[i++] = ptr;
- while (*ptr)
- ++ptr;
- ++ptr;
- }
-
- Q_ASSERT(i == QXcbAtom::NAtoms);
-
xcb_intern_atom_cookie_t cookies[QXcbAtom::NAtoms];
+ while ((name_len = strlen(name)) != 0) {
+ cookies[i] = xcb_intern_atom(connection, false, name_len, name);
+ ++i;
+ name += name_len + 1; // jump over the \0
+ }
+
Q_ASSERT(i == QXcbAtom::NAtoms);
- for (i = 0; i < QXcbAtom::NAtoms; ++i)
- cookies[i] = xcb_intern_atom(connection, false, strlen(names[i]), names[i]);
for (i = 0; i < QXcbAtom::NAtoms; ++i) {
xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(connection, cookies[i], nullptr);
- m_allAtoms[i] = reply->atom;
- free(reply);
+ if (reply) {
+ m_allAtoms[i] = reply->atom;
+ free(reply);
+ }
}
}
diff --git a/src/plugins/platforms/xcb/qxcbatom.h b/src/plugins/platforms/xcb/qxcbatom.h
index 233d2eadb7..bc677eaf3e 100644
--- a/src/plugins/platforms/xcb/qxcbatom.h
+++ b/src/plugins/platforms/xcb/qxcbatom.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and 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$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QXCBATOM_H
#define QXCBATOM_H
@@ -46,197 +10,206 @@ class QXcbAtom
public:
enum Atom {
// window-manager <-> client protocols
- WM_PROTOCOLS,
- WM_DELETE_WINDOW,
- WM_TAKE_FOCUS,
- _NET_WM_PING,
- _NET_WM_CONTEXT_HELP,
- _NET_WM_SYNC_REQUEST,
- _NET_WM_SYNC_REQUEST_COUNTER,
- MANAGER, // System tray notification
- _NET_SYSTEM_TRAY_OPCODE, // System tray operation
+ AtomWM_PROTOCOLS,
+ AtomWM_DELETE_WINDOW,
+ AtomWM_TAKE_FOCUS,
+ Atom_NET_WM_PING,
+ Atom_NET_WM_CONTEXT_HELP,
+ Atom_NET_WM_SYNC_REQUEST,
+ Atom_NET_WM_SYNC_REQUEST_COUNTER,
+ AtomMANAGER, // System tray notification
+ Atom_NET_SYSTEM_TRAY_OPCODE, // System tray operation
// ICCCM window state
- WM_STATE,
- WM_CHANGE_STATE,
- WM_CLASS,
- WM_NAME,
+ AtomWM_STATE,
+ AtomWM_CHANGE_STATE,
+ AtomWM_CLASS,
+ AtomWM_NAME,
// Session management
- WM_CLIENT_LEADER,
- WM_WINDOW_ROLE,
- SM_CLIENT_ID,
- WM_CLIENT_MACHINE,
+ AtomWM_CLIENT_LEADER,
+ AtomWM_WINDOW_ROLE,
+ AtomSM_CLIENT_ID,
+ AtomWM_CLIENT_MACHINE,
// Clipboard
- CLIPBOARD,
- INCR,
- TARGETS,
- MULTIPLE,
- TIMESTAMP,
- SAVE_TARGETS,
- CLIP_TEMPORARY,
- _QT_SELECTION,
- _QT_CLIPBOARD_SENTINEL,
- _QT_SELECTION_SENTINEL,
- CLIPBOARD_MANAGER,
+ AtomCLIPBOARD,
+ AtomINCR,
+ AtomTARGETS,
+ AtomMULTIPLE,
+ AtomTIMESTAMP,
+ AtomSAVE_TARGETS,
+ AtomCLIP_TEMPORARY,
+ Atom_QT_SELECTION,
+ Atom_QT_CLIPBOARD_SENTINEL,
+ Atom_QT_SELECTION_SENTINEL,
+ AtomCLIPBOARD_MANAGER,
- RESOURCE_MANAGER,
+ AtomRESOURCE_MANAGER,
- _XSETROOT_ID,
+ Atom_XSETROOT_ID,
- _QT_SCROLL_DONE,
- _QT_INPUT_ENCODING,
+ Atom_QT_SCROLL_DONE,
+ Atom_QT_INPUT_ENCODING,
// Qt/XCB specific
- _QT_CLOSE_CONNECTION,
+ Atom_QT_CLOSE_CONNECTION,
- _MOTIF_WM_HINTS,
+ Atom_QT_GET_TIMESTAMP,
- DTWM_IS_RUNNING,
- ENLIGHTENMENT_DESKTOP,
- _DT_SAVE_MODE,
- _SGI_DESKS_MANAGER,
+ Atom_MOTIF_WM_HINTS,
+
+ AtomDTWM_IS_RUNNING,
+ AtomENLIGHTENMENT_DESKTOP,
+ Atom_DT_SAVE_MODE,
+ Atom_SGI_DESKS_MANAGER,
// EWMH (aka NETWM)
- _NET_SUPPORTED,
- _NET_VIRTUAL_ROOTS,
- _NET_WORKAREA,
-
- _NET_MOVERESIZE_WINDOW,
- _NET_WM_MOVERESIZE,
-
- _NET_WM_NAME,
- _NET_WM_ICON_NAME,
- _NET_WM_ICON,
-
- _NET_WM_PID,
-
- _NET_WM_WINDOW_OPACITY,
-
- _NET_WM_STATE,
- _NET_WM_STATE_ABOVE,
- _NET_WM_STATE_BELOW,
- _NET_WM_STATE_FULLSCREEN,
- _NET_WM_STATE_MAXIMIZED_HORZ,
- _NET_WM_STATE_MAXIMIZED_VERT,
- _NET_WM_STATE_MODAL,
- _NET_WM_STATE_STAYS_ON_TOP,
- _NET_WM_STATE_DEMANDS_ATTENTION,
-
- _NET_WM_USER_TIME,
- _NET_WM_USER_TIME_WINDOW,
- _NET_WM_FULL_PLACEMENT,
-
- _NET_WM_WINDOW_TYPE,
- _NET_WM_WINDOW_TYPE_DESKTOP,
- _NET_WM_WINDOW_TYPE_DOCK,
- _NET_WM_WINDOW_TYPE_TOOLBAR,
- _NET_WM_WINDOW_TYPE_MENU,
- _NET_WM_WINDOW_TYPE_UTILITY,
- _NET_WM_WINDOW_TYPE_SPLASH,
- _NET_WM_WINDOW_TYPE_DIALOG,
- _NET_WM_WINDOW_TYPE_DROPDOWN_MENU,
- _NET_WM_WINDOW_TYPE_POPUP_MENU,
- _NET_WM_WINDOW_TYPE_TOOLTIP,
- _NET_WM_WINDOW_TYPE_NOTIFICATION,
- _NET_WM_WINDOW_TYPE_COMBO,
- _NET_WM_WINDOW_TYPE_DND,
- _NET_WM_WINDOW_TYPE_NORMAL,
- _KDE_NET_WM_WINDOW_TYPE_OVERRIDE,
-
- _KDE_NET_WM_FRAME_STRUT,
- _NET_FRAME_EXTENTS,
-
- _NET_STARTUP_INFO,
- _NET_STARTUP_INFO_BEGIN,
-
- _NET_SUPPORTING_WM_CHECK,
-
- _NET_WM_CM_S0,
-
- _NET_SYSTEM_TRAY_VISUAL,
-
- _NET_ACTIVE_WINDOW,
+ Atom_NET_SUPPORTED,
+ Atom_NET_VIRTUAL_ROOTS,
+ Atom_NET_WORKAREA,
+
+ Atom_NET_MOVERESIZE_WINDOW,
+ Atom_NET_WM_MOVERESIZE,
+
+ Atom_NET_WM_NAME,
+ Atom_NET_WM_ICON_NAME,
+ Atom_NET_WM_ICON,
+
+ Atom_NET_WM_PID,
+
+ Atom_NET_WM_WINDOW_OPACITY,
+
+ Atom_NET_WM_STATE,
+ Atom_NET_WM_STATE_ABOVE,
+ Atom_NET_WM_STATE_BELOW,
+ Atom_NET_WM_STATE_FULLSCREEN,
+ Atom_NET_WM_STATE_MAXIMIZED_HORZ,
+ Atom_NET_WM_STATE_MAXIMIZED_VERT,
+ Atom_NET_WM_STATE_MODAL,
+ Atom_NET_WM_STATE_STAYS_ON_TOP,
+ Atom_NET_WM_STATE_DEMANDS_ATTENTION,
+ Atom_NET_WM_STATE_HIDDEN,
+
+ Atom_NET_WM_USER_TIME,
+ Atom_NET_WM_USER_TIME_WINDOW,
+ Atom_NET_WM_FULL_PLACEMENT,
+
+ Atom_NET_WM_WINDOW_TYPE,
+ Atom_NET_WM_WINDOW_TYPE_DESKTOP,
+ Atom_NET_WM_WINDOW_TYPE_DOCK,
+ Atom_NET_WM_WINDOW_TYPE_TOOLBAR,
+ Atom_NET_WM_WINDOW_TYPE_MENU,
+ Atom_NET_WM_WINDOW_TYPE_UTILITY,
+ Atom_NET_WM_WINDOW_TYPE_SPLASH,
+ Atom_NET_WM_WINDOW_TYPE_DIALOG,
+ Atom_NET_WM_WINDOW_TYPE_DROPDOWN_MENU,
+ Atom_NET_WM_WINDOW_TYPE_POPUP_MENU,
+ Atom_NET_WM_WINDOW_TYPE_TOOLTIP,
+ Atom_NET_WM_WINDOW_TYPE_NOTIFICATION,
+ Atom_NET_WM_WINDOW_TYPE_COMBO,
+ Atom_NET_WM_WINDOW_TYPE_DND,
+ Atom_NET_WM_WINDOW_TYPE_NORMAL,
+ Atom_KDE_NET_WM_WINDOW_TYPE_OVERRIDE,
+
+ Atom_KDE_NET_WM_DESKTOP_FILE,
+ Atom_KDE_NET_WM_FRAME_STRUT,
+ Atom_NET_FRAME_EXTENTS,
+
+ Atom_NET_STARTUP_INFO,
+ Atom_NET_STARTUP_INFO_BEGIN,
+ Atom_NET_STARTUP_ID,
+
+ Atom_NET_SUPPORTING_WM_CHECK,
+
+ Atom_NET_WM_CM_S0,
+
+ Atom_NET_SYSTEM_TRAY_VISUAL,
+
+ Atom_NET_ACTIVE_WINDOW,
// Property formats
- TEXT,
- UTF8_STRING,
- CARDINAL,
+ AtomTEXT,
+ AtomUTF8_STRING,
+ AtomCARDINAL,
// Xdnd
- XdndEnter,
- XdndPosition,
- XdndStatus,
- XdndLeave,
- XdndDrop,
- XdndFinished,
- XdndTypelist,
- XdndActionList,
-
- XdndSelection,
-
- XdndAware,
- XdndProxy,
-
- XdndActionCopy,
- XdndActionLink,
- XdndActionMove,
- XdndActionPrivate,
+ AtomXdndEnter,
+ AtomXdndPosition,
+ AtomXdndStatus,
+ AtomXdndLeave,
+ AtomXdndDrop,
+ AtomXdndFinished,
+ AtomXdndTypelist,
+ AtomXdndActionList,
+
+ AtomXdndSelection,
+
+ AtomXdndAware,
+ AtomXdndProxy,
+
+ AtomXdndActionCopy,
+ AtomXdndActionLink,
+ AtomXdndActionMove,
+ AtomXdndActionAsk,
+ AtomXdndActionPrivate,
// Xkb
- _XKB_RULES_NAMES,
+ Atom_XKB_RULES_NAMES,
// XEMBED
- _XEMBED,
- _XEMBED_INFO,
+ Atom_XEMBED,
+ Atom_XEMBED_INFO,
// XInput2
- ButtonLeft,
- ButtonMiddle,
- ButtonRight,
- ButtonWheelUp,
- ButtonWheelDown,
- ButtonHorizWheelLeft,
- ButtonHorizWheelRight,
- AbsMTPositionX,
- AbsMTPositionY,
- AbsMTTouchMajor,
- AbsMTTouchMinor,
- AbsMTOrientation,
- AbsMTPressure,
- AbsMTTrackingID,
- MaxContacts,
- RelX,
- RelY,
+ AtomButtonLeft,
+ AtomButtonMiddle,
+ AtomButtonRight,
+ AtomButtonWheelUp,
+ AtomButtonWheelDown,
+ AtomButtonHorizWheelLeft,
+ AtomButtonHorizWheelRight,
+ AtomAbsMTPositionX,
+ AtomAbsMTPositionY,
+ AtomAbsMTTouchMajor,
+ AtomAbsMTTouchMinor,
+ AtomAbsMTOrientation,
+ AtomAbsMTPressure,
+ AtomAbsMTTrackingID,
+ AtomMaxContacts,
+ AtomRelX,
+ AtomRelY,
// XInput2 tablet
- AbsX,
- AbsY,
- AbsPressure,
- AbsTiltX,
- AbsTiltY,
- AbsWheel,
- AbsDistance,
- WacomSerialIDs,
- INTEGER,
- RelHorizWheel,
- RelVertWheel,
- RelHorizScroll,
- RelVertScroll,
-
- _XSETTINGS_SETTINGS,
-
- _COMPIZ_DECOR_PENDING,
- _COMPIZ_DECOR_REQUEST,
- _COMPIZ_DECOR_DELETE_PIXMAP,
- _COMPIZ_TOOLKIT_ACTION,
- _GTK_LOAD_ICONTHEMES,
-
- AT_SPI_BUS,
-
- EDID,
- EDID_DATA,
- XFree86_DDC_EDID1_RAWDATA,
+ AtomAbsX,
+ AtomAbsY,
+ AtomAbsPressure,
+ AtomAbsTiltX,
+ AtomAbsTiltY,
+ AtomAbsWheel,
+ AtomAbsDistance,
+ AtomWacomSerialIDs,
+ AtomINTEGER,
+ AtomRelHorizWheel,
+ AtomRelVertWheel,
+ AtomRelHorizScroll,
+ AtomRelVertScroll,
+
+ Atom_XSETTINGS_SETTINGS,
+
+ Atom_COMPIZ_DECOR_PENDING,
+ Atom_COMPIZ_DECOR_REQUEST,
+ Atom_COMPIZ_DECOR_DELETE_PIXMAP,
+ Atom_COMPIZ_TOOLKIT_ACTION,
+ Atom_GTK_APPLICATION_ID,
+ Atom_GTK_LOAD_ICONTHEMES,
+
+ AtomAT_SPI_BUS,
+
+ AtomEDID,
+ AtomEDID_DATA,
+ AtomXFree86_DDC_EDID1_RAWDATA,
+
+ Atom_ICC_PROFILE,
NAtoms
};
diff --git a/src/plugins/platforms/xcb/qxcbbackingstore.cpp b/src/plugins/platforms/xcb/qxcbbackingstore.cpp
index 8f55bc2e96..8353fac6a9 100644
--- a/src/plugins/platforms/xcb/qxcbbackingstore.cpp
+++ b/src/plugins/platforms/xcb/qxcbbackingstore.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qxcbbackingstore.h"
@@ -209,7 +173,7 @@ void QXcbBackingStoreImage::init(const QSize &size, uint depth, QImage::Format f
m_qimage_format = format;
m_hasAlpha = QImage::toPixelFormat(m_qimage_format).alphaUsage() == QPixelFormat::UsesAlpha;
if (!m_hasAlpha)
- m_qimage_format = qt_maybeAlphaVersionWithSameDepth(m_qimage_format);
+ m_qimage_format = qt_maybeDataCompatibleAlphaVersion(m_qimage_format);
memset(&m_shm_info, 0, sizeof m_shm_info);
@@ -479,24 +443,28 @@ bool QXcbBackingStoreImage::scroll(const QRegion &area, int dx, int dy)
const QRect bounds(QPoint(), size());
const QRegion scrollArea(area & bounds);
const QPoint delta(dx, dy);
+ const QRegion destinationRegion = scrollArea.translated(delta).intersected(bounds);
if (m_clientSideScroll) {
if (m_qimage.isNull())
return false;
if (hasShm())
- preparePaint(scrollArea);
+ preparePaint(destinationRegion);
- for (const QRect &rect : scrollArea)
- qt_scrollRectInImage(m_qimage, rect, delta);
+ const QRect rect = scrollArea.boundingRect();
+ qt_scrollRectInImage(m_qimage, rect, delta);
} else {
- if (hasShm())
- shmPutImage(m_xcb_pixmap, m_pendingFlush.intersected(scrollArea));
- else
- flushPixmap(scrollArea);
-
ensureGC(m_xcb_pixmap);
+ if (hasShm()) {
+ QRegion partialFlushRegion = m_pendingFlush.intersected(scrollArea);
+ shmPutImage(m_xcb_pixmap, partialFlushRegion);
+ m_pendingFlush -= partialFlushRegion;
+ } else {
+ flushPixmap(scrollArea);
+ }
+
for (const QRect &src : scrollArea) {
const QRect dst = src.translated(delta).intersected(bounds);
xcb_copy_area(xcb_connection(),
@@ -507,14 +475,13 @@ bool QXcbBackingStoreImage::scroll(const QRegion &area, int dx, int dy)
dst.x(), dst.y(),
dst.width(), dst.height());
}
- }
- m_scrolledRegion |= scrollArea.translated(delta).intersected(bounds);
- if (hasShm()) {
- m_pendingFlush -= scrollArea;
- m_pendingFlush -= m_scrolledRegion;
+ if (hasShm())
+ m_pendingFlush -= destinationRegion;
}
+ m_scrolledRegion |= destinationRegion;
+
return true;
}
@@ -537,7 +504,7 @@ void QXcbBackingStoreImage::ensureGC(xcb_drawable_t dst)
static inline void copy_unswapped(char *dst, int dstBytesPerLine, const QImage &img, const QRect &rect)
{
const uchar *srcData = img.constBits();
- const int srcBytesPerLine = img.bytesPerLine();
+ const qsizetype srcBytesPerLine = img.bytesPerLine();
const int leftOffset = rect.left() * img.depth() >> 3;
const int bottom = rect.bottom() + 1;
@@ -553,7 +520,7 @@ template <class Pixel>
static inline void copy_swapped(char *dst, const int dstStride, const QImage &img, const QRect &rect)
{
const uchar *srcData = img.constBits();
- const int srcBytesPerLine = img.bytesPerLine();
+ const qsizetype srcBytesPerLine = img.bytesPerLine();
const int left = rect.left();
const int width = rect.width();
@@ -710,9 +677,10 @@ void QXcbBackingStoreImage::put(xcb_drawable_t dst, const QRegion &region, const
Q_ASSERT(!m_clientSideScroll);
ensureGC(dst);
- setClip(region);
if (hasShm()) {
+ setClip(region); // Clip in window local coordinates
+
// Copy scrolled area on server-side from pixmap to window
const QRegion scrolledRegion = m_scrolledRegion.translated(-offset);
for (const QRect &rect : scrolledRegion) {
@@ -733,7 +701,15 @@ void QXcbBackingStoreImage::put(xcb_drawable_t dst, const QRegion &region, const
const QRect bounds = region.boundingRect();
const QPoint target = bounds.topLeft();
const QRect source = bounds.translated(offset);
- flushPixmap(region);
+
+ // First clip in backingstore-local coordinates, and upload
+ // the changed parts of the backingstore to the server.
+ setClip(source);
+ flushPixmap(source);
+
+ // Then clip in window local coordinates, and copy the updated
+ // parts of the backingstore image server-side to the window.
+ setClip(region);
xcb_copy_area(xcb_connection(),
m_xcb_pixmap,
dst,
@@ -833,7 +809,18 @@ QImage QXcbBackingStore::toImage() const
// If the backingstore is rgbSwapped, return the internal image type here.
if (!m_rgbImage.isNull())
return m_rgbImage;
- return m_image && m_image->image() ? *m_image->image() : QImage();
+
+ if (!m_image || !m_image->image())
+ return QImage();
+
+ m_image->flushScrolledRegion(true);
+
+ QImage image = *m_image->image();
+
+ // Return an image that does not share QImageData with the original image,
+ // even if they both point to the same data of the m_xcb_image, otherwise
+ // painting to m_qimage would detach it from the m_xcb_image data.
+ return QImage(image.constBits(), image.width(), image.height(), image.format());
}
QPlatformGraphicsBuffer *QXcbBackingStore::graphicsBuffer() const
@@ -878,26 +865,31 @@ void QXcbBackingStore::render(xcb_window_t window, const QRegion &region, const
m_image->put(window, region, offset);
}
-#ifndef QT_NO_OPENGL
-void QXcbBackingStore::composeAndFlush(QWindow *window, const QRegion &region, const QPoint &offset,
- QPlatformTextureList *textures,
- bool translucentBackground)
+QPlatformBackingStore::FlushResult QXcbBackingStore::rhiFlush(QWindow *window,
+ qreal sourceDevicePixelRatio,
+ const QRegion &region,
+ const QPoint &offset,
+ QPlatformTextureList *textures,
+ bool translucentBackground)
{
if (!m_image || m_image->size().isEmpty())
- return;
+ return FlushFailed;
m_image->flushScrolledRegion(true);
- QPlatformBackingStore::composeAndFlush(window, region, offset, textures, translucentBackground);
-
+ auto result = QPlatformBackingStore::rhiFlush(window, sourceDevicePixelRatio, region, offset,
+ textures, translucentBackground);
+ if (result != FlushSuccess)
+ return result;
QXcbWindow *platformWindow = static_cast<QXcbWindow *>(window->handle());
if (platformWindow->needsSync()) {
platformWindow->updateSyncRequestCounter();
} else {
xcb_flush(xcb_connection());
}
+
+ return FlushSuccess;
}
-#endif // QT_NO_OPENGL
void QXcbBackingStore::resize(const QSize &size, const QRegion &)
{
diff --git a/src/plugins/platforms/xcb/qxcbbackingstore.h b/src/plugins/platforms/xcb/qxcbbackingstore.h
index 0c30929d4e..979b254326 100644
--- a/src/plugins/platforms/xcb/qxcbbackingstore.h
+++ b/src/plugins/platforms/xcb/qxcbbackingstore.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QXCBBACKINGSTORE_H
#define QXCBBACKINGSTORE_H
@@ -59,11 +23,12 @@ public:
QPaintDevice *paintDevice() override;
void flush(QWindow *window, const QRegion &region, const QPoint &offset) override;
-#ifndef QT_NO_OPENGL
- void composeAndFlush(QWindow *window, const QRegion &region, const QPoint &offset,
+ FlushResult rhiFlush(QWindow *window,
+ qreal sourceDevicePixelRatio,
+ const QRegion &region,
+ const QPoint &offset,
QPlatformTextureList *textures,
bool translucentBackground) override;
-#endif
QImage toImage() const override;
QPlatformGraphicsBuffer *graphicsBuffer() const override;
diff --git a/src/plugins/platforms/xcb/qxcbclipboard.cpp b/src/plugins/platforms/xcb/qxcbclipboard.cpp
index fe9ddfece7..40e2f47354 100644
--- a/src/plugins/platforms/xcb/qxcbclipboard.cpp
+++ b/src/plugins/platforms/xcb/qxcbclipboard.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qxcbclipboard.h"
@@ -67,11 +31,11 @@ public:
break;
case QClipboard::Clipboard:
- modeAtom = m_clipboard->atom(QXcbAtom::CLIPBOARD);
+ modeAtom = m_clipboard->atom(QXcbAtom::AtomCLIPBOARD);
break;
default:
- qWarning("QXcbClipboardMime: Internal error: Unsupported clipboard mode");
+ qCWarning(lcQpaClipboard, "QXcbClipboardMime: Internal error: Unsupported clipboard mode");
break;
}
}
@@ -83,7 +47,7 @@ public:
bool isEmpty() const
{
- return m_clipboard->getSelectionOwner(modeAtom) == XCB_NONE;
+ return m_clipboard->connection()->selectionOwner(modeAtom) == XCB_NONE;
}
protected:
@@ -92,12 +56,12 @@ protected:
if (isEmpty())
return QStringList();
- if (!formatList.count()) {
+ if (!formatList.size()) {
QXcbClipboardMime *that = const_cast<QXcbClipboardMime *>(this);
// get the list of targets from the current clipboard owner - we do this
// once so that multiple calls to this function don't require multiple
// server round trips...
- that->format_atoms = m_clipboard->getDataInFormat(modeAtom, m_clipboard->atom(QXcbAtom::TARGETS));
+ that->format_atoms = m_clipboard->getDataInFormat(modeAtom, m_clipboard->atom(QXcbAtom::AtomTARGETS));
if (format_atoms.size() > 0) {
const xcb_atom_t *targets = (const xcb_atom_t *) format_atoms.data();
@@ -123,28 +87,28 @@ protected:
return list.contains(format);
}
- QVariant retrieveData_sys(const QString &fmt, QVariant::Type type) const override
+ QVariant retrieveData_sys(const QString &fmt, QMetaType type) const override
{
- auto requestedType = QMetaType::Type(type);
+ auto requestedType = type;
if (fmt.isEmpty() || isEmpty())
return QByteArray();
(void)formats(); // trigger update of format list
- QVector<xcb_atom_t> atoms;
+ QList<xcb_atom_t> atoms;
const xcb_atom_t *targets = (const xcb_atom_t *) format_atoms.data();
int size = format_atoms.size() / sizeof(xcb_atom_t);
atoms.reserve(size);
for (int i = 0; i < size; ++i)
atoms.append(targets[i]);
- QByteArray encoding;
- xcb_atom_t fmtatom = mimeAtomForFormat(m_clipboard->connection(), fmt, requestedType, atoms, &encoding);
+ bool hasUtf8 = false;
+ xcb_atom_t fmtatom = mimeAtomForFormat(m_clipboard->connection(), fmt, requestedType, atoms, &hasUtf8);
if (fmtatom == 0)
return QVariant();
- return mimeConvertToFormat(m_clipboard->connection(), fmtatom, m_clipboard->getDataInFormat(modeAtom, fmtatom), fmt, requestedType, encoding);
+ return mimeConvertToFormat(m_clipboard->connection(), fmtatom, m_clipboard->getDataInFormat(modeAtom, fmtatom), fmt, requestedType, hasUtf8);
}
private:
@@ -162,7 +126,7 @@ QXcbClipboardTransaction::QXcbClipboardTransaction(QXcbClipboard *clipboard, xcb
xcb_change_window_attributes(m_clipboard->xcb_connection(), m_window,
XCB_CW_EVENT_MASK, values);
- m_abortTimerId = startTimer(m_clipboard->clipboardTimeout());
+ m_abortTimerId = startTimer(std::chrono::milliseconds{m_clipboard->clipboardTimeout()});
}
QXcbClipboardTransaction::~QXcbClipboardTransaction()
@@ -181,7 +145,7 @@ bool QXcbClipboardTransaction::updateIncrementalProperty(const xcb_property_noti
// restart the timer
if (m_abortTimerId)
killTimer(m_abortTimerId);
- m_abortTimerId = startTimer(m_clipboard->clipboardTimeout());
+ m_abortTimerId = startTimer(std::chrono::milliseconds{m_clipboard->clipboardTimeout()});
uint bytes_left = uint(m_data.size()) - m_offset;
if (bytes_left > 0) {
@@ -231,14 +195,15 @@ QXcbClipboard::QXcbClipboard(QXcbConnection *c)
m_clientClipboard[QClipboard::Selection] = nullptr;
m_timestamp[QClipboard::Clipboard] = XCB_CURRENT_TIME;
m_timestamp[QClipboard::Selection] = XCB_CURRENT_TIME;
- m_owner = connection()->getQtSelectionOwner();
if (connection()->hasXFixes()) {
const uint32_t mask = XCB_XFIXES_SELECTION_EVENT_MASK_SET_SELECTION_OWNER |
XCB_XFIXES_SELECTION_EVENT_MASK_SELECTION_WINDOW_DESTROY |
XCB_XFIXES_SELECTION_EVENT_MASK_SELECTION_CLIENT_CLOSE;
- xcb_xfixes_select_selection_input_checked(xcb_connection(), m_owner, XCB_ATOM_PRIMARY, mask);
- xcb_xfixes_select_selection_input_checked(xcb_connection(), m_owner, atom(QXcbAtom::CLIPBOARD), mask);
+ xcb_xfixes_select_selection_input_checked(xcb_connection(), connection()->qtSelectionOwner(),
+ XCB_ATOM_PRIMARY, mask);
+ xcb_xfixes_select_selection_input_checked(xcb_connection(), connection()->qtSelectionOwner(),
+ atom(QXcbAtom::AtomCLIPBOARD), mask);
}
// xcb_change_property_request_t and xcb_get_property_request_t are the same size
@@ -253,19 +218,21 @@ QXcbClipboard::~QXcbClipboard()
m_timestamp[QClipboard::Selection] != XCB_CURRENT_TIME) {
// First we check if there is a clipboard manager.
- auto reply = Q_XCB_REPLY(xcb_get_selection_owner, xcb_connection(), atom(QXcbAtom::CLIPBOARD_MANAGER));
- if (reply && reply->owner != XCB_NONE) {
+ if (connection()->selectionOwner(atom(QXcbAtom::AtomCLIPBOARD_MANAGER)) != XCB_NONE) {
// we delete the property so the manager saves all TARGETS.
- xcb_delete_property(xcb_connection(), m_owner, atom(QXcbAtom::_QT_SELECTION));
- xcb_convert_selection(xcb_connection(), m_owner, atom(QXcbAtom::CLIPBOARD_MANAGER), atom(QXcbAtom::SAVE_TARGETS),
- atom(QXcbAtom::_QT_SELECTION), connection()->time());
+ xcb_delete_property(xcb_connection(), connection()->qtSelectionOwner(),
+ atom(QXcbAtom::Atom_QT_SELECTION));
+ xcb_convert_selection(xcb_connection(), connection()->qtSelectionOwner(),
+ atom(QXcbAtom::AtomCLIPBOARD_MANAGER), atom(QXcbAtom::AtomSAVE_TARGETS),
+ atom(QXcbAtom::Atom_QT_SELECTION), connection()->time());
connection()->sync();
// waiting until the clipboard manager fetches the content.
- if (auto event = waitForClipboardEvent(m_owner, XCB_SELECTION_NOTIFY, true)) {
+ if (auto event = waitForClipboardEvent(connection()->qtSelectionOwner(),
+ XCB_SELECTION_NOTIFY, true)) {
free(event);
} else {
- qWarning("QXcbClipboard: Unable to receive an event from the "
+ qCWarning(lcQpaClipboard, "QXcbClipboard: Unable to receive an event from the "
"clipboard manager in a reasonable time");
}
}
@@ -289,15 +256,10 @@ bool QXcbClipboard::handlePropertyNotify(const xcb_generic_event_t *event)
return (*it)->updateIncrementalProperty(propertyNotify);
}
-xcb_window_t QXcbClipboard::getSelectionOwner(xcb_atom_t atom) const
-{
- return connection()->getSelectionOwner(atom);
-}
-
xcb_atom_t QXcbClipboard::atomForMode(QClipboard::Mode mode) const
{
if (mode == QClipboard::Clipboard)
- return atom(QXcbAtom::CLIPBOARD);
+ return atom(QXcbAtom::AtomCLIPBOARD);
if (mode == QClipboard::Selection)
return XCB_ATOM_PRIMARY;
return XCB_NONE;
@@ -307,7 +269,7 @@ QClipboard::Mode QXcbClipboard::modeForAtom(xcb_atom_t a) const
{
if (a == XCB_ATOM_PRIMARY)
return QClipboard::Selection;
- if (a == atom(QXcbAtom::CLIPBOARD))
+ if (a == atom(QXcbAtom::AtomCLIPBOARD))
return QClipboard::Clipboard;
// not supported enum value, used to detect errors
return QClipboard::FindBuffer;
@@ -319,8 +281,8 @@ QMimeData * QXcbClipboard::mimeData(QClipboard::Mode mode)
if (mode > QClipboard::Selection)
return nullptr;
- xcb_window_t clipboardOwner = getSelectionOwner(atomForMode(mode));
- if (clipboardOwner == owner()) {
+ xcb_window_t clipboardOwner = connection()->selectionOwner(atomForMode(mode));
+ if (clipboardOwner == connection()->qtSelectionOwner()) {
return m_clientClipboard[mode];
} else {
if (!m_xClipboard[mode])
@@ -362,7 +324,7 @@ void QXcbClipboard::setMimeData(QMimeData *data, QClipboard::Mode mode)
connection()->setTime(connection()->getTimestamp());
if (data) {
- newOwner = owner();
+ newOwner = connection()->qtSelectionOwner();
m_clientClipboard[mode] = data;
m_timestamp[mode] = connection()->time();
@@ -370,8 +332,8 @@ void QXcbClipboard::setMimeData(QMimeData *data, QClipboard::Mode mode)
xcb_set_selection_owner(xcb_connection(), newOwner, modeAtom, connection()->time());
- if (getSelectionOwner(modeAtom) != newOwner) {
- qWarning("QXcbClipboard::setMimeData: Cannot set X11 selection owner");
+ if (connection()->selectionOwner(modeAtom) != newOwner) {
+ qCWarning(lcQpaClipboard, "QXcbClipboard::setMimeData: Cannot set X11 selection owner");
}
emitChanged(mode);
@@ -386,10 +348,11 @@ bool QXcbClipboard::supportsMode(QClipboard::Mode mode) const
bool QXcbClipboard::ownsMode(QClipboard::Mode mode) const
{
- if (m_owner == XCB_NONE || mode > QClipboard::Selection)
+ if (connection()->qtSelectionOwner() == XCB_NONE || mode > QClipboard::Selection)
return false;
- Q_ASSERT(m_timestamp[mode] == XCB_CURRENT_TIME || getSelectionOwner(atomForMode(mode)) == m_owner);
+ Q_ASSERT(m_timestamp[mode] == XCB_CURRENT_TIME
+ || connection()->selectionOwner(atomForMode(mode)) == connection()->qtSelectionOwner());
return m_timestamp[mode] != XCB_CURRENT_TIME;
}
@@ -417,7 +380,7 @@ xcb_window_t QXcbClipboard::requestor() const
XCB_WINDOW_CLASS_INPUT_OUTPUT, // window class
platformScreen->screen()->root_visual, // visual
0, // value mask
- nullptr); // value list
+ nullptr); // value list
QXcbWindow::setWindowTitle(connection(), window,
QStringLiteral("Qt Clipboard Requestor Window"));
@@ -438,26 +401,21 @@ void QXcbClipboard::setRequestor(xcb_window_t window)
m_requestor = window;
}
-xcb_window_t QXcbClipboard::owner() const
-{
- return m_owner;
-}
-
xcb_atom_t QXcbClipboard::sendTargetsSelection(QMimeData *d, xcb_window_t window, xcb_atom_t property)
{
- QVector<xcb_atom_t> types;
+ QList<xcb_atom_t> types;
QStringList formats = QInternalMimeData::formatsHelper(d);
for (int i = 0; i < formats.size(); ++i) {
- QVector<xcb_atom_t> atoms = QXcbMime::mimeAtomsForFormat(connection(), formats.at(i));
+ QList<xcb_atom_t> atoms = QXcbMime::mimeAtomsForFormat(connection(), formats.at(i));
for (int j = 0; j < atoms.size(); ++j) {
if (!types.contains(atoms.at(j)))
types.append(atoms.at(j));
}
}
- types.append(atom(QXcbAtom::TARGETS));
- types.append(atom(QXcbAtom::MULTIPLE));
- types.append(atom(QXcbAtom::TIMESTAMP));
- types.append(atom(QXcbAtom::SAVE_TARGETS));
+ types.append(atom(QXcbAtom::AtomTARGETS));
+ types.append(atom(QXcbAtom::AtomMULTIPLE));
+ types.append(atom(QXcbAtom::AtomTIMESTAMP));
+ types.append(atom(QXcbAtom::AtomSAVE_TARGETS));
xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, window, property, XCB_ATOM_ATOM,
32, types.size(), (const void *)types.constData());
@@ -481,7 +439,7 @@ xcb_atom_t QXcbClipboard::sendSelection(QMimeData *d, xcb_atom_t target, xcb_win
// don't allow INCR transfers when using MULTIPLE or to
// Motif clients (since Motif doesn't support INCR)
- static xcb_atom_t motif_clip_temporary = atom(QXcbAtom::CLIP_TEMPORARY);
+ static xcb_atom_t motif_clip_temporary = atom(QXcbAtom::AtomCLIP_TEMPORARY);
bool allow_incr = property != motif_clip_temporary;
// This 'bool' can be removed once there is a proper fix for QTBUG-32853
if (m_clipboard_closing)
@@ -490,7 +448,7 @@ xcb_atom_t QXcbClipboard::sendSelection(QMimeData *d, xcb_atom_t target, xcb_win
if (data.size() > m_maxPropertyRequestDataBytes && allow_incr) {
long bytes = data.size();
xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, window, property,
- atom(QXcbAtom::INCR), 32, 1, (const void *)&bytes);
+ atom(QXcbAtom::AtomINCR), 32, 1, (const void *)&bytes);
auto transaction = new QXcbClipboardTransaction(this, window, property, data, atomFormat, dataFormat);
m_transactions.insert(window, transaction);
return property;
@@ -521,7 +479,7 @@ void QXcbClipboard::handleSelectionClearRequest(xcb_selection_clear_event_t *eve
// XGetSelectionOwner(dpy, XA_PRIMARY),
// xevent->xselectionclear.time, d->timestamp);
- xcb_window_t newOwner = getSelectionOwner(event->selection);
+ xcb_window_t newOwner = connection()->selectionOwner(event->selection);
/* If selection ownership was given up voluntarily from QClipboard::clear(), then we do nothing here
since its already handled in setMimeData. Otherwise, the event must have come from another client
@@ -538,7 +496,7 @@ void QXcbClipboard::handleSelectionClearRequest(xcb_selection_clear_event_t *eve
void QXcbClipboard::handleSelectionRequest(xcb_selection_request_event_t *req)
{
if (requestor() && req->requestor == requestor()) {
- qWarning("QXcbClipboard: Selection request should be caught before");
+ qCWarning(lcQpaClipboard, "QXcbClipboard: Selection request should be caught before");
return;
}
@@ -553,7 +511,8 @@ void QXcbClipboard::handleSelectionRequest(xcb_selection_request_event_t *req)
QMimeData *d;
QClipboard::Mode mode = modeForAtom(req->selection);
if (mode > QClipboard::Selection) {
- qWarning() << "QXcbClipboard: Unknown selection" << connection()->atomName(req->selection);
+ qCWarning(lcQpaClipboard, "QXcbClipboard: Unknown selection %s",
+ connection()->atomName(req->selection).constData());
xcb_send_event(xcb_connection(), false, req->requestor, XCB_EVENT_MASK_NO_EVENT, (const char *)&event);
return;
}
@@ -561,21 +520,21 @@ void QXcbClipboard::handleSelectionRequest(xcb_selection_request_event_t *req)
d = m_clientClipboard[mode];
if (!d) {
- qWarning("QXcbClipboard: Cannot transfer data, no data available");
+ qCWarning(lcQpaClipboard, "QXcbClipboard: Cannot transfer data, no data available");
xcb_send_event(xcb_connection(), false, req->requestor, XCB_EVENT_MASK_NO_EVENT, (const char *)&event);
return;
}
if (m_timestamp[mode] == XCB_CURRENT_TIME // we don't own the selection anymore
|| (req->time != XCB_CURRENT_TIME && req->time < m_timestamp[mode])) {
- qWarning("QXcbClipboard: SelectionRequest too old");
+ qCDebug(lcQpaClipboard, "QXcbClipboard: SelectionRequest too old");
xcb_send_event(xcb_connection(), false, req->requestor, XCB_EVENT_MASK_NO_EVENT, (const char *)&event);
return;
}
- xcb_atom_t targetsAtom = atom(QXcbAtom::TARGETS);
- xcb_atom_t multipleAtom = atom(QXcbAtom::MULTIPLE);
- xcb_atom_t timestampAtom = atom(QXcbAtom::TIMESTAMP);
+ xcb_atom_t targetsAtom = atom(QXcbAtom::AtomTARGETS);
+ xcb_atom_t multipleAtom = atom(QXcbAtom::AtomMULTIPLE);
+ xcb_atom_t timestampAtom = atom(QXcbAtom::AtomTIMESTAMP);
struct AtomPair { xcb_atom_t target; xcb_atom_t property; } *multi = nullptr;
xcb_atom_t multi_type = XCB_NONE;
@@ -623,7 +582,7 @@ void QXcbClipboard::handleSelectionRequest(xcb_selection_request_event_t *req)
property, XCB_ATOM_INTEGER, 32, 1, &m_timestamp[mode]);
ret = property;
} else {
- qWarning("QXcbClipboard: Invalid data timestamp");
+ qCWarning(lcQpaClipboard, "QXcbClipboard: Invalid data timestamp");
}
} else if (target == targetsAtom) {
ret = sendTargetsSelection(d, req->requestor, property);
@@ -667,7 +626,7 @@ void QXcbClipboard::handleXFixesSelectionRequest(xcb_xfixes_selection_notify_eve
// Note1: Here we care only about the xfixes events that come from other processes.
// Note2: If the QClipboard::clear() is issued, event->owner is XCB_NONE,
// so we check selection_timestamp to not handle our own QClipboard::clear().
- if (event->owner != owner() && event->selection_timestamp > m_timestamp[mode]) {
+ if (event->owner != connection()->qtSelectionOwner() && event->selection_timestamp > m_timestamp[mode]) {
if (!m_xClipboard[mode]) {
m_xClipboard[mode].reset(new QXcbClipboardMime(mode, this));
} else {
@@ -728,7 +687,7 @@ bool QXcbClipboard::clipboardReadProperty(xcb_window_t win, xcb_atom_t property,
// recover -- this shouldn't normally happen, but it doesn't
// hurt to be defensive
if ((int)(buffer_offset + length) > buffer->size()) {
- qWarning("QXcbClipboard: buffer overflow");
+ qCWarning(lcQpaClipboard, "QXcbClipboard: buffer overflow");
length = buffer->size() - buffer_offset;
// escape loop
@@ -749,7 +708,7 @@ bool QXcbClipboard::clipboardReadProperty(xcb_window_t win, xcb_atom_t property,
// correct size, not 0-term.
if (size)
*size = buffer_offset;
- if (*type == atom(QXcbAtom::INCR))
+ if (*type == atom(QXcbAtom::AtomINCR))
m_incr_receive_time = connection()->getTimestamp();
if (deleteProperty)
xcb_delete_property(xcb_connection(), win, property);
@@ -781,14 +740,19 @@ xcb_generic_event_t *QXcbClipboard::waitForClipboardEvent(xcb_window_t window, i
if (e) // found the waited for event
return e;
+ // It is safe to assume here that the pointed to node won't be re-used
+ // while we are holding the pointer to it. The nodes can be recycled
+ // only when they are dequeued, which is done only by
+ // QXcbConnection::processXcbEvents().
+ const QXcbEventNode *flushedTailNode = queue->flushedTail();
+
if (checkManager) {
- auto reply = Q_XCB_REPLY(xcb_get_selection_owner, xcb_connection(), atom(QXcbAtom::CLIPBOARD_MANAGER));
- if (!reply || reply->owner == XCB_NONE)
+ if (connection()->selectionOwner(atom(QXcbAtom::AtomCLIPBOARD_MANAGER)) == XCB_NONE)
return nullptr;
}
// process other clipboard events, since someone is probably requesting data from us
- auto clipboardAtom = atom(QXcbAtom::CLIPBOARD);
+ auto clipboardAtom = atom(QXcbAtom::AtomCLIPBOARD);
e = queue->peek([clipboardAtom](xcb_generic_event_t *event, int type) {
xcb_atom_t selection = XCB_ATOM_NONE;
if (type == XCB_SELECTION_REQUEST)
@@ -806,7 +770,7 @@ xcb_generic_event_t *QXcbClipboard::waitForClipboardEvent(xcb_window_t window, i
const auto elapsed = timer.elapsed();
if (elapsed < clipboard_timeout)
- queue->waitForNewEvents(clipboard_timeout - elapsed);
+ queue->waitForNewEvents(flushedTailNode, clipboard_timeout - elapsed);
} while (timer.elapsed() < clipboard_timeout);
return nullptr;
@@ -829,6 +793,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);
@@ -864,9 +830,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
@@ -878,7 +846,7 @@ QByteArray QXcbClipboard::clipboardReadIncrementalProperty(xcb_window_t win, xcb
QByteArray QXcbClipboard::getDataInFormat(xcb_atom_t modeAtom, xcb_atom_t fmtAtom)
{
- return getSelection(modeAtom, fmtAtom, atom(QXcbAtom::_QT_SELECTION));
+ return getSelection(modeAtom, fmtAtom, atom(QXcbAtom::Atom_QT_SELECTION));
}
QByteArray QXcbClipboard::getSelection(xcb_atom_t selection, xcb_atom_t target, xcb_atom_t property, xcb_timestamp_t time)
@@ -902,7 +870,7 @@ QByteArray QXcbClipboard::getSelection(xcb_atom_t selection, xcb_atom_t target,
xcb_atom_t type;
if (clipboardReadProperty(win, property, true, &buf, nullptr, &type, nullptr)) {
- if (type == atom(QXcbAtom::INCR)) {
+ if (type == atom(QXcbAtom::AtomINCR)) {
int nbytes = buf.size() >= 4 ? *((int*)buf.data()) : 0;
buf = clipboardReadIncrementalProperty(win, property, nbytes, false);
}
@@ -915,4 +883,5 @@ QByteArray QXcbClipboard::getSelection(xcb_atom_t selection, xcb_atom_t target,
QT_END_NAMESPACE
+#include "moc_qxcbclipboard.cpp"
#include "qxcbclipboard.moc"
diff --git a/src/plugins/platforms/xcb/qxcbclipboard.h b/src/plugins/platforms/xcb/qxcbclipboard.h
index 51ae0dc1ee..79c48a0af5 100644
--- a/src/plugins/platforms/xcb/qxcbclipboard.h
+++ b/src/plugins/platforms/xcb/qxcbclipboard.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QXCBCLIPBOARD_H
#define QXCBCLIPBOARD_H
@@ -45,7 +9,8 @@
#include <xcb/xcb.h>
#include <xcb/xfixes.h>
-#include <QtCore/QObject>
+#include <QtCore/qobject.h>
+#include <QtCore/qmap.h>
QT_BEGIN_NAMESPACE
@@ -97,8 +62,6 @@ public:
xcb_window_t requestor() const;
void setRequestor(xcb_window_t window);
- xcb_window_t owner() const;
-
void handleSelectionRequest(xcb_selection_request_event_t *event);
void handleSelectionClearRequest(xcb_selection_clear_event_t *event);
void handleXFixesSelectionRequest(xcb_xfixes_selection_notify_event_t *event);
@@ -110,7 +73,6 @@ public:
bool handlePropertyNotify(const xcb_generic_event_t *event);
- xcb_window_t getSelectionOwner(xcb_atom_t atom) const;
QByteArray getSelection(xcb_atom_t selection, xcb_atom_t target, xcb_atom_t property, xcb_timestamp_t t = 0);
int increment() const { return m_maxPropertyRequestDataBytes; }
@@ -133,7 +95,6 @@ private:
xcb_timestamp_t m_timestamp[2];
xcb_window_t m_requestor = XCB_NONE;
- xcb_window_t m_owner = XCB_NONE;
static const int clipboard_timeout;
diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp
index 435c4aee93..1056c6408f 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtGui/private/qguiapplication_p.h>
#include <QtCore/QDebug>
@@ -71,8 +35,14 @@
#undef explicit
#include <xcb/xinput.h>
+#if QT_CONFIG(xcb_xlib)
+#include "qt_xlib_wrapper.h"
+#endif
+
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
Q_LOGGING_CATEGORY(lcQpaXInput, "qt.qpa.input")
Q_LOGGING_CATEGORY(lcQpaXInputDevices, "qt.qpa.input.devices")
Q_LOGGING_CATEGORY(lcQpaXInputEvents, "qt.qpa.input.events")
@@ -86,6 +56,7 @@ Q_LOGGING_CATEGORY(lcQpaXDnd, "qt.qpa.xdnd")
QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGrabServer, xcb_visualid_t defaultVisualId, const char *displayName)
: QXcbBasicConnection(displayName)
+ , m_duringSystemMoveResize(false)
, m_canGrabServer(canGrabServer)
, m_defaultVisualId(defaultVisualId)
, m_nativeInterface(nativeInterface)
@@ -95,12 +66,10 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGra
m_eventQueue = new QXcbEventQueue(this);
- m_xdgCurrentDesktop = qgetenv("XDG_CURRENT_DESKTOP").toLower();
-
if (hasXRandr())
xrandrSelectEvents();
- initializeScreens();
+ initializeScreens(false);
if (hasXInput2()) {
xi2SetupDevices();
@@ -116,16 +85,16 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGra
m_drag = new QXcbDrag(this);
#endif
- m_startupId = qgetenv("DESKTOP_STARTUP_ID");
- if (!m_startupId.isNull())
+ setStartupId(qgetenv("DESKTOP_STARTUP_ID"));
+ if (!startupId().isNull())
qunsetenv("DESKTOP_STARTUP_ID");
const int focusInDelay = 100;
m_focusInTimer.setSingleShot(true);
m_focusInTimer.setInterval(focusInDelay);
- m_focusInTimer.callOnTimeout([]() {
+ m_focusInTimer.callOnTimeout(this, []() {
// No FocusIn events for us, proceed with FocusOut normally.
- QWindowSystemInterface::handleWindowActivated(nullptr, Qt::ActiveWindowFocusReason);
+ QWindowSystemInterface::handleFocusWindowChanged(nullptr, Qt::ActiveWindowFocusReason);
});
sync();
@@ -176,12 +145,12 @@ void QXcbConnection::removeWindowEventListener(xcb_window_t id)
QXcbWindowEventListener *QXcbConnection::windowEventListenerFromId(xcb_window_t id)
{
- return m_mapper.value(id, 0);
+ return m_mapper.value(id, nullptr);
}
QXcbWindow *QXcbConnection::platformWindowFromId(xcb_window_t id)
{
- QXcbWindowEventListener *listener = m_mapper.value(id, 0);
+ QXcbWindowEventListener *listener = m_mapper.value(id, nullptr);
if (listener)
return listener->toWindow();
return nullptr;
@@ -221,6 +190,12 @@ void QXcbConnection::printXcbEvent(const QLoggingCategory &log, const char *mess
}
#define CASE_PRINT_AND_RETURN(name) case name : PRINT_AND_RETURN(#name);
+#define XI_PRINT_AND_RETURN(name) { \
+ qCDebug(log, "%s | XInput Event(%s) | sequence: %d", message, name, sequence); \
+ return; \
+}
+#define XI_CASE_PRINT_AND_RETURN(name) case name : XI_PRINT_AND_RETURN(#name);
+
switch (response_type) {
CASE_PRINT_AND_RETURN( XCB_KEY_PRESS );
CASE_PRINT_AND_RETURN( XCB_KEY_RELEASE );
@@ -255,7 +230,44 @@ void QXcbConnection::printXcbEvent(const QLoggingCategory &log, const char *mess
CASE_PRINT_AND_RETURN( XCB_COLORMAP_NOTIFY );
CASE_PRINT_AND_RETURN( XCB_CLIENT_MESSAGE );
CASE_PRINT_AND_RETURN( XCB_MAPPING_NOTIFY );
- CASE_PRINT_AND_RETURN( XCB_GE_GENERIC );
+ case XCB_GE_GENERIC: {
+ if (hasXInput2() && isXIEvent(event)) {
+ auto *xiDeviceEvent = reinterpret_cast<const xcb_input_button_press_event_t*>(event); // qt_xcb_input_device_event_t
+ switch (xiDeviceEvent->event_type) {
+ XI_CASE_PRINT_AND_RETURN( XCB_INPUT_KEY_PRESS );
+ XI_CASE_PRINT_AND_RETURN( XCB_INPUT_KEY_RELEASE );
+ XI_CASE_PRINT_AND_RETURN( XCB_INPUT_BUTTON_PRESS );
+ XI_CASE_PRINT_AND_RETURN( XCB_INPUT_BUTTON_RELEASE );
+ XI_CASE_PRINT_AND_RETURN( XCB_INPUT_MOTION );
+ XI_CASE_PRINT_AND_RETURN( XCB_INPUT_ENTER );
+ XI_CASE_PRINT_AND_RETURN( XCB_INPUT_LEAVE );
+ XI_CASE_PRINT_AND_RETURN( XCB_INPUT_FOCUS_IN );
+ XI_CASE_PRINT_AND_RETURN( XCB_INPUT_FOCUS_OUT );
+ XI_CASE_PRINT_AND_RETURN( XCB_INPUT_HIERARCHY );
+ XI_CASE_PRINT_AND_RETURN( XCB_INPUT_PROPERTY );
+ XI_CASE_PRINT_AND_RETURN( XCB_INPUT_RAW_KEY_PRESS );
+ XI_CASE_PRINT_AND_RETURN( XCB_INPUT_RAW_KEY_RELEASE );
+ XI_CASE_PRINT_AND_RETURN( XCB_INPUT_RAW_BUTTON_PRESS );
+ XI_CASE_PRINT_AND_RETURN( XCB_INPUT_RAW_BUTTON_RELEASE );
+ XI_CASE_PRINT_AND_RETURN( XCB_INPUT_RAW_MOTION );
+ XI_CASE_PRINT_AND_RETURN( XCB_INPUT_TOUCH_BEGIN );
+ XI_CASE_PRINT_AND_RETURN( XCB_INPUT_TOUCH_UPDATE );
+ XI_CASE_PRINT_AND_RETURN( XCB_INPUT_TOUCH_END );
+ XI_CASE_PRINT_AND_RETURN( XCB_INPUT_TOUCH_OWNERSHIP );
+ XI_CASE_PRINT_AND_RETURN( XCB_INPUT_RAW_TOUCH_BEGIN );
+ XI_CASE_PRINT_AND_RETURN( XCB_INPUT_RAW_TOUCH_UPDATE );
+ XI_CASE_PRINT_AND_RETURN( XCB_INPUT_RAW_TOUCH_END );
+ XI_CASE_PRINT_AND_RETURN( XCB_INPUT_BARRIER_HIT );
+ XI_CASE_PRINT_AND_RETURN( XCB_INPUT_BARRIER_LEAVE );
+ default:
+ qCDebug(log, "%s | XInput Event(other type) | sequence: %d", message, sequence);
+ return;
+ }
+ } else {
+ qCDebug(log, "%s | %s(%d) | sequence: %d", message, "XCB_GE_GENERIC", response_type, sequence);
+ return;
+ }
+ }
}
// XFixes
if (isXFixesType(response_type, XCB_XFIXES_SELECTION_NOTIFY))
@@ -428,11 +440,7 @@ const char *xcb_protocol_request_codes[] =
void QXcbConnection::handleXcbError(xcb_generic_error_t *error)
{
-#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
qintptr result = 0;
-#else
- long result = 0;
-#endif
QAbstractEventDispatcher* dispatcher = QAbstractEventDispatcher::instance();
if (dispatcher && dispatcher->filterNativeEvent(m_nativeInterface->nativeEventType(), error, &result))
return;
@@ -445,12 +453,12 @@ void QXcbConnection::printXcbError(const char *message, xcb_generic_error_t *err
uint clamped_error_code = qMin<uint>(error->error_code, (sizeof(xcb_errors) / sizeof(xcb_errors[0])) - 1);
uint clamped_major_code = qMin<uint>(error->major_code, (sizeof(xcb_protocol_request_codes) / sizeof(xcb_protocol_request_codes[0])) - 1);
- qCWarning(lcQpaXcb, "%s: %d (%s), sequence: %d, resource id: %d, major code: %d (%s), minor code: %d",
- message,
- int(error->error_code), xcb_errors[clamped_error_code],
- int(error->sequence), int(error->resource_id),
- int(error->major_code), xcb_protocol_request_codes[clamped_major_code],
- int(error->minor_code));
+ qCDebug(lcQpaXcb, "%s: %d (%s), sequence: %d, resource id: %d, major code: %d (%s), minor code: %d",
+ message,
+ int(error->error_code), xcb_errors[clamped_error_code],
+ int(error->sequence), int(error->resource_id),
+ int(error->major_code), xcb_protocol_request_codes[clamped_major_code],
+ int(error->minor_code));
}
static Qt::MouseButtons translateMouseButtons(int s)
@@ -459,7 +467,7 @@ static Qt::MouseButtons translateMouseButtons(int s)
if (s & XCB_BUTTON_MASK_1)
ret |= Qt::LeftButton;
if (s & XCB_BUTTON_MASK_2)
- ret |= Qt::MidButton;
+ ret |= Qt::MiddleButton;
if (s & XCB_BUTTON_MASK_3)
ret |= Qt::RightButton;
return ret;
@@ -475,7 +483,7 @@ Qt::MouseButton QXcbConnection::translateMouseButton(xcb_button_t s)
{
switch (s) {
case 1: return Qt::LeftButton;
- case 2: return Qt::MidButton;
+ case 2: return Qt::MiddleButton;
case 3: return Qt::RightButton;
// Button values 4-7 were already handled as Wheel events, and won't occur here.
case 8: return Qt::BackButton; // Also known as Qt::ExtraButton1
@@ -527,11 +535,7 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event)
if (Q_UNLIKELY(lcQpaEvents().isDebugEnabled()))
printXcbEvent(lcQpaEvents(), "Event", event);
-#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
qintptr result = 0; // Used only by MS Windows
-#else
- long result = 0; // Used only by MS Windows
-#endif
if (QAbstractEventDispatcher *dispatcher = QAbstractEventDispatcher::instance()) {
if (dispatcher->filterNativeEvent(m_nativeInterface->nativeEventType(), event, &result))
return;
@@ -545,6 +549,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
@@ -557,6 +562,9 @@ 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);
m_buttonState = (m_buttonState & ~0x7) | translateMouseButtons(ev->state);
setButtonState(translateMouseButton(ev->detail), false);
@@ -567,6 +575,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()))
@@ -574,8 +583,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:
@@ -587,24 +602,33 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event)
if (clientMessage->format != 32)
return;
#if QT_CONFIG(draganddrop)
- if (clientMessage->type == atom(QXcbAtom::XdndStatus))
+ if (clientMessage->type == atom(QXcbAtom::AtomXdndStatus))
drag()->handleStatus(clientMessage);
- else if (clientMessage->type == atom(QXcbAtom::XdndFinished))
+ else if (clientMessage->type == atom(QXcbAtom::AtomXdndFinished))
drag()->handleFinished(clientMessage);
#endif
- if (m_systemTrayTracker && clientMessage->type == atom(QXcbAtom::MANAGER))
+ if (m_systemTrayTracker && clientMessage->type == atom(QXcbAtom::AtomMANAGER))
m_systemTrayTracker->notifyManagerClientMessageEvent(clientMessage);
HANDLE_PLATFORM_WINDOW_EVENT(xcb_client_message_event_t, window, handleClientMessageEvent);
}
case XCB_ENTER_NOTIFY:
- if (hasXInput2() && !xi2MouseEventsDisabled())
+ if (hasXInput2()) {
+ // 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() && !xi2MouseEventsDisabled())
+ {
+ 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:
@@ -612,13 +636,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;
@@ -626,9 +655,10 @@ 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))
+ if (selectionRequest->selection == atom(QXcbAtom::AtomXdndSelection))
m_drag->handleSelectionRequest(selectionRequest);
else
#endif
@@ -650,15 +680,18 @@ 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)) {
+ if (propertyNotify->atom == atom(QXcbAtom::Atom_NET_WORKAREA)) {
QXcbVirtualDesktop *virtualDesktop = virtualDesktopForRootWindow(propertyNotify->window);
if (virtualDesktop)
virtualDesktop->updateWorkArea();
+ } else if (propertyNotify->atom == atom(QXcbAtom::Atom_NET_SUPPORTED)) {
+ m_wmSupport->updateNetWMAtoms();
} else {
HANDLE_PLATFORM_WINDOW_EVENT(xcb_property_notify_event_t, window, handlePropertyNotifyEvent);
}
@@ -684,20 +717,23 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event)
#ifndef QT_NO_CLIPBOARD
m_clipboard->handleXFixesSelectionRequest(notify_event);
#endif
- for (QXcbVirtualDesktop *virtualDesktop : qAsConst(m_virtualDesktops))
+ for (QXcbVirtualDesktop *virtualDesktop : std::as_const(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()) {
switch (xkb_event->any.xkbType) {
// XkbNewKkdNotify and XkbMapNotify together capture all sorts of keymap
- // updates (e.g. xmodmap, xkbcomp, setxkbmap), with minimal redundent recompilations.
+ // updates (e.g. xmodmap, xkbcomp, setxkbmap), with minimal redundant recompilations.
case XCB_XKB_STATE_NOTIFY:
m_keyboard->updateXKBState(&xkb_event->state_notify);
break;
@@ -739,6 +775,28 @@ void QXcbConnection::setMousePressWindow(QXcbWindow *w)
m_mousePressWindow = w;
}
+QByteArray QXcbConnection::startupId() const
+{
+ return m_startupId;
+}
+void QXcbConnection::setStartupId(const QByteArray &nextId)
+{
+ m_startupId = nextId;
+ if (m_clientLeader) {
+ if (!nextId.isEmpty())
+ xcb_change_property(xcb_connection(),
+ XCB_PROP_MODE_REPLACE,
+ clientLeader(),
+ atom(QXcbAtom::Atom_NET_STARTUP_ID),
+ atom(QXcbAtom::AtomUTF8_STRING),
+ 8,
+ nextId.size(),
+ nextId.constData());
+ else
+ xcb_delete_property(xcb_connection(), clientLeader(), atom(QXcbAtom::Atom_NET_STARTUP_ID));
+ }
+}
+
void QXcbConnection::grabServer()
{
if (m_canGrabServer)
@@ -751,19 +809,31 @@ void QXcbConnection::ungrabServer()
xcb_ungrab_server(xcb_connection());
}
+QString QXcbConnection::windowManagerName() const
+{
+ QXcbVirtualDesktop *pvd = primaryVirtualDesktop();
+ if (pvd)
+ return pvd->windowManagerName().toLower();
+
+ return QString();
+}
+
xcb_timestamp_t QXcbConnection::getTimestamp()
{
// send a dummy event to myself to get the timestamp from X server.
xcb_window_t window = rootWindow();
- xcb_atom_t dummyAtom = atom(QXcbAtom::CLIP_TEMPORARY);
- xcb_change_property(xcb_connection(), XCB_PROP_MODE_APPEND, window, dummyAtom,
+ xcb_atom_t dummyAtom = atom(QXcbAtom::Atom_QT_GET_TIMESTAMP);
+ xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, window, dummyAtom,
XCB_ATOM_INTEGER, 32, 0, nullptr);
connection()->flush();
xcb_generic_event_t *event = nullptr;
- while (!event) {
+ // When disconnection is caused by X server, event will never be able to hold
+ // a valid pointer. isConnected(), which calls xcb_connection_has_error(),
+ // can handle this type of disconnection and properly quits the loop.
+ while (isConnected() && !event) {
connection()->sync();
event = eventQueue()->peek([window, dummyAtom](xcb_generic_event_t *event, int type) {
if (type != XCB_PROPERTY_NOTIFY)
@@ -773,21 +843,33 @@ xcb_timestamp_t QXcbConnection::getTimestamp()
});
}
+ if (!event) {
+ // https://www.x.org/releases/X11R7.7/doc/xproto/x11protocol.html#glossary
+ // > One timestamp value (named CurrentTime) is never generated by the
+ // > server. This value is reserved for use in requests to represent the
+ // > current server time.
+ return XCB_CURRENT_TIME;
+ }
+
xcb_property_notify_event_t *pn = reinterpret_cast<xcb_property_notify_event_t *>(event);
xcb_timestamp_t timestamp = pn->time;
free(event);
- xcb_delete_property(xcb_connection(), window, dummyAtom);
-
return timestamp;
}
-xcb_window_t QXcbConnection::getSelectionOwner(xcb_atom_t atom) const
+xcb_window_t QXcbConnection::selectionOwner(xcb_atom_t atom) const
{
- return Q_XCB_REPLY(xcb_get_selection_owner, xcb_connection(), atom)->owner;
+ auto reply = Q_XCB_REPLY(xcb_get_selection_owner, xcb_connection(), atom);
+ if (!reply) {
+ qCDebug(lcQpaXcb) << "failed to query selection owner";
+ return XCB_NONE;
+ }
+
+ return reply->owner;
}
-xcb_window_t QXcbConnection::getQtSelectionOwner()
+xcb_window_t QXcbConnection::qtSelectionOwner()
{
if (!m_qtSelectionOwner) {
xcb_screen_t *xcbScreen = primaryVirtualDesktop()->screen();
@@ -803,10 +885,10 @@ xcb_window_t QXcbConnection::getQtSelectionOwner()
XCB_WINDOW_CLASS_INPUT_OUTPUT, // window class
xcbScreen->root_visual, // visual
0, // value mask
- nullptr); // value list
+ nullptr); // value list
QXcbWindow::setWindowTitle(connection(), m_qtSelectionOwner,
- QLatin1String("Qt Selection Owner for ") + QCoreApplication::applicationName());
+ "Qt Selection Owner for "_L1 + QCoreApplication::applicationName());
}
return m_qtSelectionOwner;
}
@@ -834,12 +916,12 @@ xcb_window_t QXcbConnection::clientLeader()
QXcbWindow::setWindowTitle(connection(), m_clientLeader,
- QStringLiteral("Qt Client Leader Window"));
+ QGuiApplication::applicationDisplayName());
xcb_change_property(xcb_connection(),
XCB_PROP_MODE_REPLACE,
m_clientLeader,
- atom(QXcbAtom::WM_CLIENT_LEADER),
+ atom(QXcbAtom::AtomWM_CLIENT_LEADER),
XCB_ATOM_WINDOW,
32,
1,
@@ -852,13 +934,15 @@ xcb_window_t QXcbConnection::clientLeader()
xcb_change_property(xcb_connection(),
XCB_PROP_MODE_REPLACE,
m_clientLeader,
- atom(QXcbAtom::SM_CLIENT_ID),
+ atom(QXcbAtom::AtomSM_CLIENT_ID),
XCB_ATOM_STRING,
8,
- session.length(),
+ session.size(),
session.constData());
}
#endif
+
+ setStartupId(startupId());
}
return m_clientLeader;
}
@@ -971,8 +1055,8 @@ bool QXcbConnection::isUserInputEvent(xcb_generic_event_t *event) const
if (eventType == XCB_CLIENT_MESSAGE) {
auto clientMessage = reinterpret_cast<const xcb_client_message_event_t *>(event);
- if (clientMessage->format == 32 && clientMessage->type == atom(QXcbAtom::WM_PROTOCOLS))
- if (clientMessage->data.data32[0] == atom(QXcbAtom::WM_DELETE_WINDOW))
+ if (clientMessage->format == 32 && clientMessage->type == atom(QXcbAtom::AtomWM_PROTOCOLS))
+ if (clientMessage->data.data32[0] == atom(QXcbAtom::AtomWM_DELETE_WINDOW))
isInputEvent = true;
}
@@ -1008,6 +1092,10 @@ void QXcbConnection::processXcbEvents(QEventLoop::ProcessEventsFlags flags)
m_eventQueue->flushBufferedEvents();
}
+#if QT_CONFIG(xcb_xlib)
+ qt_XFlush(static_cast<Display *>(xlib_display()));
+#endif
+
xcb_flush(xcb_connection());
}
@@ -1053,13 +1141,6 @@ Qt::MouseButtons QXcbConnection::queryMouseButtons() const
return translateMouseButtons(stateMask);
}
-Qt::KeyboardModifiers QXcbConnection::queryKeyboardModifiers() const
-{
- int stateMask = 0;
- QXcbCursor::queryPointer(connection(), nullptr, nullptr, &stateMask);
- return keyboard()->translateModifiers(stateMask);
-}
-
QXcbGlIntegration *QXcbConnection::glIntegration() const
{
if (m_glIntegrationInitialized)
@@ -1070,7 +1151,7 @@ QXcbGlIntegration *QXcbConnection::glIntegration() const
QString glIntegrationName = QString::fromLocal8Bit(qgetenv("QT_XCB_GL_INTEGRATION"));
if (!glIntegrationName.isEmpty()) {
qCDebug(lcQpaGl) << "QT_XCB_GL_INTEGRATION is set to" << glIntegrationName;
- if (glIntegrationName != QLatin1String("none")) {
+ if (glIntegrationName != "none"_L1) {
glIntegrationNames.removeAll(glIntegrationName);
glIntegrationNames.prepend(glIntegrationName);
} else {
@@ -1139,3 +1220,5 @@ void QXcbConnectionGrabber::release()
}
QT_END_NAMESPACE
+
+#include "moc_qxcbconnection.cpp"
diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h
index 8a4b577d2e..527744fe81 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.h
+++ b/src/plugins/platforms/xcb/qxcbconnection.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QXCBCONNECTION_H
#define QXCBCONNECTION_H
@@ -44,11 +8,11 @@
#include <xcb/randr.h>
#include <QtCore/QTimer>
+#include <QtGui/qpointingdevice.h>
#include <QtGui/private/qtguiglobal_p.h>
#include "qxcbexport.h"
#include <QHash>
#include <QList>
-#include <QVector>
#include <qpa/qwindowsysteminterface.h>
#include <QtCore/QLoggingCategory>
#include <QtCore/private/qglobal_p.h>
@@ -78,6 +42,8 @@ class QXcbScreen;
class QXcbWindow;
class QXcbDrag;
class QXcbKeyboard;
+class QXcbScrollingDevice;
+class QXcbScrollingDevicePrivate;
class QXcbClipboard;
class QXcbWMSupport;
class QXcbNativeInterface;
@@ -189,8 +155,8 @@ public:
inline void setNetWmUserTime(xcb_timestamp_t t) { if (timeGreaterThan(t, m_netWmUserTime)) m_netWmUserTime = t; }
xcb_timestamp_t getTimestamp();
- xcb_window_t getSelectionOwner(xcb_atom_t atom) const;
- xcb_window_t getQtSelectionOwner();
+ xcb_window_t selectionOwner(xcb_atom_t atom) const;
+ xcb_window_t qtSelectionOwner();
void setButtonState(Qt::MouseButton button, bool down);
Qt::MouseButtons buttonState() const { return m_buttonState; }
@@ -204,36 +170,35 @@ public:
QXcbWindow *mousePressWindow() const { return m_mousePressWindow; }
void setMousePressWindow(QXcbWindow *);
- QByteArray startupId() const { return m_startupId; }
- void setStartupId(const QByteArray &nextId) { m_startupId = nextId; }
- void clearStartupId() { m_startupId.clear(); }
+ QByteArray startupId() const;
+ void setStartupId(const QByteArray &nextId);
void grabServer();
void ungrabServer();
- bool isUnity() const { return m_xdgCurrentDesktop == "unity"; }
- bool isGnome() const { return m_xdgCurrentDesktop == "gnome"; }
+ QString windowManagerName() const;
QXcbNativeInterface *nativeInterface() const { return m_nativeInterface; }
QXcbSystemTrayTracker *systemTrayTracker() const;
Qt::MouseButtons queryMouseButtons() const;
- Qt::KeyboardModifiers queryKeyboardModifiers() const;
bool isUserInputEvent(xcb_generic_event_t *event) const;
void xi2SelectStateEvents();
void xi2SelectDeviceEvents(xcb_window_t window);
- void xi2SelectDeviceEventsCompatibility(xcb_window_t window);
bool xi2SetMouseGrabEnabled(xcb_window_t w, bool grab);
- bool xi2MouseEventsDisabled() const;
+
Qt::MouseButton xiToQtMouseButton(uint32_t b);
void xi2UpdateScrollingDevices();
- bool startSystemMoveResizeForTouch(xcb_window_t window, int edges);
- void abortSystemMoveResizeForTouch();
bool isTouchScreen(int id);
+ bool startSystemMoveResizeForTouch(xcb_window_t window, int edges);
+ void abortSystemMoveResize(xcb_window_t window);
+ bool isDuringSystemMoveResize() const;
+ void setDuringSystemMoveResize(bool during);
+
bool canGrab() const { return m_canGrabServer; }
QXcbGlIntegration *glIntegration() const;
@@ -258,15 +223,26 @@ 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 initializeScreensWithoutXRandR(xcb_screen_iterator_t *it, int screenNumber, QXcbScreen **primaryScreen);
+ 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; }
- void xi2SetupDevice(void *info, bool removeExisting = true);
+ void xi2SetupSlavePointerDevice(void *info, bool removeExisting = true, QPointingDevice *master = nullptr);
void xi2SetupDevices();
+ // TODO get rid of this: store minimal necessary info in a subclass of QPointingDevicePrivate
struct TouchDeviceData {
- QTouchDevice *qtTouchDevice = nullptr;
+ QPointingDevice *qtTouchDevice = nullptr;
QHash<int, QWindowSystemInterface::TouchPoint> touchPoints;
QHash<int, QPointF> pointPressedPosition; // in screen coordinates where each point was pressed
struct ValuatorClassInfo {
@@ -275,7 +251,7 @@ private:
int number = -1;
QXcbAtom::Atom label;
};
- QVector<ValuatorClassInfo> valuatorInfo;
+ QList<ValuatorClassInfo> valuatorInfo;
// Stuff that is relevant only for touchpads
QPointF firstPressedPosition; // in screen coordinates where the first point was pressed
@@ -283,17 +259,21 @@ private:
QSizeF size; // device size in mm
bool providesTouchOrientation = false;
};
- TouchDeviceData *populateTouchDevices(void *info);
+ TouchDeviceData *populateTouchDevices(void *info, QXcbScrollingDevicePrivate *scrollingDeviceP, bool *used = nullptr);
TouchDeviceData *touchDeviceForId(int id);
void xi2HandleEvent(xcb_ge_event_t *event);
+ void xi2HandleGesturePinchEvent(void *event);
+ void xi2HandleGestureSwipeEvent(void *event);
void xi2HandleHierarchyEvent(void *event);
void xi2HandleDeviceChangedEvent(void *event);
void xi2ProcessTouch(void *xiDevEvent, QXcbWindow *platformWindow);
#if QT_CONFIG(tabletevent)
+ // TODO get rid of this: store minimal necessary info in a subclass of QXcbScrollingDevice (some tablets can scroll)
struct TabletData {
int deviceId = 0;
- QTabletEvent::PointerType pointerType = QTabletEvent::UnknownPointer;
- QTabletEvent::TabletDevice tool = QTabletEvent::Stylus;
+ QString name;
+ QPointingDevice::PointerType pointerType = QPointingDevice::PointerType::Unknown;
+ QInputDevice::DeviceType tool = QInputDevice::DeviceType::Stylus;
Qt::MouseButtons buttons;
qint64 serialId = 0;
bool inProximity = false;
@@ -309,33 +289,24 @@ private:
friend class QTypeInfo<TabletData::ValuatorClassInfo>;
bool xi2HandleTabletEvent(const void *event, TabletData *tabletData);
void xi2ReportTabletEvent(const void *event, TabletData *tabletData);
- QVector<TabletData> m_tabletData;
+ QList<TabletData> m_tabletData;
TabletData *tabletDataForDevice(int id);
#endif // QT_CONFIG(tabletevent)
- struct ScrollingDevice {
- int deviceId = 0;
- int verticalIndex = 0;
- int horizontalIndex = 0;
- double verticalIncrement = 0;
- double horizontalIncrement = 0;
- Qt::Orientations orientations;
- Qt::Orientations legacyOrientations;
- QPointF lastScrollPosition;
- };
- QHash<int, ScrollingDevice> m_scrollingDevices;
- void xi2HandleScrollEvent(void *event, ScrollingDevice &scrollingDevice);
- void xi2UpdateScrollingDevice(ScrollingDevice &scrollingDevice);
- ScrollingDevice *scrollingDeviceForId(int id);
+ void xi2HandleScrollEvent(void *event, const QPointingDevice *scrollingDevice);
+ void xi2UpdateScrollingDevice(QInputDevice *scrollingDevice);
+ QXcbScrollingDevice *scrollingDeviceForId(int id);
static bool xi2GetValuatorValueIfSet(const void *event, int valuatorNum, double *value);
QHash<int, TouchDeviceData> m_touchDevices;
+
struct StartSystemMoveResizeInfo {
xcb_window_t window = XCB_NONE;
uint16_t deviceid;
uint32_t pointid;
int edges;
} m_startSystemMoveResizeInfo;
+ bool m_duringSystemMoveResize;
const bool m_canGrabServer;
const xcb_visualid_t m_defaultVisualId;
@@ -367,31 +338,35 @@ private:
QXcbWindow *m_mouseGrabber = nullptr;
QXcbWindow *m_mousePressWindow = nullptr;
+#if QT_CONFIG(gestures)
+ qreal m_lastPinchScale = 0;
+#endif
+
xcb_window_t m_clientLeader = 0;
QByteArray m_startupId;
QXcbSystemTrayTracker *m_systemTrayTracker = nullptr;
mutable QXcbGlIntegration *m_glIntegration = nullptr;
mutable bool m_glIntegrationInitialized = false;
bool m_xiGrab = false;
- QVector<int> m_xiMasterPointerIds;
+ QList<int> m_xiMasterPointerIds;
+ QList<int> m_xiSlavePointerIds;
xcb_window_t m_qtSelectionOwner = 0;
friend class QXcbEventQueue;
- QByteArray m_xdgCurrentDesktop;
QTimer m_focusInTimer;
};
#if QT_CONFIG(tabletevent)
Q_DECLARE_TYPEINFO(QXcbConnection::TabletData::ValuatorClassInfo, Q_PRIMITIVE_TYPE);
-Q_DECLARE_TYPEINFO(QXcbConnection::TabletData, Q_MOVABLE_TYPE);
+Q_DECLARE_TYPEINFO(QXcbConnection::TabletData, Q_RELOCATABLE_TYPE);
#endif
class QXcbConnectionGrabber
{
public:
- QXcbConnectionGrabber(QXcbConnection *connection);
+ Q_NODISCARD_CTOR QXcbConnectionGrabber(QXcbConnection *connection);
~QXcbConnectionGrabber();
void release();
private:
diff --git a/src/plugins/platforms/xcb/qxcbconnection_basic.cpp b/src/plugins/platforms/xcb/qxcbconnection_basic.cpp
index 18dee89adb..6416003bea 100644
--- a/src/plugins/platforms/xcb/qxcbconnection_basic.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection_basic.cpp
@@ -1,49 +1,13 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and 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$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qxcbconnection_basic.h"
#include "qxcbbackingstore.h" // for createSystemVShmSegment()
+#include "private/qoffsetstringarray_p.h"
#include <xcb/randr.h>
#include <xcb/shm.h>
#include <xcb/sync.h>
#include <xcb/xfixes.h>
-#include <xcb/xinerama.h>
#include <xcb/render.h>
#include <xcb/xinput.h>
#define explicit dont_use_cxx_explicit
@@ -64,7 +28,7 @@ QT_BEGIN_NAMESPACE
Q_LOGGING_CATEGORY(lcQpaXcb, "qt.qpa.xcb")
#if QT_CONFIG(xcb_xlib)
-static const char * const xcbConnectionErrors[] = {
+static constexpr auto xcbConnectionErrors = qOffsetStringArray(
"No error", /* Error 0 */
"I/O error", /* XCB_CONN_ERROR */
"Unsupported extension used", /* XCB_CONN_CLOSED_EXT_NOTSUPPORTED */
@@ -73,7 +37,7 @@ static const char * const xcbConnectionErrors[] = {
"Failed to parse display string", /* XCB_CONN_CLOSED_PARSE_ERR */
"No such screen on display", /* XCB_CONN_CLOSED_INVALID_SCREEN */
"Error during FD passing" /* XCB_CONN_CLOSED_FDPASSING_FAILED */
-};
+);
static int nullErrorHandler(Display *dpy, XErrorEvent *err)
{
@@ -97,8 +61,7 @@ static int ioErrorHandler(Display *dpy)
/* Print a message with a textual description of the error */
int code = xcb_connection_has_error(conn);
const char *str = "Unknown error";
- int arrayLength = sizeof(xcbConnectionErrors) / sizeof(xcbConnectionErrors[0]);
- if (code >= 0 && code < arrayLength)
+ if (code >= 0 && code < xcbConnectionErrors.count())
str = xcbConnectionErrors[code];
qWarning("The X11 connection broke: %s (code %d)", str, code);
@@ -145,8 +108,6 @@ QXcbBasicConnection::QXcbBasicConnection(const char *displayName)
initializeShm();
if (!qEnvironmentVariableIsSet("QT_XCB_NO_XRANDR"))
initializeXRandr();
- if (!m_hasXRandr)
- initializeXinerama();
initializeXFixes();
initializeXRender();
if (!qEnvironmentVariableIsSet("QT_XCB_NO_XI2"))
@@ -179,7 +140,13 @@ xcb_atom_t QXcbBasicConnection::internAtom(const char *name)
if (!name || *name == 0)
return XCB_NONE;
- return Q_XCB_REPLY(xcb_intern_atom, m_xcbConnection, false, strlen(name), name)->atom;
+ auto reply = Q_XCB_REPLY(xcb_intern_atom, m_xcbConnection, false, strlen(name), name);
+ if (!reply) {
+ qCDebug(lcQpaXcb) << "failed to query intern atom: " << name;
+ return XCB_NONE;
+ }
+
+ return reply->atom;
}
QByteArray QXcbBasicConnection::atomName(xcb_atom_t atom)
@@ -307,17 +274,6 @@ void QXcbBasicConnection::initializeXRender()
m_xrenderVersion.second = xrenderQuery->minor_version;
}
-void QXcbBasicConnection::initializeXinerama()
-{
- const xcb_query_extension_reply_t *reply = xcb_get_extension_data(m_xcbConnection, &xcb_xinerama_id);
- if (!reply || !reply->present)
- return;
-
- auto xineramaActive = Q_XCB_REPLY(xcb_xinerama_is_active, m_xcbConnection);
- if (xineramaActive && xineramaActive->state)
- m_hasXinerama = true;
-}
-
void QXcbBasicConnection::initializeXFixes()
{
const xcb_query_extension_reply_t *reply = xcb_get_extension_data(m_xcbConnection, &xcb_xfixes_id);
@@ -347,11 +303,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;
}
@@ -363,7 +322,9 @@ void QXcbBasicConnection::initializeXInput2()
return;
}
- auto xinputQuery = Q_XCB_REPLY(xcb_input_xi_query_version, m_xcbConnection, 2, 2);
+ // depending on whether bundled xcb is used we may support different XCB protocol versions.
+ auto xinputQuery = Q_XCB_REPLY(xcb_input_xi_query_version, m_xcbConnection,
+ 2, XCB_INPUT_MINOR_VERSION);
if (!xinputQuery || xinputQuery->major_version != 2) {
qCWarning(lcQpaXcb, "X server does not support XInput 2");
return;
@@ -424,3 +385,5 @@ void QXcbBasicConnection::initializeXKB()
}
QT_END_NAMESPACE
+
+#include "moc_qxcbconnection_basic.cpp"
diff --git a/src/plugins/platforms/xcb/qxcbconnection_basic.h b/src/plugins/platforms/xcb/qxcbconnection_basic.h
index 109186f966..d44805b382 100644
--- a/src/plugins/platforms/xcb/qxcbconnection_basic.h
+++ b/src/plugins/platforms/xcb/qxcbconnection_basic.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and 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$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QXCBBASICCONNECTION_H
#define QXCBBASICCONNECTION_H
@@ -96,11 +60,14 @@ public:
bool hasShm() const { return m_hasShm; }
bool hasShmFd() const { return m_hasShmFd; }
bool hasXSync() const { return m_hasXSync; }
- bool hasXinerama() const { return m_hasXinerama; }
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 isAtLeastXI24() const { return m_xi2Enabled && m_xi2Minor >= 4; }
bool isXIEvent(xcb_generic_event_t *event) const;
bool isXIType(xcb_generic_event_t *event, uint16_t type) const;
@@ -113,7 +80,6 @@ protected:
void initializeXFixes();
void initializeXRender();
void initializeXRandr();
- void initializeXinerama();
void initializeXShape();
void initializeXKB();
void initializeXSync();
@@ -130,7 +96,6 @@ private:
QXcbAtom m_xcbAtom;
bool m_hasXFixes = false;
- bool m_hasXinerama = false;
bool m_hasXhape = false;
bool m_hasInputShape;
bool m_hasXRandr = false;
@@ -147,6 +112,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 9ba71ada37..c31e9b1039 100644
--- a/src/plugins/platforms/xcb/qxcbconnection_screens.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection_screens.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and 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$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qxcbconnection.h"
#include "qxcbscreen.h"
#include "qxcbintegration.h"
@@ -46,8 +10,6 @@
#include <qpa/qwindowsysteminterface.h>
-#include <xcb/xinerama.h>
-
void QXcbConnection::xrandrSelectEvents()
{
xcb_screen_iterator_t rootIter = xcb_setup_roots_iterator(setup());
@@ -65,8 +27,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;
@@ -75,8 +44,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;
@@ -158,7 +134,6 @@ void QXcbConnection::updateScreens(const xcb_randr_notify_event_t *event)
screen = createScreen(virtualDesktop, output, outputInfo.get());
qCDebug(lcQpaScreen) << "output" << screen->name() << "is connected and enabled";
}
- QHighDpiScaling::updateHighDpiScaling();
}
} else if (screen) {
if (output.crtc == XCB_NONE && output.mode == XCB_NONE) {
@@ -180,7 +155,7 @@ void QXcbConnection::updateScreens(const xcb_randr_notify_event_t *event)
}
}
- qCDebug(lcQpaScreen) << "primary output is" << qAsConst(m_screens).first()->name();
+ qCDebug(lcQpaScreen) << "updateScreens: primary output is" << std::as_const(m_screens).first()->name();
}
}
@@ -209,7 +184,7 @@ void QXcbConnection::updateScreen(QXcbScreen *screen, const xcb_randr_output_cha
// If the screen became primary, reshuffle the order in QGuiApplicationPrivate
const int idx = m_screens.indexOf(screen);
if (idx > 0) {
- qAsConst(m_screens).first()->setPrimary(false);
+ std::as_const(m_screens).first()->setPrimary(false);
m_screens.swapItemsAt(0, idx);
}
screen->virtualDesktop()->setPrimaryScreen(screen);
@@ -229,7 +204,7 @@ QXcbScreen *QXcbConnection::createScreen(QXcbVirtualDesktop *virtualDesktop,
if (screen->isPrimary()) {
if (!m_screens.isEmpty())
- qAsConst(m_screens).first()->setPrimary(false);
+ std::as_const(m_screens).first()->setPrimary(false);
m_screens.prepend(screen);
} else {
@@ -244,7 +219,7 @@ QXcbScreen *QXcbConnection::createScreen(QXcbVirtualDesktop *virtualDesktop,
void QXcbConnection::destroyScreen(QXcbScreen *screen)
{
QXcbVirtualDesktop *virtualDesktop = screen->virtualDesktop();
- if (virtualDesktop->screens().count() == 1) {
+ if (virtualDesktop->screens().size() == 1) {
// If there are no other screens on the same virtual desktop,
// then transform the physical screen into a fake screen.
const QString nameWas = screen->name();
@@ -266,151 +241,332 @@ 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) {
+ std::as_const(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())
+ std::as_const(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 (monitorInfo) {
+ QByteArray ba2 = atomName(monitorInfo->name);
+ if (s->name().toLocal8Bit() == 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;
+ if (isAtLeastXRandR15() && initialized)
+ m_screens.clear();
+
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);
- if (!resources_current) {
- qWarning("failed to get the current screen resources");
+ if (isAtLeastXRandR15())
+ initializeScreensFromMonitor(&it, xcbScreenNumber, &primaryScreen, initialized);
+ else if (isAtLeastXRandR12())
+ initializeScreensFromOutput(&it, xcbScreenNumber, &primaryScreen);
+ else {
+ qWarning("There is no XRandR 1.2 and later version available. There will be only fake screen(s) to use.");
+ initializeScreensWithoutXRandR(&it, xcbScreenNumber, &primaryScreen);
+ }
+
+ xcb_screen_next(&it);
+ ++xcbScreenNumber;
+ }
+
+ for (QXcbVirtualDesktop *virtualDesktop : std::as_const(m_virtualDesktops))
+ virtualDesktop->subscribeToXFixesSelectionNotify();
+
+ if (m_virtualDesktops.isEmpty()) {
+ qFatal("QXcbConnection: no screens available");
+ } else {
+ // Ensure the primary screen is first on the list
+ if (primaryScreen) {
+ if (std::as_const(m_screens).first() != primaryScreen) {
+ m_screens.removeOne(primaryScreen);
+ m_screens.prepend(primaryScreen);
+ }
+ }
+
+ // Push the screens to QGuiApplication
+ if (!initialized) {
+ for (QXcbScreen *screen : std::as_const(m_screens)) {
+ qCDebug(lcQpaScreen) << "adding" << screen << "(Primary:" << screen->isPrimary() << ")";
+ QWindowSystemInterface::handleScreenAdded(screen, screen->isPrimary());
+ }
+ }
+
+ if (!m_screens.isEmpty())
+ qCDebug(lcQpaScreen) << "initializeScreens: primary output is" << std::as_const(m_screens).first()->name();
+ }
+}
+
+void QXcbConnection::initializeScreensWithoutXRandR(xcb_screen_iterator_t *it, int xcbScreenNumber, QXcbScreen **primaryScreen)
+{
+ // XRandR extension is missing, then create a fake/legacy screen.
+ xcb_screen_t *xcbScreen = it->data;
+ QXcbVirtualDesktop *virtualDesktop = new QXcbVirtualDesktop(this, xcbScreen, xcbScreenNumber);
+ m_virtualDesktops.append(virtualDesktop);
+ QList<QPlatformScreen *> siblings;
+
+ 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::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 {
- 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());
+ resources = Q_XCB_REPLY(xcb_randr_get_screen_resources,
+ xcb_connection(), xcbScreen->root);
+ if (!resources) {
+ qWarning("failed to get the screen resources");
} else {
- auto 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());
- }
+ 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 (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 (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());
- }
+ 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());
}
}
}
}
}
- } else if (hasXinerama()) {
- // Xinerama is available
- auto screens = Q_XCB_REPLY(xcb_xinerama_query_screens, xcb_connection());
- if (screens) {
- xcb_xinerama_screen_info_iterator_t it = xcb_xinerama_query_screens_screen_info_iterator(screens.get());
- while (it.rem) {
- xcb_xinerama_screen_info_t *screen_info = it.data;
- QXcbScreen *screen = new QXcbScreen(this, virtualDesktop,
- XCB_NONE, nullptr,
- screen_info, it.index);
- siblings << screen;
- m_screens << screen;
- xcb_xinerama_screen_info_next(&it);
- }
- }
}
- 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;
+ }
+ 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);
}
- virtualDesktop->setScreens(std::move(siblings));
- xcb_screen_next(&it);
- ++xcbScreenNumber;
- } // for each xcb screen
+ siblings << screen;
+ }
+ virtualDesktop->setScreens(std::move(siblings));
+}
- for (QXcbVirtualDesktop *virtualDesktop : qAsConst(m_virtualDesktops))
- virtualDesktop->subscribeToXFixesSelectionNotify();
+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);
+ }
- if (m_virtualDesktops.isEmpty()) {
- qFatal("QXcbConnection: no screens available");
- } else {
- // Ensure the primary screen is first on the list
- if (primaryScreen) {
- if (qAsConst(m_screens).first() != primaryScreen) {
- m_screens.removeOne(primaryScreen);
- m_screens.prepend(primaryScreen);
+ if (xcbScreenNumber != primaryScreenNumber())
+ return;
+
+ QList<QPlatformScreen*> old = virtualDesktop->m_screens;
+
+ 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);
+ } else {
+ screen = findScreenForMonitorInfo(old, monitor_info);
+ if (!screen) {
+ screen = createScreen_monitor(virtualDesktop, monitor_info, monitors_r->timestamp);
+ } else {
+ updateScreen_monitor(screen, monitor_info, monitors_r->timestamp);
+ old.removeAll(screen);
}
}
+ if (!m_screens.contains(screen))
+ m_screens << screen;
+ siblings << screen;
+
+ // similar logic with QXcbConnection::initializeScreensFromOutput()
+ if (!(*primaryScreen) || monitor_info->primary) {
+ if (*primaryScreen)
+ (*primaryScreen)->setPrimary(false);
+ *primaryScreen = screen;
+ (*primaryScreen)->setPrimary(true);
+ siblings.prepend(siblings.takeLast());
+ }
- // Push the screens to QGuiApplication
- for (QXcbScreen *screen : qAsConst(m_screens)) {
- qCDebug(lcQpaScreen) << "adding" << screen << "(Primary:" << screen->isPrimary() << ")";
- QWindowSystemInterface::handleScreenAdded(screen, screen->isPrimary());
+ xcb_randr_monitor_info_next(&monitor_iter);
+ }
+ free(monitors_r);
+
+ 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;
}
- qCDebug(lcQpaScreen) << "primary output is" << qAsConst(m_screens).first()->name();
+ *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 4620f0fd1d..4f62a1880b 100644
--- a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp
@@ -1,61 +1,43 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qxcbconnection.h"
#include "qxcbkeyboard.h"
+#include "qxcbscrollingdevice_p.h"
#include "qxcbscreen.h"
#include "qxcbwindow.h"
-#include "qtouchdevice.h"
#include "QtCore/qmetaobject.h"
+#include "QtCore/qmath.h"
+#include <QtGui/qpointingdevice.h>
+#include <QtGui/private/qpointingdevice_p.h>
#include <qpa/qwindowsysteminterface_p.h>
#include <QDebug>
-#include <cmath>
#include <xcb/xinput.h>
+#if QT_CONFIG(gestures)
+#define QT_XCB_HAS_TOUCHPAD_GESTURES (XCB_INPUT_MINOR_VERSION >= 4)
+#endif
+
+using namespace Qt::StringLiterals;
+
using qt_xcb_input_device_event_t = xcb_input_button_press_event_t;
+#if QT_XCB_HAS_TOUCHPAD_GESTURES
+using qt_xcb_input_pinch_event_t = xcb_input_gesture_pinch_begin_event_t;
+using qt_xcb_input_swipe_event_t = xcb_input_gesture_swipe_begin_event_t;
+#endif
struct qt_xcb_input_event_mask_t {
xcb_input_event_mask_t header;
- uint32_t mask;
+ alignas(4) uint8_t mask[8] = {}; // up to 2 units of 4 bytes
};
+static inline void setXcbMask(uint8_t* mask, int bit)
+{
+ // note that XI protocol always uses little endian for masks over the wire
+ mask[bit >> 3] |= 1 << (bit & 7);
+}
+
void QXcbConnection::xi2SelectStateEvents()
{
// These state events do not depend on a specific X window, but are global
@@ -63,9 +45,9 @@ void QXcbConnection::xi2SelectStateEvents()
qt_xcb_input_event_mask_t xiEventMask;
xiEventMask.header.deviceid = XCB_INPUT_DEVICE_ALL;
xiEventMask.header.mask_len = 1;
- xiEventMask.mask = XCB_INPUT_XI_EVENT_MASK_HIERARCHY;
- xiEventMask.mask |= XCB_INPUT_XI_EVENT_MASK_DEVICE_CHANGED;
- xiEventMask.mask |= XCB_INPUT_XI_EVENT_MASK_PROPERTY;
+ setXcbMask(xiEventMask.mask, XCB_INPUT_HIERARCHY);
+ setXcbMask(xiEventMask.mask, XCB_INPUT_DEVICE_CHANGED);
+ setXcbMask(xiEventMask.mask, XCB_INPUT_PROPERTY);
xcb_input_xi_select_events(xcb_connection(), rootWindow(), 1, &xiEventMask.header);
}
@@ -74,23 +56,33 @@ void QXcbConnection::xi2SelectDeviceEvents(xcb_window_t window)
if (window == rootWindow())
return;
- uint32_t bitMask = XCB_INPUT_XI_EVENT_MASK_BUTTON_PRESS;
- bitMask |= XCB_INPUT_XI_EVENT_MASK_BUTTON_RELEASE;
- bitMask |= XCB_INPUT_XI_EVENT_MASK_MOTION;
+ qt_xcb_input_event_mask_t mask;
+
+ setXcbMask(mask.mask, XCB_INPUT_BUTTON_PRESS);
+ setXcbMask(mask.mask, XCB_INPUT_BUTTON_RELEASE);
+ setXcbMask(mask.mask, XCB_INPUT_MOTION);
// There is a check for enter/leave events in plain xcb enter/leave event handler,
// core enter/leave events will be ignored in this case.
- bitMask |= XCB_INPUT_XI_EVENT_MASK_ENTER;
- bitMask |= XCB_INPUT_XI_EVENT_MASK_LEAVE;
+ setXcbMask(mask.mask, XCB_INPUT_ENTER);
+ setXcbMask(mask.mask, XCB_INPUT_LEAVE);
if (isAtLeastXI22()) {
- bitMask |= XCB_INPUT_XI_EVENT_MASK_TOUCH_BEGIN;
- bitMask |= XCB_INPUT_XI_EVENT_MASK_TOUCH_UPDATE;
- bitMask |= XCB_INPUT_XI_EVENT_MASK_TOUCH_END;
+ setXcbMask(mask.mask, XCB_INPUT_TOUCH_BEGIN);
+ setXcbMask(mask.mask, XCB_INPUT_TOUCH_UPDATE);
+ setXcbMask(mask.mask, XCB_INPUT_TOUCH_END);
}
+#if QT_CONFIG(gestures) && QT_XCB_HAS_TOUCHPAD_GESTURES
+ if (isAtLeastXI24()) {
+ setXcbMask(mask.mask, XCB_INPUT_GESTURE_PINCH_BEGIN);
+ setXcbMask(mask.mask, XCB_INPUT_GESTURE_PINCH_UPDATE);
+ setXcbMask(mask.mask, XCB_INPUT_GESTURE_PINCH_END);
+ setXcbMask(mask.mask, XCB_INPUT_GESTURE_SWIPE_BEGIN);
+ setXcbMask(mask.mask, XCB_INPUT_GESTURE_SWIPE_UPDATE);
+ setXcbMask(mask.mask, XCB_INPUT_GESTURE_SWIPE_END);
+ }
+#endif // QT_CONFIG(gestures) && QT_XCB_HAS_TOUCHPAD_GESTURES
- qt_xcb_input_event_mask_t mask;
- mask.header.deviceid = XCB_INPUT_DEVICE_ALL_MASTER;
- mask.header.mask_len = 1;
- mask.mask = bitMask;
+ mask.header.deviceid = XCB_INPUT_DEVICE_ALL;
+ mask.header.mask_len = 2;
xcb_void_cookie_t cookie =
xcb_input_xi_select_events_checked(xcb_connection(), window, 1, &mask.header);
xcb_generic_error_t *error = xcb_request_check(xcb_connection(), cookie);
@@ -107,27 +99,163 @@ static inline qreal fixed3232ToReal(xcb_input_fp3232_t val)
return qreal(val.integral) + qreal(val.frac) / (1ULL << 32);
}
-void QXcbConnection::xi2SetupDevice(void *info, bool removeExisting)
+#if QT_CONFIG(tabletevent)
+/*!
+ \internal
+ Find the existing QPointingDevice instance representing a particular tablet or stylus;
+ or create and register a new instance if it was not found.
+
+ An instance can be uniquely identified by its \a devType, \a pointerType and \a uniqueId.
+ The rest of the arguments are necessary to create a new instance.
+
+ If the instance represents a stylus, the instance representing the tablet
+ itself must be given as \a master. Otherwise, \a master must be the xinput
+ master device (core pointer) to which the tablet belongs. It should not be
+ null, because \a master is also the QObject::parent() for memory management.
+
+ Proximity events have incomplete information. So as a side effect, if an
+ existing instance is found, it is updated with the given \a usbId and
+ \a toolId, and the seat ID of \a master, in case those values were only
+ now discovered, or the seat assignment changed (?).
+*/
+static const QPointingDevice *tabletToolInstance(QPointingDevice *master, const QString &tabletName,
+ qint64 id, quint32 usbId, quint32 toolId, qint64 uniqueId,
+ QPointingDevice::PointerType pointerTypeOverride = QPointingDevice::PointerType::Unknown,
+ QPointingDevice::Capabilities capsOverride = QInputDevice::Capability::None)
+{
+ QInputDevice::DeviceType devType = QInputDevice::DeviceType::Stylus;
+ QPointingDevice::PointerType pointerType = QPointingDevice::PointerType::Pen;
+ QPointingDevice::Capabilities caps = QInputDevice::Capability::Position |
+ QInputDevice::Capability::Pressure |
+ QInputDevice::Capability::MouseEmulation |
+ QInputDevice::Capability::Hover |
+ capsOverride;
+ int buttonCount = 3; // the tip, plus two barrel buttons
+ // keep in sync with wacom_intuos_inout() in Linux kernel driver wacom_wac.c
+ // TODO yeah really, there are many more now so this needs updating
+ switch (toolId) {
+ case 0xd12:
+ case 0x912:
+ case 0x112:
+ case 0x913: /* Intuos3 Airbrush */
+ case 0x902: /* Intuos4/5 13HD/24HD Airbrush */
+ case 0x100902: /* Intuos4/5 13HD/24HD Airbrush */
+ devType = QInputDevice::DeviceType::Airbrush;
+ caps.setFlag(QInputDevice::Capability::XTilt);
+ caps.setFlag(QInputDevice::Capability::YTilt);
+ caps.setFlag(QInputDevice::Capability::TangentialPressure);
+ buttonCount = 2;
+ break;
+ case 0x91b: /* Intuos3 Airbrush Eraser */
+ case 0x90a: /* Intuos4/5 13HD/24HD Airbrush Eraser */
+ case 0x10090a: /* Intuos4/5 13HD/24HD Airbrush Eraser */
+ devType = QInputDevice::DeviceType::Airbrush;
+ pointerType = QPointingDevice::PointerType::Eraser;
+ caps.setFlag(QInputDevice::Capability::XTilt);
+ caps.setFlag(QInputDevice::Capability::YTilt);
+ caps.setFlag(QInputDevice::Capability::TangentialPressure);
+ buttonCount = 2;
+ break;
+ case 0x007: /* Mouse 4D and 2D */
+ case 0x09c:
+ case 0x094:
+ // TODO set something to indicate a multi-dimensional capability:
+ // Capability::3D or 4D or QPointingDevice::setMaximumDimensions()?
+ devType = QInputDevice::DeviceType::Mouse;
+ buttonCount = 5; // TODO only if it's a 4D Mouse
+ break;
+ case 0x017: /* Intuos3 2D Mouse */
+ case 0x806: /* Intuos4 Mouse */
+ devType = QInputDevice::DeviceType::Mouse;
+ break;
+ case 0x096: /* Lens cursor */
+ case 0x097: /* Intuos3 Lens cursor */
+ case 0x006: /* Intuos4 Lens cursor */
+ devType = QInputDevice::DeviceType::Puck;
+ break;
+ case 0x885: /* Intuos3 Art Pen (Marker Pen) */
+ case 0x100804: /* Intuos4/5 13HD/24HD Art Pen */
+ caps.setFlag(QInputDevice::Capability::XTilt);
+ caps.setFlag(QInputDevice::Capability::YTilt);
+ caps.setFlag(QInputDevice::Capability::Rotation);
+ buttonCount = 1;
+ break;
+ case 0x10080c: /* Intuos4/5 13HD/24HD Art Pen Eraser */
+ pointerType = QPointingDevice::PointerType::Eraser;
+ caps.setFlag(QInputDevice::Capability::XTilt);
+ caps.setFlag(QInputDevice::Capability::YTilt);
+ caps.setFlag(QInputDevice::Capability::Rotation);
+ buttonCount = 1;
+ break;
+ case 0:
+ pointerType = QPointingDevice::PointerType::Unknown;
+ break;
+ }
+ if (pointerTypeOverride != QPointingDevice::PointerType::Unknown)
+ pointerType = pointerTypeOverride;
+ const QPointingDevice *ret = QPointingDevicePrivate::queryTabletDevice(devType, pointerType,
+ QPointingDeviceUniqueId::fromNumericId(uniqueId),
+ caps, id);
+ if (!ret) {
+ ret = new QPointingDevice(tabletName, id, devType, pointerType, caps, 1, buttonCount,
+ master ? master->seatName() : QString(),
+ QPointingDeviceUniqueId::fromNumericId(uniqueId), master);
+ QWindowSystemInterface::registerInputDevice(ret);
+ }
+ QPointingDevicePrivate *devPriv = QPointingDevicePrivate::get(const_cast<QPointingDevice *>(ret));
+ devPriv->busId = QString::number(usbId, 16);
+ devPriv->toolId = toolId;
+ if (master)
+ devPriv->seatName = master->seatName();
+ return ret;
+}
+
+static const char *toolName(QInputDevice::DeviceType tool) {
+ static const QMetaObject *metaObject = qt_getEnumMetaObject(tool);
+ static const QMetaEnum me = metaObject->enumerator(metaObject->indexOfEnumerator(qt_getEnumName(tool)));
+ return me.valueToKey(int(tool));
+}
+
+static const char *pointerTypeName(QPointingDevice::PointerType ptype) {
+ static const QMetaObject *metaObject = qt_getEnumMetaObject(ptype);
+ static const QMetaEnum me = metaObject->enumerator(metaObject->indexOfEnumerator(qt_getEnumName(ptype)));
+ return me.valueToKey(int(ptype));
+}
+#endif
+
+void QXcbConnection::xi2SetupSlavePointerDevice(void *info, bool removeExisting, QPointingDevice *master)
{
auto *deviceInfo = reinterpret_cast<xcb_input_xi_device_info_t *>(info);
if (removeExisting) {
#if QT_CONFIG(tabletevent)
- for (int i = 0; i < m_tabletData.count(); ++i) {
+ for (int i = 0; i < m_tabletData.size(); ++i) {
if (m_tabletData.at(i).deviceId == deviceInfo->deviceid) {
m_tabletData.remove(i);
break;
}
}
#endif
- m_scrollingDevices.remove(deviceInfo->deviceid);
m_touchDevices.remove(deviceInfo->deviceid);
}
- qCDebug(lcQpaXInputDevices) << "input device " << xcb_input_xi_device_info_name(deviceInfo) << "ID" << deviceInfo->deviceid;
+ const QByteArray nameRaw = QByteArray(xcb_input_xi_device_info_name(deviceInfo),
+ xcb_input_xi_device_info_name_length(deviceInfo));
+ const QString name = QString::fromUtf8(nameRaw);
+ m_xiSlavePointerIds.append(deviceInfo->deviceid);
+ qCDebug(lcQpaXInputDevices) << "input device " << name << "ID" << deviceInfo->deviceid;
#if QT_CONFIG(tabletevent)
TabletData tabletData;
#endif
- ScrollingDevice scrollingDevice;
+ QXcbScrollingDevicePrivate *scrollingDeviceP = nullptr;
+ bool used = false;
+ auto scrollingDevice = [&]() {
+ if (!scrollingDeviceP)
+ scrollingDeviceP = new QXcbScrollingDevicePrivate(name, deviceInfo->deviceid,
+ QInputDevice::Capability::Scroll);
+ return scrollingDeviceP;
+ };
+
+ int buttonCount = 32;
auto classes_it = xcb_input_xi_device_info_classes_iterator(deviceInfo);
for (; classes_it.rem; xcb_input_device_class_next(&classes_it)) {
xcb_input_device_class_t *classinfo = classes_it.data;
@@ -145,22 +273,24 @@ void QXcbConnection::xi2SetupDevice(void *info, bool removeExisting)
tabletData.valuatorInfo[valuatorAtom] = info;
}
#endif // QT_CONFIG(tabletevent)
- if (valuatorAtom == QXcbAtom::RelHorizScroll || valuatorAtom == QXcbAtom::RelHorizWheel)
- scrollingDevice.lastScrollPosition.setX(fixed3232ToReal(vci->value));
- else if (valuatorAtom == QXcbAtom::RelVertScroll || valuatorAtom == QXcbAtom::RelVertWheel)
- scrollingDevice.lastScrollPosition.setY(fixed3232ToReal(vci->value));
+ if (valuatorAtom == QXcbAtom::AtomRelHorizScroll || valuatorAtom == QXcbAtom::AtomRelHorizWheel)
+ scrollingDevice()->lastScrollPosition.setX(fixed3232ToReal(vci->value));
+ else if (valuatorAtom == QXcbAtom::AtomRelVertScroll || valuatorAtom == QXcbAtom::AtomRelVertWheel)
+ scrollingDevice()->lastScrollPosition.setY(fixed3232ToReal(vci->value));
break;
}
case XCB_INPUT_DEVICE_CLASS_TYPE_SCROLL: {
auto *sci = reinterpret_cast<xcb_input_scroll_class_t *>(classinfo);
if (sci->scroll_type == XCB_INPUT_SCROLL_TYPE_VERTICAL) {
- scrollingDevice.orientations |= Qt::Vertical;
- scrollingDevice.verticalIndex = sci->number;
- scrollingDevice.verticalIncrement = fixed3232ToReal(sci->increment);
+ auto dev = scrollingDevice();
+ dev->orientations.setFlag(Qt::Vertical);
+ dev->verticalIndex = sci->number;
+ dev->verticalIncrement = fixed3232ToReal(sci->increment);
} else if (sci->scroll_type == XCB_INPUT_SCROLL_TYPE_HORIZONTAL) {
- scrollingDevice.orientations |= Qt::Horizontal;
- scrollingDevice.horizontalIndex = sci->number;
- scrollingDevice.horizontalIncrement = fixed3232ToReal(sci->increment);
+ auto dev = scrollingDevice();
+ dev->orientations.setFlag(Qt::Horizontal);
+ dev->horizontalIndex = sci->number;
+ dev->horizontalIncrement = fixed3232ToReal(sci->increment);
}
break;
}
@@ -173,16 +303,17 @@ void QXcbConnection::xi2SetupDevice(void *info, bool removeExisting)
xcb_atom_t label5 = labels[4];
// Some drivers have no labels on the wheel buttons, some have no label on just one and some have no label on
// button 4 and the wrong one on button 5. So we just check that they are not labelled with unrelated buttons.
- if ((!label4 || qatom(label4) == QXcbAtom::ButtonWheelUp || qatom(label4) == QXcbAtom::ButtonWheelDown) &&
- (!label5 || qatom(label5) == QXcbAtom::ButtonWheelUp || qatom(label5) == QXcbAtom::ButtonWheelDown))
- scrollingDevice.legacyOrientations |= Qt::Vertical;
+ if ((!label4 || qatom(label4) == QXcbAtom::AtomButtonWheelUp || qatom(label4) == QXcbAtom::AtomButtonWheelDown) &&
+ (!label5 || qatom(label5) == QXcbAtom::AtomButtonWheelUp || qatom(label5) == QXcbAtom::AtomButtonWheelDown))
+ scrollingDevice()->legacyOrientations |= Qt::Vertical;
}
if (bci->num_buttons >= 7) {
xcb_atom_t label6 = labels[5];
xcb_atom_t label7 = labels[6];
- if ((!label6 || qatom(label6) == QXcbAtom::ButtonHorizWheelLeft) && (!label7 || qatom(label7) == QXcbAtom::ButtonHorizWheelRight))
- scrollingDevice.legacyOrientations |= Qt::Horizontal;
+ if ((!label6 || qatom(label6) == QXcbAtom::AtomButtonHorizWheelLeft) && (!label7 || qatom(label7) == QXcbAtom::AtomButtonHorizWheelRight))
+ scrollingDevice()->legacyOrientations |= Qt::Horizontal;
}
+ buttonCount = bci->num_buttons;
qCDebug(lcQpaXInputDevices, " has %d buttons", bci->num_buttons);
break;
}
@@ -190,6 +321,9 @@ void QXcbConnection::xi2SetupDevice(void *info, bool removeExisting)
qCDebug(lcQpaXInputDevices) << " it's a keyboard";
break;
case XCB_INPUT_DEVICE_CLASS_TYPE_TOUCH:
+#if QT_CONFIG(gestures) && QT_XCB_HAS_TOUCHPAD_GESTURES
+ case XCB_INPUT_DEVICE_CLASS_TYPE_GESTURE:
+#endif // QT_CONFIG(gestures) && QT_XCB_HAS_TOUCHPAD_GESTURES
// will be handled in populateTouchDevices()
break;
default:
@@ -200,93 +334,126 @@ void QXcbConnection::xi2SetupDevice(void *info, bool removeExisting)
bool isTablet = false;
#if QT_CONFIG(tabletevent)
// If we have found the valuators which we expect a tablet to have, it might be a tablet.
- if (tabletData.valuatorInfo.contains(QXcbAtom::AbsX) &&
- tabletData.valuatorInfo.contains(QXcbAtom::AbsY) &&
- tabletData.valuatorInfo.contains(QXcbAtom::AbsPressure))
+ if (tabletData.valuatorInfo.contains(QXcbAtom::AtomAbsX) &&
+ tabletData.valuatorInfo.contains(QXcbAtom::AtomAbsY) &&
+ tabletData.valuatorInfo.contains(QXcbAtom::AtomAbsPressure))
isTablet = true;
// But we need to be careful not to take the touch and tablet-button devices as tablets.
- QByteArray name = QByteArray(xcb_input_xi_device_info_name(deviceInfo),
- xcb_input_xi_device_info_name_length(deviceInfo)).toLower();
- QString dbgType = QLatin1String("UNKNOWN");
- if (name.contains("eraser")) {
+ QByteArray nameLower = nameRaw.toLower();
+ QString dbgType = "UNKNOWN"_L1;
+ if (nameLower.contains("eraser")) {
isTablet = true;
- tabletData.pointerType = QTabletEvent::Eraser;
- dbgType = QLatin1String("eraser");
- } else if (name.contains("cursor") && !(name.contains("cursor controls") && name.contains("trackball"))) {
+ tabletData.pointerType = QPointingDevice::PointerType::Eraser;
+ dbgType = "eraser"_L1;
+ } else if (nameLower.contains("cursor") && !(nameLower.contains("cursor controls") && nameLower.contains("trackball"))) {
isTablet = true;
- tabletData.pointerType = QTabletEvent::Cursor;
- dbgType = QLatin1String("cursor");
- } else if (name.contains("wacom") && name.contains("finger touch")) {
+ tabletData.pointerType = QPointingDevice::PointerType::Cursor;
+ dbgType = "cursor"_L1;
+ } else if (nameLower.contains("wacom") && nameLower.contains("finger touch")) {
isTablet = false;
- } else if ((name.contains("pen") || name.contains("stylus")) && isTablet) {
- tabletData.pointerType = QTabletEvent::Pen;
- dbgType = QLatin1String("pen");
- } else if (name.contains("wacom") && isTablet && !name.contains("touch")) {
+ } else if ((nameLower.contains("pen") || nameLower.contains("stylus")) && isTablet) {
+ tabletData.pointerType = QPointingDevice::PointerType::Pen;
+ dbgType = "pen"_L1;
+ } else if (nameLower.contains("wacom") && isTablet && !nameLower.contains("touch")) {
// combined device (evdev) rather than separate pen/eraser (wacom driver)
- tabletData.pointerType = QTabletEvent::Pen;
- dbgType = QLatin1String("pen");
- } else if (name.contains("aiptek") /* && device == QXcbAtom::KEYBOARD */) {
+ tabletData.pointerType = QPointingDevice::PointerType::Pen;
+ dbgType = "pen"_L1;
+ } else if (nameLower.contains("aiptek") /* && device == QXcbAtom::AtomKEYBOARD */) {
// some "Genius" tablets
isTablet = true;
- tabletData.pointerType = QTabletEvent::Pen;
- dbgType = QLatin1String("pen");
- } else if (name.contains("waltop") && name.contains("tablet")) {
+ tabletData.pointerType = QPointingDevice::PointerType::Pen;
+ dbgType = "pen"_L1;
+ } else if (nameLower.contains("waltop") && nameLower.contains("tablet")) {
// other "Genius" tablets
// WALTOP International Corp. Slim Tablet
isTablet = true;
- tabletData.pointerType = QTabletEvent::Pen;
- dbgType = QLatin1String("pen");
- } else if (name.contains("uc-logic") && isTablet) {
- tabletData.pointerType = QTabletEvent::Pen;
- dbgType = QLatin1String("pen");
- } else if (name.contains("ugee")) {
+ tabletData.pointerType = QPointingDevice::PointerType::Pen;
+ dbgType = "pen"_L1;
+ } else if (nameLower.contains("uc-logic") && isTablet) {
+ tabletData.pointerType = QPointingDevice::PointerType::Pen;
+ dbgType = "pen"_L1;
+ } else if (nameLower.contains("ugee")) {
isTablet = true;
- tabletData.pointerType = QTabletEvent::Pen;
- dbgType = QLatin1String("pen");
+ tabletData.pointerType = QPointingDevice::PointerType::Pen;
+ dbgType = "pen"_L1;
} else {
isTablet = false;
}
if (isTablet) {
tabletData.deviceId = deviceInfo->deviceid;
+ tabletData.name = name;
m_tabletData.append(tabletData);
qCDebug(lcQpaXInputDevices) << " it's a tablet with pointer type" << dbgType;
+ QPointingDevice::Capabilities capsOverride = QInputDevice::Capability::None;
+ if (tabletData.valuatorInfo.contains(QXcbAtom::AtomAbsTiltX))
+ capsOverride.setFlag(QInputDevice::Capability::XTilt);
+ if (tabletData.valuatorInfo.contains(QXcbAtom::AtomAbsTiltY))
+ capsOverride.setFlag(QInputDevice::Capability::YTilt);
+ // TODO can we get USB ID?
+ Q_ASSERT(deviceInfo->deviceid == tabletData.deviceId);
+ const QPointingDevice *dev = tabletToolInstance(master,
+ tabletData.name, deviceInfo->deviceid, 0, 0, tabletData.serialId,
+ tabletData.pointerType, capsOverride);
+ Q_ASSERT(dev);
}
#endif // QT_CONFIG(tabletevent)
- if (scrollingDevice.orientations || scrollingDevice.legacyOrientations) {
- scrollingDevice.deviceId = deviceInfo->deviceid;
+ if (scrollingDeviceP) {
// Only use legacy wheel button events when we don't have real scroll valuators.
- scrollingDevice.legacyOrientations &= ~scrollingDevice.orientations;
- m_scrollingDevices.insert(scrollingDevice.deviceId, scrollingDevice);
+ scrollingDeviceP->legacyOrientations &= ~scrollingDeviceP->orientations;
qCDebug(lcQpaXInputDevices) << " it's a scrolling device";
}
if (!isTablet) {
- TouchDeviceData *dev = populateTouchDevices(deviceInfo);
+ TouchDeviceData *dev = populateTouchDevices(deviceInfo, scrollingDeviceP, &used);
if (dev && lcQpaXInputDevices().isDebugEnabled()) {
- if (dev->qtTouchDevice->type() == QTouchDevice::TouchScreen)
+ if (dev->qtTouchDevice->type() == QInputDevice::DeviceType::TouchScreen)
qCDebug(lcQpaXInputDevices, " it's a touchscreen with type %d capabilities 0x%X max touch points %d",
- dev->qtTouchDevice->type(), (unsigned int)dev->qtTouchDevice->capabilities(),
- dev->qtTouchDevice->maximumTouchPoints());
- else if (dev->qtTouchDevice->type() == QTouchDevice::TouchPad)
+ int(dev->qtTouchDevice->type()), qint32(dev->qtTouchDevice->capabilities()),
+ dev->qtTouchDevice->maximumPoints());
+ else if (dev->qtTouchDevice->type() == QInputDevice::DeviceType::TouchPad)
qCDebug(lcQpaXInputDevices, " it's a touchpad with type %d capabilities 0x%X max touch points %d size %f x %f",
- dev->qtTouchDevice->type(), (unsigned int)dev->qtTouchDevice->capabilities(),
- dev->qtTouchDevice->maximumTouchPoints(),
+ int(dev->qtTouchDevice->type()), qint32(dev->qtTouchDevice->capabilities()),
+ dev->qtTouchDevice->maximumPoints(),
dev->size.width(), dev->size.height());
}
}
+ if (!QInputDevicePrivate::fromId(deviceInfo->deviceid)) {
+ qCDebug(lcQpaXInputDevices) << " it's a mouse";
+ QInputDevice::Capabilities caps = QInputDevice::Capability::Position | QInputDevice::Capability::Hover;
+ if (scrollingDeviceP) {
+ scrollingDeviceP->capabilities |= caps;
+ scrollingDeviceP->buttonCount = buttonCount;
+ if (master)
+ scrollingDeviceP->seatName = master->seatName();
+ QWindowSystemInterface::registerInputDevice(new QXcbScrollingDevice(*scrollingDeviceP, master));
+ used = true;
+ } else {
+ QWindowSystemInterface::registerInputDevice(new QPointingDevice(
+ name, deviceInfo->deviceid,
+ QInputDevice::DeviceType::Mouse, QPointingDevice::PointerType::Generic,
+ caps, 1, buttonCount, (master ? master->seatName() : QString()), QPointingDeviceUniqueId(), master));
+ }
+ }
+
+ if (!used && scrollingDeviceP) {
+ QXcbScrollingDevice *holder = new QXcbScrollingDevice(*scrollingDeviceP, master);
+ holder->deleteLater();
+ }
}
+/*!
+ Find all X11 input devices at startup, or react to a device hierarchy event,
+ and create/delete the corresponding QInputDevice instances as necessary.
+ Afterwards, we expect QInputDevice::devices() to contain only the
+ Qt-relevant devices that \c {xinput list} reports. The parent of each master
+ device is this QXcbConnection object; the parent of each slave is its master.
+*/
void QXcbConnection::xi2SetupDevices()
{
-#if QT_CONFIG(tabletevent)
- m_tabletData.clear();
-#endif
- m_scrollingDevices.clear();
- m_touchDevices.clear();
m_xiMasterPointerIds.clear();
auto reply = Q_XCB_REPLY(xcb_input_xi_query_device, xcb_connection(), XCB_INPUT_DEVICE_ALL);
@@ -295,122 +462,89 @@ void QXcbConnection::xi2SetupDevices()
return;
}
+ // Start with all known devices; remove the ones that still exist.
+ // Afterwards, previousDevices will be the list of those that we should delete.
+ QList<const QInputDevice *> previousDevices = QInputDevice::devices();
+ // Return true if the device with the given systemId is new;
+ // otherwise remove it from previousDevices and return false.
+ auto newOrKeep = [&previousDevices](qint64 systemId) {
+ // if nothing is removed from previousDevices, it's a new device
+ return !previousDevices.removeIf([systemId](const QInputDevice *dev) {
+ return dev->systemId() == systemId;
+ });
+ };
+
+ // XInput doesn't provide a way to identify "seats"; but each device has an attachment to another device.
+ // So we make up a seatId: master-keyboard-id << 16 | master-pointer-id.
+
auto it = xcb_input_xi_query_device_infos_iterator(reply.get());
for (; it.rem; xcb_input_xi_device_info_next(&it)) {
xcb_input_xi_device_info_t *deviceInfo = it.data;
- if (deviceInfo->type == XCB_INPUT_DEVICE_TYPE_MASTER_POINTER) {
+ switch (deviceInfo->type) {
+ case XCB_INPUT_DEVICE_TYPE_MASTER_KEYBOARD: {
+ if (newOrKeep(deviceInfo->deviceid)) {
+ auto dev = new QInputDevice(QString::fromUtf8(xcb_input_xi_device_info_name(deviceInfo)),
+ deviceInfo->deviceid, QInputDevice::DeviceType::Keyboard,
+ QString::number(deviceInfo->deviceid << 16 | deviceInfo->attachment, 16), this);
+ QWindowSystemInterface::registerInputDevice(dev);
+ }
+ } break;
+ case XCB_INPUT_DEVICE_TYPE_MASTER_POINTER: {
m_xiMasterPointerIds.append(deviceInfo->deviceid);
+ if (newOrKeep(deviceInfo->deviceid)) {
+ auto dev = new QXcbScrollingDevice(QString::fromUtf8(xcb_input_xi_device_info_name(deviceInfo)), deviceInfo->deviceid,
+ QInputDevice::Capability::Position | QInputDevice::Capability::Scroll | QInputDevice::Capability::Hover,
+ 32, QString::number(deviceInfo->attachment << 16 | deviceInfo->deviceid, 16), this);
+ QWindowSystemInterface::registerInputDevice(dev);
+ }
continue;
+ } break;
+ default:
+ break;
}
- // only slave pointer devices are relevant here
- if (deviceInfo->type == XCB_INPUT_DEVICE_TYPE_SLAVE_POINTER)
- xi2SetupDevice(deviceInfo, false);
}
- if (m_xiMasterPointerIds.size() > 1)
- qCDebug(lcQpaXInputDevices) << "multi-pointer X detected";
-}
-
-/*! \internal
-
- Notes on QT_XCB_NO_XI2_MOUSE Handling:
-
- Here we don't select pointer button press/release and motion events on master devices, instead
- we select these events directly on slave devices. This means that a master device will fallback
- to sending core events for every XI_* event that is sent directly by a slave device. For more
- details see "Event processing for attached slave devices" in XInput2 specification. To prevent
- handling of the same event twice, we have checks for xi2MouseEventsDisabled() in XI2 event
- handlers (but this is somewhat inconsistent in some situations). If the purpose for
- QT_XCB_NO_XI2_MOUSE was so that an application using QAbstractNativeEventFilter would see core
- mouse events before they are handled by Qt then QT_XCB_NO_XI2_MOUSE won't always work as
- expected (e.g. we handle scroll event directly from a slave device event, before an application
- has seen the fallback core event from a master device).
-
- The commit introducing QT_XCB_NO_XI2_MOUSE also states that setting this envvar "restores the
- old behavior with broken grabbing". It did not elaborate why grabbing was not fixed for this
- code path. The issue that this envvar tries to solve seem to be less important than broken
- grabbing (broken apparently only for touch events). Thus, if you really want core mouse events
- in your application and do not care about broken touch, then use QT_XCB_NO_XI2 (more on this
- below) to disable the extension all together. The reason why grabbing might have not been fixed
- is that calling XIGrabDevice with this code path for some reason always returns AlreadyGrabbed
- (by debugging X server's code it appears that when we call XIGrabDevice, an X server first grabs
- pointer via core pointer and then fails to do XI2 grab with AlreadyGrabbed; disclaimer - I did
- not debug this in great detail). When we try supporting odd setups like QT_XCB_NO_XI2_MOUSE, we
- are asking for trouble anyways.
-
- In conclusion, introduction of QT_XCB_NO_XI2_MOUSE causes more issues than solves - the above
- mentioned inconsistencies, maintenance of this code path and that QT_XCB_NO_XI2_MOUSE replaces
- less important issue with somewhat more important issue. It also makes us to use less optimal
- code paths in certain situations (see xi2HandleHierarchyEvent). Using of QT_XCB_NO_XI2 has its
- drawbacks too - no tablet and touch events. So the only real fix in this case is at an
- application side (teach the application about xcb_ge_event_t events). Based on this,
- QT_XCB_NO_XI2_MOUSE will be removed in ### Qt 6. It should not have existed in the first place,
- native events seen by QAbstractNativeEventFilter is not really a public API, applications should
- expect changes at this level and do ifdefs if something changes between Qt version.
-*/
-void QXcbConnection::xi2SelectDeviceEventsCompatibility(xcb_window_t window)
-{
- if (window == rootWindow())
- return;
-
- uint32_t mask = 0;
-
- if (isAtLeastXI22()) {
- mask |= XCB_INPUT_XI_EVENT_MASK_TOUCH_BEGIN;
- mask |= XCB_INPUT_XI_EVENT_MASK_TOUCH_UPDATE;
- mask |= XCB_INPUT_XI_EVENT_MASK_TOUCH_END;
-
- qt_xcb_input_event_mask_t xiMask;
- xiMask.header.deviceid = XCB_INPUT_DEVICE_ALL_MASTER;
- xiMask.header.mask_len = 1;
- xiMask.mask = mask;
-
- xcb_void_cookie_t cookie =
- xcb_input_xi_select_events_checked(xcb_connection(), window, 1, &xiMask.header);
- xcb_generic_error_t *error = xcb_request_check(xcb_connection(), cookie);
- if (error) {
- qCDebug(lcQpaXInput, "failed to select events, window %x, error code %d", window, error->error_code);
- free(error);
- } else {
- QWindowSystemInterfacePrivate::TabletEvent::setPlatformSynthesizesMouse(false);
+ it = xcb_input_xi_query_device_infos_iterator(reply.get());
+ for (; it.rem; xcb_input_xi_device_info_next(&it)) {
+ xcb_input_xi_device_info_t *deviceInfo = it.data;
+ switch (deviceInfo->type) {
+ case XCB_INPUT_DEVICE_TYPE_MASTER_KEYBOARD:
+ case XCB_INPUT_DEVICE_TYPE_MASTER_POINTER:
+ // already registered
+ break;
+ case XCB_INPUT_DEVICE_TYPE_SLAVE_POINTER: {
+ if (newOrKeep(deviceInfo->deviceid)) {
+ m_xiSlavePointerIds.append(deviceInfo->deviceid);
+ QInputDevice *master = const_cast<QInputDevice *>(QInputDevicePrivate::fromId(deviceInfo->attachment));
+ Q_ASSERT(master);
+ xi2SetupSlavePointerDevice(deviceInfo, false, qobject_cast<QPointingDevice *>(master));
+ }
+ } break;
+ case XCB_INPUT_DEVICE_TYPE_SLAVE_KEYBOARD: {
+ if (newOrKeep(deviceInfo->deviceid)) {
+ QInputDevice *master = const_cast<QInputDevice *>(QInputDevicePrivate::fromId(deviceInfo->attachment));
+ Q_ASSERT(master);
+ QWindowSystemInterface::registerInputDevice(new QInputDevice(
+ QString::fromUtf8(xcb_input_xi_device_info_name(deviceInfo)), deviceInfo->deviceid,
+ QInputDevice::DeviceType::Keyboard, master->seatName(), master));
+ }
+ } break;
+ case XCB_INPUT_DEVICE_TYPE_FLOATING_SLAVE:
+ break;
}
}
- mask = XCB_INPUT_XI_EVENT_MASK_BUTTON_PRESS;
- mask |= XCB_INPUT_XI_EVENT_MASK_BUTTON_RELEASE;
- mask |= XCB_INPUT_XI_EVENT_MASK_MOTION;
-
-#if QT_CONFIG(tabletevent)
- QSet<int> tabletDevices;
- if (!m_tabletData.isEmpty()) {
- const int nrTablets = m_tabletData.count();
- QVector<qt_xcb_input_event_mask_t> xiEventMask(nrTablets);
- for (int i = 0; i < nrTablets; ++i) {
- int deviceId = m_tabletData.at(i).deviceId;
- tabletDevices.insert(deviceId);
- xiEventMask[i].header.deviceid = deviceId;
- xiEventMask[i].header.mask_len = 1;
- xiEventMask[i].mask = mask;
- }
- xcb_input_xi_select_events(xcb_connection(), window, nrTablets, &(xiEventMask.data()->header));
+ // previousDevices is now the list of those that are no longer found
+ qCDebug(lcQpaXInputDevices) << "removed" << previousDevices;
+ for (auto it = previousDevices.constBegin(); it != previousDevices.constEnd(); ++it) {
+ const auto id = (*it)->systemId();
+ m_xiSlavePointerIds.removeAll(id);
+ m_touchDevices.remove(id);
}
-#endif
+ qDeleteAll(previousDevices);
- if (!m_scrollingDevices.isEmpty()) {
- QVector<qt_xcb_input_event_mask_t> xiEventMask(m_scrollingDevices.size());
- int i = 0;
- for (const ScrollingDevice& scrollingDevice : qAsConst(m_scrollingDevices)) {
-#if QT_CONFIG(tabletevent)
- if (tabletDevices.contains(scrollingDevice.deviceId))
- continue; // All necessary events are already captured.
-#endif
- xiEventMask[i].header.deviceid = scrollingDevice.deviceId;
- xiEventMask[i].header.mask_len = 1;
- xiEventMask[i].mask = mask;
- i++;
- }
- xcb_input_xi_select_events(xcb_connection(), window, i, &(xiEventMask.data()->header));
- }
+ if (m_xiMasterPointerIds.size() > 1)
+ qCDebug(lcQpaXInputDevices) << "multi-pointer X detected";
}
QXcbConnection::TouchDeviceData *QXcbConnection::touchDeviceForId(int id)
@@ -421,16 +555,16 @@ QXcbConnection::TouchDeviceData *QXcbConnection::touchDeviceForId(int id)
return dev;
}
-QXcbConnection::TouchDeviceData *QXcbConnection::populateTouchDevices(void *info)
+QXcbConnection::TouchDeviceData *QXcbConnection::populateTouchDevices(void *info, QXcbScrollingDevicePrivate *scrollingDeviceP, bool *used)
{
- auto *deviceinfo = reinterpret_cast<xcb_input_xi_device_info_t *>(info);
- QTouchDevice::Capabilities caps;
- int type = -1;
+ auto *deviceInfo = reinterpret_cast<xcb_input_xi_device_info_t *>(info);
+ QPointingDevice::Capabilities caps;
+ QInputDevice::DeviceType type = QInputDevice::DeviceType::Unknown;
int maxTouchPoints = 1;
bool isTouchDevice = false;
bool hasRelativeCoords = false;
TouchDeviceData dev;
- auto classes_it = xcb_input_xi_device_info_classes_iterator(deviceinfo);
+ auto classes_it = xcb_input_xi_device_info_classes_iterator(deviceInfo);
for (; classes_it.rem; xcb_input_device_class_next(&classes_it)) {
xcb_input_device_class_t *classinfo = classes_it.data;
switch (classinfo->type) {
@@ -440,14 +574,26 @@ QXcbConnection::TouchDeviceData *QXcbConnection::populateTouchDevices(void *info
qCDebug(lcQpaXInputDevices, " has touch class with mode %d", tci->mode);
switch (tci->mode) {
case XCB_INPUT_TOUCH_MODE_DEPENDENT:
- type = QTouchDevice::TouchPad;
+ type = QInputDevice::DeviceType::TouchPad;
break;
case XCB_INPUT_TOUCH_MODE_DIRECT:
- type = QTouchDevice::TouchScreen;
+ type = QInputDevice::DeviceType::TouchScreen;
break;
}
break;
}
+#if QT_CONFIG(gestures) && QT_XCB_HAS_TOUCHPAD_GESTURES
+ case XCB_INPUT_DEVICE_CLASS_TYPE_GESTURE: {
+ // Note that gesture devices can only be touchpads (i.e. dependent devices in XInput
+ // naming convention). According to XI 2.4, the same device can't have touch and
+ // gesture device classes.
+ auto *gci = reinterpret_cast<xcb_input_gesture_class_t *>(classinfo);
+ maxTouchPoints = gci->num_touches;
+ qCDebug(lcQpaXInputDevices, " has gesture class");
+ type = QInputDevice::DeviceType::TouchPad;
+ break;
+ }
+#endif // QT_CONFIG(gestures) && QT_XCB_HAS_TOUCHPAD_GESTURES
case XCB_INPUT_DEVICE_CLASS_TYPE_VALUATOR: {
auto *vci = reinterpret_cast<xcb_input_valuator_class_t *>(classinfo);
const QXcbAtom::Atom valuatorAtom = qatom(vci->label);
@@ -462,26 +608,28 @@ QXcbConnection::TouchDeviceData *QXcbConnection::populateTouchDevices(void *info
// Some devices (mice) report a resolution of 0; they will be excluded later,
// for now just prevent a division by zero
const int vciResolution = vci->resolution ? vci->resolution : 1;
- if (valuatorAtom == QXcbAtom::AbsMTPositionX)
- caps |= QTouchDevice::Position | QTouchDevice::NormalizedPosition;
- else if (valuatorAtom == QXcbAtom::AbsMTTouchMajor)
- caps |= QTouchDevice::Area;
- else if (valuatorAtom == QXcbAtom::AbsMTOrientation)
+ if (valuatorAtom == QXcbAtom::AtomAbsMTPositionX)
+ caps |= QInputDevice::Capability::Position | QInputDevice::Capability::NormalizedPosition;
+ else if (valuatorAtom == QXcbAtom::AtomAbsMTTouchMajor)
+ caps |= QInputDevice::Capability::Area;
+ else if (valuatorAtom == QXcbAtom::AtomAbsMTOrientation)
dev.providesTouchOrientation = true;
- else if (valuatorAtom == QXcbAtom::AbsMTPressure || valuatorAtom == QXcbAtom::AbsPressure)
- caps |= QTouchDevice::Pressure;
- else if (valuatorAtom == QXcbAtom::RelX) {
+ else if (valuatorAtom == QXcbAtom::AtomAbsMTPressure || valuatorAtom == QXcbAtom::AtomAbsPressure)
+ caps |= QInputDevice::Capability::Pressure;
+ else if (valuatorAtom == QXcbAtom::AtomRelX) {
hasRelativeCoords = true;
dev.size.setWidth((fixed3232ToReal(vci->max) - fixed3232ToReal(vci->min)) * 1000.0 / vciResolution);
- } else if (valuatorAtom == QXcbAtom::RelY) {
+ } else if (valuatorAtom == QXcbAtom::AtomRelY) {
hasRelativeCoords = true;
dev.size.setHeight((fixed3232ToReal(vci->max) - fixed3232ToReal(vci->min)) * 1000.0 / vciResolution);
- } else if (valuatorAtom == QXcbAtom::AbsX) {
- caps |= QTouchDevice::Position;
+ } else if (valuatorAtom == QXcbAtom::AtomAbsX) {
+ caps |= QInputDevice::Capability::Position;
dev.size.setWidth((fixed3232ToReal(vci->max) - fixed3232ToReal(vci->min)) * 1000.0 / vciResolution);
- } else if (valuatorAtom == QXcbAtom::AbsY) {
- caps |= QTouchDevice::Position;
+ } else if (valuatorAtom == QXcbAtom::AtomAbsY) {
+ caps |= QInputDevice::Capability::Position;
dev.size.setHeight((fixed3232ToReal(vci->max) - fixed3232ToReal(vci->min)) * 1000.0 / vciResolution);
+ } else if (valuatorAtom == QXcbAtom::AtomRelVertWheel || valuatorAtom == QXcbAtom::AtomRelHorizWheel) {
+ caps |= QInputDevice::Capability::Scroll;
}
break;
}
@@ -489,41 +637,71 @@ QXcbConnection::TouchDeviceData *QXcbConnection::populateTouchDevices(void *info
break;
}
}
- if (type < 0 && caps && hasRelativeCoords) {
- type = QTouchDevice::TouchPad;
+ if (type == QInputDevice::DeviceType::Unknown && caps && hasRelativeCoords) {
+ type = QInputDevice::DeviceType::TouchPad;
if (dev.size.width() < 10 || dev.size.height() < 10 ||
dev.size.width() > 10000 || dev.size.height() > 10000)
dev.size = QSizeF(130, 110);
}
- if (!isAtLeastXI22() || type == QTouchDevice::TouchPad)
- caps |= QTouchDevice::MouseEmulation;
-
- if (type >= QTouchDevice::TouchScreen && type <= QTouchDevice::TouchPad) {
- dev.qtTouchDevice = new QTouchDevice;
- dev.qtTouchDevice->setName(QString::fromUtf8(xcb_input_xi_device_info_name(deviceinfo),
- xcb_input_xi_device_info_name_length(deviceinfo)));
- dev.qtTouchDevice->setType((QTouchDevice::DeviceType)type);
- dev.qtTouchDevice->setCapabilities(caps);
- dev.qtTouchDevice->setMaximumTouchPoints(maxTouchPoints);
+ if (!isAtLeastXI22() || type == QInputDevice::DeviceType::TouchPad)
+ caps |= QInputDevice::Capability::MouseEmulation;
+
+ if (type == QInputDevice::DeviceType::TouchScreen || type == QInputDevice::DeviceType::TouchPad) {
+ QInputDevice *master = const_cast<QInputDevice *>(QInputDevicePrivate::fromId(deviceInfo->attachment));
+ Q_ASSERT(master);
+ if (scrollingDeviceP) {
+ // valuators were already discovered in QXcbConnection::xi2SetupSlavePointerDevice, so just finish initialization
+ scrollingDeviceP->deviceType = type;
+ scrollingDeviceP->pointerType = QPointingDevice::PointerType::Finger;
+ scrollingDeviceP->capabilities |= caps;
+ scrollingDeviceP->maximumTouchPoints = maxTouchPoints;
+ scrollingDeviceP->buttonCount = 3;
+ scrollingDeviceP->seatName = master->seatName();
+ dev.qtTouchDevice = new QXcbScrollingDevice(*scrollingDeviceP, master);
+ if (Q_UNLIKELY(!caps.testFlag(QInputDevice::Capability::Scroll)))
+ qCDebug(lcQpaXInputDevices) << "unexpectedly missing RelVert/HorizWheel atoms for touchpad with scroll capability" << dev.qtTouchDevice;
+ *used = true;
+ } else {
+ dev.qtTouchDevice = new QPointingDevice(QString::fromUtf8(xcb_input_xi_device_info_name(deviceInfo),
+ xcb_input_xi_device_info_name_length(deviceInfo)),
+ deviceInfo->deviceid,
+ type, QPointingDevice::PointerType::Finger, caps, maxTouchPoints, 0,
+ master->seatName(), QPointingDeviceUniqueId(), master);
+ }
if (caps != 0)
- QWindowSystemInterface::registerTouchDevice(dev.qtTouchDevice);
- m_touchDevices[deviceinfo->deviceid] = dev;
+ QWindowSystemInterface::registerInputDevice(dev.qtTouchDevice);
+ m_touchDevices[deviceInfo->deviceid] = dev;
isTouchDevice = true;
}
- return isTouchDevice ? &m_touchDevices[deviceinfo->deviceid] : nullptr;
+ return isTouchDevice ? &m_touchDevices[deviceInfo->deviceid] : nullptr;
}
-#if QT_CONFIG(tabletevent)
static inline qreal fixed1616ToReal(xcb_input_fp1616_t val)
{
return qreal(val) / 0x10000;
}
-#endif // QT_CONFIG(tabletevent)
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) && xiEvent->event_type != XCB_INPUT_PROPERTY) {
+ if (!m_duringSystemMoveResize)
+ return;
+ if (xiEvent->event == XCB_NONE)
+ return;
+
+ if (xiEvent->event_type == XCB_INPUT_BUTTON_RELEASE
+ && xiEvent->detail == XCB_BUTTON_INDEX_1 ) {
+ abortSystemMoveResize(xiEvent->event);
+ } else if (xiEvent->event_type == XCB_INPUT_TOUCH_END) {
+ abortSystemMoveResize(xiEvent->event);
+ return;
+ } else {
+ return;
+ }
+ }
int sourceDeviceId = xiEvent->deviceid; // may be the master id
qt_xcb_input_device_event_t *xiDeviceEvent = nullptr;
xcb_input_enter_event_t *xiEnterEvent = nullptr;
@@ -542,6 +720,18 @@ void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event)
sourceDeviceId = xiDeviceEvent->sourceid; // use the actual device id instead of the master
break;
}
+#if QT_CONFIG(gestures) && QT_XCB_HAS_TOUCHPAD_GESTURES
+ case XCB_INPUT_GESTURE_PINCH_BEGIN:
+ case XCB_INPUT_GESTURE_PINCH_UPDATE:
+ case XCB_INPUT_GESTURE_PINCH_END:
+ xi2HandleGesturePinchEvent(event);
+ return;
+ case XCB_INPUT_GESTURE_SWIPE_BEGIN:
+ case XCB_INPUT_GESTURE_SWIPE_UPDATE:
+ case XCB_INPUT_GESTURE_SWIPE_END:
+ xi2HandleGestureSwipeEvent(event);
+ return;
+#endif // QT_CONFIG(gestures) && QT_XCB_HAS_TOUCHPAD_GESTURES
case XCB_INPUT_ENTER:
case XCB_INPUT_LEAVE: {
xiEnterEvent = reinterpret_cast<xcb_input_enter_event_t *>(event);
@@ -566,22 +756,24 @@ void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event)
#if QT_CONFIG(tabletevent)
if (!xiEnterEvent) {
+ // TODO we need the UID here; tabletDataForDevice doesn't have enough to go on (?)
QXcbConnection::TabletData *tablet = tabletDataForDevice(sourceDeviceId);
if (tablet && xi2HandleTabletEvent(event, tablet))
return;
}
#endif // QT_CONFIG(tabletevent)
- if (ScrollingDevice *device = scrollingDeviceForId(sourceDeviceId))
- xi2HandleScrollEvent(event, *device);
+ if (auto device = QPointingDevicePrivate::pointingDeviceById(sourceDeviceId))
+ xi2HandleScrollEvent(event, device);
+ else
+ qCDebug(lcQpaXInputEvents) << "scroll event from unregistered device" << sourceDeviceId;
if (xiDeviceEvent) {
switch (xiDeviceEvent->event_type) {
case XCB_INPUT_BUTTON_PRESS:
case XCB_INPUT_BUTTON_RELEASE:
case XCB_INPUT_MOTION:
- if (!xi2MouseEventsDisabled() && eventListener &&
- !(xiDeviceEvent->flags & XCB_INPUT_POINTER_EVENT_FLAGS_POINTER_EMULATED))
+ if (eventListener && !(xiDeviceEvent->flags & XCB_INPUT_POINTER_EVENT_FLAGS_POINTER_EMULATED))
eventListener->handleXIMouseEvent(event);
break;
@@ -593,11 +785,15 @@ void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event)
event->event_type, xiDeviceEvent->sequence, xiDeviceEvent->detail,
fixed1616ToReal(xiDeviceEvent->event_x), fixed1616ToReal(xiDeviceEvent->event_y),
fixed1616ToReal(xiDeviceEvent->root_x), fixed1616ToReal(xiDeviceEvent->root_y),xiDeviceEvent->event);
- if (QXcbWindow *platformWindow = platformWindowFromId(xiDeviceEvent->event))
+ if (QXcbWindow *platformWindow = platformWindowFromId(xiDeviceEvent->event)) {
xi2ProcessTouch(xiDeviceEvent, platformWindow);
+ } else { // When the window cannot be matched, delete it from touchPoints
+ if (TouchDeviceData *dev = touchDeviceForId(xiDeviceEvent->sourceid))
+ dev->touchPoints.remove((xiDeviceEvent->detail % INT_MAX));
+ }
break;
}
- } else if (xiEnterEvent && !xi2MouseEventsDisabled() && eventListener) {
+ } else if (xiEnterEvent && eventListener) {
switch (xiEnterEvent->event_type) {
case XCB_INPUT_ENTER:
case XCB_INPUT_LEAVE:
@@ -607,30 +803,31 @@ void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event)
}
}
-bool QXcbConnection::xi2MouseEventsDisabled() const
-{
- static bool xi2MouseDisabled = qEnvironmentVariableIsSet("QT_XCB_NO_XI2_MOUSE");
- // FIXME: Don't use XInput2 mouse events when Xinerama extension
- // is enabled, because it causes problems with multi-monitor setup.
- return xi2MouseDisabled || hasXinerama();
-}
-
bool QXcbConnection::isTouchScreen(int id)
{
auto device = touchDeviceForId(id);
- return device && device->qtTouchDevice->type() == QTouchDevice::TouchScreen;
+ return device && device->qtTouchDevice->type() == QInputDevice::DeviceType::TouchScreen;
}
void QXcbConnection::xi2ProcessTouch(void *xiDevEvent, QXcbWindow *platformWindow)
{
auto *xiDeviceEvent = reinterpret_cast<xcb_input_touch_begin_event_t *>(xiDevEvent);
TouchDeviceData *dev = touchDeviceForId(xiDeviceEvent->sourceid);
- Q_ASSERT(dev);
+ if (!dev) {
+ qCDebug(lcQpaXInputEvents) << "didn't find the dev for given sourceid - " << xiDeviceEvent->sourceid
+ << ", try to repopulate xi2 devices";
+ xi2SetupDevices();
+ dev = touchDeviceForId(xiDeviceEvent->sourceid);
+ if (!dev) {
+ qCDebug(lcQpaXInputEvents) << "still can't find the dev for it, give up.";
+ return;
+ }
+ }
const bool firstTouch = dev->touchPoints.isEmpty();
if (xiDeviceEvent->event_type == XCB_INPUT_TOUCH_BEGIN) {
QWindowSystemInterface::TouchPoint tp;
tp.id = xiDeviceEvent->detail % INT_MAX;
- tp.state = Qt::TouchPointPressed;
+ tp.state = QEventPoint::State::Pressed;
tp.pressure = -1.0;
dev->touchPoints[tp.id] = tp;
}
@@ -641,39 +838,39 @@ void QXcbConnection::xi2ProcessTouch(void *xiDevEvent, QXcbWindow *platformWindo
qreal nx = -1.0, ny = -1.0;
qreal w = 0.0, h = 0.0;
bool majorAxisIsY = touchPoint.area.height() > touchPoint.area.width();
- for (const TouchDeviceData::ValuatorClassInfo &vci : qAsConst(dev->valuatorInfo)) {
+ for (const TouchDeviceData::ValuatorClassInfo &vci : std::as_const(dev->valuatorInfo)) {
double value;
if (!xi2GetValuatorValueIfSet(xiDeviceEvent, vci.number, &value))
continue;
if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled()))
qCDebug(lcQpaXInputEvents, " valuator %20s value %lf from range %lf -> %lf",
- atomName(vci.label).constData(), value, vci.min, vci.max);
+ atomName(atom(vci.label)).constData(), value, vci.min, vci.max);
if (value > vci.max)
value = vci.max;
if (value < vci.min)
value = vci.min;
qreal valuatorNormalized = (value - vci.min) / (vci.max - vci.min);
- if (vci.label == QXcbAtom::RelX) {
+ if (vci.label == QXcbAtom::AtomRelX) {
nx = valuatorNormalized;
- } else if (vci.label == QXcbAtom::RelY) {
+ } else if (vci.label == QXcbAtom::AtomRelY) {
ny = valuatorNormalized;
- } else if (vci.label == QXcbAtom::AbsX) {
+ } else if (vci.label == QXcbAtom::AtomAbsX) {
nx = valuatorNormalized;
- } else if (vci.label == QXcbAtom::AbsY) {
+ } else if (vci.label == QXcbAtom::AtomAbsY) {
ny = valuatorNormalized;
- } else if (vci.label == QXcbAtom::AbsMTPositionX) {
+ } else if (vci.label == QXcbAtom::AtomAbsMTPositionX) {
nx = valuatorNormalized;
- } else if (vci.label == QXcbAtom::AbsMTPositionY) {
+ } else if (vci.label == QXcbAtom::AtomAbsMTPositionY) {
ny = valuatorNormalized;
- } else if (vci.label == QXcbAtom::AbsMTTouchMajor) {
+ } else if (vci.label == QXcbAtom::AtomAbsMTTouchMajor) {
const qreal sw = screen->geometry().width();
const qreal sh = screen->geometry().height();
- w = valuatorNormalized * std::sqrt(sw * sw + sh * sh);
- } else if (vci.label == QXcbAtom::AbsMTTouchMinor) {
+ w = valuatorNormalized * qHypot(sw, sh);
+ } else if (vci.label == QXcbAtom::AtomAbsMTTouchMinor) {
const qreal sw = screen->geometry().width();
const qreal sh = screen->geometry().height();
- h = valuatorNormalized * std::sqrt(sw * sw + sh * sh);
- } else if (vci.label == QXcbAtom::AbsMTOrientation) {
+ h = valuatorNormalized * qHypot(sw, sh);
+ } else if (vci.label == QXcbAtom::AtomAbsMTOrientation) {
// Find the closest axis.
// 0 corresponds to the Y axis, vci.max to the X axis.
// Flipping over the Y axis and rotating by 180 degrees
@@ -684,7 +881,7 @@ void QXcbConnection::xi2ProcessTouch(void *xiDevEvent, QXcbWindow *platformWindo
value -= 2 * vci.max;
value = qAbs(value);
majorAxisIsY = value < vci.max - value;
- } else if (vci.label == QXcbAtom::AbsMTPressure || vci.label == QXcbAtom::AbsPressure) {
+ } else if (vci.label == QXcbAtom::AtomAbsMTPressure || vci.label == QXcbAtom::AtomAbsPressure) {
touchPoint.pressure = valuatorNormalized;
}
@@ -730,21 +927,21 @@ void QXcbConnection::xi2ProcessTouch(void *xiDevEvent, QXcbWindow *platformWindo
}
break;
case XCB_INPUT_TOUCH_UPDATE:
- if (dev->qtTouchDevice->type() == QTouchDevice::TouchPad && dev->pointPressedPosition.value(touchPoint.id) == QPointF(x, y)) {
+ if (dev->qtTouchDevice->type() == QInputDevice::DeviceType::TouchPad && dev->pointPressedPosition.value(touchPoint.id) == QPointF(x, y)) {
qreal dx = (nx - dev->firstPressedNormalPosition.x()) *
dev->size.width() * screen->geometry().width() / screen->physicalSize().width();
qreal dy = (ny - dev->firstPressedNormalPosition.y()) *
dev->size.height() * screen->geometry().height() / screen->physicalSize().height();
x = dev->firstPressedPosition.x() + dx;
y = dev->firstPressedPosition.y() + dy;
- touchPoint.state = Qt::TouchPointMoved;
+ touchPoint.state = QEventPoint::State::Updated;
} else if (touchPoint.area.center() != QPoint(x, y)) {
- touchPoint.state = Qt::TouchPointMoved;
- if (dev->qtTouchDevice->type() == QTouchDevice::TouchPad)
+ touchPoint.state = QEventPoint::State::Updated;
+ if (dev->qtTouchDevice->type() == QInputDevice::DeviceType::TouchPad)
dev->pointPressedPosition[touchPoint.id] = QPointF(x, y);
}
- if (dev->qtTouchDevice->type() == QTouchDevice::TouchScreen &&
+ if (dev->qtTouchDevice->type() == QInputDevice::DeviceType::TouchScreen &&
xiDeviceEvent->event == m_startSystemMoveResizeInfo.window &&
xiDeviceEvent->sourceid == m_startSystemMoveResizeInfo.deviceid &&
xiDeviceEvent->detail == m_startSystemMoveResizeInfo.pointid) {
@@ -759,8 +956,8 @@ void QXcbConnection::xi2ProcessTouch(void *xiDevEvent, QXcbWindow *platformWindo
}
break;
case XCB_INPUT_TOUCH_END:
- touchPoint.state = Qt::TouchPointReleased;
- if (dev->qtTouchDevice->type() == QTouchDevice::TouchPad && dev->pointPressedPosition.value(touchPoint.id) == QPointF(x, y)) {
+ touchPoint.state = QEventPoint::State::Released;
+ if (dev->qtTouchDevice->type() == QInputDevice::DeviceType::TouchPad && dev->pointPressedPosition.value(touchPoint.id) == QPointF(x, y)) {
qreal dx = (nx - dev->firstPressedNormalPosition.x()) *
dev->size.width() * screen->geometry().width() / screen->physicalSize().width();
qreal dy = (ny - dev->firstPressedNormalPosition.y()) *
@@ -778,13 +975,13 @@ void QXcbConnection::xi2ProcessTouch(void *xiDevEvent, QXcbWindow *platformWindo
" area " << touchPoint.area << " pressure " << touchPoint.pressure;
Qt::KeyboardModifiers modifiers = keyboard()->translateModifiers(xiDeviceEvent->mods.effective);
QWindowSystemInterface::handleTouchEvent(platformWindow->window(), xiDeviceEvent->time, dev->qtTouchDevice, dev->touchPoints.values(), modifiers);
- if (touchPoint.state == Qt::TouchPointReleased)
+ if (touchPoint.state == QEventPoint::State::Released)
// If a touchpoint was released, we can forget it, because the ID won't be reused.
dev->touchPoints.remove(touchPoint.id);
else
// Make sure that we don't send TouchPointPressed/Moved in more than one QTouchEvent
// with this touch point if the next XI2 event is about a different touch point.
- touchPoint.state = Qt::TouchPointStationary;
+ touchPoint.state = QEventPoint::State::Stationary;
}
bool QXcbConnection::startSystemMoveResizeForTouch(xcb_window_t window, int edges)
@@ -792,15 +989,17 @@ bool QXcbConnection::startSystemMoveResizeForTouch(xcb_window_t window, int edge
QHash<int, TouchDeviceData>::const_iterator devIt = m_touchDevices.constBegin();
for (; devIt != m_touchDevices.constEnd(); ++devIt) {
TouchDeviceData deviceData = devIt.value();
- if (deviceData.qtTouchDevice->type() == QTouchDevice::TouchScreen) {
+ if (deviceData.qtTouchDevice->type() == QInputDevice::DeviceType::TouchScreen) {
auto pointIt = deviceData.touchPoints.constBegin();
for (; pointIt != deviceData.touchPoints.constEnd(); ++pointIt) {
- Qt::TouchPointState state = pointIt.value().state;
- if (state == Qt::TouchPointMoved || state == Qt::TouchPointPressed || state == Qt::TouchPointStationary) {
+ QEventPoint::State state = pointIt.value().state;
+ if (state == QEventPoint::State::Updated || state == QEventPoint::State::Pressed || state == QEventPoint::State::Stationary) {
m_startSystemMoveResizeInfo.window = window;
m_startSystemMoveResizeInfo.deviceid = devIt.key();
m_startSystemMoveResizeInfo.pointid = pointIt.key();
m_startSystemMoveResizeInfo.edges = edges;
+ setDuringSystemMoveResize(true);
+ qCDebug(lcQpaXInputDevices) << "triggered system move or resize from touch";
return true;
}
}
@@ -809,9 +1008,38 @@ bool QXcbConnection::startSystemMoveResizeForTouch(xcb_window_t window, int edge
return false;
}
-void QXcbConnection::abortSystemMoveResizeForTouch()
+void QXcbConnection::abortSystemMoveResize(xcb_window_t window)
{
+ qCDebug(lcQpaXInputDevices) << "sending client message NET_WM_MOVERESIZE_CANCEL to window: " << window;
m_startSystemMoveResizeInfo.window = XCB_NONE;
+
+ const xcb_atom_t moveResize = connection()->atom(QXcbAtom::Atom_NET_WM_MOVERESIZE);
+ xcb_client_message_event_t xev;
+ xev.response_type = XCB_CLIENT_MESSAGE;
+ xev.type = moveResize;
+ xev.sequence = 0;
+ xev.window = window;
+ xev.format = 32;
+ xev.data.data32[0] = 0;
+ xev.data.data32[1] = 0;
+ xev.data.data32[2] = 11; // _NET_WM_MOVERESIZE_CANCEL
+ xev.data.data32[3] = 0;
+ xev.data.data32[4] = 0;
+ xcb_send_event(xcb_connection(), false, primaryScreen()->root(),
+ XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY,
+ (const char *)&xev);
+
+ m_duringSystemMoveResize = false;
+}
+
+bool QXcbConnection::isDuringSystemMoveResize() const
+{
+ return m_duringSystemMoveResize;
+}
+
+void QXcbConnection::setDuringSystemMoveResize(bool during)
+{
+ m_duringSystemMoveResize = during;
}
bool QXcbConnection::xi2SetMouseGrabEnabled(xcb_window_t w, bool grab)
@@ -819,20 +1047,33 @@ bool QXcbConnection::xi2SetMouseGrabEnabled(xcb_window_t w, bool grab)
bool ok = false;
if (grab) { // grab
- uint32_t mask = XCB_INPUT_XI_EVENT_MASK_BUTTON_PRESS
- | XCB_INPUT_XI_EVENT_MASK_BUTTON_RELEASE
- | XCB_INPUT_XI_EVENT_MASK_MOTION
- | XCB_INPUT_XI_EVENT_MASK_ENTER
- | XCB_INPUT_XI_EVENT_MASK_LEAVE
- | XCB_INPUT_XI_EVENT_MASK_TOUCH_BEGIN
- | XCB_INPUT_XI_EVENT_MASK_TOUCH_UPDATE
- | XCB_INPUT_XI_EVENT_MASK_TOUCH_END;
-
- for (int id : qAsConst(m_xiMasterPointerIds)) {
+ uint8_t mask[8] = {};
+ setXcbMask(mask, XCB_INPUT_BUTTON_PRESS);
+ setXcbMask(mask, XCB_INPUT_BUTTON_RELEASE);
+ setXcbMask(mask, XCB_INPUT_MOTION);
+ setXcbMask(mask, XCB_INPUT_ENTER);
+ setXcbMask(mask, XCB_INPUT_LEAVE);
+ if (isAtLeastXI22()) {
+ setXcbMask(mask, XCB_INPUT_TOUCH_BEGIN);
+ setXcbMask(mask, XCB_INPUT_TOUCH_UPDATE);
+ setXcbMask(mask, XCB_INPUT_TOUCH_END);
+ }
+#if QT_CONFIG(gestures) && QT_XCB_HAS_TOUCHPAD_GESTURES
+ if (isAtLeastXI24()) {
+ setXcbMask(mask, XCB_INPUT_GESTURE_PINCH_BEGIN);
+ setXcbMask(mask, XCB_INPUT_GESTURE_PINCH_UPDATE);
+ setXcbMask(mask, XCB_INPUT_GESTURE_PINCH_END);
+ setXcbMask(mask, XCB_INPUT_GESTURE_SWIPE_BEGIN);
+ setXcbMask(mask, XCB_INPUT_GESTURE_SWIPE_UPDATE);
+ setXcbMask(mask, XCB_INPUT_GESTURE_SWIPE_END);
+ }
+#endif // QT_CONFIG(gestures) && QT_XCB_HAS_TOUCHPAD_GESTURES
+
+ for (int id : std::as_const(m_xiMasterPointerIds)) {
xcb_generic_error_t *error = nullptr;
auto cookie = xcb_input_xi_grab_device(xcb_connection(), w, XCB_CURRENT_TIME, XCB_CURSOR_NONE, id,
XCB_INPUT_GRAB_MODE_22_ASYNC, XCB_INPUT_GRAB_MODE_22_ASYNC,
- false, 1, &mask);
+ false, 2, reinterpret_cast<uint32_t *>(mask));
auto *reply = xcb_input_xi_grab_device_reply(xcb_connection(), cookie, &error);
if (error) {
qCDebug(lcQpaXInput, "failed to grab events for device %d on window %x"
@@ -846,7 +1087,7 @@ bool QXcbConnection::xi2SetMouseGrabEnabled(xcb_window_t w, bool grab)
free(reply);
}
} else { // ungrab
- for (int id : qAsConst(m_xiMasterPointerIds)) {
+ for (int id : std::as_const(m_xiMasterPointerIds)) {
auto cookie = xcb_input_xi_ungrab_device_checked(xcb_connection(), XCB_CURRENT_TIME, id);
xcb_generic_error_t *error = xcb_request_check(xcb_connection(), cookie);
if (error) {
@@ -870,37 +1111,192 @@ bool QXcbConnection::xi2SetMouseGrabEnabled(xcb_window_t w, bool grab)
void QXcbConnection::xi2HandleHierarchyEvent(void *event)
{
auto *xiEvent = reinterpret_cast<xcb_input_hierarchy_event_t *>(event);
- // We only care about hotplugged devices
- if (!(xiEvent->flags & (XCB_INPUT_HIERARCHY_MASK_SLAVE_REMOVED | XCB_INPUT_HIERARCHY_MASK_SLAVE_ADDED)))
+ // We care about hotplugged devices (slaves) and master devices.
+ // We don't report anything for DEVICE_ENABLED or DEVICE_DISABLED
+ // (but often that goes with adding or removal anyway).
+ // We don't react to SLAVE_ATTACHED or SLAVE_DETACHED either.
+ if (xiEvent->flags & (XCB_INPUT_HIERARCHY_MASK_MASTER_ADDED |
+ XCB_INPUT_HIERARCHY_MASK_MASTER_REMOVED |
+ XCB_INPUT_HIERARCHY_MASK_SLAVE_REMOVED |
+ XCB_INPUT_HIERARCHY_MASK_SLAVE_ADDED))
+ xi2SetupDevices();
+}
+
+#if QT_XCB_HAS_TOUCHPAD_GESTURES
+void QXcbConnection::xi2HandleGesturePinchEvent(void *event)
+{
+ auto *xiEvent = reinterpret_cast<qt_xcb_input_pinch_event_t *>(event);
+
+ if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled())) {
+ qCDebug(lcQpaXInputEvents, "XI2 gesture event type %d seq %d fingers %d pos %6.1f, "
+ "%6.1f root pos %6.1f, %6.1f delta_angle %6.1f scale %6.1f on window %x",
+ xiEvent->event_type, xiEvent->sequence, xiEvent->detail,
+ fixed1616ToReal(xiEvent->event_x), fixed1616ToReal(xiEvent->event_y),
+ fixed1616ToReal(xiEvent->root_x), fixed1616ToReal(xiEvent->root_y),
+ fixed1616ToReal(xiEvent->delta_angle), fixed1616ToReal(xiEvent->scale),
+ xiEvent->event);
+ }
+ QXcbWindow *platformWindow = platformWindowFromId(xiEvent->event);
+ if (!platformWindow)
return;
- xi2SetupDevices();
+ setTime(xiEvent->time);
+
+ TouchDeviceData *dev = touchDeviceForId(xiEvent->sourceid);
+ Q_ASSERT(dev);
+
+ uint32_t fingerCount = xiEvent->detail;
+
+ switch (xiEvent->event_type) {
+ case XCB_INPUT_GESTURE_PINCH_BEGIN:
+ // Gestures must be accepted when we are grabbing gesture events. Otherwise the entire
+ // sequence will get replayed when the grab ends.
+ if (m_xiGrab) {
+ xcb_input_xi_allow_events(xcb_connection(), XCB_CURRENT_TIME, xiEvent->deviceid,
+ XCB_INPUT_EVENT_MODE_ASYNC_DEVICE, 0, xiEvent->event);
+ }
+ m_lastPinchScale = 1.0;
+ QWindowSystemInterface::handleGestureEvent(platformWindow->window(), xiEvent->time,
+ dev->qtTouchDevice,
+ Qt::BeginNativeGesture,
+ platformWindow->lastPointerPosition(),
+ platformWindow->lastPointerGlobalPosition(),
+ fingerCount);
+ break;
+
+ case XCB_INPUT_GESTURE_PINCH_UPDATE: {
+ qreal rotationDelta = fixed1616ToReal(xiEvent->delta_angle);
+ qreal scale = fixed1616ToReal(xiEvent->scale);
+ qreal scaleDelta = scale - m_lastPinchScale;
+ m_lastPinchScale = scale;
+
+ QPointF delta = QPointF(fixed1616ToReal(xiEvent->delta_x),
+ fixed1616ToReal(xiEvent->delta_y));
+
+ if (!delta.isNull()) {
+ QWindowSystemInterface::handleGestureEventWithValueAndDelta(
+ platformWindow->window(), xiEvent->time, dev->qtTouchDevice,
+ Qt::PanNativeGesture, 0, delta,
+ platformWindow->lastPointerPosition(),
+ platformWindow->lastPointerGlobalPosition(),
+ fingerCount);
+ }
+ if (rotationDelta != 0) {
+ QWindowSystemInterface::handleGestureEventWithRealValue(
+ platformWindow->window(), xiEvent->time, dev->qtTouchDevice,
+ Qt::RotateNativeGesture,
+ rotationDelta,
+ platformWindow->lastPointerPosition(),
+ platformWindow->lastPointerGlobalPosition(),
+ fingerCount);
+ }
+ if (scaleDelta != 0) {
+ QWindowSystemInterface::handleGestureEventWithRealValue(
+ platformWindow->window(), xiEvent->time, dev->qtTouchDevice,
+ Qt::ZoomNativeGesture,
+ scaleDelta,
+ platformWindow->lastPointerPosition(),
+ platformWindow->lastPointerGlobalPosition(),
+ fingerCount);
+ }
+ break;
+ }
+ case XCB_INPUT_GESTURE_PINCH_END:
+ QWindowSystemInterface::handleGestureEvent(platformWindow->window(), xiEvent->time,
+ dev->qtTouchDevice,
+ Qt::EndNativeGesture,
+ platformWindow->lastPointerPosition(),
+ platformWindow->lastPointerGlobalPosition(),
+ fingerCount);
+ break;
+ }
+}
+
+void QXcbConnection::xi2HandleGestureSwipeEvent(void *event)
+{
+ auto *xiEvent = reinterpret_cast<qt_xcb_input_swipe_event_t *>(event);
+
+ if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled())) {
+ qCDebug(lcQpaXInputEvents, "XI2 gesture event type %d seq %d detail %d pos %6.1f, %6.1f root pos %6.1f, %6.1f on window %x",
+ xiEvent->event_type, xiEvent->sequence, xiEvent->detail,
+ fixed1616ToReal(xiEvent->event_x), fixed1616ToReal(xiEvent->event_y),
+ fixed1616ToReal(xiEvent->root_x), fixed1616ToReal(xiEvent->root_y),
+ xiEvent->event);
+ }
+ QXcbWindow *platformWindow = platformWindowFromId(xiEvent->event);
+ if (!platformWindow)
+ return;
+
+ setTime(xiEvent->time);
+
+ TouchDeviceData *dev = touchDeviceForId(xiEvent->sourceid);
+ Q_ASSERT(dev);
+
+ uint32_t fingerCount = xiEvent->detail;
- if (xi2MouseEventsDisabled()) {
- // In compatibility mode (a.k.a xi2MouseEventsDisabled() mode) we select events for
- // each device separately. When a new device appears, we have to select events from
- // this device on all event-listening windows. This is not needed when events are
- // selected via XIAllDevices/XIAllMasterDevices (as in xi2SelectDeviceEvents()).
- for (auto it = m_mapper.cbegin(), end = m_mapper.cend(); it != end; ++it)
- xi2SelectDeviceEventsCompatibility(it.key());
+ switch (xiEvent->event_type) {
+ case XCB_INPUT_GESTURE_SWIPE_BEGIN:
+ // Gestures must be accepted when we are grabbing gesture events. Otherwise the entire
+ // sequence will get replayed when the grab ends.
+ if (m_xiGrab) {
+ xcb_input_xi_allow_events(xcb_connection(), XCB_CURRENT_TIME, xiEvent->deviceid,
+ XCB_INPUT_EVENT_MODE_ASYNC_DEVICE, 0, xiEvent->event);
+ }
+ QWindowSystemInterface::handleGestureEvent(platformWindow->window(), xiEvent->time,
+ dev->qtTouchDevice,
+ Qt::BeginNativeGesture,
+ platformWindow->lastPointerPosition(),
+ platformWindow->lastPointerGlobalPosition(),
+ fingerCount);
+ break;
+ case XCB_INPUT_GESTURE_SWIPE_UPDATE: {
+ QPointF delta = QPointF(fixed1616ToReal(xiEvent->delta_x),
+ fixed1616ToReal(xiEvent->delta_y));
+
+ if (xiEvent->delta_x != 0 || xiEvent->delta_y != 0) {
+ QWindowSystemInterface::handleGestureEventWithValueAndDelta(
+ platformWindow->window(), xiEvent->time, dev->qtTouchDevice,
+ Qt::PanNativeGesture, 0, delta,
+ platformWindow->lastPointerPosition(),
+ platformWindow->lastPointerGlobalPosition(),
+ fingerCount);
+ }
+ break;
+ }
+ case XCB_INPUT_GESTURE_SWIPE_END:
+ QWindowSystemInterface::handleGestureEvent(platformWindow->window(), xiEvent->time,
+ dev->qtTouchDevice,
+ Qt::EndNativeGesture,
+ platformWindow->lastPointerPosition(),
+ platformWindow->lastPointerGlobalPosition(),
+ fingerCount);
+ break;
}
}
+#else // QT_XCB_HAS_TOUCHPAD_GESTURES
+void QXcbConnection::xi2HandleGesturePinchEvent(void*) {}
+void QXcbConnection::xi2HandleGestureSwipeEvent(void*) {}
+#endif
+
void QXcbConnection::xi2HandleDeviceChangedEvent(void *event)
{
auto *xiEvent = reinterpret_cast<xcb_input_device_changed_event_t *>(event);
switch (xiEvent->reason) {
case XCB_INPUT_CHANGE_REASON_DEVICE_CHANGE: {
+ // Don't call xi2SetupSlavePointerDevice() again for an already-known device, and never for a master.
+ if (m_xiMasterPointerIds.contains(xiEvent->deviceid) || m_xiSlavePointerIds.contains(xiEvent->deviceid))
+ return;
auto reply = Q_XCB_REPLY(xcb_input_xi_query_device, xcb_connection(), xiEvent->sourceid);
if (!reply || reply->num_infos <= 0)
return;
auto it = xcb_input_xi_query_device_infos_iterator(reply.get());
- xi2SetupDevice(it.data);
+ xi2SetupSlavePointerDevice(it.data);
break;
}
case XCB_INPUT_CHANGE_REASON_SLAVE_SWITCH: {
- if (ScrollingDevice *scrollingDevice = scrollingDeviceForId(xiEvent->sourceid))
- xi2UpdateScrollingDevice(*scrollingDevice);
+ if (auto *scrollingDevice = scrollingDeviceForId(xiEvent->sourceid))
+ xi2UpdateScrollingDevice(scrollingDevice);
break;
}
default:
@@ -909,16 +1305,21 @@ void QXcbConnection::xi2HandleDeviceChangedEvent(void *event)
}
}
-void QXcbConnection::xi2UpdateScrollingDevice(ScrollingDevice &scrollingDevice)
+void QXcbConnection::xi2UpdateScrollingDevice(QInputDevice *dev)
{
- auto reply = Q_XCB_REPLY(xcb_input_xi_query_device, xcb_connection(), scrollingDevice.deviceId);
+ QXcbScrollingDevice *scrollDev = qobject_cast<QXcbScrollingDevice *>(dev);
+ if (!scrollDev || !scrollDev->capabilities().testFlag(QInputDevice::Capability::Scroll))
+ return;
+ QXcbScrollingDevicePrivate *scrollingDevice = QXcbScrollingDevice::get(scrollDev);
+
+ auto reply = Q_XCB_REPLY(xcb_input_xi_query_device, xcb_connection(), scrollingDevice->systemId);
if (!reply || reply->num_infos <= 0) {
- qCDebug(lcQpaXInputDevices, "scrolling device %d no longer present", scrollingDevice.deviceId);
+ qCDebug(lcQpaXInputDevices, "scrolling device %lld no longer present", scrollingDevice->systemId);
return;
}
QPointF lastScrollPosition;
if (lcQpaXInputEvents().isDebugEnabled())
- lastScrollPosition = scrollingDevice.lastScrollPosition;
+ lastScrollPosition = scrollingDevice->lastScrollPosition;
xcb_input_xi_device_info_t *deviceInfo = xcb_input_xi_query_device_infos_iterator(reply.get()).data;
auto classes_it = xcb_input_xi_device_info_classes_iterator(deviceInfo);
@@ -927,69 +1328,73 @@ void QXcbConnection::xi2UpdateScrollingDevice(ScrollingDevice &scrollingDevice)
if (classInfo->type == XCB_INPUT_DEVICE_CLASS_TYPE_VALUATOR) {
auto *vci = reinterpret_cast<xcb_input_valuator_class_t *>(classInfo);
const int valuatorAtom = qatom(vci->label);
- if (valuatorAtom == QXcbAtom::RelHorizScroll || valuatorAtom == QXcbAtom::RelHorizWheel)
- scrollingDevice.lastScrollPosition.setX(fixed3232ToReal(vci->value));
- else if (valuatorAtom == QXcbAtom::RelVertScroll || valuatorAtom == QXcbAtom::RelVertWheel)
- scrollingDevice.lastScrollPosition.setY(fixed3232ToReal(vci->value));
+ if (valuatorAtom == QXcbAtom::AtomRelHorizScroll || valuatorAtom == QXcbAtom::AtomRelHorizWheel)
+ scrollingDevice->lastScrollPosition.setX(fixed3232ToReal(vci->value));
+ else if (valuatorAtom == QXcbAtom::AtomRelVertScroll || valuatorAtom == QXcbAtom::AtomRelVertWheel)
+ scrollingDevice->lastScrollPosition.setY(fixed3232ToReal(vci->value));
}
}
- if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled() && lastScrollPosition != scrollingDevice.lastScrollPosition))
- qCDebug(lcQpaXInputEvents, "scrolling device %d moved from (%f, %f) to (%f, %f)", scrollingDevice.deviceId,
+ if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled() && lastScrollPosition != scrollingDevice->lastScrollPosition))
+ qCDebug(lcQpaXInputEvents, "scrolling device %lld moved from (%f, %f) to (%f, %f)", scrollingDevice->systemId,
lastScrollPosition.x(), lastScrollPosition.y(),
- scrollingDevice.lastScrollPosition.x(),
- scrollingDevice.lastScrollPosition.y());
+ scrollingDevice->lastScrollPosition.x(),
+ scrollingDevice->lastScrollPosition.y());
}
void QXcbConnection::xi2UpdateScrollingDevices()
{
- QHash<int, ScrollingDevice>::iterator it = m_scrollingDevices.begin();
- const QHash<int, ScrollingDevice>::iterator end = m_scrollingDevices.end();
- while (it != end) {
- xi2UpdateScrollingDevice(it.value());
- ++it;
+ const auto &devices = QInputDevice::devices();
+ for (const QInputDevice *dev : devices) {
+ if (dev->capabilities().testFlag(QInputDevice::Capability::Scroll))
+ xi2UpdateScrollingDevice(const_cast<QInputDevice *>(dev));
}
}
-QXcbConnection::ScrollingDevice *QXcbConnection::scrollingDeviceForId(int id)
+QXcbScrollingDevice *QXcbConnection::scrollingDeviceForId(int id)
{
- ScrollingDevice *dev = nullptr;
- if (m_scrollingDevices.contains(id))
- dev = &m_scrollingDevices[id];
- return dev;
+ const QPointingDevice *dev = QPointingDevicePrivate::pointingDeviceById(id);
+ if (!dev|| !dev->capabilities().testFlag(QInputDevice::Capability::Scroll))
+ return nullptr;
+ return qobject_cast<QXcbScrollingDevice *>(const_cast<QPointingDevice *>(dev));
}
-void QXcbConnection::xi2HandleScrollEvent(void *event, ScrollingDevice &scrollingDevice)
+void QXcbConnection::xi2HandleScrollEvent(void *event, const QPointingDevice *dev)
{
auto *xiDeviceEvent = reinterpret_cast<qt_xcb_input_device_event_t *>(event);
- if (xiDeviceEvent->event_type == XCB_INPUT_MOTION && scrollingDevice.orientations) {
+ const QXcbScrollingDevice *scrollDev = qobject_cast<const QXcbScrollingDevice *>(dev);
+ if (!scrollDev || !scrollDev->capabilities().testFlag(QInputDevice::Capability::Scroll))
+ return;
+ const QXcbScrollingDevicePrivate *scrollingDevice = QXcbScrollingDevice::get(scrollDev);
+
+ if (xiDeviceEvent->event_type == XCB_INPUT_MOTION && scrollingDevice->orientations) {
if (QXcbWindow *platformWindow = platformWindowFromId(xiDeviceEvent->event)) {
QPoint rawDelta;
QPoint angleDelta;
double value;
- if (scrollingDevice.orientations & Qt::Vertical) {
- if (xi2GetValuatorValueIfSet(xiDeviceEvent, scrollingDevice.verticalIndex, &value)) {
- double delta = scrollingDevice.lastScrollPosition.y() - value;
- scrollingDevice.lastScrollPosition.setY(value);
- angleDelta.setY((delta / scrollingDevice.verticalIncrement) * 120);
+ if (scrollingDevice->orientations & Qt::Vertical) {
+ if (xi2GetValuatorValueIfSet(xiDeviceEvent, scrollingDevice->verticalIndex, &value)) {
+ double delta = scrollingDevice->lastScrollPosition.y() - value;
+ scrollingDevice->lastScrollPosition.setY(value);
+ angleDelta.setY((delta / scrollingDevice->verticalIncrement) * 120);
// With most drivers the increment is 1 for wheels.
// For libinput it is hardcoded to a useless 15.
// For a proper touchpad driver it should be in the same order of magnitude as 120
- if (scrollingDevice.verticalIncrement > 15)
+ if (scrollingDevice->verticalIncrement > 15)
rawDelta.setY(delta);
- else if (scrollingDevice.verticalIncrement < -15)
+ else if (scrollingDevice->verticalIncrement < -15)
rawDelta.setY(-delta);
}
}
- if (scrollingDevice.orientations & Qt::Horizontal) {
- if (xi2GetValuatorValueIfSet(xiDeviceEvent, scrollingDevice.horizontalIndex, &value)) {
- double delta = scrollingDevice.lastScrollPosition.x() - value;
- scrollingDevice.lastScrollPosition.setX(value);
- angleDelta.setX((delta / scrollingDevice.horizontalIncrement) * 120);
+ if (scrollingDevice->orientations & Qt::Horizontal) {
+ if (xi2GetValuatorValueIfSet(xiDeviceEvent, scrollingDevice->horizontalIndex, &value)) {
+ double delta = scrollingDevice->lastScrollPosition.x() - value;
+ scrollingDevice->lastScrollPosition.setX(value);
+ angleDelta.setX((delta / scrollingDevice->horizontalIncrement) * 120);
// See comment under vertical
- if (scrollingDevice.horizontalIncrement > 15)
+ if (scrollingDevice->horizontalIncrement > 15)
rawDelta.setX(delta);
- else if (scrollingDevice.horizontalIncrement < -15)
+ else if (scrollingDevice->horizontalIncrement < -15)
rawDelta.setX(-delta);
}
}
@@ -1001,20 +1406,22 @@ void QXcbConnection::xi2HandleScrollEvent(void *event, ScrollingDevice &scrollin
angleDelta = angleDelta.transposed();
rawDelta = rawDelta.transposed();
}
- qCDebug(lcQpaXInputEvents) << "scroll wheel @ window pos" << local << "delta px" << rawDelta << "angle" << angleDelta;
- QWindowSystemInterface::handleWheelEvent(platformWindow->window(), xiDeviceEvent->time, local, global, rawDelta, angleDelta, modifiers);
+ qCDebug(lcQpaXInputEvents) << "scroll wheel from device" << scrollingDevice->systemId
+ << "@ window pos" << local << "delta px" << rawDelta << "angle" << angleDelta;
+ QWindowSystemInterface::handleWheelEvent(platformWindow->window(), xiDeviceEvent->time, dev,
+ local, global, rawDelta, angleDelta, modifiers);
}
}
- } else if (xiDeviceEvent->event_type == XCB_INPUT_BUTTON_RELEASE && scrollingDevice.legacyOrientations) {
+ } else if (xiDeviceEvent->event_type == XCB_INPUT_BUTTON_RELEASE && scrollingDevice->legacyOrientations) {
if (QXcbWindow *platformWindow = platformWindowFromId(xiDeviceEvent->event)) {
QPoint angleDelta;
- if (scrollingDevice.legacyOrientations & Qt::Vertical) {
+ if (scrollingDevice->legacyOrientations & Qt::Vertical) {
if (xiDeviceEvent->detail == 4)
angleDelta.setY(120);
else if (xiDeviceEvent->detail == 5)
angleDelta.setY(-120);
}
- if (scrollingDevice.legacyOrientations & Qt::Horizontal) {
+ if (scrollingDevice->legacyOrientations & Qt::Horizontal) {
if (xiDeviceEvent->detail == 6)
angleDelta.setX(120);
else if (xiDeviceEvent->detail == 7)
@@ -1027,7 +1434,8 @@ void QXcbConnection::xi2HandleScrollEvent(void *event, ScrollingDevice &scrollin
if (modifiers & Qt::AltModifier)
angleDelta = angleDelta.transposed();
qCDebug(lcQpaXInputEvents) << "scroll wheel (button" << xiDeviceEvent->detail << ") @ window pos" << local << "delta angle" << angleDelta;
- QWindowSystemInterface::handleWheelEvent(platformWindow->window(), xiDeviceEvent->time, local, global, QPoint(), angleDelta, modifiers);
+ QWindowSystemInterface::handleWheelEvent(platformWindow->window(), xiDeviceEvent->time, dev,
+ local, global, QPoint(), angleDelta, modifiers);
}
}
}
@@ -1083,51 +1491,6 @@ Qt::MouseButton QXcbConnection::xiToQtMouseButton(uint32_t b)
}
#if QT_CONFIG(tabletevent)
-static QTabletEvent::TabletDevice toolIdToTabletDevice(quint32 toolId) {
- // keep in sync with wacom_intuos_inout() in Linux kernel driver wacom_wac.c
- switch (toolId) {
- case 0xd12:
- case 0x912:
- case 0x112:
- case 0x913: /* Intuos3 Airbrush */
- case 0x91b: /* Intuos3 Airbrush Eraser */
- case 0x902: /* Intuos4/5 13HD/24HD Airbrush */
- case 0x90a: /* Intuos4/5 13HD/24HD Airbrush Eraser */
- case 0x100902: /* Intuos4/5 13HD/24HD Airbrush */
- case 0x10090a: /* Intuos4/5 13HD/24HD Airbrush Eraser */
- return QTabletEvent::Airbrush;
- case 0x007: /* Mouse 4D and 2D */
- case 0x09c:
- case 0x094:
- return QTabletEvent::FourDMouse;
- case 0x017: /* Intuos3 2D Mouse */
- case 0x806: /* Intuos4 Mouse */
- case 0x096: /* Lens cursor */
- case 0x097: /* Intuos3 Lens cursor */
- case 0x006: /* Intuos4 Lens cursor */
- return QTabletEvent::Puck;
- case 0x885: /* Intuos3 Art Pen (Marker Pen) */
- case 0x100804: /* Intuos4/5 13HD/24HD Art Pen */
- case 0x10080c: /* Intuos4/5 13HD/24HD Art Pen Eraser */
- return QTabletEvent::RotationStylus;
- case 0:
- return QTabletEvent::NoDevice;
- }
- return QTabletEvent::Stylus; // Safe default assumption if nonzero
-}
-
-static const char *toolName(QTabletEvent::TabletDevice tool) {
- static const QMetaObject *metaObject = qt_getEnumMetaObject(tool);
- static const QMetaEnum me = metaObject->enumerator(metaObject->indexOfEnumerator(qt_getEnumName(tool)));
- return me.valueToKey(tool);
-}
-
-static const char *pointerTypeName(QTabletEvent::PointerType ptype) {
- static const QMetaObject *metaObject = qt_getEnumMetaObject(ptype);
- static const QMetaEnum me = metaObject->enumerator(metaObject->indexOfEnumerator(qt_getEnumName(ptype)));
- return me.valueToKey(ptype);
-}
-
bool QXcbConnection::xi2HandleTabletEvent(const void *event, TabletData *tabletData)
{
bool handled = true;
@@ -1154,7 +1517,7 @@ bool QXcbConnection::xi2HandleTabletEvent(const void *event, TabletData *tabletD
// The evdev driver doesn't do it this way.
const auto *ev = reinterpret_cast<const xcb_input_property_event_t *>(event);
if (ev->what == XCB_INPUT_PROPERTY_FLAG_MODIFIED) {
- if (ev->property == atom(QXcbAtom::WacomSerialIDs)) {
+ if (ev->property == atom(QXcbAtom::AtomWacomSerialIDs)) {
enum WacomSerialIndex {
_WACSER_USB_ID = 0,
_WACSER_LAST_TOOL_SERIAL,
@@ -1167,7 +1530,7 @@ bool QXcbConnection::xi2HandleTabletEvent(const void *event, TabletData *tabletD
auto reply = Q_XCB_REPLY(xcb_input_xi_get_property, xcb_connection(), tabletData->deviceId, 0,
ev->property, XCB_GET_PROPERTY_TYPE_ANY, 0, 100);
if (reply) {
- if (reply->type == atom(QXcbAtom::INTEGER) && reply->format == 32 && reply->num_items == _WACSER_COUNT) {
+ if (reply->type == atom(QXcbAtom::AtomINTEGER) && reply->format == 32 && reply->num_items == _WACSER_COUNT) {
quint32 *ptr = reinterpret_cast<quint32 *>(xcb_input_xi_get_property_items(reply.get()));
quint32 tool = ptr[_WACSER_TOOL_ID];
// Workaround for http://sourceforge.net/p/linuxwacom/bugs/246/
@@ -1175,30 +1538,35 @@ bool QXcbConnection::xi2HandleTabletEvent(const void *event, TabletData *tabletD
if (!tool && ptr[_WACSER_TOOL_SERIAL])
tool = ptr[_WACSER_TOOL_SERIAL];
+ QWindow *win = nullptr; // TODO QTBUG-111400 get the position somehow, then the window
// The property change event informs us which tool is in proximity or which one left proximity.
if (tool) {
+ const QPointingDevice *dev = tabletToolInstance(nullptr, tabletData->name,
+ tabletData->deviceId, ptr[_WACSER_USB_ID], tool,
+ qint64(ptr[_WACSER_TOOL_SERIAL])); // TODO look up the master
tabletData->inProximity = true;
- tabletData->tool = toolIdToTabletDevice(tool);
- tabletData->serialId = qint64(ptr[_WACSER_USB_ID]) << 32 | qint64(ptr[_WACSER_TOOL_SERIAL]);
- QWindowSystemInterface::handleTabletEnterProximityEvent(ev->time,
- tabletData->tool, tabletData->pointerType, tabletData->serialId);
+ tabletData->tool = dev->type();
+ tabletData->serialId = qint64(ptr[_WACSER_TOOL_SERIAL]);
+ QWindowSystemInterface::handleTabletEnterLeaveProximityEvent(win, ev->time, dev, true); // enter
} else {
- tabletData->inProximity = false;
- tabletData->tool = toolIdToTabletDevice(ptr[_WACSER_LAST_TOOL_ID]);
+ tool = ptr[_WACSER_LAST_TOOL_ID];
// Workaround for http://sourceforge.net/p/linuxwacom/bugs/246/
// e.g. on Thinkpad Helix, tool ID will be 0 and serial will be 1
- if (!tabletData->tool)
- tabletData->tool = toolIdToTabletDevice(ptr[_WACSER_LAST_TOOL_SERIAL]);
- tabletData->serialId = qint64(ptr[_WACSER_USB_ID]) << 32 | qint64(ptr[_WACSER_LAST_TOOL_SERIAL]);
- QWindowSystemInterface::handleTabletLeaveProximityEvent(ev->time,
- tabletData->tool, tabletData->pointerType, tabletData->serialId);
+ if (!tool)
+ tool = ptr[_WACSER_LAST_TOOL_SERIAL];
+ auto *dev = qobject_cast<const QPointingDevice *>(QInputDevicePrivate::fromId(tabletData->deviceId));
+ Q_ASSERT(dev);
+ tabletData->tool = dev->type();
+ tabletData->inProximity = false;
+ tabletData->serialId = qint64(ptr[_WACSER_LAST_TOOL_SERIAL]);
+ QWindowSystemInterface::handleTabletEnterLeaveProximityEvent(win, ev->time, dev, false); // leave
}
// TODO maybe have a hash of tabletData->deviceId to device data so we can
// look up the tablet name here, and distinguish multiple tablets
- if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled()))
- qCDebug(lcQpaXInputEvents, "XI2 proximity change on tablet %d (USB %x): last tool: %x id %x current tool: %x id %x %s",
- tabletData->deviceId, ptr[_WACSER_USB_ID], ptr[_WACSER_LAST_TOOL_SERIAL], ptr[_WACSER_LAST_TOOL_ID],
- ptr[_WACSER_TOOL_SERIAL], ptr[_WACSER_TOOL_ID], toolName(tabletData->tool));
+ qCDebug(lcQpaXInputDevices, "XI2 proximity change on tablet %d %s (USB %x): last tool: %x id %x current tool: %x id %x %s",
+ tabletData->deviceId, qPrintable(tabletData->name), ptr[_WACSER_USB_ID],
+ ptr[_WACSER_LAST_TOOL_SERIAL], ptr[_WACSER_LAST_TOOL_ID],
+ ptr[_WACSER_TOOL_SERIAL], ptr[_WACSER_TOOL_ID], toolName(tabletData->tool));
}
}
}
@@ -1218,6 +1586,7 @@ inline qreal scaleOneValuator(qreal normValue, qreal screenMin, qreal screenSize
return screenMin + normValue * screenSize;
}
+// TODO QPointingDevice not TabletData
void QXcbConnection::xi2ReportTabletEvent(const void *event, TabletData *tabletData)
{
auto *ev = reinterpret_cast<const qt_xcb_input_device_event_t *>(event);
@@ -1231,6 +1600,9 @@ void QXcbConnection::xi2ReportTabletEvent(const void *event, TabletData *tabletD
double pressure = 0, rotation = 0, tangentialPressure = 0;
int xTilt = 0, yTilt = 0;
static const bool useValuators = !qEnvironmentVariableIsSet("QT_XCB_TABLET_LEGACY_COORDINATES");
+ const QPointingDevice *dev = QPointingDevicePrivate::tabletDevice(QInputDevice::DeviceType(tabletData->tool),
+ QPointingDevice::PointerType(tabletData->pointerType),
+ QPointingDeviceUniqueId::fromNumericId(tabletData->serialId));
// Valuators' values are relative to the physical size of the current virtual
// screen. Therefore we cannot use QScreen/QWindow geometry and should use
@@ -1249,38 +1621,37 @@ void QXcbConnection::xi2ReportTabletEvent(const void *event, TabletData *tabletD
xi2GetValuatorValueIfSet(event, classInfo.number, &classInfo.curVal);
double normalizedValue = (classInfo.curVal - classInfo.minVal) / (classInfo.maxVal - classInfo.minVal);
switch (valuator) {
- case QXcbAtom::AbsX:
+ case QXcbAtom::AtomAbsX:
if (Q_LIKELY(useValuators)) {
const qreal value = scaleOneValuator(normalizedValue, physicalScreenArea.x(), physicalScreenArea.width());
global.setX(value);
- // mapFromGlobal is ok for nested/embedded windows, but works only with whole-number QPoint;
- // so map it first, then add back the sub-pixel position
- local.setX(window->mapFromGlobal(QPoint(int(value), 0)).x() + (value - int(value)));
+ local.setX(xcbWindow->mapFromGlobalF(global).x());
}
break;
- case QXcbAtom::AbsY:
+ case QXcbAtom::AtomAbsY:
if (Q_LIKELY(useValuators)) {
qreal value = scaleOneValuator(normalizedValue, physicalScreenArea.y(), physicalScreenArea.height());
global.setY(value);
- local.setY(window->mapFromGlobal(QPoint(0, int(value))).y() + (value - int(value)));
+ local.setY(xcbWindow->mapFromGlobalF(global).y());
}
break;
- case QXcbAtom::AbsPressure:
+ case QXcbAtom::AtomAbsPressure:
pressure = normalizedValue;
break;
- case QXcbAtom::AbsTiltX:
+ case QXcbAtom::AtomAbsTiltX:
xTilt = classInfo.curVal;
break;
- case QXcbAtom::AbsTiltY:
+ case QXcbAtom::AtomAbsTiltY:
yTilt = classInfo.curVal;
break;
- case QXcbAtom::AbsWheel:
+ case QXcbAtom::AtomAbsWheel:
switch (tabletData->tool) {
- case QTabletEvent::Airbrush:
+ case QInputDevice::DeviceType::Airbrush:
tangentialPressure = normalizedValue * 2.0 - 1.0; // Convert 0..1 range to -1..+1 range
break;
- case QTabletEvent::RotationStylus:
- rotation = normalizedValue * 360.0 - 180.0; // Convert 0..1 range to -180..+180 degrees
+ case QInputDevice::DeviceType::Stylus:
+ if (dev->capabilities().testFlag(QInputDevice::Capability::Rotation))
+ rotation = normalizedValue * 360.0 - 180.0; // Convert 0..1 range to -180..+180 degrees
break;
default: // Other types of styli do not use this valuator
break;
@@ -1292,23 +1663,22 @@ void QXcbConnection::xi2ReportTabletEvent(const void *event, TabletData *tabletD
}
if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled()))
- qCDebug(lcQpaXInputEvents, "XI2 event on tablet %d with tool %s type %s seq %d detail %d time %d "
+ qCDebug(lcQpaXInputEvents, "XI2 event on tablet %d with tool %s %llx type %s seq %d detail %d time %d "
"pos %6.1f, %6.1f root pos %6.1f, %6.1f buttons 0x%x pressure %4.2lf tilt %d, %d rotation %6.2lf modifiers 0x%x",
- tabletData->deviceId, toolName(tabletData->tool), pointerTypeName(tabletData->pointerType),
+ tabletData->deviceId, toolName(tabletData->tool), tabletData->serialId, pointerTypeName(tabletData->pointerType),
ev->sequence, ev->detail, ev->time,
local.x(), local.y(), global.x(), global.y(),
(int)tabletData->buttons, pressure, xTilt, yTilt, rotation, (int)modifiers);
- QWindowSystemInterface::handleTabletEvent(window, ev->time, local, global,
- tabletData->tool, tabletData->pointerType,
+ QWindowSystemInterface::handleTabletEvent(window, ev->time, dev, local, global,
tabletData->buttons, pressure,
xTilt, yTilt, tangentialPressure,
- rotation, 0, tabletData->serialId, modifiers);
+ rotation, 0, modifiers);
}
QXcbConnection::TabletData *QXcbConnection::tabletDataForDevice(int id)
{
- for (int i = 0; i < m_tabletData.count(); ++i) {
+ for (int i = 0; i < m_tabletData.size(); ++i) {
if (m_tabletData.at(i).deviceId == id)
return &m_tabletData[i];
}
diff --git a/src/plugins/platforms/xcb/qxcbcursor.cpp b/src/plugins/platforms/xcb/qxcbcursor.cpp
index 639e4f039c..dc9ed46956 100644
--- a/src/plugins/platforms/xcb/qxcbcursor.cpp
+++ b/src/plugins/platforms/xcb/qxcbcursor.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qxcbcursor.h"
#include "qxcbconnection.h"
@@ -43,35 +7,23 @@
#include "qxcbimage.h"
#include "qxcbxsettings.h"
-#if QT_CONFIG(library)
-#include <QtCore/QLibrary>
-#endif
#include <QtGui/QWindow>
#include <QtGui/QBitmap>
#include <QtGui/private/qguiapplication_p.h>
+#include <qpa/qplatformtheme.h>
+
+#if QT_CONFIG(xcb_xlib)
#include <X11/cursorfont.h>
+#else
+#include "qxcbcursorfont.h"
+#endif
+
#include <xcb/xfixes.h>
#include <xcb/xcb_image.h>
QT_BEGIN_NAMESPACE
-typedef int (*PtrXcursorLibraryLoadCursor)(void *, const char *);
-typedef char *(*PtrXcursorLibraryGetTheme)(void *);
-typedef int (*PtrXcursorLibrarySetTheme)(void *, const char *);
-typedef int (*PtrXcursorLibraryGetDefaultSize)(void *);
-
-#if QT_CONFIG(xcb_xlib) && QT_CONFIG(library)
-#include <X11/Xlib.h>
-enum {
- XCursorShape = CursorShape
-};
-#undef CursorShape
-
-static PtrXcursorLibraryLoadCursor ptrXcursorLibraryLoadCursor = nullptr;
-static PtrXcursorLibraryGetTheme ptrXcursorLibraryGetTheme = nullptr;
-static PtrXcursorLibrarySetTheme ptrXcursorLibrarySetTheme = nullptr;
-static PtrXcursorLibraryGetDefaultSize ptrXcursorLibraryGetDefaultSize = nullptr;
-#endif
+using namespace Qt::StringLiterals;
static xcb_font_t cursorFont = 0;
static int cursorCount = 0;
@@ -289,10 +241,10 @@ QXcbCursorCacheKey::QXcbCursorCacheKey(const QCursor &c)
if (pixmapCacheKey) {
bitmapCacheKey = pixmapCacheKey;
} else {
- Q_ASSERT(c.bitmap());
- Q_ASSERT(c.mask());
- bitmapCacheKey = c.bitmap()->cacheKey();
- maskCacheKey = c.mask()->cacheKey();
+ Q_ASSERT(!c.bitmap().isNull());
+ Q_ASSERT(!c.mask().isNull());
+ bitmapCacheKey = c.bitmap().cacheKey();
+ maskCacheKey = c.mask().cacheKey();
}
}
}
@@ -300,50 +252,28 @@ QXcbCursorCacheKey::QXcbCursorCacheKey(const QCursor &c)
#endif // !QT_NO_CURSOR
QXcbCursor::QXcbCursor(QXcbConnection *conn, QXcbScreen *screen)
- : QXcbObject(conn), m_screen(screen), m_gtkCursorThemeInitialized(false)
+ : QXcbObject(conn), m_screen(screen), m_cursorContext(nullptr), m_callbackForPropertyRegistered(false)
{
#if QT_CONFIG(cursor)
// see NUM_BITMAPS in libXcursor/src/xcursorint.h
m_bitmapCache.setMaxCost(8);
#endif
+ updateContext();
+
if (cursorCount++)
return;
cursorFont = xcb_generate_id(xcb_connection());
const char *cursorStr = "cursor";
xcb_open_font(xcb_connection(), cursorFont, strlen(cursorStr), cursorStr);
-
-#if QT_CONFIG(xcb_xlib) && QT_CONFIG(library)
- static bool function_ptrs_not_initialized = true;
- if (function_ptrs_not_initialized) {
- QLibrary xcursorLib(QLatin1String("Xcursor"), 1);
- bool xcursorFound = xcursorLib.load();
- if (!xcursorFound) { // try without the version number
- xcursorLib.setFileName(QLatin1String("Xcursor"));
- xcursorFound = xcursorLib.load();
- }
- if (xcursorFound) {
- ptrXcursorLibraryLoadCursor =
- (PtrXcursorLibraryLoadCursor) xcursorLib.resolve("XcursorLibraryLoadCursor");
- ptrXcursorLibraryGetTheme =
- (PtrXcursorLibraryGetTheme) xcursorLib.resolve("XcursorGetTheme");
- ptrXcursorLibrarySetTheme =
- (PtrXcursorLibrarySetTheme) xcursorLib.resolve("XcursorSetTheme");
- ptrXcursorLibraryGetDefaultSize =
- (PtrXcursorLibraryGetDefaultSize) xcursorLib.resolve("XcursorGetDefaultSize");
- }
- function_ptrs_not_initialized = false;
- }
-
-#endif
}
QXcbCursor::~QXcbCursor()
{
xcb_connection_t *conn = xcb_connection();
- if (m_gtkCursorThemeInitialized) {
+ if (m_callbackForPropertyRegistered) {
m_screen->xSettings()->removeCallbackForHandle(this);
}
@@ -351,9 +281,33 @@ QXcbCursor::~QXcbCursor()
xcb_close_font(conn, cursorFont);
#ifndef QT_NO_CURSOR
- for (xcb_cursor_t cursor : qAsConst(m_cursorHash))
+ for (xcb_cursor_t cursor : std::as_const(m_cursorHash))
xcb_free_cursor(conn, cursor);
#endif
+
+ if (m_cursorContext)
+ xcb_cursor_context_free(m_cursorContext);
+}
+
+QSize QXcbCursor::size() const
+{
+ if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme())
+ return theme->themeHint(QPlatformTheme::MouseCursorSize).toSize();
+ return QSize(24, 24);
+}
+
+void QXcbCursor::updateContext()
+{
+ if (m_cursorContext)
+ xcb_cursor_context_free(m_cursorContext);
+
+ m_cursorContext = nullptr;
+
+ xcb_connection_t *conn = xcb_connection();
+ if (xcb_cursor_context_new(conn, m_screen->screen(), &m_cursorContext) < 0) {
+ qWarning() << "xcb: Could not initialize xcb-cursor";
+ m_cursorContext = nullptr;
+ }
}
#ifndef QT_NO_CURSOR
@@ -516,77 +470,44 @@ xcb_cursor_t QXcbCursor::createNonStandardCursor(int cshape)
return cursor;
}
-#if QT_CONFIG(xcb_xlib) && QT_CONFIG(library)
-bool updateCursorTheme(void *dpy, const QByteArray &theme) {
- if (!ptrXcursorLibraryGetTheme
- || !ptrXcursorLibrarySetTheme)
- return false;
- QByteArray oldTheme = ptrXcursorLibraryGetTheme(dpy);
- if (oldTheme == theme)
- return false;
-
- int setTheme = ptrXcursorLibrarySetTheme(dpy,theme.constData());
- return setTheme;
-}
-
- void QXcbCursor::cursorThemePropertyChanged(QXcbVirtualDesktop *screen, const QByteArray &name, const QVariant &property, void *handle)
+void QXcbCursor::cursorThemePropertyChanged(QXcbVirtualDesktop *screen, const QByteArray &name, const QVariant &property, void *handle)
{
Q_UNUSED(screen);
Q_UNUSED(name);
+ Q_UNUSED(property);
QXcbCursor *self = static_cast<QXcbCursor *>(handle);
- updateCursorTheme(self->connection()->xlib_display(),property.toByteArray());
-}
-
-static xcb_cursor_t loadCursor(void *dpy, int cshape)
-{
- xcb_cursor_t cursor = XCB_NONE;
- if (!ptrXcursorLibraryLoadCursor || !dpy)
- return cursor;
-
- for (const char *cursorName: cursorNames[cshape]) {
- cursor = ptrXcursorLibraryLoadCursor(dpy, cursorName);
- if (cursor != XCB_NONE)
- break;
- }
-
- return cursor;
+ self->m_cursorHash.clear();
+ self->updateContext();
}
-#endif // QT_CONFIG(xcb_xlib) / QT_CONFIG(library)
xcb_cursor_t QXcbCursor::createFontCursor(int cshape)
{
+ if (!m_cursorContext)
+ return XCB_NONE;
+
xcb_connection_t *conn = xcb_connection();
int cursorId = cursorIdForShape(cshape);
xcb_cursor_t cursor = XCB_NONE;
- // Try Xcursor first
-#if QT_CONFIG(xcb_xlib) && QT_CONFIG(library)
+ if (!m_callbackForPropertyRegistered && m_screen->xSettings()->initialized()) {
+ m_screen->xSettings()->registerCallbackForProperty("Gtk/CursorThemeName", cursorThemePropertyChanged, this);
+
+ m_callbackForPropertyRegistered = true;
+ }
+
+ // Try xcb-cursor 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);
- }
- m_gtkCursorThemeInitialized = true;
+ for (const char *cursorName : cursorNames[cshape]) {
+ cursor = xcb_cursor_load_cursor(m_cursorContext, cursorName);
+ if (cursor != XCB_NONE)
+ return cursor;
}
}
- if (cursor)
- return cursor;
- if (!cursor && cursorId) {
- cursor = XCreateFontCursor(static_cast<Display *>(connection()->xlib_display()), cursorId);
- if (cursor)
- return cursor;
- }
-
-#endif
// Non-standard X11 cursors are created from bitmaps
cursor = createNonStandardCursor(cshape);
- // Create a glpyh cursor if everything else failed
+ // Create a glyph cursor if everything else failed
if (!cursor && cursorId) {
cursor = xcb_generate_id(conn);
xcb_create_glyph_cursor(conn, cursor, cursorFont, cursorFont,
@@ -613,8 +534,8 @@ xcb_cursor_t QXcbCursor::createBitmapCursor(QCursor *cursor)
qCWarning(lcQpaXcb, "xrender >= 0.5 required to create pixmap cursors");
} else {
xcb_connection_t *conn = xcb_connection();
- xcb_pixmap_t cp = qt_xcb_XPixmapFromBitmap(m_screen, cursor->bitmap()->toImage());
- xcb_pixmap_t mp = qt_xcb_XPixmapFromBitmap(m_screen, cursor->mask()->toImage());
+ xcb_pixmap_t cp = qt_xcb_XPixmapFromBitmap(m_screen, cursor->bitmap().toImage());
+ xcb_pixmap_t mp = qt_xcb_XPixmapFromBitmap(m_screen, cursor->mask().toImage());
c = xcb_generate_id(conn);
xcb_create_cursor(conn, c, cp, mp, 0, 0, 0, 0xFFFF, 0xFFFF, 0xFFFF,
spot.x(), spot.y());
@@ -668,7 +589,8 @@ void QXcbCursor::setPos(const QPoint &pos)
{
QXcbVirtualDesktop *virtualDesktop = nullptr;
queryPointer(connection(), &virtualDesktop, nullptr);
- xcb_warp_pointer(xcb_connection(), XCB_NONE, virtualDesktop->root(), 0, 0, 0, 0, pos.x(), pos.y());
+ if (virtualDesktop)
+ xcb_warp_pointer(xcb_connection(), XCB_NONE, virtualDesktop->root(), 0, 0, 0, 0, pos.x(), pos.y());
xcb_flush(xcb_connection());
}
diff --git a/src/plugins/platforms/xcb/qxcbcursor.h b/src/plugins/platforms/xcb/qxcbcursor.h
index 0b238823f0..bf26861e8f 100644
--- a/src/plugins/platforms/xcb/qxcbcursor.h
+++ b/src/plugins/platforms/xcb/qxcbcursor.h
@@ -1,47 +1,12 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QXCBCURSOR_H
#define QXCBCURSOR_H
#include <qpa/qplatformcursor.h>
#include "qxcbscreen.h"
+#include <xcb/xcb_cursor.h>
#include <QtCore/QCache>
@@ -65,9 +30,9 @@ inline bool operator==(const QXcbCursorCacheKey &k1, const QXcbCursorCacheKey &k
return k1.shape == k2.shape && k1.bitmapCacheKey == k2.bitmapCacheKey && k1.maskCacheKey == k2.maskCacheKey;
}
-inline uint qHash(const QXcbCursorCacheKey &k, uint seed) noexcept
+inline size_t qHash(const QXcbCursorCacheKey &k, size_t seed) noexcept
{
- return (uint(k.shape) + uint(k.bitmapCacheKey) + uint(k.maskCacheKey)) ^ seed;
+ return (size_t(k.shape) + size_t(k.bitmapCacheKey) + size_t(k.maskCacheKey)) ^ seed;
}
#endif // !QT_NO_CURSOR
@@ -83,6 +48,10 @@ public:
QPoint pos() const override;
void setPos(const QPoint &pos) override;
+ QSize size() const override;
+
+ void updateContext();
+
static void queryPointer(QXcbConnection *c, QXcbVirtualDesktop **virtualDesktop, QPoint *pos, int *keybMask = nullptr);
#ifndef QT_NO_CURSOR
@@ -111,17 +80,16 @@ private:
#endif
QXcbScreen *m_screen;
+ xcb_cursor_context_t *m_cursorContext;
#ifndef QT_NO_CURSOR
CursorHash m_cursorHash;
BitmapCursorCache m_bitmapCache;
#endif
-#if QT_CONFIG(xcb_xlib) && QT_CONFIG(library)
static void cursorThemePropertyChanged(QXcbVirtualDesktop *screen,
const QByteArray &name,
const QVariant &property,
void *handle);
-#endif
- bool m_gtkCursorThemeInitialized;
+ bool m_callbackForPropertyRegistered;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/xcb/qxcbcursorfont.h b/src/plugins/platforms/xcb/qxcbcursorfont.h
new file mode 100644
index 0000000000..fe74e27691
--- /dev/null
+++ b/src/plugins/platforms/xcb/qxcbcursorfont.h
@@ -0,0 +1,88 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+// copied from <X11/cursorfont.h>
+
+#ifndef QXCBCURSORFONT_H
+#define QXCBCURSORFONT_H
+
+#define XC_num_glyphs 154
+#define XC_X_cursor 0
+#define XC_arrow 2
+#define XC_based_arrow_down 4
+#define XC_based_arrow_up 6
+#define XC_boat 8
+#define XC_bogosity 10
+#define XC_bottom_left_corner 12
+#define XC_bottom_right_corner 14
+#define XC_bottom_side 16
+#define XC_bottom_tee 18
+#define XC_box_spiral 20
+#define XC_center_ptr 22
+#define XC_circle 24
+#define XC_clock 26
+#define XC_coffee_mug 28
+#define XC_cross 30
+#define XC_cross_reverse 32
+#define XC_crosshair 34
+#define XC_diamond_cross 36
+#define XC_dot 38
+#define XC_dotbox 40
+#define XC_double_arrow 42
+#define XC_draft_large 44
+#define XC_draft_small 46
+#define XC_draped_box 48
+#define XC_exchange 50
+#define XC_fleur 52
+#define XC_gobbler 54
+#define XC_gumby 56
+#define XC_hand1 58
+#define XC_hand2 60
+#define XC_heart 62
+#define XC_icon 64
+#define XC_iron_cross 66
+#define XC_left_ptr 68
+#define XC_left_side 70
+#define XC_left_tee 72
+#define XC_leftbutton 74
+#define XC_ll_angle 76
+#define XC_lr_angle 78
+#define XC_man 80
+#define XC_middlebutton 82
+#define XC_mouse 84
+#define XC_pencil 86
+#define XC_pirate 88
+#define XC_plus 90
+#define XC_question_arrow 92
+#define XC_right_ptr 94
+#define XC_right_side 96
+#define XC_right_tee 98
+#define XC_rightbutton 100
+#define XC_rtl_logo 102
+#define XC_sailboat 104
+#define XC_sb_down_arrow 106
+#define XC_sb_h_double_arrow 108
+#define XC_sb_left_arrow 110
+#define XC_sb_right_arrow 112
+#define XC_sb_up_arrow 114
+#define XC_sb_v_double_arrow 116
+#define XC_shuttle 118
+#define XC_sizing 120
+#define XC_spider 122
+#define XC_spraycan 124
+#define XC_star 126
+#define XC_target 128
+#define XC_tcross 130
+#define XC_top_left_arrow 132
+#define XC_top_left_corner 134
+#define XC_top_right_corner 136
+#define XC_top_side 138
+#define XC_top_tee 140
+#define XC_trek 142
+#define XC_ul_angle 144
+#define XC_umbrella 146
+#define XC_ur_angle 148
+#define XC_watch 150
+#define XC_xterm 152
+
+#endif /* QXCBCURSORFONT_H */
diff --git a/src/plugins/platforms/xcb/qxcbdrag.cpp b/src/plugins/platforms/xcb/qxcbdrag.cpp
index e76fc8bd40..6e5dd770b9 100644
--- a/src/plugins/platforms/xcb/qxcbdrag.cpp
+++ b/src/plugins/platforms/xcb/qxcbdrag.cpp
@@ -1,46 +1,11 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qxcbdrag.h"
#include <xcb/xcb.h>
#include "qxcbconnection.h"
#include "qxcbclipboard.h"
+#include "qxcbkeyboard.h"
#include "qxcbmime.h"
#include "qxcbwindow.h"
#include "qxcbscreen.h"
@@ -63,6 +28,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::Literals::StringLiterals;
+
const int xdnd_version = 5;
static inline xcb_window_t xcb_window(QPlatformWindow *w)
@@ -80,7 +47,7 @@ static xcb_window_t xdndProxy(QXcbConnection *c, xcb_window_t w)
xcb_window_t proxy = XCB_NONE;
auto reply = Q_XCB_REPLY(xcb_get_property, c->xcb_connection(),
- false, w, c->atom(QXcbAtom::XdndProxy), XCB_ATOM_WINDOW, 0, 1);
+ false, w, c->atom(QXcbAtom::AtomXdndProxy), XCB_ATOM_WINDOW, 0, 1);
if (reply && reply->type == XCB_ATOM_WINDOW)
proxy = *((xcb_window_t *)xcb_get_property_value(reply.get()));
@@ -90,14 +57,14 @@ static xcb_window_t xdndProxy(QXcbConnection *c, xcb_window_t w)
// exists and is real?
reply = Q_XCB_REPLY(xcb_get_property, c->xcb_connection(),
- false, proxy, c->atom(QXcbAtom::XdndProxy), XCB_ATOM_WINDOW, 0, 1);
+ false, proxy, c->atom(QXcbAtom::AtomXdndProxy), XCB_ATOM_WINDOW, 0, 1);
if (reply && reply->type == XCB_ATOM_WINDOW) {
xcb_window_t p = *((xcb_window_t *)xcb_get_property_value(reply.get()));
if (proxy != p)
- proxy = 0;
+ proxy = XCB_NONE;
} else {
- proxy = 0;
+ proxy = XCB_NONE;
}
return proxy;
@@ -112,9 +79,9 @@ public:
protected:
bool hasFormat_sys(const QString &mimeType) const override;
QStringList formats_sys() const override;
- QVariant retrieveData_sys(const QString &mimeType, QVariant::Type type) const override;
+ QVariant retrieveData_sys(const QString &mimeType, QMetaType type) const override;
- QVariant xdndObtainData(const QByteArray &format, QMetaType::Type requestedType) const;
+ QVariant xdndObtainData(const QByteArray &format, QMetaType requestedType) const;
QXcbDrag *drag;
};
@@ -174,26 +141,23 @@ void QXcbDrag::startDrag()
{
init();
-#ifndef QT_NO_CLIPBOARD
- qCDebug(lcQpaXDnd) << "starting drag where source:" << connection()->clipboard()->owner();
- xcb_set_selection_owner(xcb_connection(), connection()->clipboard()->owner(),
- atom(QXcbAtom::XdndSelection), connection()->time());
-#endif
+ qCDebug(lcQpaXDnd) << "starting drag where source:" << connection()->qtSelectionOwner();
+ xcb_set_selection_owner(xcb_connection(), connection()->qtSelectionOwner(),
+ atom(QXcbAtom::AtomXdndSelection), connection()->time());
QStringList fmts = QXcbMime::formatsHelper(drag()->mimeData());
for (int i = 0; i < fmts.size(); ++i) {
- QVector<xcb_atom_t> atoms = QXcbMime::mimeAtomsForFormat(connection(), fmts.at(i));
+ QList<xcb_atom_t> atoms = QXcbMime::mimeAtomsForFormat(connection(), fmts.at(i));
for (int j = 0; j < atoms.size(); ++j) {
if (!drag_types.contains(atoms.at(j)))
drag_types.append(atoms.at(j));
}
}
-#ifndef QT_NO_CLIPBOARD
+
if (drag_types.size() > 3)
- xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, connection()->clipboard()->owner(),
- atom(QXcbAtom::XdndTypelist),
+ xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, connection()->qtSelectionOwner(),
+ atom(QXcbAtom::AtomXdndTypelist),
XCB_ATOM_ATOM, 32, drag_types.size(), (const void *)drag_types.constData());
-#endif
setUseCompositing(current_virtual_desktop->compositingActive());
setScreen(current_virtual_desktop->screens().constFirst()->screen());
@@ -216,6 +180,22 @@ void QXcbDrag::endDrag()
initiatorWindow.clear();
}
+Qt::DropAction QXcbDrag::defaultAction(Qt::DropActions possibleActions, Qt::KeyboardModifiers modifiers) const
+{
+ if (currentDrag() || drop_actions.isEmpty())
+ return QBasicDrag::defaultAction(possibleActions, modifiers);
+
+ return toDropAction(drop_actions.first());
+}
+
+void QXcbDrag::handlePropertyNotifyEvent(const xcb_property_notify_event_t *event)
+{
+ if (event->window != xdnd_dragsource || event->atom != atom(QXcbAtom::AtomXdndActionList))
+ return;
+
+ readActionList();
+}
+
static
bool windowInteractsWithPosition(xcb_connection_t *connection, const QPoint & pos, xcb_window_t w, xcb_shape_sk_t shapeType)
{
@@ -256,7 +236,7 @@ xcb_window_t QXcbDrag::findRealWindow(const QPoint & pos, xcb_window_t w, int md
bool windowContainsMouse = !ignoreNonXdndAwareWindows;
{
auto reply = Q_XCB_REPLY(xcb_get_property, xcb_connection(),
- false, w, connection()->atom(QXcbAtom::XdndAware),
+ false, w, connection()->atom(QXcbAtom::AtomXdndAware),
XCB_GET_PROPERTY_TYPE_ANY, 0, 0);
bool isAware = reply && reply->type != XCB_NONE;
if (isAware) {
@@ -329,7 +309,7 @@ bool QXcbDrag::findXdndAwareTarget(const QPoint &globalPos, xcb_window_t *target
xcb_window_t child = translate->child;
auto reply = Q_XCB_REPLY(xcb_get_property, xcb_connection(), false, target,
- atom(QXcbAtom::XdndAware), XCB_GET_PROPERTY_TYPE_ANY, 0, 0);
+ atom(QXcbAtom::AtomXdndAware), XCB_GET_PROPERTY_TYPE_ANY, 0, 0);
bool aware = reply && reply->type != XCB_NONE;
if (aware) {
qCDebug(lcQpaXDnd) << "found XdndAware on" << target;
@@ -402,12 +382,13 @@ void QXcbDrag::move(const QPoint &globalPos, Qt::MouseButtons b, Qt::KeyboardMod
if (proxy_target) {
auto reply = Q_XCB_REPLY(xcb_get_property, xcb_connection(),
false, proxy_target,
- atom(QXcbAtom::XdndAware), XCB_GET_PROPERTY_TYPE_ANY, 0, 1);
- if (!reply || reply->type == XCB_NONE)
+ atom(QXcbAtom::AtomXdndAware), XCB_GET_PROPERTY_TYPE_ANY, 0, 1);
+ if (!reply || reply->type == XCB_NONE) {
target = 0;
-
- target_version = *(uint32_t *)xcb_get_property_value(reply.get());
- target_version = qMin(xdnd_version, target_version ? target_version : 1);
+ } else {
+ target_version = *(uint32_t *)xcb_get_property_value(reply.get());
+ target_version = qMin(xdnd_version, target_version ? target_version : 1);
+ }
}
if (target != current_target) {
@@ -426,12 +407,8 @@ void QXcbDrag::move(const QPoint &globalPos, Qt::MouseButtons b, Qt::KeyboardMod
enter.sequence = 0;
enter.window = target;
enter.format = 32;
- enter.type = atom(QXcbAtom::XdndEnter);
-#ifndef QT_NO_CLIPBOARD
- enter.data.data32[0] = connection()->clipboard()->owner();
-#else
- enter.data.data32[0] = 0;
-#endif
+ enter.type = atom(QXcbAtom::AtomXdndEnter);
+ enter.data.data32[0] = connection()->qtSelectionOwner();
enter.data.data32[1] = flags;
enter.data.data32[2] = drag_types.size() > 0 ? drag_types.at(0) : 0;
enter.data.data32[3] = drag_types.size() > 1 ? drag_types.at(1) : 0;
@@ -461,31 +438,31 @@ void QXcbDrag::move(const QPoint &globalPos, Qt::MouseButtons b, Qt::KeyboardMod
move.sequence = 0;
move.window = target;
move.format = 32;
- move.type = atom(QXcbAtom::XdndPosition);
-#ifndef QT_NO_CLIPBOARD
- move.data.data32[0] = connection()->clipboard()->owner();
-#else
- move.data.data32[0] = 0;
-#endif
+ move.type = atom(QXcbAtom::AtomXdndPosition);
+ move.data.data32[0] = connection()->qtSelectionOwner();
move.data.data32[1] = 0; // flags
move.data.data32[2] = (globalPos.x() << 16) + globalPos.y();
move.data.data32[3] = connection()->time();
- move.data.data32[4] = toXdndAction(defaultAction(currentDrag()->supportedActions(), mods));
+ const auto supportedActions = currentDrag()->supportedActions();
+ const auto requestedAction = defaultAction(supportedActions, mods);
+ move.data.data32[4] = toXdndAction(requestedAction);
qCDebug(lcQpaXDnd) << "sending XdndPosition to target:" << target;
source_time = connection()->time();
- if (w)
+ if (w) {
handle_xdnd_position(w, &move, b, mods);
- else
+ } else {
+ setActionList(requestedAction, supportedActions);
xcb_send_event(xcb_connection(), false, proxy_target, XCB_EVENT_MASK_NO_EVENT, (const char *)&move);
+ }
}
static const bool isUnity = qgetenv("XDG_CURRENT_DESKTOP").toLower() == "unity";
if (isUnity && xdndCollectionWindow == XCB_NONE) {
QString name = QXcbWindow::windowTitle(connection(), target);
- if (name == QStringLiteral("XdndCollectionWindowImp"))
+ if (name == "XdndCollectionWindowImp"_L1)
xdndCollectionWindow = target;
}
if (target == xdndCollectionWindow) {
@@ -507,12 +484,8 @@ void QXcbDrag::drop(const QPoint &globalPos, Qt::MouseButtons b, Qt::KeyboardMod
drop.sequence = 0;
drop.window = current_target;
drop.format = 32;
- drop.type = atom(QXcbAtom::XdndDrop);
-#ifndef QT_NO_CLIPBOARD
- drop.data.data32[0] = connection()->clipboard()->owner();
-#else
- drop.data.data32[0] = 0;
-#endif
+ drop.type = atom(QXcbAtom::AtomXdndDrop);
+ drop.data.data32[0] = connection()->qtSelectionOwner();
drop.data.data32[1] = 0; // flags
drop.data.data32[2] = connection()->time();
@@ -551,36 +524,100 @@ void QXcbDrag::drop(const QPoint &globalPos, Qt::MouseButtons b, Qt::KeyboardMod
Qt::DropAction QXcbDrag::toDropAction(xcb_atom_t a) const
{
- if (a == atom(QXcbAtom::XdndActionCopy) || a == 0)
+ if (a == atom(QXcbAtom::AtomXdndActionCopy) || a == 0)
return Qt::CopyAction;
- if (a == atom(QXcbAtom::XdndActionLink))
+ if (a == atom(QXcbAtom::AtomXdndActionLink))
return Qt::LinkAction;
- if (a == atom(QXcbAtom::XdndActionMove))
+ if (a == atom(QXcbAtom::AtomXdndActionMove))
return Qt::MoveAction;
return Qt::CopyAction;
}
+Qt::DropActions QXcbDrag::toDropActions(const QList<xcb_atom_t> &atoms) const
+{
+ Qt::DropActions actions;
+ for (const auto actionAtom : atoms) {
+ if (actionAtom != atom(QXcbAtom::AtomXdndActionAsk))
+ actions |= toDropAction(actionAtom);
+ }
+ return actions;
+}
+
xcb_atom_t QXcbDrag::toXdndAction(Qt::DropAction a) const
{
switch (a) {
case Qt::CopyAction:
- return atom(QXcbAtom::XdndActionCopy);
+ return atom(QXcbAtom::AtomXdndActionCopy);
case Qt::LinkAction:
- return atom(QXcbAtom::XdndActionLink);
+ return atom(QXcbAtom::AtomXdndActionLink);
case Qt::MoveAction:
case Qt::TargetMoveAction:
- return atom(QXcbAtom::XdndActionMove);
+ return atom(QXcbAtom::AtomXdndActionMove);
case Qt::IgnoreAction:
return XCB_NONE;
default:
- return atom(QXcbAtom::XdndActionCopy);
+ return atom(QXcbAtom::AtomXdndActionCopy);
+ }
+}
+
+void QXcbDrag::readActionList()
+{
+ drop_actions.clear();
+ auto reply = Q_XCB_REPLY(xcb_get_property, xcb_connection(), false, xdnd_dragsource,
+ atom(QXcbAtom::AtomXdndActionList), XCB_ATOM_ATOM,
+ 0, 1024);
+ if (reply && reply->type != XCB_NONE && reply->format == 32) {
+ int length = xcb_get_property_value_length(reply.get()) / 4;
+
+ xcb_atom_t *atoms = (xcb_atom_t *)xcb_get_property_value(reply.get());
+ for (int i = 0; i < length; ++i)
+ drop_actions.append(atoms[i]);
}
}
+void QXcbDrag::setActionList(Qt::DropAction requestedAction, Qt::DropActions supportedActions)
+{
+#ifndef QT_NO_CLIPBOARD
+ QList<xcb_atom_t> actions;
+ if (requestedAction != Qt::IgnoreAction)
+ actions.append(toXdndAction(requestedAction));
+
+ auto checkAppend = [this, requestedAction, supportedActions, &actions](Qt::DropAction action) {
+ if (requestedAction != action && supportedActions & action)
+ actions.append(toXdndAction(action));
+ };
+
+ checkAppend(Qt::CopyAction);
+ checkAppend(Qt::MoveAction);
+ checkAppend(Qt::LinkAction);
+
+ if (current_actions != actions) {
+ xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, connection()->qtSelectionOwner(),
+ atom(QXcbAtom::AtomXdndActionList),
+ XCB_ATOM_ATOM, 32, actions.size(), actions.constData());
+ current_actions = actions;
+ }
+#endif
+}
+
+void QXcbDrag::startListeningForActionListChanges()
+{
+ connection()->addWindowEventListener(xdnd_dragsource, this);
+ const uint32_t event_mask[] = { XCB_EVENT_MASK_PROPERTY_CHANGE };
+ xcb_change_window_attributes(xcb_connection(), xdnd_dragsource, XCB_CW_EVENT_MASK, event_mask);
+}
+
+void QXcbDrag::stopListeningForActionListChanges()
+{
+ const uint32_t event_mask[] = { XCB_EVENT_MASK_NO_EVENT };
+ xcb_change_window_attributes(xcb_connection(), xdnd_dragsource, XCB_CW_EVENT_MASK, event_mask);
+ connection()->removeWindowEventListener(xdnd_dragsource);
+}
+
int QXcbDrag::findTransactionByWindow(xcb_window_t window)
{
int at = -1;
- for (int i = 0; i < transactions.count(); ++i) {
+ for (int i = 0; i < transactions.size(); ++i) {
const Transaction &t = transactions.at(i);
if (t.target == window || t.proxy_target == window) {
at = i;
@@ -593,7 +630,7 @@ int QXcbDrag::findTransactionByWindow(xcb_window_t window)
int QXcbDrag::findTransactionByTime(xcb_timestamp_t timestamp)
{
int at = -1;
- for (int i = 0; i < transactions.count(); ++i) {
+ for (int i = 0; i < transactions.size(); ++i) {
const Transaction &t = transactions.at(i);
if (t.timestamp == timestamp) {
at = i;
@@ -605,7 +642,7 @@ int QXcbDrag::findTransactionByTime(xcb_timestamp_t timestamp)
#if 0
// for embedding only
-static QWidget* current_embedding_widget = 0;
+static QWidget* current_embedding_widget = nullptr;
static xcb_client_message_event_t last_enter_event;
@@ -657,6 +694,9 @@ void QXcbDrag::handleEnter(QPlatformWindow *, const xcb_client_message_event_t *
return;
xdnd_dragsource = event->data.data32[0];
+ startListeningForActionListChanges();
+ readActionList();
+
if (!proxy)
proxy = xdndProxy(connection(), xdnd_dragsource);
current_proxy_target = proxy ? proxy : xdnd_dragsource;
@@ -664,7 +704,7 @@ void QXcbDrag::handleEnter(QPlatformWindow *, const xcb_client_message_event_t *
if (event->data.data32[1] & 1) {
// get the types from XdndTypeList
auto reply = Q_XCB_REPLY(xcb_get_property, xcb_connection(), false, xdnd_dragsource,
- atom(QXcbAtom::XdndTypelist), XCB_ATOM_ATOM,
+ atom(QXcbAtom::AtomXdndTypelist), XCB_ATOM_ATOM,
0, xdnd_max_type);
if (reply && reply->type != XCB_NONE && reply->format == 32) {
int length = xcb_get_property_value_length(reply.get()) / 4;
@@ -683,7 +723,7 @@ void QXcbDrag::handleEnter(QPlatformWindow *, const xcb_client_message_event_t *
xdnd_types.append(event->data.data32[i]);
}
}
- for(int i = 0; i < xdnd_types.length(); ++i)
+ for(int i = 0; i < xdnd_types.size(); ++i)
qCDebug(lcQpaXDnd) << " " << connection()->atomName(xdnd_types.at(i));
}
@@ -697,7 +737,7 @@ void QXcbDrag::handle_xdnd_position(QPlatformWindow *w, const xcb_client_message
QPoint p((e->data.data32[2] & 0xffff0000) >> 16, e->data.data32[2] & 0x0000ffff);
Q_ASSERT(w);
QRect geometry = w->geometry();
- p -= geometry.topLeft();
+ p -= w->isEmbedded() ? w->mapToGlobal(geometry.topLeft()) : geometry.topLeft();
if (!w || !w->window() || (w->window()->type() == Qt::Desktop))
return;
@@ -723,11 +763,13 @@ void QXcbDrag::handle_xdnd_position(QPlatformWindow *w, const xcb_client_message
supported_actions = currentDrag()->supportedActions();
} else {
dropData = m_dropData;
- supported_actions = Qt::DropActions(toDropAction(e->data.data32[4]));
+ supported_actions = toDropActions(drop_actions);
+ if (e->data.data32[4] != atom(QXcbAtom::AtomXdndActionAsk))
+ supported_actions |= Qt::DropActions(toDropAction(e->data.data32[4]));
}
auto buttons = currentDrag() ? b : connection()->queryMouseButtons();
- auto modifiers = currentDrag() ? mods : connection()->queryKeyboardModifiers();
+ auto modifiers = currentDrag() ? mods : connection()->keyboard()->queryKeyboardModifiers();
QPlatformDragQtResponse qt_response = QWindowSystemInterface::handleDrag(
w->window(), dropData, p, supported_actions, buttons, modifiers);
@@ -744,7 +786,7 @@ void QXcbDrag::handle_xdnd_position(QPlatformWindow *w, const xcb_client_message
response.sequence = 0;
response.window = xdnd_dragsource;
response.format = 32;
- response.type = atom(QXcbAtom::XdndStatus);
+ response.type = atom(QXcbAtom::AtomXdndStatus);
response.data.data32[0] = xcb_window(w);
response.data.data32[1] = qt_response.isAccepted(); // flags
response.data.data32[2] = 0; // x, y
@@ -771,11 +813,9 @@ void QXcbDrag::handle_xdnd_position(QPlatformWindow *w, const xcb_client_message
qCDebug(lcQpaXDnd) << "sending XdndStatus to source:" << xdnd_dragsource;
-#ifndef QT_NO_CLIPBOARD
- if (xdnd_dragsource == connection()->clipboard()->owner())
+ if (xdnd_dragsource == connection()->qtSelectionOwner())
handle_xdnd_status(&response);
else
-#endif
xcb_send_event(xcb_connection(), false, current_proxy_target,
XCB_EVENT_MASK_NO_EVENT, (const char *)&response);
}
@@ -798,7 +838,7 @@ namespace
void QXcbDrag::handlePosition(QPlatformWindow * w, const xcb_client_message_event_t *event)
{
xcb_client_message_event_t *lastEvent = const_cast<xcb_client_message_event_t *>(event);
- ClientMessageScanner scanner(atom(QXcbAtom::XdndPosition));
+ ClientMessageScanner scanner(atom(QXcbAtom::AtomXdndPosition));
while (auto nextEvent = connection()->eventQueue()->peek(scanner)) {
if (lastEvent != event)
free(lastEvent);
@@ -841,16 +881,12 @@ void QXcbDrag::handle_xdnd_status(const xcb_client_message_event_t *event)
void QXcbDrag::handleStatus(const xcb_client_message_event_t *event)
{
- if (
-#ifndef QT_NO_CLIPBOARD
- event->window != connection()->clipboard()->owner() ||
-#endif
- !drag())
+ if (event->window != connection()->qtSelectionOwner() || !drag())
return;
xcb_client_message_event_t *lastEvent = const_cast<xcb_client_message_event_t *>(event);
xcb_generic_event_t *nextEvent;
- ClientMessageScanner scanner(atom(QXcbAtom::XdndStatus));
+ ClientMessageScanner scanner(atom(QXcbAtom::AtomXdndStatus));
while ((nextEvent = connection()->eventQueue()->peek(scanner))) {
if (lastEvent != event)
free(lastEvent);
@@ -867,8 +903,10 @@ void QXcbDrag::handleLeave(QPlatformWindow *w, const xcb_client_message_event_t
// If the target receives XdndLeave, it frees any cached data and forgets the whole incident.
qCDebug(lcQpaXDnd) << "target:" << event->window << "received XdndLeave";
- if (!currentWindow || w != currentWindow.data()->handle())
+ if (!currentWindow || w != currentWindow.data()->handle()) {
+ stopListeningForActionListChanges();
return; // sanity
+ }
// ###
// if (checkEmbedded(current_embedding_widget, event)) {
@@ -883,6 +921,8 @@ void QXcbDrag::handleLeave(QPlatformWindow *w, const xcb_client_message_event_t
event->data.data32[0], xdnd_dragsource);
}
+ stopListeningForActionListChanges();
+
QWindowSystemInterface::handleDrag(w->window(), nullptr, QPoint(), Qt::IgnoreAction, { }, { });
}
@@ -897,12 +937,8 @@ void QXcbDrag::send_leave()
leave.sequence = 0;
leave.window = current_target;
leave.format = 32;
- leave.type = atom(QXcbAtom::XdndLeave);
-#ifndef QT_NO_CLIPBOARD
- leave.data.data32[0] = connection()->clipboard()->owner();
-#else
- leave.data.data32[0] = 0;
-#endif
+ leave.type = atom(QXcbAtom::AtomXdndLeave);
+ leave.data.data32[0] = connection()->qtSelectionOwner();
leave.data.data32[1] = 0; // flags
leave.data.data32[2] = 0; // x, y
leave.data.data32[3] = 0; // w, h
@@ -929,6 +965,7 @@ void QXcbDrag::handleDrop(QPlatformWindow *, const xcb_client_message_event_t *e
qCDebug(lcQpaXDnd) << "target:" << event->window << "received XdndDrop";
if (!currentWindow) {
+ stopListeningForActionListChanges();
xdnd_dragsource = 0;
return; // sanity
}
@@ -946,46 +983,62 @@ void QXcbDrag::handleDrop(QPlatformWindow *, const xcb_client_message_event_t *e
Qt::DropActions supported_drop_actions;
QMimeData *dropData = nullptr;
+ // this could be a same-application drop, just proxied due to
+ // some XEMBEDding, so try to find the real QMimeData used
+ // based on the timestamp for this drop.
+ int at = findTransactionByTime(target_time);
+ if (at != -1) {
+ qCDebug(lcQpaXDnd) << "found one transaction via findTransactionByTime()";
+ dropData = transactions.at(at).drag->mimeData();
+ // Can't use the source QMimeData if we need the image conversion code from xdndObtainData
+ if (dropData && dropData->hasImage())
+ dropData = 0;
+ }
+ // if we can't find it, then use the data in the drag manager
if (currentDrag()) {
- dropData = currentDrag()->mimeData();
+ if (!dropData)
+ dropData = currentDrag()->mimeData();
supported_drop_actions = Qt::DropActions(l[4]);
} else {
- dropData = m_dropData;
- supported_drop_actions = accepted_drop_action;
+ if (!dropData)
+ dropData = m_dropData;
+ supported_drop_actions = accepted_drop_action | toDropActions(drop_actions);
}
if (!dropData)
return;
- // ###
- // int at = findXdndDropTransactionByTime(target_time);
- // if (at != -1)
- // dropData = QDragManager::dragPrivate(X11->dndDropTransactions.at(at).object)->data;
- // if we can't find it, then use the data in the drag manager
auto buttons = currentDrag() ? b : connection()->queryMouseButtons();
- auto modifiers = currentDrag() ? mods : connection()->queryKeyboardModifiers();
+ auto modifiers = currentDrag() ? mods : connection()->keyboard()->queryKeyboardModifiers();
QPlatformDropQtResponse response = QWindowSystemInterface::handleDrop(
currentWindow.data(), dropData, currentPosition, supported_drop_actions,
buttons, modifiers);
- setExecutedDropAction(response.acceptedAction());
+ Qt::DropAction acceptedAaction = response.acceptedAction();
+ if (!response.isAccepted()) {
+ // Ignore a failed drag
+ acceptedAaction = Qt::IgnoreAction;
+ }
+ setExecutedDropAction(acceptedAaction);
- xcb_client_message_event_t finished;
+ xcb_client_message_event_t finished = {};
finished.response_type = XCB_CLIENT_MESSAGE;
finished.sequence = 0;
finished.window = xdnd_dragsource;
finished.format = 32;
- finished.type = atom(QXcbAtom::XdndFinished);
+ finished.type = atom(QXcbAtom::AtomXdndFinished);
finished.data.data32[0] = currentWindow ? xcb_window(currentWindow.data()) : XCB_NONE;
finished.data.data32[1] = response.isAccepted(); // flags
- finished.data.data32[2] = toXdndAction(response.acceptedAction());
+ finished.data.data32[2] = toXdndAction(acceptedAaction);
qCDebug(lcQpaXDnd) << "sending XdndFinished to source:" << xdnd_dragsource;
xcb_send_event(xcb_connection(), false, current_proxy_target,
XCB_EVENT_MASK_NO_EVENT, (char *)&finished);
+ stopListeningForActionListChanges();
+
dropped = true;
}
@@ -994,10 +1047,8 @@ void QXcbDrag::handleFinished(const xcb_client_message_event_t *event)
// Source receives XdndFinished when target is done processing the drop data.
qCDebug(lcQpaXDnd) << "source:" << event->window << "received XdndFinished";
-#ifndef QT_NO_CLIPBOARD
- if (event->window != connection()->clipboard()->owner())
+ if (event->window != connection()->qtSelectionOwner())
return;
-#endif
const unsigned long *l = (const unsigned long *)event->data.data32;
if (l[0]) {
@@ -1041,7 +1092,7 @@ void QXcbDrag::timerEvent(QTimerEvent* e)
{
if (e->timerId() == cleanup_timer) {
bool stopTimer = true;
- for (int i = 0; i < transactions.count(); ++i) {
+ for (int i = 0; i < transactions.size(); ++i) {
const Transaction &t = transactions.at(i);
if (t.targetWindow) {
// dnd within the same process, don't delete, these are taken care of
@@ -1049,7 +1100,7 @@ void QXcbDrag::timerEvent(QTimerEvent* e)
continue;
}
QTime currentTime = QTime::currentTime();
- int delta = t.time.msecsTo(currentTime);
+ std::chrono::milliseconds delta{t.time.msecsTo(currentTime)};
if (delta > XdndDropTransactionTimeout) {
/* delete transactions which are older than XdndDropTransactionTimeout. It could mean
one of these:
@@ -1093,7 +1144,7 @@ static xcb_window_t findXdndAwareParent(QXcbConnection *c, xcb_window_t window)
forever {
// check if window has XdndAware
auto gpReply = Q_XCB_REPLY(xcb_get_property, c->xcb_connection(), false, window,
- c->atom(QXcbAtom::XdndAware), XCB_GET_PROPERTY_TYPE_ANY, 0, 0);
+ c->atom(QXcbAtom::AtomXdndAware), XCB_GET_PROPERTY_TYPE_ANY, 0, 0);
bool aware = gpReply && gpReply->type != XCB_NONE;
if (aware) {
target = window;
@@ -1183,6 +1234,7 @@ void QXcbDrag::handleSelectionRequest(const xcb_selection_request_event_t *event
bool QXcbDrag::dndEnable(QXcbWindow *w, bool on)
{
+ qCDebug(lcQpaXDnd) << "dndEnable" << static_cast<QPlatformWindow *>(w) << on;
// Windows announce that they support the XDND protocol by creating a window property XdndAware.
if (on) {
QXcbWindow *window = nullptr;
@@ -1199,7 +1251,7 @@ bool QXcbDrag::dndEnable(QXcbWindow *w, bool on)
desktop_proxy = new QWindow;
window = static_cast<QXcbWindow *>(desktop_proxy->handle());
proxy_id = window->xcb_window();
- xcb_atom_t xdnd_proxy = atom(QXcbAtom::XdndProxy);
+ xcb_atom_t xdnd_proxy = atom(QXcbAtom::AtomXdndProxy);
xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, w->xcb_window(), xdnd_proxy,
XCB_ATOM_WINDOW, 32, 1, &proxy_id);
xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, proxy_id, xdnd_proxy,
@@ -1213,14 +1265,14 @@ bool QXcbDrag::dndEnable(QXcbWindow *w, bool on)
qCDebug(lcQpaXDnd) << "setting XdndAware for" << window->xcb_window();
xcb_atom_t atm = xdnd_version;
xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, window->xcb_window(),
- atom(QXcbAtom::XdndAware), XCB_ATOM_ATOM, 32, 1, &atm);
+ atom(QXcbAtom::AtomXdndAware), XCB_ATOM_ATOM, 32, 1, &atm);
return true;
} else {
return false;
}
} else {
if (w->window()->type() == Qt::Desktop) {
- xcb_delete_property(xcb_connection(), w->xcb_window(), atom(QXcbAtom::XdndProxy));
+ xcb_delete_property(xcb_connection(), w->xcb_window(), atom(QXcbAtom::AtomXdndProxy));
delete desktop_proxy;
desktop_proxy = nullptr;
} else {
@@ -1245,14 +1297,14 @@ QXcbDropData::~QXcbDropData()
{
}
-QVariant QXcbDropData::retrieveData_sys(const QString &mimetype, QVariant::Type requestedType) const
+QVariant QXcbDropData::retrieveData_sys(const QString &mimetype, QMetaType requestedType) const
{
QByteArray mime = mimetype.toLatin1();
- QVariant data = xdndObtainData(mime, QMetaType::Type(requestedType));
+ QVariant data = xdndObtainData(mime, requestedType);
return data;
}
-QVariant QXcbDropData::xdndObtainData(const QByteArray &format, QMetaType::Type requestedType) const
+QVariant QXcbDropData::xdndObtainData(const QByteArray &format, QMetaType requestedType) const
{
QByteArray result;
@@ -1260,26 +1312,26 @@ QVariant QXcbDropData::xdndObtainData(const QByteArray &format, QMetaType::Type
QXcbWindow *xcb_window = c->platformWindowFromId(drag->xdnd_dragsource);
if (xcb_window && drag->currentDrag() && xcb_window->window()->type() != Qt::Desktop) {
QMimeData *data = drag->currentDrag()->mimeData();
- if (data->hasFormat(QLatin1String(format)))
- result = data->data(QLatin1String(format));
+ if (data->hasFormat(QLatin1StringView(format)))
+ result = data->data(QLatin1StringView(format));
return result;
}
- QVector<xcb_atom_t> atoms = drag->xdnd_types;
- QByteArray encoding;
- xcb_atom_t a = mimeAtomForFormat(c, QLatin1String(format), requestedType, atoms, &encoding);
+ QList<xcb_atom_t> atoms = drag->xdnd_types;
+ bool hasUtf8 = false;
+ xcb_atom_t a = mimeAtomForFormat(c, QLatin1StringView(format), requestedType, atoms, &hasUtf8);
if (a == XCB_NONE)
return result;
#ifndef QT_NO_CLIPBOARD
- if (c->clipboard()->getSelectionOwner(drag->atom(QXcbAtom::XdndSelection)) == XCB_NONE)
+ if (c->selectionOwner(c->atom(QXcbAtom::AtomXdndSelection)) == XCB_NONE)
return result; // should never happen?
- xcb_atom_t xdnd_selection = c->atom(QXcbAtom::XdndSelection);
+ xcb_atom_t xdnd_selection = c->atom(QXcbAtom::AtomXdndSelection);
result = c->clipboard()->getSelection(xdnd_selection, a, xdnd_selection, drag->targetTime());
#endif
- return mimeConvertToFormat(c, a, result, QLatin1String(format), requestedType, encoding);
+ return mimeConvertToFormat(c, a, result, QLatin1StringView(format), requestedType, hasUtf8);
}
bool QXcbDropData::hasFormat_sys(const QString &format) const
diff --git a/src/plugins/platforms/xcb/qxcbdrag.h b/src/plugins/platforms/xcb/qxcbdrag.h
index 7bef7a818a..ae7cc915c8 100644
--- a/src/plugins/platforms/xcb/qxcbdrag.h
+++ b/src/plugins/platforms/xcb/qxcbdrag.h
@@ -1,57 +1,20 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QXCBDRAG_H
#define QXCBDRAG_H
#include <qpa/qplatformdrag.h>
#include <private/qsimpledrag_p.h>
-#include <qxcbobject.h>
#include <xcb/xcb.h>
-#include <qpoint.h>
-#include <qrect.h>
-#include <qsharedpointer.h>
-#include <qpointer.h>
-#include <qvector.h>
+#include <qbackingstore.h>
#include <qdatetime.h>
+#include <qlist.h>
#include <qpixmap.h>
-#include <qbackingstore.h>
+#include <qpoint.h>
+#include <qpointer.h>
+#include <qrect.h>
+#include <qxcbobject.h>
#include <QtCore/QDebug>
@@ -68,7 +31,7 @@ class QXcbScreen;
class QDrag;
class QShapedPixmapWindow;
-class QXcbDrag : public QXcbObject, public QBasicDrag
+class QXcbDrag : public QXcbObject, public QBasicDrag, public QXcbWindowEventListener
{
public:
QXcbDrag(QXcbConnection *c);
@@ -82,6 +45,10 @@ public:
void drop(const QPoint &globalPos, Qt::MouseButtons b, Qt::KeyboardModifiers mods) override;
void endDrag() override;
+ Qt::DropAction defaultAction(Qt::DropActions possibleActions, Qt::KeyboardModifiers modifiers) const override;
+
+ void handlePropertyNotifyEvent(const xcb_property_notify_event_t *event) override;
+
void handleEnter(QPlatformWindow *window, const xcb_client_message_event_t *event, xcb_window_t proxy = 0);
void handlePosition(QPlatformWindow *w, const xcb_client_message_event_t *event);
void handleLeave(QPlatformWindow *w, const xcb_client_message_event_t *event);
@@ -114,8 +81,14 @@ private:
void send_leave();
Qt::DropAction toDropAction(xcb_atom_t atom) const;
+ Qt::DropActions toDropActions(const QList<xcb_atom_t> &atoms) const;
xcb_atom_t toXdndAction(Qt::DropAction a) const;
+ void readActionList();
+ void setActionList(Qt::DropAction requestedAction, Qt::DropActions supportedActions);
+ void startListeningForActionListChanges();
+ void stopListeningForActionListChanges();
+
QPointer<QWindow> initiatorWindow;
QPointer<QWindow> currentWindow;
QPoint currentPosition;
@@ -129,7 +102,7 @@ private:
// the types in this drop. 100 is no good, but at least it's big.
enum { xdnd_max_type = 100 };
- QVector<xcb_atom_t> xdnd_types;
+ QList<xcb_atom_t> xdnd_types;
// timestamp from XdndPosition and XdndDroptime for retrieving the data
xcb_timestamp_t target_time;
@@ -154,10 +127,13 @@ private:
QXcbVirtualDesktop *current_virtual_desktop;
// 10 minute timer used to discard old XdndDrop transactions
- enum { XdndDropTransactionTimeout = 600000 };
+ static constexpr std::chrono::minutes XdndDropTransactionTimeout{10};
int cleanup_timer;
- QVector<xcb_atom_t> drag_types;
+ QList<xcb_atom_t> drag_types;
+
+ QList<xcb_atom_t> current_actions;
+ QList<xcb_atom_t> drop_actions;
struct Transaction
{
@@ -170,7 +146,7 @@ private:
QTime time;
};
friend class QTypeInfo<Transaction>;
- QVector<Transaction> transactions;
+ QList<Transaction> transactions;
int transaction_expiry_timer;
void restartDropExpiryTimer();
@@ -178,7 +154,7 @@ private:
int findTransactionByTime(xcb_timestamp_t timestamp);
xcb_window_t findRealWindow(const QPoint & pos, xcb_window_t w, int md, bool ignoreNonXdndAwareWindows);
};
-Q_DECLARE_TYPEINFO(QXcbDrag::Transaction, Q_MOVABLE_TYPE);
+Q_DECLARE_TYPEINFO(QXcbDrag::Transaction, Q_RELOCATABLE_TYPE);
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/xcb/qxcbeventdispatcher.cpp b/src/plugins/platforms/xcb/qxcbeventdispatcher.cpp
index 3cb2a5b5ef..7049fd8656 100644
--- a/src/plugins/platforms/xcb/qxcbeventdispatcher.cpp
+++ b/src/plugins/platforms/xcb/qxcbeventdispatcher.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and 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$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qxcbeventdispatcher.h"
#include "qxcbconnection.h"
@@ -63,18 +27,6 @@ bool QXcbUnixEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags
return QWindowSystemInterface::sendWindowSystemEvents(flags) || didSendEvents;
}
-bool QXcbUnixEventDispatcher::hasPendingEvents()
-{
- extern uint qGlobalPostedEventsCount();
- return qGlobalPostedEventsCount() || QWindowSystemInterface::windowSystemEventsQueued();
-}
-
-void QXcbUnixEventDispatcher::flush()
-{
- if (qApp)
- qApp->sendPostedEvents();
-}
-
#if QT_CONFIG(glib)
struct XcbEventSource
{
@@ -86,7 +38,7 @@ struct XcbEventSource
static gboolean xcbSourcePrepare(GSource *source, gint *timeout)
{
- Q_UNUSED(timeout)
+ Q_UNUSED(timeout);
auto xcbEventSource = reinterpret_cast<XcbEventSource *>(source);
return xcbEventSource->dispatcher_p->wakeUpCalled;
}
@@ -116,8 +68,9 @@ QXcbGlibEventDispatcher::QXcbGlibEventDispatcher(QXcbConnection *connection, QOb
m_xcbEventSourceFuncs.dispatch = xcbSourceDispatch;
m_xcbEventSourceFuncs.finalize = nullptr;
- m_xcbEventSource = reinterpret_cast<XcbEventSource *>(
- g_source_new(&m_xcbEventSourceFuncs, sizeof(XcbEventSource)));
+ GSource *source = g_source_new(&m_xcbEventSourceFuncs, sizeof(XcbEventSource));
+ g_source_set_name(source, "[Qt] XcbEventSource");
+ m_xcbEventSource = reinterpret_cast<XcbEventSource *>(source);
m_xcbEventSource->dispatcher = this;
m_xcbEventSource->dispatcher_p = d_func();
@@ -160,3 +113,5 @@ QAbstractEventDispatcher *QXcbEventDispatcher::createEventDispatcher(QXcbConnect
}
QT_END_NAMESPACE
+
+#include "moc_qxcbeventdispatcher.cpp"
diff --git a/src/plugins/platforms/xcb/qxcbeventdispatcher.h b/src/plugins/platforms/xcb/qxcbeventdispatcher.h
index ddf448cf87..9c7e745ac9 100644
--- a/src/plugins/platforms/xcb/qxcbeventdispatcher.h
+++ b/src/plugins/platforms/xcb/qxcbeventdispatcher.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and 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$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QXCBEVENTDISPATCHER_H
#define QXCBEVENTDISPATCHER_H
@@ -60,12 +24,6 @@ public:
~QXcbUnixEventDispatcher();
bool processEvents(QEventLoop::ProcessEventsFlags flags) override;
- // Maybe some user code depends on deprecated QUnixEventDispatcherQPA::
- // hasPendingEvents() / flush() implementation, so keep it around until
- // Qt 6. These methods are deprecated in QAbstractEventDispatcher.
- bool hasPendingEvents() override; // ### Qt 6 remove
- void flush() override; // ### Qt 6 remove
-
private:
QXcbConnection *m_connection;
};
diff --git a/src/plugins/platforms/xcb/qxcbeventqueue.cpp b/src/plugins/platforms/xcb/qxcbeventqueue.cpp
index 759ee3cc95..33795d63cf 100644
--- a/src/plugins/platforms/xcb/qxcbeventqueue.cpp
+++ b/src/plugins/platforms/xcb/qxcbeventqueue.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and 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$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qxcbeventqueue.h"
#include "qxcbconnection.h"
@@ -47,8 +11,8 @@
QT_BEGIN_NAMESPACE
-static QBasicMutex qAppExiting;
-static bool dispatcherOwnerDestructing = false;
+Q_CONSTINIT static QBasicMutex qAppExiting;
+Q_CONSTINIT static bool dispatcherOwnerDestructing = false;
/*!
\class QXcbEventQueue
@@ -62,8 +26,8 @@ static bool dispatcherOwnerDestructing = false;
when accessing the tail node. It does not dequeue the last node and does not
access (read or write) the tail node's 'next' member. This lets the reader
add more items at the same time as the main thread is dequeuing nodes from
- the head. A custom linked list implementation is used, because QLinkedList
- does not have any thread-safety guarantees and the custom list is more
+ the head. A custom linked list implementation is used, because std::list
+ does not have any thread-safety guarantees. The custom list is
lightweight - no reference counting, back links, etc.
Memory management:
@@ -226,6 +190,8 @@ void QXcbEventQueue::run()
};
while (!m_closeConnectionDetected && (event = xcb_wait_for_event(connection))) {
+ // This lock can block only if there are users of waitForNewEvents().
+ // Currently only the clipboard implementation relies on it.
m_newEventsMutex.lock();
enqueueEvent(event);
while (!m_closeConnectionDetected && (event = xcb_poll_for_queued_event(connection)))
@@ -350,12 +316,12 @@ bool QXcbEventQueue::peekEventQueue(PeekerCallback peeker, void *peekerData,
return result;
}
-void QXcbEventQueue::waitForNewEvents(unsigned long time)
+void QXcbEventQueue::waitForNewEvents(const QXcbEventNode *sinceFlushedTail,
+ unsigned long time)
{
QMutexLocker locker(&m_newEventsMutex);
- QXcbEventNode *tailBeforeFlush = m_flushedTail;
flushBufferedEvents();
- if (tailBeforeFlush != m_flushedTail)
+ if (sinceFlushedTail != m_flushedTail)
return;
m_newEventsCondition.wait(&m_newEventsMutex, time);
}
@@ -379,7 +345,7 @@ void QXcbEventQueue::sendCloseConnectionEvent() const
event.format = 32;
event.sequence = 0;
event.window = window;
- event.type = m_connection->atom(QXcbAtom::_QT_CLOSE_CONNECTION);
+ event.type = m_connection->atom(QXcbAtom::Atom_QT_CLOSE_CONNECTION);
event.data.data32[0] = 0;
xcb_send_event(c, false, window, XCB_EVENT_MASK_NO_EVENT, reinterpret_cast<const char *>(&event));
@@ -391,10 +357,12 @@ bool QXcbEventQueue::isCloseConnectionEvent(const xcb_generic_event_t *event)
{
if (event && (event->response_type & ~0x80) == XCB_CLIENT_MESSAGE) {
auto clientMessage = reinterpret_cast<const xcb_client_message_event_t *>(event);
- if (clientMessage->type == m_connection->atom(QXcbAtom::_QT_CLOSE_CONNECTION))
+ if (clientMessage->type == m_connection->atom(QXcbAtom::Atom_QT_CLOSE_CONNECTION))
m_closeConnectionDetected = true;
}
return m_closeConnectionDetected;
}
QT_END_NAMESPACE
+
+#include "moc_qxcbeventqueue.cpp"
diff --git a/src/plugins/platforms/xcb/qxcbeventqueue.h b/src/plugins/platforms/xcb/qxcbeventqueue.h
index e7327b3fd6..7d8f6d5417 100644
--- a/src/plugins/platforms/xcb/qxcbeventqueue.h
+++ b/src/plugins/platforms/xcb/qxcbeventqueue.h
@@ -1,48 +1,12 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and 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$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QXCBEVENTQUEUE_H
#define QXCBEVENTQUEUE_H
#include <QtCore/QThread>
#include <QtCore/QHash>
#include <QtCore/QEventLoop>
-#include <QtCore/QVector>
+#include <QtCore/QList>
#include <QtCore/QMutex>
#include <QtCore/QWaitCondition>
@@ -75,11 +39,24 @@ public:
enum { PoolSize = 100 }; // 2.4 kB with 100 nodes
enum PeekOption {
- PeekDefault = 0, // see qx11info_x11.h for docs
+ // See qx11info_x11.cpp in X11 Extras module.
+ PeekDefault = 0,
+ // See qx11info_x11.cpp in X11 Extras module.
PeekFromCachedIndex = 1,
+ // Used by the event compression algorithms to determine if
+ // the currently processed event (which has been already dequeued)
+ // can be compressed. Returns from the QXcbEventQueue::peek()
+ // on the first match.
PeekRetainMatch = 2,
- PeekRemoveMatch = 3,
- PeekRemoveMatchContinue = 4
+ // Marks the event in the node as "nullptr". The actual
+ // node remains in the queue. The nodes are unlinked only
+ // by dequeueNode(). Returns from the QXcbEventQueue::peek()
+ // on the first match.
+ PeekConsumeMatch = 3,
+ // Same as above, but continues to the next node in the
+ // queue. Repeats this until the flushed tailed node has
+ // been reached.
+ PeekConsumeMatchAndContinue = 4
};
Q_DECLARE_FLAGS(PeekOptions, PeekOption)
@@ -92,10 +69,11 @@ public:
void wakeUpDispatcher();
// ### peek() and peekEventQueue() could be unified. Note that peekEventQueue()
- // is public API exposed via QX11Extras/QX11Info.
+ // is public API exposed via QX11Extras/QX11Info. PeekOption could be reworked to
+ // have values that can be OR-ed together.
template<typename Peeker>
xcb_generic_event_t *peek(Peeker &&peeker) {
- return peek(PeekRemoveMatch, std::forward<Peeker>(peeker));
+ return peek(PeekConsumeMatch, std::forward<Peeker>(peeker));
}
template<typename Peeker>
inline xcb_generic_event_t *peek(PeekOption config, Peeker &&peeker);
@@ -107,7 +85,9 @@ public:
bool peekEventQueue(PeekerCallback peeker, void *peekerData = nullptr,
PeekOptions option = PeekDefault, qint32 peekerId = -1);
- void waitForNewEvents(unsigned long time = std::numeric_limits<unsigned long>::max());
+ const QXcbEventNode *flushedTail() const { return m_flushedTail; }
+ void waitForNewEvents(const QXcbEventNode *sinceFlushedTail,
+ unsigned long time = (std::numeric_limits<unsigned long>::max)());
private:
QXcbEventNode *qXcbEventNodeFactory(xcb_generic_event_t *event);
@@ -132,7 +112,7 @@ private:
bool m_peekerIndexCacheDirty = false;
QHash<qint32, QXcbEventNode *> m_peekerToNode;
- QVector<xcb_generic_event_t *> m_inputEvents;
+ QList<xcb_generic_event_t *> m_inputEvents;
// debug stats
quint64 m_nodesOnHeap = 0;
@@ -152,9 +132,10 @@ xcb_generic_event_t *QXcbEventQueue::peek(PeekOption option, Peeker &&peeker)
do {
xcb_generic_event_t *event = node->event;
if (event && peeker(event, event->response_type & ~0x80)) {
- if (option == PeekRemoveMatch || option == PeekRemoveMatchContinue)
+ if (option == PeekConsumeMatch || option == PeekConsumeMatchAndContinue)
node->event = nullptr;
- if (option != PeekRemoveMatchContinue)
+
+ if (option != PeekConsumeMatchAndContinue)
return event;
}
if (node == m_flushedTail)
diff --git a/src/plugins/platforms/xcb/qxcbexport.h b/src/plugins/platforms/xcb/qxcbexport.h
index 4db23a9c0d..1a16341559 100644
--- a/src/plugins/platforms/xcb/qxcbexport.h
+++ b/src/plugins/platforms/xcb/qxcbexport.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QXCBEXPORT_H
#define QXCBEXPORT_H
diff --git a/src/plugins/platforms/xcb/qxcbimage.cpp b/src/plugins/platforms/xcb/qxcbimage.cpp
index b0e610dd51..8b4d919875 100644
--- a/src/plugins/platforms/xcb/qxcbimage.cpp
+++ b/src/plugins/platforms/xcb/qxcbimage.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qxcbimage.h"
#include <QtCore/QtEndian>
@@ -212,7 +176,7 @@ xcb_pixmap_t qt_xcb_XPixmapFromBitmap(QXcbScreen *screen, const QImage &image)
}
const int width = bitmap.width();
const int height = bitmap.height();
- const int bytesPerLine = bitmap.bytesPerLine();
+ const qsizetype bytesPerLine = bitmap.bytesPerLine();
int destLineSize = width / 8;
if (width % 8)
++destLineSize;
diff --git a/src/plugins/platforms/xcb/qxcbimage.h b/src/plugins/platforms/xcb/qxcbimage.h
index d718089ec2..c022fae639 100644
--- a/src/plugins/platforms/xcb/qxcbimage.h
+++ b/src/plugins/platforms/xcb/qxcbimage.h
@@ -1,47 +1,10 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QXCBIMAGE_H
#define QXCBIMAGE_H
#include "qxcbscreen.h"
-#include <QtCore/QPair>
#include <QtGui/QImage>
#include <QtGui/QPixmap>
#include <xcb/xcb_image.h>
diff --git a/src/plugins/platforms/xcb/qxcbintegration.cpp b/src/plugins/platforms/xcb/qxcbintegration.cpp
index cea0511822..4dafae31e3 100644
--- a/src/plugins/platforms/xcb/qxcbintegration.cpp
+++ b/src/plugins/platforms/xcb/qxcbintegration.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qxcbintegration.h"
#include "qxcbconnection.h"
@@ -56,14 +20,12 @@
#ifndef QT_NO_SESSIONMANAGER
#include "qxcbsessionmanager.h"
#endif
+#include "qxcbxsettings.h"
#include <xcb/xcb.h>
-#include <QtFontDatabaseSupport/private/qgenericunixfontdatabase_p.h>
-#include <QtServiceSupport/private/qgenericunixservices_p.h>
-#if QT_CONFIG(opengl)
-#include <QtPlatformCompositorSupport/qpa/qplatformbackingstoreopenglsupport.h>
-#endif
+#include <QtGui/private/qgenericunixfontdatabase_p.h>
+#include <QtGui/private/qgenericunixservices_p.h>
#include <stdio.h>
@@ -87,10 +49,10 @@
#include <QtGui/QOpenGLContext>
#include <QtGui/QScreen>
#include <QtGui/QOffscreenSurface>
-#ifndef QT_NO_ACCESSIBILITY
+#if QT_CONFIG(accessibility)
#include <qpa/qplatformaccessibility.h>
-#ifndef QT_NO_ACCESSIBILITY_ATSPI_BRIDGE
-#include <QtLinuxAccessibilitySupport/private/bridge_p.h>
+#if QT_CONFIG(accessibility_atspi_bridge)
+#include <QtGui/private/qspiaccessiblebridge_p.h>
#endif
#endif
@@ -103,16 +65,18 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
// Find out if our parent process is gdb by looking at the 'exe' symlink under /proc,.
// or, for older Linuxes, read out 'cmdline'.
static bool runningUnderDebugger()
{
#if defined(QT_DEBUG) && defined(Q_OS_LINUX)
- const QString parentProc = QLatin1String("/proc/") + QString::number(getppid());
- const QFileInfo parentProcExe(parentProc + QLatin1String("/exe"));
+ const QString parentProc = "/proc/"_L1 + QString::number(getppid());
+ const QFileInfo parentProcExe(parentProc + "/exe"_L1);
if (parentProcExe.isSymLink())
- return parentProcExe.symLinkTarget().endsWith(QLatin1String("/gdb"));
- QFile f(parentProc + QLatin1String("/cmdline"));
+ return parentProcExe.symLinkTarget().endsWith("/gdb"_L1);
+ QFile f(parentProc + "/cmdline"_L1);
if (!f.open(QIODevice::ReadOnly))
return false;
QByteArray s;
@@ -129,19 +93,26 @@ static bool runningUnderDebugger()
#endif
}
+class QXcbUnixServices : public QGenericUnixServices
+{
+public:
+ QString portalWindowIdentifier(QWindow *window) override;
+};
+
+
QXcbIntegration *QXcbIntegration::m_instance = nullptr;
QXcbIntegration::QXcbIntegration(const QStringList &parameters, int &argc, char **argv)
- : m_services(new QGenericUnixServices)
+ : m_services(new QXcbUnixServices)
, m_instanceName(nullptr)
, m_canGrab(true)
, m_defaultVisualId(UINT_MAX)
{
+ Q_UNUSED(parameters);
+
m_instance = this;
qApp->setAttribute(Qt::AA_CompressHighFrequencyEvents, true);
- QWindowSystemInterface::setPlatformFiltersEvents(true);
-
qRegisterMetaType<QXcbWindow*>();
#if QT_CONFIG(xcb_xlib)
XInitThreads();
@@ -180,7 +151,7 @@ QXcbIntegration::QXcbIntegration(const QStringList &parameters, int &argc, char
bool underDebugger = runningUnderDebugger();
if (noGrabArg && doGrabArg && underDebugger) {
- qWarning("Both -nograb and -dograb command line arguments specified. Please pick one. -nograb takes prcedence");
+ qWarning("Both -nograb and -dograb command line arguments specified. Please pick one. -nograb takes precedence");
doGrabArg = false;
}
@@ -196,40 +167,27 @@ QXcbIntegration::QXcbIntegration(const QStringList &parameters, int &argc, char
if (canNotGrabEnv)
m_canGrab = false;
- const int numParameters = parameters.size();
- m_connections.reserve(1 + numParameters / 2);
-
- auto conn = new QXcbConnection(m_nativeInterface.data(), m_canGrab, m_defaultVisualId, displayName);
- if (!conn->isConnected()) {
- delete conn;
+ m_connection = new QXcbConnection(m_nativeInterface.data(), m_canGrab, m_defaultVisualId, displayName);
+ if (!m_connection->isConnected()) {
+ delete m_connection;
+ m_connection = nullptr;
return;
}
- m_connections << conn;
-
- // ### Qt 6 (QTBUG-52408) remove this multi-connection code path
- for (int i = 0; i < numParameters - 1; i += 2) {
- qCDebug(lcQpaXcb) << "connecting to additional display: " << parameters.at(i) << parameters.at(i+1);
- QString display = parameters.at(i) + QLatin1Char(':') + parameters.at(i+1);
- conn = new QXcbConnection(m_nativeInterface.data(), m_canGrab, m_defaultVisualId, display.toLatin1().constData());
- if (conn->isConnected())
- m_connections << conn;
- else
- delete conn;
- }
m_fontDatabase.reset(new QGenericUnixFontDatabase());
#if QT_CONFIG(xcb_native_painting)
if (nativePaintingEnabled()) {
qCDebug(lcQpaXcb, "QXCB USING NATIVE PAINTING");
- qt_xcb_native_x11_info_init(defaultConnection());
+ qt_xcb_native_x11_info_init(connection());
}
#endif
}
QXcbIntegration::~QXcbIntegration()
{
- qDeleteAll(m_connections);
+ delete m_connection;
+ m_connection = nullptr;
m_instance = nullptr;
}
@@ -246,10 +204,10 @@ QPlatformPixmap *QXcbIntegration::createPlatformPixmap(QPlatformPixmap::PixelTyp
QPlatformWindow *QXcbIntegration::createPlatformWindow(QWindow *window) const
{
QXcbGlIntegration *glIntegration = nullptr;
- const bool isTrayIconWindow = QXcbWindow::isTrayIconWindow(window);;
+ const bool isTrayIconWindow = QXcbWindow::isTrayIconWindow(window);
if (window->type() != Qt::Desktop && !isTrayIconWindow) {
if (window->supportsOpenGL()) {
- glIntegration = defaultConnection()->glIntegration();
+ glIntegration = connection()->glIntegration();
if (glIntegration) {
QXcbWindow *xcbWindow = glIntegration->createWindow(window);
xcbWindow->create();
@@ -279,16 +237,38 @@ QPlatformWindow *QXcbIntegration::createForeignWindow(QWindow *window, WId nativ
#ifndef QT_NO_OPENGL
QPlatformOpenGLContext *QXcbIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const
{
- QXcbScreen *screen = static_cast<QXcbScreen *>(context->screen()->handle());
- QXcbGlIntegration *glIntegration = screen->connection()->glIntegration();
+ QXcbGlIntegration *glIntegration = m_connection->glIntegration();
if (!glIntegration) {
qWarning("QXcbIntegration: Cannot create platform OpenGL context, neither GLX nor EGL are enabled");
return nullptr;
}
return glIntegration->createPlatformOpenGLContext(context);
}
+
+# if QT_CONFIG(xcb_glx_plugin)
+QOpenGLContext *QXcbIntegration::createOpenGLContext(GLXContext context, void *visualInfo, QOpenGLContext *shareContext) const
+{
+ using namespace QNativeInterface::Private;
+ if (auto *glxIntegration = dynamic_cast<QGLXIntegration*>(m_connection->glIntegration()))
+ return glxIntegration->createOpenGLContext(context, visualInfo, shareContext);
+ else
+ return nullptr;
+}
+# endif
+
+#if QT_CONFIG(egl)
+QOpenGLContext *QXcbIntegration::createOpenGLContext(EGLContext context, EGLDisplay display, QOpenGLContext *shareContext) const
+{
+ using namespace QNativeInterface::Private;
+ if (auto *eglIntegration = dynamic_cast<QEGLIntegration*>(m_connection->glIntegration()))
+ return eglIntegration->createOpenGLContext(context, display, shareContext);
+ else
+ return nullptr;
+}
#endif
+#endif // QT_NO_OPENGL
+
QPlatformBackingStore *QXcbIntegration::createPlatformBackingStore(QWindow *window) const
{
QPlatformBackingStore *backingStore = nullptr;
@@ -304,9 +284,6 @@ QPlatformBackingStore *QXcbIntegration::createPlatformBackingStore(QWindow *wind
backingStore = new QXcbBackingStore(window);
}
Q_ASSERT(backingStore);
-#ifndef QT_NO_OPENGL
- backingStore->setOpenGLSupport(new QPlatformBackingStoreOpenGLSupport(backingStore));
-#endif
return backingStore;
}
@@ -327,7 +304,7 @@ bool QXcbIntegration::hasCapability(QPlatformIntegration::Capability cap) const
case OpenGL:
case ThreadedOpenGL:
{
- if (const auto *integration = defaultConnection()->glIntegration())
+ if (const auto *integration = connection()->glIntegration())
return cap != ThreadedOpenGL || integration->supportsThreadedOpenGL();
return false;
}
@@ -342,8 +319,8 @@ bool QXcbIntegration::hasCapability(QPlatformIntegration::Capability cap) const
case SwitchableWidgetComposition:
{
- return m_connections.at(0)->glIntegration()
- && m_connections.at(0)->glIntegration()->supportsSwitchableWidgetComposition();
+ return m_connection->glIntegration()
+ && m_connection->glIntegration()->supportsSwitchableWidgetComposition();
}
default: return QPlatformIntegration::hasCapability(cap);
@@ -352,22 +329,41 @@ bool QXcbIntegration::hasCapability(QPlatformIntegration::Capability cap) const
QAbstractEventDispatcher *QXcbIntegration::createEventDispatcher() const
{
- return QXcbEventDispatcher::createEventDispatcher(defaultConnection());
+ return QXcbEventDispatcher::createEventDispatcher(connection());
}
+using namespace Qt::Literals::StringLiterals;
+static const auto xsNetCursorBlink = "Net/CursorBlink"_ba;
+static const auto xsNetCursorBlinkTime = "Net/CursorBlinkTime"_ba;
+static const auto xsNetDoubleClickTime = "Net/DoubleClickTime"_ba;
+static const auto xsNetDoubleClickDistance = "Net/DoubleClickDistance"_ba;
+static const auto xsNetDndDragThreshold = "Net/DndDragThreshold"_ba;
+
void QXcbIntegration::initialize()
{
- const QLatin1String defaultInputContext("compose");
+ const auto defaultInputContext = "compose"_L1;
// Perform everything that may potentially need the event dispatcher (timers, socket
// notifiers) here instead of the constructor.
- QString icStr = QPlatformInputContextFactory::requested();
- if (icStr.isNull())
- icStr = defaultInputContext;
- m_inputContext.reset(QPlatformInputContextFactory::create(icStr));
- if (!m_inputContext && icStr != defaultInputContext && icStr != QLatin1String("none"))
+ auto icStrs = QPlatformInputContextFactory::requested();
+ if (icStrs.isEmpty())
+ icStrs = { defaultInputContext };
+ m_inputContext.reset(QPlatformInputContextFactory::create(icStrs));
+ if (!m_inputContext && !icStrs.contains(defaultInputContext)
+ && icStrs != QStringList{"none"_L1})
m_inputContext.reset(QPlatformInputContextFactory::create(defaultInputContext));
- defaultConnection()->keyboard()->initialize();
+ connection()->keyboard()->initialize();
+
+ auto notifyThemeChanged = [](QXcbVirtualDesktop *, const QByteArray &, const QVariant &, void *) {
+ QWindowSystemInterface::handleThemeChange();
+ };
+
+ auto *xsettings = connection()->primaryScreen()->xSettings();
+ xsettings->registerCallbackForProperty(xsNetCursorBlink, notifyThemeChanged, this);
+ xsettings->registerCallbackForProperty(xsNetCursorBlinkTime, notifyThemeChanged, this);
+ xsettings->registerCallbackForProperty(xsNetDoubleClickTime, notifyThemeChanged, this);
+ xsettings->registerCallbackForProperty(xsNetDoubleClickDistance, notifyThemeChanged, this);
+ xsettings->registerCallbackForProperty(xsNetDndDragThreshold, notifyThemeChanged, this);
}
void QXcbIntegration::moveToScreen(QWindow *window, int screen)
@@ -389,7 +385,7 @@ QPlatformNativeInterface * QXcbIntegration::nativeInterface() const
#ifndef QT_NO_CLIPBOARD
QPlatformClipboard *QXcbIntegration::clipboard() const
{
- return m_connections.at(0)->clipboard();
+ return m_connection->clipboard();
}
#endif
@@ -405,7 +401,7 @@ QPlatformDrag *QXcbIntegration::drag() const
return simpleDrag;
}
- return m_connections.at(0)->drag();
+ return m_connection->drag();
}
#endif
@@ -414,7 +410,7 @@ QPlatformInputContext *QXcbIntegration::inputContext() const
return m_inputContext.data();
}
-#ifndef QT_NO_ACCESSIBILITY
+#if QT_CONFIG(accessibility)
QPlatformAccessibility *QXcbIntegration::accessibility() const
{
#if !defined(QT_NO_ACCESSIBILITY_ATSPI_BRIDGE)
@@ -434,14 +430,9 @@ QPlatformServices *QXcbIntegration::services() const
return m_services.data();
}
-Qt::KeyboardModifiers QXcbIntegration::queryKeyboardModifiers() const
-{
- return m_connections.at(0)->queryKeyboardModifiers();
-}
-
-QList<int> QXcbIntegration::possibleKeys(const QKeyEvent *e) const
+QPlatformKeyMapper *QXcbIntegration::keyMapper() const
{
- return m_connections.at(0)->keyboard()->possibleKeys(e);
+ return m_connection->keyboard();
}
QStringList QXcbIntegration::themeNames() const
@@ -454,31 +445,53 @@ QPlatformTheme *QXcbIntegration::createPlatformTheme(const QString &name) const
return QGenericUnixTheme::createUnixTheme(name);
}
+#define RETURN_VALID_XSETTINGS(key) { \
+ auto value = connection()->primaryScreen()->xSettings()->setting(key); \
+ if (value.isValid()) return value; \
+}
+
QVariant QXcbIntegration::styleHint(QPlatformIntegration::StyleHint hint) const
{
switch (hint) {
- case QPlatformIntegration::CursorFlashTime:
- case QPlatformIntegration::KeyboardInputInterval:
+ case QPlatformIntegration::CursorFlashTime: {
+ bool ok = false;
+ // If cursor blinking is off, returns 0 to keep the cursor awlays display.
+ if (connection()->primaryScreen()->xSettings()->setting(xsNetCursorBlink).toInt(&ok) == 0 && ok)
+ return 0;
+
+ RETURN_VALID_XSETTINGS(xsNetCursorBlinkTime);
+ break;
+ }
case QPlatformIntegration::MouseDoubleClickInterval:
+ RETURN_VALID_XSETTINGS(xsNetDoubleClickTime);
+ break;
+ case QPlatformIntegration::MouseDoubleClickDistance:
+ RETURN_VALID_XSETTINGS(xsNetDoubleClickDistance);
+ break;
+ case QPlatformIntegration::KeyboardInputInterval:
case QPlatformIntegration::StartDragTime:
case QPlatformIntegration::KeyboardAutoRepeatRate:
case QPlatformIntegration::PasswordMaskDelay:
case QPlatformIntegration::StartDragVelocity:
case QPlatformIntegration::UseRtlExtensions:
case QPlatformIntegration::PasswordMaskCharacter:
+ case QPlatformIntegration::FlickMaximumVelocity:
+ case QPlatformIntegration::FlickDeceleration:
// TODO using various xcb, gnome or KDE settings
break; // Not implemented, use defaults
+ case QPlatformIntegration::FlickStartDistance:
case QPlatformIntegration::StartDragDistance: {
+ RETURN_VALID_XSETTINGS(xsNetDndDragThreshold);
// The default (in QPlatformTheme::defaultThemeHint) is 10 pixels, but
// on a high-resolution screen it makes sense to increase it.
- qreal dpi = 100.0;
- if (const QXcbScreen *screen = defaultConnection()->primaryScreen()) {
+ qreal dpi = 100;
+ if (const QXcbScreen *screen = connection()->primaryScreen()) {
if (screen->logicalDpi().first > dpi)
dpi = screen->logicalDpi().first;
if (screen->logicalDpi().second > dpi)
dpi = screen->logicalDpi().second;
}
- return 10.0 * dpi / 100.0;
+ return (hint == QPlatformIntegration::FlickStartDistance ? qreal(15) : qreal(10)) * dpi / qreal(100);
}
case QPlatformIntegration::ShowIsFullScreen:
// X11 always has support for windows, but the
@@ -498,7 +511,7 @@ static QString argv0BaseName()
const QStringList arguments = QCoreApplication::arguments();
if (!arguments.isEmpty() && !arguments.front().isEmpty()) {
result = arguments.front();
- const int lastSlashPos = result.lastIndexOf(QLatin1Char('/'));
+ const int lastSlashPos = result.lastIndexOf(u'/');
if (lastSlashPos != -1)
result.remove(0, lastSlashPos + 1);
}
@@ -543,9 +556,7 @@ QPlatformSessionManager *QXcbIntegration::createPlatformSessionManager(const QSt
void QXcbIntegration::sync()
{
- for (int i = 0; i < m_connections.size(); i++) {
- m_connections.at(i)->sync();
- }
+ m_connection->sync();
}
// For QApplication::beep()
@@ -579,4 +590,15 @@ QPlatformVulkanInstance *QXcbIntegration::createPlatformVulkanInstance(QVulkanIn
}
#endif
+void QXcbIntegration::setApplicationBadge(qint64 number)
+{
+ auto unixServices = dynamic_cast<QGenericUnixServices *>(services());
+ unixServices->setApplicationBadge(number);
+}
+
+QString QXcbUnixServices::portalWindowIdentifier(QWindow *window)
+{
+ return "x11:"_L1 + QString::number(window->winId(), 16);
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/xcb/qxcbintegration.h b/src/plugins/platforms/xcb/qxcbintegration.h
index 571726c354..a1e0c3f3e1 100644
--- a/src/plugins/platforms/xcb/qxcbintegration.h
+++ b/src/plugins/platforms/xcb/qxcbintegration.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QXCBINTEGRATION_H
#define QXCBINTEGRATION_H
@@ -43,6 +7,7 @@
#include <QtGui/private/qtguiglobal_p.h>
#include <qpa/qplatformintegration.h>
#include <qpa/qplatformscreen.h>
+#include <qpa/qplatformopenglcontext.h>
#include "qxcbexport.h"
@@ -55,6 +20,14 @@ class QAbstractEventDispatcher;
class QXcbNativeInterface;
class Q_XCB_EXPORT QXcbIntegration : public QPlatformIntegration
+#ifndef QT_NO_OPENGL
+# if QT_CONFIG(xcb_glx_plugin)
+ , public QNativeInterface::Private::QGLXIntegration
+# endif
+# if QT_CONFIG(egl)
+ , public QNativeInterface::Private::QEGLIntegration
+# endif
+#endif
{
public:
QXcbIntegration(const QStringList &parameters, int &argc, char **argv);
@@ -65,6 +38,12 @@ public:
QPlatformWindow *createForeignWindow(QWindow *window, WId nativeHandle) const override;
#ifndef QT_NO_OPENGL
QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const override;
+# if QT_CONFIG(xcb_glx_plugin)
+ QOpenGLContext *createOpenGLContext(GLXContext context, void *visualInfo, QOpenGLContext *shareContext) const override;
+# endif
+# if QT_CONFIG(egl)
+ QOpenGLContext *createOpenGLContext(EGLContext context, EGLDisplay display, QOpenGLContext *shareContext) const override;
+# endif
#endif
QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const override;
@@ -89,21 +68,20 @@ public:
QPlatformInputContext *inputContext() const override;
-#ifndef QT_NO_ACCESSIBILITY
+#if QT_CONFIG(accessibility)
QPlatformAccessibility *accessibility() const override;
#endif
QPlatformServices *services() const override;
- Qt::KeyboardModifiers queryKeyboardModifiers() const override;
- QList<int> possibleKeys(const QKeyEvent *e) const override;
+ QPlatformKeyMapper *keyMapper() const override;
QStringList themeNames() const override;
QPlatformTheme *createPlatformTheme(const QString &name) const override;
QVariant styleHint(StyleHint hint) const override;
- bool hasDefaultConnection() const { return !m_connections.isEmpty(); }
- QXcbConnection *defaultConnection() const { return m_connections.first(); }
+ bool hasConnection() const { return m_connection; }
+ QXcbConnection *connection() const { return m_connection; }
QByteArray wmClass() const;
@@ -123,15 +101,17 @@ public:
static QXcbIntegration *instance() { return m_instance; }
+ void setApplicationBadge(qint64 number) override;
+
private:
- QList<QXcbConnection *> m_connections;
+ QXcbConnection *m_connection = nullptr;
QScopedPointer<QPlatformFontDatabase> m_fontDatabase;
QScopedPointer<QXcbNativeInterface> m_nativeInterface;
QScopedPointer<QPlatformInputContext> m_inputContext;
-#ifndef QT_NO_ACCESSIBILITY
+#if QT_CONFIG(accessibility)
mutable QScopedPointer<QPlatformAccessibility> m_accessibility;
#endif
diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.cpp b/src/plugins/platforms/xcb/qxcbkeyboard.cpp
index e8286381a2..17da54bc7a 100644
--- a/src/plugins/platforms/xcb/qxcbkeyboard.cpp
+++ b/src/plugins/platforms/xcb/qxcbkeyboard.cpp
@@ -1,44 +1,9 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qxcbkeyboard.h"
#include "qxcbwindow.h"
#include "qxcbscreen.h"
+#include "qxcbcursor.h"
#include <qpa/qwindowsysteminterface.h>
#include <qpa/qplatforminputcontext.h>
@@ -223,7 +188,7 @@ struct xkb_keymap *QXcbKeyboard::keymapFromCore(const KeysymModifierMap &keysymM
// Generate mapping between symbolic names and keysyms
{
- QVector<xcb_keysym_t> xkeymap;
+ QList<xcb_keysym_t> xkeymap;
int keysymsPerKeycode = 0;
{
int keycodeCount = maxKeycode - minKeycode + 1;
@@ -257,7 +222,7 @@ struct xkb_keymap *QXcbKeyboard::keymapFromCore(const KeysymModifierMap &keysymM
const int maxGroup1 = 4; // We only support 4 shift states anyway
const int maxGroup2 = 2; // Only 3rd and 4th keysym are group 2
xcb_keysym_t symbolsGroup1[maxGroup1];
- xcb_keysym_t symbolsGroup2[maxGroup2];
+ xcb_keysym_t symbolsGroup2[maxGroup2] = { XKB_KEY_NoSymbol, XKB_KEY_NoSymbol };
for (int i = 0; i < maxGroup1 + maxGroup2; i++) {
xcb_keysym_t sym = i < keysymsPerKeycode ? codeMap[i] : XKB_KEY_NoSymbol;
if (mapGroup2ToLevel3) {
@@ -413,9 +378,18 @@ void QXcbKeyboard::updateKeymap()
QXkbCommon::verifyHasLatinLayout(m_xkbKeymap.get());
}
-QList<int> QXcbKeyboard::possibleKeys(const QKeyEvent *event) const
+QList<QKeyCombination> QXcbKeyboard::possibleKeyCombinations(const QKeyEvent *event) const
{
- return QXkbCommon::possibleKeys(m_xkbState.get(), event, m_superAsMeta, m_hyperAsMeta);
+ return QXkbCommon::possibleKeyCombinations(
+ m_xkbState.get(), event, m_superAsMeta, m_hyperAsMeta);
+}
+
+Qt::KeyboardModifiers QXcbKeyboard::queryKeyboardModifiers() const
+{
+ // FIXME: Should we base this on m_xkbState?
+ int stateMask = 0;
+ QXcbCursor::queryPointer(connection(), nullptr, nullptr, &stateMask);
+ return translateModifiers(stateMask);
}
void QXcbKeyboard::updateXKBState(xcb_xkb_state_notify_event_t *state)
@@ -441,7 +415,7 @@ static xkb_layout_index_t lockedGroup(quint16 state)
void QXcbKeyboard::updateXKBStateFromCore(quint16 state)
{
- if (m_config && !connection()->hasXKB()) {
+ if (m_config) {
struct xkb_state *xkbState = m_xkbState.get();
xkb_mod_mask_t modsDepressed = xkb_state_serialize_mods(xkbState, XKB_STATE_MODS_DEPRESSED);
xkb_mod_mask_t modsLatched = xkb_state_serialize_mods(xkbState, XKB_STATE_MODS_LATCHED);
@@ -463,7 +437,7 @@ void QXcbKeyboard::updateXKBStateFromCore(quint16 state)
void QXcbKeyboard::updateXKBStateFromXI(void *modInfo, void *groupInfo)
{
- if (m_config && !connection()->hasXKB()) {
+ if (m_config) {
auto *mods = static_cast<xcb_input_modifier_info_t *>(modInfo);
auto *group = static_cast<xcb_input_group_info_t *>(groupInfo);
const xkb_state_component changedComponents
diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.h b/src/plugins/platforms/xcb/qxcbkeyboard.h
index 0ee08aeff2..62d9268c64 100644
--- a/src/plugins/platforms/xcb/qxcbkeyboard.h
+++ b/src/plugins/platforms/xcb/qxcbkeyboard.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QXCBKEYBOARD_H
#define QXCBKEYBOARD_H
@@ -47,14 +11,16 @@
#include <xcb/xkb.h>
#undef explicit
-#include <QtXkbCommonSupport/private/qxkbcommon_p.h>
+#include <QtGui/private/qxkbcommon_p.h>
#include <xkbcommon/xkbcommon-x11.h>
+#include <qpa/qplatformkeymapper.h>
+
#include <QEvent>
QT_BEGIN_NAMESPACE
-class QXcbKeyboard : public QXcbObject
+class QXcbKeyboard : public QXcbObject, public QPlatformKeyMapper
{
public:
QXcbKeyboard(QXcbConnection *connection);
@@ -70,7 +36,9 @@ public:
Qt::KeyboardModifiers translateModifiers(int s) const;
void updateKeymap(xcb_mapping_notify_event_t *event);
void updateKeymap();
- QList<int> possibleKeys(const QKeyEvent *event) const;
+
+ QList<QKeyCombination> possibleKeyCombinations(const QKeyEvent *event) const override;
+ Qt::KeyboardModifiers queryKeyboardModifiers() const override;
void updateXKBMods();
xkb_mod_mask_t xkbModMask(quint16 state);
diff --git a/src/plugins/platforms/xcb/qxcbmain.cpp b/src/plugins/platforms/xcb/qxcbmain.cpp
index c1e37f3704..e4254203fc 100644
--- a/src/plugins/platforms/xcb/qxcbmain.cpp
+++ b/src/plugins/platforms/xcb/qxcbmain.cpp
@@ -1,47 +1,13 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <qpa/qplatformintegrationplugin.h>
#include "qxcbintegration.h"
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
class QXcbIntegrationPlugin : public QPlatformIntegrationPlugin
{
Q_OBJECT
@@ -52,9 +18,9 @@ public:
QPlatformIntegration* QXcbIntegrationPlugin::create(const QString& system, const QStringList& parameters, int &argc, char **argv)
{
- if (!system.compare(QLatin1String("xcb"), Qt::CaseInsensitive)) {
+ if (!system.compare("xcb"_L1, Qt::CaseInsensitive)) {
auto xcbIntegration = new QXcbIntegration(parameters, argc, argv);
- if (!xcbIntegration->hasDefaultConnection()) {
+ if (!xcbIntegration->hasConnection()) {
delete xcbIntegration;
return nullptr;
}
diff --git a/src/plugins/platforms/xcb/qxcbmime.cpp b/src/plugins/platforms/xcb/qxcbmime.cpp
index 0b3219f792..860d195d13 100644
--- a/src/plugins/platforms/xcb/qxcbmime.cpp
+++ b/src/plugins/platforms/xcb/qxcbmime.cpp
@@ -1,51 +1,16 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qxcbmime.h"
-#include <QtCore/QTextCodec>
#include <QtGui/QImageWriter>
#include <QtCore/QBuffer>
#include <qdebug.h>
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
QXcbMime::QXcbMime()
: QInternalMimeData()
{ }
@@ -62,13 +27,13 @@ QString QXcbMime::mimeAtomToString(QXcbConnection *connection, xcb_atom_t a)
// special cases for string type
if (a == XCB_ATOM_STRING
- || a == connection->atom(QXcbAtom::UTF8_STRING)
- || a == connection->atom(QXcbAtom::TEXT))
- return QLatin1String("text/plain");
+ || a == connection->atom(QXcbAtom::AtomUTF8_STRING)
+ || a == connection->atom(QXcbAtom::AtomTEXT))
+ return "text/plain"_L1;
// special case for images
if (a == XCB_ATOM_PIXMAP)
- return QLatin1String("image/ppm");
+ return "image/ppm"_L1;
QByteArray atomName = connection->atomName(a);
@@ -89,18 +54,18 @@ bool QXcbMime::mimeDataForAtom(QXcbConnection *connection, xcb_atom_t a, QMimeDa
*atomFormat = a;
*dataFormat = 8;
- if ((a == connection->atom(QXcbAtom::UTF8_STRING)
+ if ((a == connection->atom(QXcbAtom::AtomUTF8_STRING)
|| a == XCB_ATOM_STRING
- || a == connection->atom(QXcbAtom::TEXT))
- && QInternalMimeData::hasFormatHelper(QLatin1String("text/plain"), mimeData)) {
- if (a == connection->atom(QXcbAtom::UTF8_STRING)) {
- *data = QInternalMimeData::renderDataHelper(QLatin1String("text/plain"), mimeData);
+ || a == connection->atom(QXcbAtom::AtomTEXT))
+ && QInternalMimeData::hasFormatHelper("text/plain"_L1, mimeData)) {
+ if (a == connection->atom(QXcbAtom::AtomUTF8_STRING)) {
+ *data = QInternalMimeData::renderDataHelper("text/plain"_L1, mimeData);
ret = true;
} else if (a == XCB_ATOM_STRING ||
- a == connection->atom(QXcbAtom::TEXT)) {
+ a == connection->atom(QXcbAtom::AtomTEXT)) {
// ICCCM says STRING is latin1
*data = QString::fromUtf8(QInternalMimeData::renderDataHelper(
- QLatin1String("text/plain"), mimeData)).toLatin1();
+ "text/plain"_L1, mimeData)).toLatin1();
ret = true;
}
return ret;
@@ -111,18 +76,16 @@ bool QXcbMime::mimeDataForAtom(QXcbConnection *connection, xcb_atom_t a, QMimeDa
*data = QInternalMimeData::renderDataHelper(atomName, mimeData);
// mimeAtomToString() converts "text/x-moz-url" to "text/uri-list",
// so QXcbConnection::atomName() has to be used.
- if (atomName == QLatin1String("text/uri-list")
+ if (atomName == "text/uri-list"_L1
&& connection->atomName(a) == "text/x-moz-url") {
- const QString mozUri = QLatin1String(data->split('\n').constFirst()) + QLatin1Char('\n');
- *data = QByteArray(reinterpret_cast<const char *>(mozUri.utf16()),
- mozUri.length() * 2);
- } else if (atomName == QLatin1String("application/x-color"))
+ const QString mozUri = QLatin1StringView(data->split('\n').constFirst()) + u'\n';
+ data->assign({reinterpret_cast<const char *>(mozUri.data()), mozUri.size() * 2});
+ } else if (atomName == "application/x-color"_L1)
*dataFormat = 16;
ret = true;
} else if ((a == XCB_ATOM_PIXMAP || a == XCB_ATOM_BITMAP) && mimeData->hasImage()) {
ret = true;
- } else if (atomName == QLatin1String("text/plain")
- && mimeData->hasFormat(QLatin1String("text/uri-list"))) {
+ } else if (atomName == "text/plain"_L1 && mimeData->hasFormat("text/uri-list"_L1)) {
// Return URLs also as plain text.
*data = QInternalMimeData::renderDataHelper(atomName, mimeData);
ret = true;
@@ -130,84 +93,76 @@ bool QXcbMime::mimeDataForAtom(QXcbConnection *connection, xcb_atom_t a, QMimeDa
return ret;
}
-QVector<xcb_atom_t> QXcbMime::mimeAtomsForFormat(QXcbConnection *connection, const QString &format)
+QList<xcb_atom_t> QXcbMime::mimeAtomsForFormat(QXcbConnection *connection, const QString &format)
{
- QVector<xcb_atom_t> atoms;
+ QList<xcb_atom_t> atoms;
atoms.reserve(7);
atoms.append(connection->internAtom(format.toLatin1()));
// special cases for strings
- if (format == QLatin1String("text/plain")) {
- atoms.append(connection->atom(QXcbAtom::UTF8_STRING));
+ if (format == "text/plain"_L1) {
+ atoms.append(connection->atom(QXcbAtom::AtomUTF8_STRING));
atoms.append(XCB_ATOM_STRING);
- atoms.append(connection->atom(QXcbAtom::TEXT));
+ atoms.append(connection->atom(QXcbAtom::AtomTEXT));
}
// special cases for uris
- if (format == QLatin1String("text/uri-list")) {
+ if (format == "text/uri-list"_L1) {
atoms.append(connection->internAtom("text/x-moz-url"));
atoms.append(connection->internAtom("text/plain"));
}
//special cases for images
- if (format == QLatin1String("image/ppm"))
+ if (format == "image/ppm"_L1)
atoms.append(XCB_ATOM_PIXMAP);
- if (format == QLatin1String("image/pbm"))
+ if (format == "image/pbm"_L1)
atoms.append(XCB_ATOM_BITMAP);
return atoms;
}
QVariant QXcbMime::mimeConvertToFormat(QXcbConnection *connection, xcb_atom_t a, const QByteArray &d, const QString &format,
- QMetaType::Type requestedType, const QByteArray &encoding)
+ QMetaType requestedType, bool hasUtf8)
{
QByteArray data = d;
QString atomName = mimeAtomToString(connection, a);
// qDebug() << "mimeConvertDataToFormat" << format << atomName << data;
- if (!encoding.isEmpty()
- && atomName == format + QLatin1String(";charset=") + QLatin1String(encoding)) {
-
-#if QT_CONFIG(textcodec)
- if (requestedType == QMetaType::QString) {
- QTextCodec *codec = QTextCodec::codecForName(encoding);
- if (codec)
- return codec->toUnicode(data);
- }
-#endif
-
+ if (hasUtf8 && atomName == format + ";charset=utf-8"_L1) {
+ if (requestedType.id() == QMetaType::QString)
+ return QString::fromUtf8(data);
return data;
}
// special cases for string types
- if (format == QLatin1String("text/plain")) {
+ if (format == "text/plain"_L1) {
if (data.endsWith('\0'))
data.chop(1);
- if (a == connection->atom(QXcbAtom::UTF8_STRING)) {
+ if (a == connection->atom(QXcbAtom::AtomUTF8_STRING)) {
return QString::fromUtf8(data);
}
if (a == XCB_ATOM_STRING ||
- a == connection->atom(QXcbAtom::TEXT))
+ a == connection->atom(QXcbAtom::AtomTEXT))
return QString::fromLatin1(data);
}
// If data contains UTF16 text, convert it to a string.
// Firefox uses UTF16 without BOM for text/x-moz-url, "text/html",
// Google Chrome uses UTF16 without BOM for "text/x-moz-url",
// UTF16 with BOM for "text/html".
- if ((format == QLatin1String("text/html") || format == QLatin1String("text/uri-list"))
+ if ((format == "text/html"_L1 || format == "text/uri-list"_L1)
&& data.size() > 1) {
const quint8 byte0 = data.at(0);
const quint8 byte1 = data.at(1);
if ((byte0 == 0xff && byte1 == 0xfe) || (byte0 == 0xfe && byte1 == 0xff)
|| (byte0 != 0 && byte1 == 0) || (byte0 == 0 && byte1 != 0)) {
- const QString str = QString::fromUtf16(
- reinterpret_cast<const ushort *>(data.constData()), data.size() / 2);
+ const QStringView str(
+ reinterpret_cast<const char16_t *>(data.constData()), data.size() / 2);
if (!str.isNull()) {
- if (format == QLatin1String("text/uri-list")) {
- const auto urls = str.splitRef(QLatin1Char('\n'));
+ if (format == "text/uri-list"_L1) {
+ const auto urls = QStringView{str}.split(u'\n');
QList<QVariant> list;
list.reserve(urls.size());
- for (const QStringRef &s : urls) {
+ for (const QStringView &s : urls) {
const QUrl url(s.trimmed().toString());
if (url.isValid())
list.append(url);
@@ -219,7 +174,7 @@ QVariant QXcbMime::mimeConvertToFormat(QXcbConnection *connection, xcb_atom_t a,
return list.constFirst();
return list;
} else {
- return str;
+ return str.toString();
}
}
}
@@ -233,7 +188,7 @@ QVariant QXcbMime::mimeConvertToFormat(QXcbConnection *connection, xcb_atom_t a,
#if 0 // ###
// special case for images
- if (format == QLatin1String("image/ppm")) {
+ if (format == "image/ppm"_L1) {
if (a == XCB_ATOM_PIXMAP && data.size() == sizeof(Pixmap)) {
Pixmap xpm = *((Pixmap*)data.data());
if (!xpm)
@@ -264,23 +219,23 @@ QVariant QXcbMime::mimeConvertToFormat(QXcbConnection *connection, xcb_atom_t a,
return QVariant();
}
-xcb_atom_t QXcbMime::mimeAtomForFormat(QXcbConnection *connection, const QString &format, QMetaType::Type requestedType,
- const QVector<xcb_atom_t> &atoms, QByteArray *requestedEncoding)
+xcb_atom_t QXcbMime::mimeAtomForFormat(QXcbConnection *connection, const QString &format, QMetaType requestedType,
+ const QList<xcb_atom_t> &atoms, bool *hasUtf8)
{
- requestedEncoding->clear();
+ *hasUtf8 = false;
// find matches for string types
- if (format == QLatin1String("text/plain")) {
- if (atoms.contains(connection->atom(QXcbAtom::UTF8_STRING)))
- return connection->atom(QXcbAtom::UTF8_STRING);
+ if (format == "text/plain"_L1) {
+ if (atoms.contains(connection->atom(QXcbAtom::AtomUTF8_STRING)))
+ return connection->atom(QXcbAtom::AtomUTF8_STRING);
if (atoms.contains(XCB_ATOM_STRING))
return XCB_ATOM_STRING;
- if (atoms.contains(connection->atom(QXcbAtom::TEXT)))
- return connection->atom(QXcbAtom::TEXT);
+ if (atoms.contains(connection->atom(QXcbAtom::AtomTEXT)))
+ return connection->atom(QXcbAtom::AtomTEXT);
}
// find matches for uri types
- if (format == QLatin1String("text/uri-list")) {
+ if (format == "text/uri-list"_L1) {
xcb_atom_t a = connection->internAtom(format.toLatin1());
if (a && atoms.contains(a))
return a;
@@ -290,23 +245,23 @@ xcb_atom_t QXcbMime::mimeAtomForFormat(QXcbConnection *connection, const QString
}
// find match for image
- if (format == QLatin1String("image/ppm")) {
+ if (format == "image/ppm"_L1) {
if (atoms.contains(XCB_ATOM_PIXMAP))
return XCB_ATOM_PIXMAP;
}
// for string/text requests try to use a format with a well-defined charset
// first to avoid encoding problems
- if (requestedType == QMetaType::QString
- && format.startsWith(QLatin1String("text/"))
- && !format.contains(QLatin1String("charset="))) {
+ if (requestedType.id() == QMetaType::QString
+ && format.startsWith("text/"_L1)
+ && !format.contains("charset="_L1)) {
QString formatWithCharset = format;
- formatWithCharset.append(QLatin1String(";charset=utf-8"));
+ formatWithCharset.append(";charset=utf-8"_L1);
xcb_atom_t a = connection->internAtom(std::move(formatWithCharset).toLatin1());
if (a && atoms.contains(a)) {
- *requestedEncoding = "utf-8";
+ *hasUtf8 = true;
return a;
}
}
@@ -319,3 +274,5 @@ xcb_atom_t QXcbMime::mimeAtomForFormat(QXcbConnection *connection, const QString
}
QT_END_NAMESPACE
+
+#include "moc_qxcbmime.cpp"
diff --git a/src/plugins/platforms/xcb/qxcbmime.h b/src/plugins/platforms/xcb/qxcbmime.h
index dcb4f6b6c6..4c99c39c8b 100644
--- a/src/plugins/platforms/xcb/qxcbmime.h
+++ b/src/plugins/platforms/xcb/qxcbmime.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QXCBMIME_H
#define QXCBMIME_H
@@ -55,14 +19,14 @@ public:
QXcbMime();
~QXcbMime();
- static QVector<xcb_atom_t> mimeAtomsForFormat(QXcbConnection *connection, const QString &format);
+ static QList<xcb_atom_t> mimeAtomsForFormat(QXcbConnection *connection, const QString &format);
static QString mimeAtomToString(QXcbConnection *connection, xcb_atom_t a);
static bool mimeDataForAtom(QXcbConnection *connection, xcb_atom_t a, QMimeData *mimeData, QByteArray *data,
xcb_atom_t *atomFormat, int *dataFormat);
static QVariant mimeConvertToFormat(QXcbConnection *connection, xcb_atom_t a, const QByteArray &data, const QString &format,
- QMetaType::Type requestedType, const QByteArray &encoding);
- static xcb_atom_t mimeAtomForFormat(QXcbConnection *connection, const QString &format, QMetaType::Type requestedType,
- const QVector<xcb_atom_t> &atoms, QByteArray *requestedEncoding);
+ QMetaType requestedType, bool hasUtf8);
+ static xcb_atom_t mimeAtomForFormat(QXcbConnection *connection, const QString &format, QMetaType requestedType,
+ const QList<xcb_atom_t> &atoms, bool *hasUtf8);
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp
index 30fa6864ac..06f5241d8c 100644
--- a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp
+++ b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qxcbnativeinterface.h"
@@ -53,9 +17,6 @@
#include <QtGui/qopenglcontext.h>
#include <QtGui/qscreen.h>
-#include <QtPlatformHeaders/qxcbwindowfunctions.h>
-#include <QtPlatformHeaders/qxcbscreenfunctions.h>
-
#include <stdio.h>
#include <algorithm>
@@ -121,7 +82,7 @@ void *QXcbNativeInterface::nativeResourceForIntegration(const QByteArray &resour
case RootWindow:
result = rootWindow();
break;
- case Display:
+ case XDisplay:
result = display();
break;
case AtspiBus:
@@ -158,7 +119,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
@@ -206,7 +167,7 @@ void *QXcbNativeInterface::nativeResourceForWindow(const QByteArray &resourceStr
return result;
switch (resourceType(lowerCaseResource)) {
- case Display:
+ case XDisplay:
result = displayForWindow(window);
break;
case Connection:
@@ -311,27 +272,9 @@ QPlatformNativeInterface::NativeResourceForBackingStoreFunction QXcbNativeInterf
QFunctionPointer QXcbNativeInterface::platformFunction(const QByteArray &function) const
{
const QByteArray lowerCaseFunction = function.toLower();
- QFunctionPointer func = handlerPlatformFunction(lowerCaseFunction);
- if (func)
+ if (QFunctionPointer func = handlerPlatformFunction(lowerCaseFunction))
return func;
- //case sensitive
- if (function == QXcbWindowFunctions::setWmWindowTypeIdentifier())
- return QFunctionPointer(QXcbWindowFunctions::SetWmWindowType(QXcbWindow::setWmWindowTypeStatic));
-
- if (function == QXcbWindowFunctions::setWmWindowRoleIdentifier())
- return QFunctionPointer(QXcbWindowFunctions::SetWmWindowRole(QXcbWindow::setWmWindowRoleStatic));
-
- if (function == QXcbWindowFunctions::setWmWindowIconTextIdentifier())
- return QFunctionPointer(QXcbWindowFunctions::SetWmWindowIconText(QXcbWindow::setWindowIconTextStatic));
-
- if (function == QXcbWindowFunctions::visualIdIdentifier()) {
- return QFunctionPointer(QXcbWindowFunctions::VisualId(QXcbWindow::visualIdStatic));
- }
-
- if (function == QXcbScreenFunctions::virtualDesktopNumberIdentifier())
- return QFunctionPointer(QXcbScreenFunctions::VirtualDesktopNumber(reinterpret_cast<void *>(QXcbScreen::virtualDesktopNumberStatic)));
-
return nullptr;
}
@@ -362,55 +305,54 @@ void *QXcbNativeInterface::getTimestamp(const QXcbScreen *screen)
void *QXcbNativeInterface::startupId()
{
QXcbIntegration* integration = QXcbIntegration::instance();
- QXcbConnection *defaultConnection = integration->defaultConnection();
- if (defaultConnection)
- return reinterpret_cast<void *>(const_cast<char *>(defaultConnection->startupId().constData()));
+ QXcbConnection *connection = integration->connection();
+ if (connection)
+ return reinterpret_cast<void *>(const_cast<char *>(connection->startupId().constData()));
return nullptr;
}
void *QXcbNativeInterface::x11Screen()
{
QXcbIntegration *integration = QXcbIntegration::instance();
- QXcbConnection *defaultConnection = integration->defaultConnection();
- if (defaultConnection)
- return reinterpret_cast<void *>(defaultConnection->primaryScreenNumber());
+ QXcbConnection *connection = integration->connection();
+ if (connection)
+ return reinterpret_cast<void *>(connection->primaryScreenNumber());
return nullptr;
}
void *QXcbNativeInterface::rootWindow()
{
QXcbIntegration *integration = QXcbIntegration::instance();
- QXcbConnection *defaultConnection = integration->defaultConnection();
- if (defaultConnection)
- return reinterpret_cast<void *>(defaultConnection->rootWindow());
+ QXcbConnection *connection = integration->connection();
+ if (connection)
+ return reinterpret_cast<void *>(connection->rootWindow());
return nullptr;
}
-void *QXcbNativeInterface::display()
+Display *QXcbNativeInterface::display() const
{
#if QT_CONFIG(xcb_xlib)
QXcbIntegration *integration = QXcbIntegration::instance();
- QXcbConnection *defaultConnection = integration->defaultConnection();
- if (defaultConnection)
- return defaultConnection->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->defaultConnection()->xcb_connection();
+ return integration->connection()->xcb_connection();
}
void *QXcbNativeInterface::atspiBus()
{
QXcbIntegration *integration = static_cast<QXcbIntegration *>(QGuiApplicationPrivate::platformIntegration());
- QXcbConnection *defaultConnection = integration->defaultConnection();
- if (defaultConnection) {
- auto atspiBusAtom = defaultConnection->atom(QXcbAtom::AT_SPI_BUS);
- auto reply = Q_XCB_REPLY(xcb_get_property, defaultConnection->xcb_connection(),
- false, defaultConnection->rootWindow(),
+ QXcbConnection *connection = integration->connection();
+ if (connection) {
+ auto atspiBusAtom = connection->atom(QXcbAtom::AtomAT_SPI_BUS);
+ auto reply = Q_XCB_REPLY(xcb_get_property, connection->xcb_connection(),
+ false, connection->rootWindow(),
atspiBusAtom, XCB_ATOM_STRING, 0, 128);
if (!reply)
return nullptr;
@@ -440,29 +382,29 @@ void QXcbNativeInterface::setAppUserTime(QScreen* screen, xcb_timestamp_t time)
qint32 QXcbNativeInterface::generatePeekerId()
{
QXcbIntegration *integration = QXcbIntegration::instance();
- return integration->defaultConnection()->eventQueue()->generatePeekerId();
+ return integration->connection()->eventQueue()->generatePeekerId();
}
bool QXcbNativeInterface::removePeekerId(qint32 peekerId)
{
QXcbIntegration *integration = QXcbIntegration::instance();
- return integration->defaultConnection()->eventQueue()->removePeekerId(peekerId);
+ return integration->connection()->eventQueue()->removePeekerId(peekerId);
}
bool QXcbNativeInterface::peekEventQueue(QXcbEventQueue::PeekerCallback peeker, void *peekerData,
QXcbEventQueue::PeekOptions option, qint32 peekerId)
{
QXcbIntegration *integration = QXcbIntegration::instance();
- return integration->defaultConnection()->eventQueue()->peekEventQueue(peeker, peekerData, option, peekerId);
+ return integration->connection()->eventQueue()->peekEventQueue(peeker, peekerData, option, peekerId);
}
void QXcbNativeInterface::setStartupId(const char *data)
{
QByteArray startupId(data);
QXcbIntegration *integration = QXcbIntegration::instance();
- QXcbConnection *defaultConnection = integration->defaultConnection();
- if (defaultConnection)
- defaultConnection->setStartupId(startupId);
+ QXcbConnection *connection = integration->connection();
+ if (connection)
+ connection->setStartupId(startupId);
}
QXcbScreen *QXcbNativeInterface::qPlatformScreenForWindow(QWindow *window)
@@ -635,7 +577,7 @@ static void dumpNativeWindowsRecursion(const QXcbConnection *connection, xcb_win
const int oldFieldWidth = str.fieldWidth();
const QChar oldPadChar =str.padChar();
str.setFieldWidth(8);
- str.setPadChar(QLatin1Char('0'));
+ str.setPadChar(u'0');
str << Qt::hex << window;
str.setFieldWidth(oldFieldWidth);
str.setPadChar(oldPadChar);
@@ -671,7 +613,9 @@ QString QXcbNativeInterface::dumpConnectionNativeWindows(const QXcbConnection *c
QString QXcbNativeInterface::dumpNativeWindows(WId root) const
{
- return dumpConnectionNativeWindows(QXcbIntegration::instance()->defaultConnection(), root);
+ return dumpConnectionNativeWindows(QXcbIntegration::instance()->connection(), root);
}
QT_END_NAMESPACE
+
+#include "moc_qxcbnativeinterface.cpp"
diff --git a/src/plugins/platforms/xcb/qxcbnativeinterface.h b/src/plugins/platforms/xcb/qxcbnativeinterface.h
index 4656f46be5..62bfb4c634 100644
--- a/src/plugins/platforms/xcb/qxcbnativeinterface.h
+++ b/src/plugins/platforms/xcb/qxcbnativeinterface.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QXCBNATIVEINTERFACE_H
#define QXCBNATIVEINTERFACE_H
@@ -45,6 +9,8 @@
#include <QtCore/QRect>
+#include <QtGui/qguiapplication.h>
+
#include "qxcbexport.h"
#include "qxcbconnection.h"
@@ -54,11 +20,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 +76,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);
@@ -133,8 +102,6 @@ signals:
private:
const QByteArray m_nativeEventType = QByteArrayLiteral("xcb_generic_event_t");
- xcb_atom_t m_sysTraySelectionAtom = XCB_ATOM_NONE;
-
static QXcbScreen *qPlatformScreenForWindow(QWindow *window);
QList<QXcbNativeInterfaceHandler *> m_handlers;
diff --git a/src/plugins/platforms/xcb/qxcbobject.h b/src/plugins/platforms/xcb/qxcbobject.h
index 931bed9ec1..965ec636b7 100644
--- a/src/plugins/platforms/xcb/qxcbobject.h
+++ b/src/plugins/platforms/xcb/qxcbobject.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QXCBOBJECT_H
#define QXCBOBJECT_H
diff --git a/src/plugins/platforms/xcb/qxcbscreen.cpp b/src/plugins/platforms/xcb/qxcbscreen.cpp
index 698be45aa8..06f4b66edb 100644
--- a/src/plugins/platforms/xcb/qxcbscreen.cpp
+++ b/src/plugins/platforms/xcb/qxcbscreen.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qxcbscreen.h"
#include "qxcbwindow.h"
@@ -62,7 +26,7 @@ QXcbVirtualDesktop::QXcbVirtualDesktop(QXcbConnection *connection, xcb_screen_t
{
const QByteArray cmAtomName = "_NET_WM_CM_S" + QByteArray::number(m_number);
m_net_wm_cm_atom = connection->internAtom(cmAtomName.constData());
- m_compositingActive = connection->getSelectionOwner(m_net_wm_cm_atom);
+ m_compositingActive = connection->selectionOwner(m_net_wm_cm_atom);
m_workArea = getWorkArea();
@@ -86,7 +50,7 @@ QXcbVirtualDesktop::QXcbVirtualDesktop(QXcbConnection *connection, xcb_screen_t
auto reply = Q_XCB_REPLY_UNCHECKED(xcb_get_property, xcb_connection(),
false, screen->root,
- atom(QXcbAtom::_NET_SUPPORTING_WM_CHECK),
+ atom(QXcbAtom::Atom_NET_SUPPORTING_WM_CHECK),
XCB_ATOM_WINDOW, 0, 1024);
if (reply && reply->format == 32 && reply->type == XCB_ATOM_WINDOW) {
xcb_window_t windowManager = *((xcb_window_t *)xcb_get_property_value(reply.get()));
@@ -112,11 +76,24 @@ QXcbVirtualDesktop::QXcbVirtualDesktop(QXcbConnection *connection, xcb_screen_t
xcb_depth_next(&depth_iterator);
}
+
+ auto dpiChangedCallback = [](QXcbVirtualDesktop *desktop, const QByteArray &, const QVariant &property, void *) {
+ if (!desktop->setDpiFromXSettings(property))
+ return;
+ const auto dpi = desktop->forcedDpi();
+ for (QXcbScreen *screen : desktop->connection()->screens())
+ QWindowSystemInterface::handleScreenLogicalDotsPerInchChange(screen->QPlatformScreen::screen(), dpi, dpi);
+ };
+ setDpiFromXSettings(xSettings()->setting("Xft/DPI"));
+ xSettings()->registerCallbackForProperty("Xft/DPI", dpiChangedCallback, nullptr);
}
QXcbVirtualDesktop::~QXcbVirtualDesktop()
{
delete m_xSettings;
+
+ for (auto cmap : std::as_const(m_visualColormaps))
+ xcb_free_colormap(xcb_connection(), cmap);
}
QDpi QXcbVirtualDesktop::dpi() const
@@ -164,7 +141,7 @@ bool QXcbVirtualDesktop::compositingActive() const
if (connection()->hasXFixes())
return m_compositingActive;
else
- return connection()->getSelectionOwner(m_net_wm_cm_atom);
+ return connection()->selectionOwner(m_net_wm_cm_atom);
}
void QXcbVirtualDesktop::handleXFixesSelectionNotify(xcb_xfixes_selection_notify_event_t *notify_event)
@@ -179,7 +156,7 @@ void QXcbVirtualDesktop::subscribeToXFixesSelectionNotify()
const uint32_t mask = XCB_XFIXES_SELECTION_EVENT_MASK_SET_SELECTION_OWNER |
XCB_XFIXES_SELECTION_EVENT_MASK_SELECTION_WINDOW_DESTROY |
XCB_XFIXES_SELECTION_EVENT_MASK_SELECTION_CLIENT_CLOSE;
- xcb_xfixes_select_selection_input_checked(xcb_connection(), connection()->getQtSelectionOwner(), m_net_wm_cm_atom, mask);
+ xcb_xfixes_select_selection_input_checked(xcb_connection(), connection()->qtSelectionOwner(), m_net_wm_cm_atom, mask);
}
}
@@ -245,7 +222,7 @@ void QXcbVirtualDesktop::handleScreenChange(xcb_randr_screen_change_notify_event
case XCB_RANDR_ROTATION_REFLECT_Y: break;
}
- for (QPlatformScreen *platformScreen: qAsConst(m_screens)) {
+ for (QPlatformScreen *platformScreen : std::as_const(m_screens)) {
QDpi ldpi = platformScreen->logicalDpi();
QWindowSystemInterface::handleScreenLogicalDotsPerInchChange(platformScreen->screen(), ldpi.first, ldpi.second);
}
@@ -258,7 +235,7 @@ void QXcbVirtualDesktop::handleScreenChange(xcb_randr_screen_change_notify_event
_NET_WORKAREA means with multiple attached monitors. This gets worse when monitors have
different dimensions and/or screens are not virtually aligned. In Qt we want the available
geometry per monitor (QScreen), not desktop (represented by _NET_WORKAREA). WM specification
- does not have an atom for this. Thus, QScreen is limted by the lack of support from the
+ does not have an atom for this. Thus, QScreen is limited by the lack of support from the
underlying system.
One option could be that Qt does WM's job of calculating this by subtracting geometries of
@@ -272,7 +249,7 @@ QRect QXcbVirtualDesktop::getWorkArea() const
{
QRect r;
auto workArea = Q_XCB_REPLY_UNCHECKED(xcb_get_property, xcb_connection(), false, screen()->root,
- atom(QXcbAtom::_NET_WORKAREA),
+ atom(QXcbAtom::Atom_NET_WORKAREA),
XCB_ATOM_CARDINAL, 0, 1024);
if (workArea && workArea->type == XCB_ATOM_CARDINAL && workArea->format == 32 && workArea->value_len >= 4) {
// If workArea->value_len > 4, the remaining ones seem to be for WM's virtual desktops
@@ -284,7 +261,7 @@ QRect QXcbVirtualDesktop::getWorkArea() const
uint32_t *geom = (uint32_t*)xcb_get_property_value(workArea.get());
r = QRect(geom[0], geom[1], geom[2], geom[3]);
} else {
- r = QRect(QPoint(), size());
+ r.setWidth(-1);
}
return r;
}
@@ -294,11 +271,16 @@ void QXcbVirtualDesktop::updateWorkArea()
QRect workArea = getWorkArea();
if (m_workArea != workArea) {
m_workArea = workArea;
- for (QPlatformScreen *screen : qAsConst(m_screens))
+ for (QPlatformScreen *screen : std::as_const(m_screens))
((QXcbScreen *)screen)->updateAvailableGeometry();
}
}
+QRect QXcbVirtualDesktop::availableGeometry(const QRect &screenGeometry) const
+{
+ return m_workArea.width() >= 0 ? screenGeometry & m_workArea : screenGeometry;
+}
+
static inline QSizeF sizeInMillimeters(const QSize &size, const QDpi &dpi)
{
return QSizeF(Q_MM_PER_INCH * size.width() / dpi.first,
@@ -403,6 +385,19 @@ void QXcbVirtualDesktop::readXResources()
}
}
+bool QXcbVirtualDesktop::setDpiFromXSettings(const QVariant &property)
+{
+ bool ok;
+ int dpiTimes1k = property.toInt(&ok);
+ if (!ok)
+ return false;
+ int dpi = dpiTimes1k / 1024;
+ if (m_forcedDpi == dpi)
+ return false;
+ m_forcedDpi = dpi;
+ return true;
+}
+
QSurfaceFormat QXcbVirtualDesktop::surfaceFormatFor(const QSurfaceFormat &format) const
{
const xcb_visualid_t xcb_visualid = connection()->hasDefaultVisualId() ? connection()->defaultVisualId()
@@ -479,17 +474,34 @@ quint8 QXcbVirtualDesktop::depthOfVisual(xcb_visualid_t visualid) const
return *it;
}
+xcb_colormap_t QXcbVirtualDesktop::colormapForVisual(xcb_visualid_t visualid) const
+{
+ auto it = m_visualColormaps.constFind(visualid);
+ if (it != m_visualColormaps.constEnd())
+ return *it;
+
+ auto cmap = xcb_generate_id(xcb_connection());
+ xcb_create_colormap(xcb_connection(),
+ XCB_COLORMAP_ALLOC_NONE,
+ cmap,
+ screen()->root,
+ visualid);
+ m_visualColormaps.insert(visualid, cmap);
+ return cmap;
+}
+
QXcbScreen::QXcbScreen(QXcbConnection *connection, QXcbVirtualDesktop *virtualDesktop,
- xcb_randr_output_t outputId, xcb_randr_get_output_info_reply_t *output,
- const xcb_xinerama_screen_info_t *xineramaScreenInfo, int xineramaScreenIdx)
+ 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())
+ , m_cursor(std::make_unique<QXcbCursor>(connection, this))
{
- 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);
@@ -497,27 +509,34 @@ QXcbScreen::QXcbScreen(QXcbConnection *connection, QXcbVirtualDesktop *virtualDe
updateGeometry(QRect(crtc->x, crtc->y, crtc->width, crtc->height), crtc->rotation);
updateRefreshRate(crtc->mode);
}
- } else if (xineramaScreenInfo) {
- m_geometry = QRect(xineramaScreenInfo->x_org, xineramaScreenInfo->y_org,
- xineramaScreenInfo->width, xineramaScreenInfo->height);
- m_availableGeometry = m_geometry & m_virtualDesktop->workArea();
- m_sizeMillimeters = sizeInMillimeters(m_geometry.size(), m_virtualDesktop->dpi());
- if (xineramaScreenIdx > -1)
- m_outputName += QLatin1Char('-') + QString::number(xineramaScreenIdx);
}
if (m_geometry.isEmpty())
m_geometry = QRect(QPoint(), virtualDesktop->size());
if (m_availableGeometry.isEmpty())
- m_availableGeometry = m_geometry & m_virtualDesktop->workArea();
+ m_availableGeometry = m_virtualDesktop->availableGeometry(m_geometry);
if (m_sizeMillimeters.isEmpty())
m_sizeMillimeters = virtualDesktop->physicalSize();
- m_cursor = new QXcbCursor(connection, this);
+ updateColorSpaceAndEdid();
+}
- if (connection->hasXRandr()) { // Parse EDID
+void QXcbScreen::updateColorSpaceAndEdid()
+{
+ {
+ // Read colord ICC data (from GNOME settings)
+ auto reply = Q_XCB_REPLY_UNCHECKED(xcb_get_property, xcb_connection(),
+ false, screen()->root,
+ connection()->atom(QXcbAtom::Atom_ICC_PROFILE),
+ XCB_ATOM_CARDINAL, 0, 8192);
+ if (reply->format == 8 && reply->type == XCB_ATOM_CARDINAL) {
+ QByteArray data(reinterpret_cast<const char *>(xcb_get_property_value(reply.get())), reply->value_len);
+ m_colorSpace = QColorSpace::fromIccProfile(data);
+ }
+ }
+ if (connection()->isAtLeastXRandR12()) { // Parse EDID
QByteArray edid = getEdid();
if (m_edid.parse(edid)) {
qCDebug(lcQpaScreen, "EDID data for output \"%s\": identifier '%s', manufacturer '%s',"
@@ -528,6 +547,27 @@ QXcbScreen::QXcbScreen(QXcbConnection *connection, QXcbVirtualDesktop *virtualDe
m_edid.model.toLatin1().constData(),
m_edid.serialNumber.toLatin1().constData(),
m_edid.physicalSize.width(), m_edid.physicalSize.height());
+ if (!m_colorSpace.isValid()) {
+ if (m_edid.sRgb)
+ m_colorSpace = QColorSpace::SRgb;
+ else {
+ if (!m_edid.useTables) {
+ m_colorSpace = QColorSpace(m_edid.whiteChromaticity, m_edid.redChromaticity,
+ m_edid.greenChromaticity, m_edid.blueChromaticity,
+ QColorSpace::TransferFunction::Gamma, m_edid.gamma);
+ } else {
+ if (m_edid.tables.size() == 1) {
+ m_colorSpace = QColorSpace(m_edid.whiteChromaticity, m_edid.redChromaticity,
+ m_edid.greenChromaticity, m_edid.blueChromaticity,
+ m_edid.tables[0]);
+ } else if (m_edid.tables.size() == 3) {
+ m_colorSpace = QColorSpace(m_edid.whiteChromaticity, m_edid.redChromaticity,
+ m_edid.greenChromaticity, m_edid.blueChromaticity,
+ m_edid.tables[0], m_edid.tables[1], m_edid.tables[2]);
+ }
+ }
+ }
+ }
} else {
// This property is defined by the xrandr spec. Parsing failure indicates a valid error,
// but keep this as debug, for details see 4f515815efc318ddc909a0399b71b8a684962f38.
@@ -535,11 +575,144 @@ QXcbScreen::QXcbScreen(QXcbConnection *connection, QXcbVirtualDesktop *virtualDe
"edid data: " << edid;
}
}
+ if (!m_colorSpace.isValid())
+ 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)
+ , m_cursor(std::make_unique<QXcbCursor>(connection, this))
+{
+ 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();
+ m_output = XCB_NONE;
+ m_crtc = XCB_NONE;
+ m_singlescreen = false;
+
+ if (!monitorInfo) {
+ m_monitor = nullptr;
+ 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;
+ qCDebug(lcQpaScreen) << "xcb_randr_monitor_info_t: primary=" << m_monitor->primary << ", x=" << m_monitor->x << ", y=" << m_monitor->y
+ << ", width=" << m_monitor->width << ", height=" << m_monitor->height
+ << ", width_in_millimeters=" << m_monitor->width_in_millimeters << ", height_in_millimeters=" << m_monitor->height_in_millimeters;
+ QRect monitorGeometry = QRect(m_monitor->x, m_monitor->y,
+ m_monitor->width, m_monitor->height);
+ m_sizeMillimeters = QSize(m_monitor->width_in_millimeters, m_monitor->height_in_millimeters);
+
+ 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];
+ if (m_output == XCB_NONE) {
+ m_output = outputs[i];
+ m_outputSizeMillimeters = QSize(output->mm_width, output->mm_height);
+ }
+ m_crtcs << output->crtc;
+ if (m_crtc == XCB_NONE)
+ m_crtc = 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) {
+ 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);
+
+ if (m_sizeMillimeters.isEmpty())
+ m_sizeMillimeters = virtualDesktop()->physicalSize();
+
+ m_outputName = getName(monitorInfo);
+ m_primary = false;
+ if (connection()->primaryScreenNumber() == virtualDesktop()->number()) {
+ if (monitorInfo->primary || isPrimaryInXScreen())
+ m_primary = true;
+ }
+
+ updateColorSpaceAndEdid();
+}
+
+QString QXcbScreen::defaultName()
+{
+ QString name;
+ QByteArray displayName = connection()->displayName();
+ int dotPos = displayName.lastIndexOf('.');
+ if (dotPos != -1)
+ displayName.truncate(dotPos);
+ name = QString::fromLocal8Bit(displayName) + u'.'
+ + QString::number(m_virtualDesktop->number());
+ return name;
+}
+
+bool QXcbScreen::isPrimaryInXScreen()
+{
+ auto primary = Q_XCB_REPLY(xcb_randr_get_output_primary, connection()->xcb_connection(), root());
+ if (!primary)
+ qWarning("failed to get the primary output of the screen");
+
+ const bool isPrimary = primary ? (m_monitor ? m_outputs.contains(primary->output) : m_output == primary->output) : false;
+
+ return isPrimary;
}
QXcbScreen::~QXcbScreen()
{
- delete m_cursor;
}
QString QXcbScreen::getOutputName(xcb_randr_get_output_info_reply_t *outputInfo)
@@ -549,11 +722,23 @@ 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)
displayName.truncate(dotPos);
- name = QString::fromLocal8Bit(displayName) + QLatin1Char('.')
+ name = QString::fromLocal8Bit(displayName) + u'.'
+ QString::number(m_virtualDesktop->number());
}
return name;
@@ -611,7 +796,7 @@ void QXcbScreen::windowShown(QXcbWindow *window)
// Freedesktop.org Startup Notification
if (!connection()->startupId().isEmpty() && window->window()->isTopLevel()) {
sendStartupMessage(QByteArrayLiteral("remove: ID=") + connection()->startupId());
- connection()->clearStartupId();
+ connection()->setStartupId({});
}
}
@@ -632,15 +817,15 @@ void QXcbScreen::sendStartupMessage(const QByteArray &message) const
xcb_client_message_event_t ev;
ev.response_type = XCB_CLIENT_MESSAGE;
ev.format = 8;
- ev.type = connection()->atom(QXcbAtom::_NET_STARTUP_INFO_BEGIN);
+ ev.type = connection()->atom(QXcbAtom::Atom_NET_STARTUP_INFO_BEGIN);
ev.sequence = 0;
ev.window = rootWindow;
int sent = 0;
- int length = message.length() + 1; // include NUL byte
+ int length = message.size() + 1; // include NUL byte
const char *data = message.constData();
do {
if (sent == 20)
- ev.type = connection()->atom(QXcbAtom::_NET_STARTUP_INFO);
+ ev.type = connection()->atom(QXcbAtom::Atom_NET_STARTUP_INFO);
const int start = sent;
const int numBytes = qMin(length - start, 20);
@@ -654,7 +839,7 @@ void QXcbScreen::sendStartupMessage(const QByteArray &message) const
QRect QXcbScreen::availableGeometry() const
{
static bool enforceNetWorkarea = !qEnvironmentVariableIsEmpty("QT_RELY_ON_NET_WORKAREA_ATOM");
- bool isMultiHeadSystem = virtualSiblings().length() > 1;
+ bool isMultiHeadSystem = virtualSiblings().size() > 1;
bool useScreenGeometry = isMultiHeadSystem && !enforceNetWorkarea;
return useScreenGeometry ? m_geometry : m_availableGeometry;
}
@@ -665,7 +850,9 @@ QImage::Format QXcbScreen::format() const
bool needsRgbSwap;
qt_xcb_imageFormatForVisual(connection(), screen()->root_depth, visualForId(screen()->root_visual), &format, &needsRgbSwap);
// We are ignoring needsRgbSwap here and just assumes the backing-store will handle it.
- return format;
+ if (format != QImage::Format_Invalid)
+ return format;
+ return QImage::Format_RGB32;
}
int QXcbScreen::forcedDpi() const
@@ -682,17 +869,23 @@ QDpi QXcbScreen::logicalDpi() const
if (forcedDpi > 0)
return QDpi(forcedDpi, forcedDpi);
- return m_virtualDesktop->dpi();
+ // Fall back to 96 DPI in case no logical DPI is set. We don't want to
+ // return physical DPI here, since that is a different type of DPI: Logical
+ // DPI typically accounts for user preference and viewing distance, and is
+ // quantized into DPI classes (96, 144, 192, etc); pysical DPI is an exact
+ // physical measure.
+ return QDpi(96, 96);
}
QPlatformCursor *QXcbScreen::cursor() const
{
- return m_cursor;
+ return m_cursor.get();
}
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;
@@ -700,17 +893,9 @@ void QXcbScreen::setOutput(xcb_randr_output_t outputId,
// TODO: Send an event to the QScreen instance that the screen changed its name
}
-int QXcbScreen::virtualDesktopNumberStatic(const QScreen *screen)
-{
- if (screen && screen->handle())
- return static_cast<const QXcbScreen *>(screen->handle())->screenNumber();
-
- return 0;
-}
-
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(),
@@ -726,19 +911,23 @@ void QXcbScreen::updateGeometry(const QRect &geometry, uint8_t rotation)
switch (rotation) {
case XCB_RANDR_ROTATION_ROTATE_0: // xrandr --rotate normal
m_orientation = Qt::LandscapeOrientation;
- m_sizeMillimeters = m_outputSizeMillimeters;
+ if (!m_monitor)
+ m_sizeMillimeters = m_outputSizeMillimeters;
break;
case XCB_RANDR_ROTATION_ROTATE_90: // xrandr --rotate left
m_orientation = Qt::PortraitOrientation;
- m_sizeMillimeters = m_outputSizeMillimeters.transposed();
+ if (!m_monitor)
+ m_sizeMillimeters = m_outputSizeMillimeters.transposed();
break;
case XCB_RANDR_ROTATION_ROTATE_180: // xrandr --rotate inverted
m_orientation = Qt::InvertedLandscapeOrientation;
- m_sizeMillimeters = m_outputSizeMillimeters;
+ if (!m_monitor)
+ m_sizeMillimeters = m_outputSizeMillimeters;
break;
case XCB_RANDR_ROTATION_ROTATE_270: // xrandr --rotate right
m_orientation = Qt::InvertedPortraitOrientation;
- m_sizeMillimeters = m_outputSizeMillimeters.transposed();
+ if (!m_monitor)
+ m_sizeMillimeters = m_outputSizeMillimeters.transposed();
break;
}
@@ -749,7 +938,7 @@ void QXcbScreen::updateGeometry(const QRect &geometry, uint8_t rotation)
m_sizeMillimeters = sizeInMillimeters(geometry.size(), m_virtualDesktop->dpi());
m_geometry = geometry;
- m_availableGeometry = geometry & m_virtualDesktop->workArea();
+ m_availableGeometry = m_virtualDesktop->availableGeometry(m_geometry);
QWindowSystemInterface::handleScreenGeometryChange(QPlatformScreen::screen(), m_geometry, m_availableGeometry);
if (m_orientation != oldOrientation)
QWindowSystemInterface::handleScreenOrientationChange(QPlatformScreen::screen(), m_orientation);
@@ -757,7 +946,7 @@ void QXcbScreen::updateGeometry(const QRect &geometry, uint8_t rotation)
void QXcbScreen::updateAvailableGeometry()
{
- QRect availableGeometry = m_geometry & m_virtualDesktop->workArea();
+ QRect availableGeometry = m_virtualDesktop->availableGeometry(m_geometry);
if (m_availableGeometry != availableGeometry) {
m_availableGeometry = availableGeometry;
QWindowSystemInterface::handleScreenGeometryChange(QPlatformScreen::screen(), m_geometry, m_availableGeometry);
@@ -766,7 +955,7 @@ void QXcbScreen::updateAvailableGeometry()
void QXcbScreen::updateRefreshRate(xcb_randr_mode_t mode)
{
- if (!connection()->hasXRandr())
+ if (!connection()->isAtLeastXRandR12())
return;
if (m_mode == mode)
@@ -902,15 +1091,15 @@ 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
- result = getOutputProperty(atom(QXcbAtom::EDID));
+ result = getOutputProperty(atom(QXcbAtom::AtomEDID));
if (result.isEmpty())
- result = getOutputProperty(atom(QXcbAtom::EDID_DATA));
+ result = getOutputProperty(atom(QXcbAtom::AtomEDID_DATA));
if (result.isEmpty())
- result = getOutputProperty(atom(QXcbAtom::XFree86_DDC_EDID1_RAWDATA));
+ result = getOutputProperty(atom(QXcbAtom::AtomXFree86_DDC_EDID1_RAWDATA));
return result;
}
diff --git a/src/plugins/platforms/xcb/qxcbscreen.h b/src/plugins/platforms/xcb/qxcbscreen.h
index 79698b4ef3..49165d3ba4 100644
--- a/src/plugins/platforms/xcb/qxcbscreen.h
+++ b/src/plugins/platforms/xcb/qxcbscreen.h
@@ -1,59 +1,24 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QXCBSCREEN_H
#define QXCBSCREEN_H
#include <qpa/qplatformscreen.h>
+#include <qpa/qplatformscreen_p.h>
#include <QtCore/QString>
#include <xcb/xcb.h>
#include <xcb/randr.h>
#include <xcb/xfixes.h>
-#include <xcb/xinerama.h>
#include "qxcbobject.h"
-#include "qxcbscreen.h"
#include <private/qfontengine_p.h>
-#include <QtEdidSupport/private/qedidparser_p.h>
+#include <QtGui/private/qedidparser_p.h>
+
+#include <memory>
QT_BEGIN_NAMESPACE
@@ -88,8 +53,8 @@ public:
bool compositingActive() const;
- QRect workArea() const { return m_workArea; }
void updateWorkArea();
+ QRect availableGeometry(const QRect &screenGeometry) const;
void handleXFixesSelectionNotify(xcb_xfixes_selection_notify_event_t *notify_event);
void subscribeToXFixesSelectionNotify();
@@ -108,6 +73,7 @@ public:
const xcb_visualtype_t *visualForFormat(const QSurfaceFormat &format) const;
const xcb_visualtype_t *visualForId(xcb_visualid_t) const;
quint8 depthOfVisual(xcb_visualid_t) const;
+ xcb_colormap_t colormapForVisual(xcb_visualid_t) const;
private:
QRect getWorkArea() const;
@@ -117,6 +83,8 @@ private:
QByteArray &stringValue);
void readXResources();
+ bool setDpiFromXSettings(const QVariant &property);
+
xcb_screen_t *m_screen;
const int m_number;
QList<QPlatformScreen *> m_screens;
@@ -134,18 +102,24 @@ private:
QString m_windowManagerName;
QMap<xcb_visualid_t, xcb_visualtype_t> m_visuals;
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
+ , public QNativeInterface::Private::QXcbScreen
{
public:
QXcbScreen(QXcbConnection *connection, QXcbVirtualDesktop *virtualDesktop,
- xcb_randr_output_t outputId, xcb_randr_get_output_info_reply_t *outputInfo,
- const xcb_xinerama_screen_info_t *xineramaScreenInfo = nullptr, int xineramaScreenIdx = -1);
+ 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;
@@ -159,9 +133,10 @@ public:
QRect availableGeometry() const override;
int depth() const override { return screen()->root_depth; }
QImage::Format format() const override;
+ QColorSpace colorSpace() const override { return m_colorSpace; }
QSizeF physicalSize() const override { return m_sizeMillimeters; }
QDpi logicalDpi() const override;
- QDpi logicalBaseDpi() const override { return QDpi(96, 96); };
+ QDpi logicalBaseDpi() const override { return QDpi(96, 96); }
QPlatformCursor *cursor() const override;
qreal refreshRate() const override { return m_refreshRate; }
Qt::ScreenOrientation orientation() const override { return m_orientation; }
@@ -172,7 +147,7 @@ public:
bool isPrimary() const { return m_primary; }
int screenNumber() const { return m_virtualDesktop->number(); }
- static int virtualDesktopNumberStatic(const QScreen *screen);
+ int virtualDesktopNumber() const override { return screenNumber(); }
xcb_screen_t *screen() const { return m_virtualDesktop->screen(); }
xcb_window_t root() const { return screen()->root; }
@@ -180,9 +155,15 @@ 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();
+ bool isPrimaryInXScreen();
void windowShown(QXcbWindow *window);
QString windowManagerName() const { return m_virtualDesktop->windowManagerName(); }
@@ -191,6 +172,7 @@ public:
const xcb_visualtype_t *visualForFormat(const QSurfaceFormat &format) const { return m_virtualDesktop->visualForFormat(format); }
const xcb_visualtype_t *visualForId(xcb_visualid_t visualid) const;
+ xcb_colormap_t colormapForVisual(xcb_visualid_t visualid) const { return m_virtualDesktop->colormapForVisual(visualid); }
quint8 depthOfVisual(xcb_visualid_t visualid) const { return m_virtualDesktop->depthOfVisual(visualid); }
QString name() const override { return m_outputName; }
@@ -210,24 +192,35 @@ private:
void sendStartupMessage(const QByteArray &message) const;
int forcedDpi() const;
+ void updateColorSpaceAndEdid();
QByteArray getOutputProperty(xcb_atom_t atom) const;
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;
QRect m_geometry;
QRect m_availableGeometry;
+ QColorSpace m_colorSpace;
Qt::ScreenOrientation m_orientation = Qt::PrimaryOrientation;
- QXcbCursor *m_cursor;
+ std::unique_ptr<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/qxcbscrollingdevice.cpp b/src/plugins/platforms/xcb/qxcbscrollingdevice.cpp
new file mode 100644
index 0000000000..cf80855854
--- /dev/null
+++ b/src/plugins/platforms/xcb/qxcbscrollingdevice.cpp
@@ -0,0 +1,16 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+#include "qxcbscrollingdevice_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QXcbScrollingDevicePrivate::QXcbScrollingDevicePrivate(const QString &name, qint64 id, QInputDevice::Capabilities caps,
+ int buttonCount, const QString &seatName)
+ : QPointingDevicePrivate(name, id, QInputDevice::DeviceType::Mouse, QPointingDevice::PointerType::Generic,
+ caps, 1, buttonCount, seatName)
+{
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qxcbscrollingdevice_p.cpp"
diff --git a/src/plugins/platforms/xcb/qxcbscrollingdevice_p.h b/src/plugins/platforms/xcb/qxcbscrollingdevice_p.h
new file mode 100644
index 0000000000..3ee0c06a86
--- /dev/null
+++ b/src/plugins/platforms/xcb/qxcbscrollingdevice_p.h
@@ -0,0 +1,56 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QXCBSCROLLINGDEVICE_P_H
+#define QXCBSCROLLINGDEVICE_P_H
+
+#include <QtGui/private/qpointingdevice_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QXcbScrollingDevicePrivate : public QPointingDevicePrivate
+{
+ Q_DECLARE_PUBLIC(QPointingDevice)
+public:
+ QXcbScrollingDevicePrivate(const QString &name, qint64 id, QPointingDevice::Capabilities caps,
+ int buttonCount = 3, const QString &seatName = QString());
+
+ // scrolling-related data
+ int verticalIndex = 0;
+ int horizontalIndex = 0;
+ double verticalIncrement = 0;
+ double horizontalIncrement = 0;
+ Qt::Orientations orientations;
+ Qt::Orientations legacyOrientations;
+ mutable QPointF lastScrollPosition;
+ // end of scrolling-related data
+};
+
+class QXcbScrollingDevice : public QPointingDevice
+{
+ Q_OBJECT
+public:
+ QXcbScrollingDevice(QXcbScrollingDevicePrivate &d, QObject *parent)
+ : QPointingDevice(d, parent) {}
+
+ QXcbScrollingDevice(const QString &name, qint64 deviceId, Capabilities caps, int buttonCount,
+ const QString &seatName = QString(), QObject *parent = nullptr)
+ : QPointingDevice(*new QXcbScrollingDevicePrivate(name, deviceId, caps, buttonCount, seatName), parent)
+ {
+ }
+
+ inline static QXcbScrollingDevicePrivate *get(QXcbScrollingDevice *q)
+ {
+ return static_cast<QXcbScrollingDevicePrivate *>(QObjectPrivate::get(q));
+ }
+
+ inline static const QXcbScrollingDevicePrivate *get(const QXcbScrollingDevice *q)
+ {
+ return static_cast<const QXcbScrollingDevicePrivate *>(QObjectPrivate::get(q));
+ }
+
+};
+
+QT_END_NAMESPACE
+
+#endif // QXCBSCROLLINGDEVICE_P_H
diff --git a/src/plugins/platforms/xcb/qxcbsessionmanager.cpp b/src/plugins/platforms/xcb/qxcbsessionmanager.cpp
index 2eb32c069e..b4e28ab831 100644
--- a/src/plugins/platforms/xcb/qxcbsessionmanager.cpp
+++ b/src/plugins/platforms/xcb/qxcbsessionmanager.cpp
@@ -1,47 +1,12 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Teo Mrnjavac <teo@kde.org>
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2013 Teo Mrnjavac <teo@kde.org>
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qxcbsessionmanager.h"
#ifndef QT_NO_SESSIONMANAGER
+#include <QtCore/qvarlengtharray.h>
#include <qpa/qwindowsysteminterface.h>
#include <qguiapplication.h>
@@ -54,6 +19,8 @@
#include <cerrno> // ERANGE
+using namespace Qt::StringLiterals;
+
class QSmSocketReceiver : public QObject
{
Q_OBJECT
@@ -61,11 +28,11 @@ public:
QSmSocketReceiver(int socket)
{
QSocketNotifier* sn = new QSocketNotifier(socket, QSocketNotifier::Read, this);
- connect(sn, SIGNAL(activated(int)), this, SLOT(socketActivated(int)));
+ connect(sn, SIGNAL(activated(QSocketDescriptor)), this, SLOT(socketActivated()));
}
public Q_SLOTS:
- void socketActivated(int);
+ void socketActivated();
};
@@ -134,19 +101,19 @@ static void sm_setProperty(const QString &name, const QString &value)
{
QByteArray v = value.toUtf8();
SmPropValue prop;
- prop.length = v.length();
+ prop.length = v.size();
prop.value = (SmPointer) const_cast<char *>(v.constData());
sm_setProperty(name.toLatin1().data(), SmARRAY8, 1, &prop);
}
static void sm_setProperty(const QString &name, const QStringList &value)
{
- SmPropValue *prop = new SmPropValue[value.count()];
+ SmPropValue *prop = new SmPropValue[value.size()];
int count = 0;
QList<QByteArray> vl;
vl.reserve(value.size());
for (QStringList::ConstIterator it = value.begin(); it != value.end(); ++it) {
- prop[count].length = (*it).length();
+ prop[count].length = (*it).size();
vl.append((*it).toUtf8());
prop[count].value = (char*)vl.constLast().data();
++count;
@@ -193,7 +160,7 @@ static void sm_performSaveYourself(QXcbSessionManager *sm)
timeval tv;
gettimeofday(&tv, nullptr);
sm->setSessionKey(QString::number(qulonglong(tv.tv_sec)) +
- QLatin1Char('_') +
+ u'_' +
QString::number(qulonglong(tv.tv_usec)));
QStringList arguments = QCoreApplication::arguments();
@@ -227,12 +194,11 @@ static void sm_performSaveYourself(QXcbSessionManager *sm)
// generate a restart and discard command that makes sense
QStringList restart;
- restart << argument0 << QLatin1String("-session")
- << sm->sessionId() + QLatin1Char('_') + sm->sessionKey();
+ restart << argument0 << "-session"_L1 << sm->sessionId() + u'_' + sm->sessionKey();
- QFileInfo fi = QCoreApplication::applicationFilePath();
+ QFileInfo fi(QCoreApplication::applicationFilePath());
if (qAppName().compare(fi.fileName(), Qt::CaseInsensitive) != 0)
- restart << QLatin1String("-name") << qAppName();
+ restart << "-name"_L1 << qAppName();
sm->setRestartCommand(restart);
QStringList discard;
sm->setDiscardCommand(discard);
@@ -242,7 +208,7 @@ static void sm_performSaveYourself(QXcbSessionManager *sm)
sm->appCommitData();
if (sm_isshutdown && sm_cancel)
break; // we cancelled the shutdown, no need to save state
- // fall through
+ Q_FALLTHROUGH();
case SmSaveLocal:
sm->appSaveState();
break;
@@ -327,7 +293,7 @@ static void sm_saveYourselfPhase2Callback(SmcConn smcConn, SmPointer clientData)
}
-void QSmSocketReceiver::socketActivated(int)
+void QSmSocketReceiver::socketActivated()
{
IceProcessMessages(SmcGetIceConnection(smcConnection), nullptr, nullptr);
}
diff --git a/src/plugins/platforms/xcb/qxcbsessionmanager.h b/src/plugins/platforms/xcb/qxcbsessionmanager.h
index 79c587b38d..10759319d2 100644
--- a/src/plugins/platforms/xcb/qxcbsessionmanager.h
+++ b/src/plugins/platforms/xcb/qxcbsessionmanager.h
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Teo Mrnjavac <teo@kde.org>
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2013 Teo Mrnjavac <teo@kde.org>
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QXCBSESSIONMANAGER_H
#define QXCBSESSIONMANAGER_H
diff --git a/src/plugins/platforms/xcb/qxcbsystemtraytracker.cpp b/src/plugins/platforms/xcb/qxcbsystemtraytracker.cpp
index ff5ad98cd2..84d2d73f91 100644
--- a/src/plugins/platforms/xcb/qxcbsystemtraytracker.cpp
+++ b/src/plugins/platforms/xcb/qxcbsystemtraytracker.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qxcbsystemtraytracker.h"
#include "qxcbconnection.h"
@@ -56,13 +20,13 @@ enum {
};
// QXcbSystemTrayTracker provides API for accessing the tray window and tracks
-// its lifecyle by listening for its destruction and recreation.
+// its lifecycle by listening for its destruction and recreation.
// See http://standards.freedesktop.org/systemtray-spec/systemtray-spec-latest.html
QXcbSystemTrayTracker *QXcbSystemTrayTracker::create(QXcbConnection *connection)
{
// Selection, tray atoms for GNOME, NET WM Specification
- const xcb_atom_t trayAtom = connection->atom(QXcbAtom::_NET_SYSTEM_TRAY_OPCODE);
+ const xcb_atom_t trayAtom = connection->atom(QXcbAtom::Atom_NET_SYSTEM_TRAY_OPCODE);
if (!trayAtom)
return nullptr;
const QByteArray netSysTray = QByteArrayLiteral("_NET_SYSTEM_TRAY_S") + QByteArray::number(connection->primaryScreenNumber());
@@ -83,14 +47,6 @@ QXcbSystemTrayTracker::QXcbSystemTrayTracker(QXcbConnection *connection,
{
}
-xcb_window_t QXcbSystemTrayTracker::locateTrayWindow(const QXcbConnection *connection, xcb_atom_t selection)
-{
- auto reply = Q_XCB_REPLY(xcb_get_selection_owner, connection->xcb_connection(), selection);
- if (!reply)
- return 0;
- return reply->owner;
-}
-
// Request a window to be docked on the tray.
void QXcbSystemTrayTracker::requestSystemTrayWindowDock(xcb_window_t window) const
{
@@ -110,7 +66,7 @@ void QXcbSystemTrayTracker::requestSystemTrayWindowDock(xcb_window_t window) con
xcb_window_t QXcbSystemTrayTracker::trayWindow()
{
if (!m_trayWindow) {
- m_trayWindow = QXcbSystemTrayTracker::locateTrayWindow(m_connection, m_selection);
+ m_trayWindow = m_connection->selectionOwner(m_selection);
if (m_trayWindow) { // Listen for DestroyNotify on tray.
m_connection->addWindowEventListener(m_trayWindow, this);
const quint32 mask = XCB_CW_EVENT_MASK;
@@ -157,7 +113,7 @@ xcb_visualid_t QXcbSystemTrayTracker::netSystemTrayVisual()
if (m_trayWindow == XCB_WINDOW_NONE)
return XCB_NONE;
- xcb_atom_t tray_atom = m_connection->atom(QXcbAtom::_NET_SYSTEM_TRAY_VISUAL);
+ xcb_atom_t tray_atom = m_connection->atom(QXcbAtom::Atom_NET_SYSTEM_TRAY_VISUAL);
// Get the xcb property for the _NET_SYSTEM_TRAY_VISUAL atom
auto systray_atom_reply = Q_XCB_REPLY_UNCHECKED(xcb_get_property, m_connection->xcb_connection(),
@@ -176,3 +132,5 @@ xcb_visualid_t QXcbSystemTrayTracker::netSystemTrayVisual()
}
QT_END_NAMESPACE
+
+#include "moc_qxcbsystemtraytracker.cpp"
diff --git a/src/plugins/platforms/xcb/qxcbsystemtraytracker.h b/src/plugins/platforms/xcb/qxcbsystemtraytracker.h
index d2fc24c957..5c054626b6 100644
--- a/src/plugins/platforms/xcb/qxcbsystemtraytracker.h
+++ b/src/plugins/platforms/xcb/qxcbsystemtraytracker.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QXCBSYSTEMTRAYTRACKER_H
#define QXCBSYSTEMTRAYTRACKER_H
@@ -70,7 +34,7 @@ private:
explicit QXcbSystemTrayTracker(QXcbConnection *connection,
xcb_atom_t trayAtom,
xcb_atom_t selection);
- static xcb_window_t locateTrayWindow(const QXcbConnection *connection, xcb_atom_t selection);
+
void emitSystemTrayWindowChanged();
xcb_visualid_t netSystemTrayVisual();
diff --git a/src/plugins/platforms/xcb/qxcbvulkaninstance.cpp b/src/plugins/platforms/xcb/qxcbvulkaninstance.cpp
index bb82bcec39..b1fcfd665b 100644
--- a/src/plugins/platforms/xcb/qxcbvulkaninstance.cpp
+++ b/src/plugins/platforms/xcb/qxcbvulkaninstance.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qxcbvulkaninstance.h"
#include "qxcbwindow.h"
@@ -48,7 +12,7 @@ QXcbVulkanInstance::QXcbVulkanInstance(QVulkanInstance *instance)
m_getPhysDevPresSupport(nullptr),
m_createSurface(nullptr)
{
- loadVulkanLibrary(QStringLiteral("vulkan"));
+ loadVulkanLibrary(QStringLiteral("vulkan"), 1);
}
QXcbVulkanInstance::~QXcbVulkanInstance()
diff --git a/src/plugins/platforms/xcb/qxcbvulkaninstance.h b/src/plugins/platforms/xcb/qxcbvulkaninstance.h
index 53f7345254..445cd706ae 100644
--- a/src/plugins/platforms/xcb/qxcbvulkaninstance.h
+++ b/src/plugins/platforms/xcb/qxcbvulkaninstance.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QXCBVULKANINSTANCE_H
#define QXCBVULKANINSTANCE_H
@@ -46,7 +10,7 @@
#define VK_USE_PLATFORM_XCB_KHR
-#include <QtVulkanSupport/private/qbasicvulkanplatforminstance_p.h>
+#include <QtGui/private/qbasicvulkanplatforminstance_p.h>
#include <QLibrary>
QT_BEGIN_NAMESPACE
diff --git a/src/plugins/platforms/xcb/qxcbvulkanwindow.cpp b/src/plugins/platforms/xcb/qxcbvulkanwindow.cpp
index a05ecab51d..b8cd75588a 100644
--- a/src/plugins/platforms/xcb/qxcbvulkanwindow.cpp
+++ b/src/plugins/platforms/xcb/qxcbvulkanwindow.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qxcbvulkanwindow.h"
diff --git a/src/plugins/platforms/xcb/qxcbvulkanwindow.h b/src/plugins/platforms/xcb/qxcbvulkanwindow.h
index 43c96820c5..377acd2e8c 100644
--- a/src/plugins/platforms/xcb/qxcbvulkanwindow.h
+++ b/src/plugins/platforms/xcb/qxcbvulkanwindow.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QXCBVULKANWINDOW_H
#define QXCBVULKANWINDOW_H
diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp
index 71ec47b053..09d4cd9833 100644
--- a/src/plugins/platforms/xcb/qxcbwindow.cpp
+++ b/src/plugins/platforms/xcb/qxcbwindow.cpp
@@ -1,47 +1,12 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qxcbwindow.h"
#include <QtDebug>
#include <QMetaEnum>
#include <QScreen>
+#include <QtCore/QFileInfo>
#include <QtGui/QIcon>
#include <QtGui/QRegion>
#include <QtGui/private/qhighdpiscaling_p.h>
@@ -75,7 +40,6 @@
#include <qpa/qplatformbackingstore.h>
#include <qpa/qwindowsysteminterface.h>
-#include <QTextCodec>
#include <stdio.h>
#if QT_CONFIG(xcb_xlib)
@@ -85,7 +49,7 @@
#undef register
#endif
-#define XCOORD_MAX 16383
+#define XCOORD_MAX 32767
enum {
defaultWindowWidth = 160,
defaultWindowHeight = 160
@@ -93,6 +57,11 @@ enum {
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
+Q_LOGGING_CATEGORY(lcQpaWindow, "qt.qpa.window");
+Q_LOGGING_CATEGORY(lcQpaXcbWindow, "qt.qpa.xcb.window");
+
Q_DECLARE_TYPEINFO(xcb_rectangle_t, Q_PRIMITIVE_TYPE);
#undef FocusIn
@@ -127,12 +96,14 @@ const quint32 XEMBED_VERSION = 0;
QXcbScreen *QXcbWindow::parentScreen()
{
- return parent() ? static_cast<QXcbWindow*>(parent())->parentScreen() : xcbScreen();
+ return QPlatformWindow::parent() ? static_cast<QXcbWindow*>(QPlatformWindow::parent())->parentScreen() : xcbScreen();
}
-//QPlatformWindow::screenForGeometry version that uses deviceIndependentGeometry
QXcbScreen *QXcbWindow::initialScreen() const
{
+ // Resolve initial screen via QWindowPrivate::screenForGeometry(),
+ // which works in platform independent coordinates, as opposed to
+ // QPlatformWindow::screenForGeometry() that uses native coordinates.
QWindowPrivate *windowPrivate = qt_window_private(window());
QScreen *screen = windowPrivate->screenForGeometry(window()->geometry());
return static_cast<QXcbScreen*>(screen->handle());
@@ -164,6 +135,7 @@ void QXcbWindow::setImageFormatForVisual(const xcb_visualtype_t *visual)
case 16:
qWarning("Using RGB16 fallback, if this works your X11 server is reporting a bad screen format.");
m_imageFormat = QImage::Format_RGB16;
+ break;
default:
break;
}
@@ -184,35 +156,24 @@ static inline XTextProperty* qstringToXTP(Display *dpy, const QString& s)
free_prop = true;
}
-#if QT_CONFIG(textcodec)
- static const QTextCodec* mapper = QTextCodec::codecForLocale();
int errCode = 0;
- if (mapper) {
- QByteArray mapped = mapper->fromUnicode(s);
- char* tl[2];
- tl[0] = mapped.data();
- tl[1] = nullptr;
- errCode = XmbTextListToTextProperty(dpy, tl, 1, XStdICCTextStyle, &tp);
- if (errCode < 0)
- qCDebug(lcQpaXcb, "XmbTextListToTextProperty result code %d", errCode);
- }
- if (!mapper || errCode < 0) {
- mapper = QTextCodec::codecForName("latin1");
- if (!mapper || !mapper->canEncode(s))
- return nullptr;
-#endif
+ QByteArray mapped = s.toLocal8Bit(); // should always be utf-8
+ char* tl[2];
+ tl[0] = mapped.data();
+ tl[1] = nullptr;
+ errCode = XmbTextListToTextProperty(dpy, tl, 1, XStdICCTextStyle, &tp);
+ if (errCode < 0)
+ qCDebug(lcQpaXcb, "XmbTextListToTextProperty result code %d", errCode);
+
+ if (errCode < 0) {
static QByteArray qcs;
qcs = s.toLatin1();
tp.value = (uchar*)qcs.data();
tp.encoding = XA_STRING;
tp.format = 8;
- tp.nitems = qcs.length();
+ tp.nitems = qcs.size();
free_prop = false;
-#if QT_CONFIG(textcodec)
}
-#else
- Q_UNUSED(dpy);
-#endif
return &tp;
}
#endif // QT_CONFIG(xcb_xlib)
@@ -258,13 +219,14 @@ enum : quint32 {
| XCB_EVENT_MASK_POINTER_MOTION,
transparentForInputEventMask = baseEventMask
- | XCB_EVENT_MASK_VISIBILITY_CHANGE | XCB_EVENT_MASK_RESIZE_REDIRECT
+ | XCB_EVENT_MASK_VISIBILITY_CHANGE
| XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT
| XCB_EVENT_MASK_COLOR_MAP_CHANGE | XCB_EVENT_MASK_OWNER_GRAB_BUTTON
};
void QXcbWindow::create()
{
+ xcb_window_t old_m_window = m_window;
destroy();
m_windowState = Qt::WindowNoState;
@@ -273,8 +235,10 @@ void QXcbWindow::create()
Qt::WindowType type = window()->type();
QXcbScreen *currentScreen = xcbScreen();
- QXcbScreen *platformScreen = parent() ? parentScreen() : initialScreen();
- QRect rect = QHighDpi::toNativePixels(window()->geometry(), platformScreen);
+ QXcbScreen *platformScreen = QPlatformWindow::parent() ? parentScreen() : initialScreen();
+ QRect rect = QPlatformWindow::parent()
+ ? QHighDpi::toNativeLocalPosition(window()->geometry(), platformScreen)
+ : QHighDpi::toNativePixels(window()->geometry(), platformScreen);
if (type == Qt::Desktop) {
m_window = platformScreen->root();
@@ -295,11 +259,6 @@ void QXcbWindow::create()
return;
}
- QPlatformWindow::setGeometry(rect);
-
- if (platformScreen != currentScreen)
- QWindowSystemInterface::handleWindowScreenChanged(window(), platformScreen->QPlatformScreen::screen());
-
const QSize minimumSize = windowMinimumSize();
if (rect.width() > 0 || rect.height() > 0) {
rect.setWidth(qBound(1, rect.width(), XCOORD_MAX));
@@ -311,12 +270,17 @@ void QXcbWindow::create()
rect.setHeight(QHighDpi::toNativePixels(int(defaultWindowHeight), platformScreen->QPlatformScreen::screen()));
}
+ QPlatformWindow::setGeometry(rect);
+
+ if (platformScreen != currentScreen)
+ QWindowSystemInterface::handleWindowScreenChanged(window(), platformScreen->QPlatformScreen::screen());
+
xcb_window_t xcb_parent_id = platformScreen->root();
- if (parent()) {
- xcb_parent_id = static_cast<QXcbWindow *>(parent())->xcb_window();
- m_embedded = parent()->isForeignWindow();
+ if (QPlatformWindow::parent()) {
+ xcb_parent_id = static_cast<QXcbWindow *>(QPlatformWindow::parent())->xcb_window();
+ m_embedded = QPlatformWindow::parent()->isForeignWindow();
- QSurfaceFormat parentFormat = parent()->window()->requestedFormat();
+ QSurfaceFormat parentFormat = QPlatformWindow::parent()->window()->requestedFormat();
if (window()->surfaceType() != QSurface::OpenGLSurface && parentFormat.hasAlpha()) {
window()->setFormat(parentFormat);
}
@@ -334,16 +298,16 @@ void QXcbWindow::create()
qWarning() << "Failed to use requested visual id.";
}
- if (parent()) {
+ if (QPlatformWindow::parent()) {
// When using a Vulkan QWindow via QWidget::createWindowContainer() we
// must make sure the visuals are compatible. Now, the parent will be
// of RasterGLSurface which typically chooses a GLX/EGL compatible
// visual which may not be what the Vulkan window would choose.
// Therefore, take the parent's visual.
if (window()->surfaceType() == QSurface::VulkanSurface
- && parent()->window()->surfaceType() != QSurface::VulkanSurface)
+ && QPlatformWindow::parent()->window()->surfaceType() != QSurface::VulkanSurface)
{
- visual = platformScreen->visualForId(static_cast<QXcbWindow *>(parent())->visualId());
+ visual = platformScreen->visualForId(static_cast<QXcbWindow *>(QPlatformWindow::parent())->visualId());
}
}
@@ -366,23 +330,8 @@ void QXcbWindow::create()
| XCB_CW_BIT_GRAVITY
| XCB_CW_OVERRIDE_REDIRECT
| XCB_CW_SAVE_UNDER
- | XCB_CW_EVENT_MASK;
-
- static auto haveOpenGL = []() {
- static const bool result = QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::OpenGL);
- return result;
- };
-
- if ((window()->supportsOpenGL() && haveOpenGL()) || m_format.hasAlpha()) {
- m_cmap = xcb_generate_id(xcb_connection());
- xcb_create_colormap(xcb_connection(),
- XCB_COLORMAP_ALLOC_NONE,
- m_cmap,
- xcb_parent_id,
- m_visualId);
-
- mask |= XCB_CW_COLORMAP;
- }
+ | XCB_CW_EVENT_MASK
+ | XCB_CW_COLORMAP;
quint32 values[] = {
XCB_BACK_PIXMAP_NONE,
@@ -391,7 +340,7 @@ void QXcbWindow::create()
type == Qt::Popup || type == Qt::ToolTip || (window()->flags() & Qt::BypassWindowManagerHint),
type == Qt::Popup || type == Qt::Tool || type == Qt::SplashScreen || type == Qt::ToolTip || type == Qt::Drawer,
defaultEventMask,
- m_cmap
+ platformScreen->colormapForVisual(m_visualId)
};
m_window = xcb_generate_id(xcb_connection());
@@ -415,20 +364,20 @@ void QXcbWindow::create()
xcb_atom_t properties[5];
int propertyCount = 0;
- properties[propertyCount++] = atom(QXcbAtom::WM_DELETE_WINDOW);
- properties[propertyCount++] = atom(QXcbAtom::WM_TAKE_FOCUS);
- properties[propertyCount++] = atom(QXcbAtom::_NET_WM_PING);
+ properties[propertyCount++] = atom(QXcbAtom::AtomWM_DELETE_WINDOW);
+ properties[propertyCount++] = atom(QXcbAtom::AtomWM_TAKE_FOCUS);
+ properties[propertyCount++] = atom(QXcbAtom::Atom_NET_WM_PING);
if (connection()->hasXSync())
- properties[propertyCount++] = atom(QXcbAtom::_NET_WM_SYNC_REQUEST);
+ properties[propertyCount++] = atom(QXcbAtom::Atom_NET_WM_SYNC_REQUEST);
if (window()->flags() & Qt::WindowContextHelpButtonHint)
- properties[propertyCount++] = atom(QXcbAtom::_NET_WM_CONTEXT_HELP);
+ properties[propertyCount++] = atom(QXcbAtom::Atom_NET_WM_CONTEXT_HELP);
xcb_change_property(xcb_connection(),
XCB_PROP_MODE_REPLACE,
m_window,
- atom(QXcbAtom::WM_PROTOCOLS),
+ atom(QXcbAtom::AtomWM_PROTOCOLS),
XCB_ATOM_ATOM,
32,
propertyCount,
@@ -439,10 +388,35 @@ void QXcbWindow::create()
const QByteArray wmClass = QXcbIntegration::instance()->wmClass();
if (!wmClass.isEmpty()) {
xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE,
- m_window, atom(QXcbAtom::WM_CLASS),
+ m_window, atom(QXcbAtom::AtomWM_CLASS),
XCB_ATOM_STRING, 8, wmClass.size(), wmClass.constData());
}
+ QString desktopFileName = QGuiApplication::desktopFileName();
+ if (QGuiApplication::desktopFileName().isEmpty()) {
+ QFileInfo fi = QFileInfo(QCoreApplication::instance()->applicationFilePath());
+ QStringList domainName =
+ QCoreApplication::instance()->organizationDomain().split(QLatin1Char('.'),
+ Qt::SkipEmptyParts);
+
+ if (domainName.isEmpty()) {
+ desktopFileName = fi.baseName();
+ } else {
+ for (int i = 0; i < domainName.size(); ++i)
+ desktopFileName.prepend(QLatin1Char('.')).prepend(domainName.at(i));
+ desktopFileName.append(fi.baseName());
+ }
+ }
+ if (!desktopFileName.isEmpty()) {
+ const QByteArray dfName = desktopFileName.toUtf8();
+ xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE,
+ m_window, atom(QXcbAtom::Atom_KDE_NET_WM_DESKTOP_FILE),
+ atom(QXcbAtom::AtomUTF8_STRING), 8, dfName.size(), dfName.constData());
+ xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE,
+ m_window, atom(QXcbAtom::Atom_GTK_APPLICATION_ID),
+ atom(QXcbAtom::AtomUTF8_STRING), 8, dfName.size(), dfName.constData());
+ }
+
if (connection()->hasXSync()) {
m_syncCounter = xcb_generate_id(xcb_connection());
xcb_sync_create_counter(xcb_connection(), m_syncCounter, m_syncValue);
@@ -450,7 +424,7 @@ void QXcbWindow::create()
xcb_change_property(xcb_connection(),
XCB_PROP_MODE_REPLACE,
m_window,
- atom(QXcbAtom::_NET_WM_SYNC_REQUEST_COUNTER),
+ atom(QXcbAtom::Atom_NET_WM_SYNC_REQUEST_COUNTER),
XCB_ATOM_CARDINAL,
32,
1,
@@ -460,13 +434,13 @@ void QXcbWindow::create()
// set the PID to let the WM kill the application if unresponsive
quint32 pid = getpid();
xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window,
- atom(QXcbAtom::_NET_WM_PID), XCB_ATOM_CARDINAL, 32,
+ atom(QXcbAtom::Atom_NET_WM_PID), XCB_ATOM_CARDINAL, 32,
1, &pid);
const QByteArray clientMachine = QSysInfo::machineHostName().toLocal8Bit();
if (!clientMachine.isEmpty()) {
xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window,
- atom(QXcbAtom::WM_CLIENT_MACHINE), XCB_ATOM_STRING, 8,
+ atom(QXcbAtom::AtomWM_CLIENT_MACHINE), XCB_ATOM_STRING, 8,
clientMachine.size(), clientMachine.constData());
}
@@ -480,31 +454,25 @@ void QXcbWindow::create()
xcb_window_t leader = connection()->clientLeader();
xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window,
- atom(QXcbAtom::WM_CLIENT_LEADER), XCB_ATOM_WINDOW, 32,
+ atom(QXcbAtom::AtomWM_CLIENT_LEADER), XCB_ATOM_WINDOW, 32,
1, &leader);
/* Add XEMBED info; this operation doesn't initiate the embedding. */
quint32 data[] = { XEMBED_VERSION, XEMBED_MAPPED };
xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window,
- atom(QXcbAtom::_XEMBED_INFO),
- atom(QXcbAtom::_XEMBED_INFO),
+ atom(QXcbAtom::Atom_XEMBED_INFO),
+ atom(QXcbAtom::Atom_XEMBED_INFO),
32, 2, (void *)data);
- if (connection()->hasXInput2()) {
- if (connection()->xi2MouseEventsDisabled())
- connection()->xi2SelectDeviceEventsCompatibility(m_window);
- else
- connection()->xi2SelectDeviceEvents(m_window);
- }
+ if (connection()->hasXInput2())
+ connection()->xi2SelectDeviceEvents(m_window);
setWindowState(window()->windowStates());
setWindowFlags(window()->flags());
setWindowTitle(window()->title());
-#if QT_CONFIG(xcb_xlib)
// force sync to read outstanding requests - see QTBUG-29106
- XSync(static_cast<Display*>(platformScreen->connection()->xlib_display()), false);
-#endif
+ connection()->sync();
#if QT_CONFIG(draganddrop)
connection()->drag()->dndEnable(this, true);
@@ -521,11 +489,22 @@ void QXcbWindow::create()
if (window()->dynamicPropertyNames().contains(wm_window_role_property_id)) {
QByteArray wmWindowRole = window()->property(wm_window_role_property_id).toByteArray();
- setWmWindowRole(wmWindowRole);
+ setWindowRole(QString::fromLatin1(wmWindowRole));
}
if (m_trayIconWindow)
m_embedded = requestSystemTrayWindowDock();
+
+ if (m_window != old_m_window) {
+ if (!m_wmTransientForChildren.isEmpty()) {
+ QList<QPointer<QXcbWindow>> transientChildren = m_wmTransientForChildren;
+ m_wmTransientForChildren.clear();
+ for (auto transientChild : transientChildren) {
+ if (transientChild)
+ transientChild->updateWmTransientFor();
+ }
+ }
+ }
}
QXcbWindow::~QXcbWindow()
@@ -533,6 +512,18 @@ QXcbWindow::~QXcbWindow()
destroy();
}
+QXcbForeignWindow::QXcbForeignWindow(QWindow *window, WId nativeHandle)
+ : QXcbWindow(window)
+{
+ m_window = nativeHandle;
+
+ // Reflect the foreign window's geometry as our own
+ if (auto geometry = Q_XCB_REPLY(xcb_get_geometry, xcb_connection(), m_window)) {
+ QRect nativeGeometry(geometry->x, geometry->y, geometry->width, geometry->height);
+ QPlatformWindow::setGeometry(nativeGeometry);
+ }
+}
+
QXcbForeignWindow::~QXcbForeignWindow()
{
// Clear window so that destroy() does not affect it
@@ -550,12 +541,14 @@ void QXcbWindow::destroy()
doFocusOut();
if (connection()->mouseGrabber() == this)
connection()->setMouseGrabber(nullptr);
+ if (connection()->mousePressWindow() == this)
+ connection()->setMousePressWindow(nullptr);
if (m_syncCounter && connection()->hasXSync())
xcb_sync_destroy_counter(xcb_connection(), m_syncCounter);
if (m_window) {
if (m_netWmUserTimeWindow) {
- xcb_delete_property(xcb_connection(), m_window, atom(QXcbAtom::_NET_WM_USER_TIME_WINDOW));
+ xcb_delete_property(xcb_connection(), m_window, atom(QXcbAtom::Atom_NET_WM_USER_TIME_WINDOW));
// Some window managers, like metacity, do XSelectInput on the _NET_WM_USER_TIME_WINDOW window,
// without trapping BadWindow (which crashes when the user time window is destroyed).
connection()->sync();
@@ -566,10 +559,9 @@ void QXcbWindow::destroy()
xcb_destroy_window(xcb_connection(), m_window);
m_window = 0;
}
- if (m_cmap) {
- xcb_free_colormap(xcb_connection(), m_cmap);
- }
+
m_mapped = false;
+ m_recreationReasons = RecreationNotNeeded;
if (m_pendingSyncRequest)
m_pendingSyncRequest->invalidate();
@@ -577,12 +569,14 @@ void QXcbWindow::destroy()
void QXcbWindow::setGeometry(const QRect &rect)
{
+ setWindowState(Qt::WindowNoState);
+
QPlatformWindow::setGeometry(rect);
propagateSizeHints();
QXcbScreen *currentScreen = xcbScreen();
- QXcbScreen *newScreen = parent() ? parentScreen() : static_cast<QXcbScreen*>(screenForGeometry(rect));
+ QXcbScreen *newScreen = QPlatformWindow::parent() ? parentScreen() : static_cast<QXcbScreen*>(screenForGeometry(rect));
if (!newScreen)
newScreen = xcbScreen();
@@ -623,9 +617,9 @@ void QXcbWindow::setGeometry(const QRect &rect)
QMargins QXcbWindow::frameMargins() const
{
if (m_dirtyFrameMargins) {
- if (connection()->wmSupport()->isSupportedByWM(atom(QXcbAtom::_NET_FRAME_EXTENTS))) {
+ if (connection()->wmSupport()->isSupportedByWM(atom(QXcbAtom::Atom_NET_FRAME_EXTENTS))) {
auto reply = Q_XCB_REPLY(xcb_get_property, xcb_connection(), false, m_window,
- atom(QXcbAtom::_NET_FRAME_EXTENTS), XCB_ATOM_CARDINAL, 0, 4);
+ atom(QXcbAtom::Atom_NET_FRAME_EXTENTS), XCB_ATOM_CARDINAL, 0, 4);
if (reply && reply->type == XCB_ATOM_CARDINAL && reply->format == 32 && reply->value_len == 4) {
quint32 *data = (quint32 *)xcb_get_property_value(reply.get());
// _NET_FRAME_EXTENTS format is left, right, top, bottom
@@ -642,7 +636,7 @@ QMargins QXcbWindow::frameMargins() const
bool foundRoot = false;
- const QVector<xcb_window_t> &virtualRoots =
+ const QList<xcb_window_t> &virtualRoots =
connection()->wmSupport()->virtualRoots();
while (!foundRoot) {
@@ -701,31 +695,58 @@ void QXcbWindow::setVisible(bool visible)
hide();
}
+void QXcbWindow::updateWmTransientFor()
+{
+ xcb_window_t transientXcbParent = XCB_NONE;
+ if (isTransient(window())) {
+ QWindow *tp = window()->transientParent();
+ if (tp && tp->handle()) {
+ QXcbWindow *handle = static_cast<QXcbWindow *>(tp->handle());
+ transientXcbParent = tp->handle()->winId();
+ if (transientXcbParent) {
+ handle->registerWmTransientForChild(this);
+ qCDebug(lcQpaXcbWindow) << Q_FUNC_INFO << static_cast<QPlatformWindow *>(handle)
+ << " registerWmTransientForChild " << static_cast<QPlatformWindow *>(this);
+ }
+ }
+ // Default to client leader if there is no transient parent, else modal dialogs can
+ // be hidden by their parents.
+ if (!transientXcbParent)
+ transientXcbParent = connection()->clientLeader();
+ if (transientXcbParent) { // ICCCM 4.1.2.6
+ xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window,
+ XCB_ATOM_WM_TRANSIENT_FOR, XCB_ATOM_WINDOW, 32,
+ 1, &transientXcbParent);
+ qCDebug(lcQpaXcbWindow, "0x%x added XCB_ATOM_WM_TRANSIENT_FOR 0x%x", m_window, transientXcbParent);
+ }
+ }
+ if (!transientXcbParent)
+ xcb_delete_property(xcb_connection(), m_window, XCB_ATOM_WM_TRANSIENT_FOR);
+}
+
+void QXcbWindow::registerWmTransientForChild(QXcbWindow *child)
+{
+ if (!child)
+ return;
+
+ if (!m_wmTransientForChildren.contains(child))
+ m_wmTransientForChildren.append(child);
+}
+
void QXcbWindow::show()
{
if (window()->isTopLevel()) {
+ if (m_recreationReasons != RecreationNotNeeded) {
+ qCDebug(lcQpaWindow) << "QXcbWindow: need to recreate window" << window() << m_recreationReasons;
+ create();
+ m_recreationReasons = RecreationNotNeeded;
+ }
// update WM_NORMAL_HINTS
propagateSizeHints();
// update WM_TRANSIENT_FOR
- xcb_window_t transientXcbParent = 0;
- if (isTransient(window())) {
- const QWindow *tp = window()->transientParent();
- if (tp && tp->handle())
- transientXcbParent = static_cast<const QXcbWindow *>(tp->handle())->winId();
- // Default to client leader if there is no transient parent, else modal dialogs can
- // be hidden by their parents.
- if (!transientXcbParent)
- transientXcbParent = connection()->clientLeader();
- if (transientXcbParent) { // ICCCM 4.1.2.6
- xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window,
- XCB_ATOM_WM_TRANSIENT_FOR, XCB_ATOM_WINDOW, 32,
- 1, &transientXcbParent);
- }
- }
- if (!transientXcbParent)
- xcb_delete_property(xcb_connection(), m_window, XCB_ATOM_WM_TRANSIENT_FOR);
+ updateWmTransientFor();
// update _NET_WM_STATE
setNetWmStateOnUnmappedWindow();
@@ -836,7 +857,7 @@ void QXcbWindow::doFocusIn()
return;
QWindow *w = static_cast<QWindowPrivate *>(QObjectPrivate::get(window()))->eventReceiver();
connection()->setFocusWindow(w);
- QWindowSystemInterface::handleWindowActivated(w, Qt::ActiveWindowFocusReason);
+ QWindowSystemInterface::handleFocusWindowChanged(w, Qt::ActiveWindowFocusReason);
}
void QXcbWindow::doFocusOut()
@@ -879,28 +900,30 @@ QXcbWindow::NetWmStates QXcbWindow::netWmStates()
NetWmStates result;
auto reply = Q_XCB_REPLY_UNCHECKED(xcb_get_property, xcb_connection(),
- 0, m_window, atom(QXcbAtom::_NET_WM_STATE),
+ 0, m_window, atom(QXcbAtom::Atom_NET_WM_STATE),
XCB_ATOM_ATOM, 0, 1024);
if (reply && reply->format == 32 && reply->type == XCB_ATOM_ATOM) {
const xcb_atom_t *states = static_cast<const xcb_atom_t *>(xcb_get_property_value(reply.get()));
const xcb_atom_t *statesEnd = states + reply->length;
- if (statesEnd != std::find(states, statesEnd, atom(QXcbAtom::_NET_WM_STATE_ABOVE)))
+ if (statesEnd != std::find(states, statesEnd, atom(QXcbAtom::Atom_NET_WM_STATE_ABOVE)))
result |= NetWmStateAbove;
- if (statesEnd != std::find(states, statesEnd, atom(QXcbAtom::_NET_WM_STATE_BELOW)))
+ if (statesEnd != std::find(states, statesEnd, atom(QXcbAtom::Atom_NET_WM_STATE_BELOW)))
result |= NetWmStateBelow;
- if (statesEnd != std::find(states, statesEnd, atom(QXcbAtom::_NET_WM_STATE_FULLSCREEN)))
+ if (statesEnd != std::find(states, statesEnd, atom(QXcbAtom::Atom_NET_WM_STATE_FULLSCREEN)))
result |= NetWmStateFullScreen;
- if (statesEnd != std::find(states, statesEnd, atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_HORZ)))
+ if (statesEnd != std::find(states, statesEnd, atom(QXcbAtom::Atom_NET_WM_STATE_MAXIMIZED_HORZ)))
result |= NetWmStateMaximizedHorz;
- if (statesEnd != std::find(states, statesEnd, atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_VERT)))
+ if (statesEnd != std::find(states, statesEnd, atom(QXcbAtom::Atom_NET_WM_STATE_MAXIMIZED_VERT)))
result |= NetWmStateMaximizedVert;
- if (statesEnd != std::find(states, statesEnd, atom(QXcbAtom::_NET_WM_STATE_MODAL)))
+ if (statesEnd != std::find(states, statesEnd, atom(QXcbAtom::Atom_NET_WM_STATE_MODAL)))
result |= NetWmStateModal;
- if (statesEnd != std::find(states, statesEnd, atom(QXcbAtom::_NET_WM_STATE_STAYS_ON_TOP)))
+ if (statesEnd != std::find(states, statesEnd, atom(QXcbAtom::Atom_NET_WM_STATE_STAYS_ON_TOP)))
result |= NetWmStateStaysOnTop;
- if (statesEnd != std::find(states, statesEnd, atom(QXcbAtom::_NET_WM_STATE_DEMANDS_ATTENTION)))
+ if (statesEnd != std::find(states, statesEnd, atom(QXcbAtom::Atom_NET_WM_STATE_DEMANDS_ATTENTION)))
result |= NetWmStateDemandsAttention;
+ if (statesEnd != std::find(states, statesEnd, atom(QXcbAtom::Atom_NET_WM_STATE_HIDDEN)))
+ result |= NetWmStateHidden;
} else {
qCDebug(lcQpaXcb, "getting net wm state (%x), empty\n", m_window);
}
@@ -917,6 +940,12 @@ void QXcbWindow::setWindowFlags(Qt::WindowFlags flags)
if (type == Qt::Popup)
flags |= Qt::X11BypassWindowManagerHint;
+ Qt::WindowFlags oldflags = window()->flags();
+ if ((oldflags & Qt::WindowStaysOnTopHint) != (flags & Qt::WindowStaysOnTopHint))
+ m_recreationReasons |= WindowStaysOnTopHintChanged;
+ if ((oldflags & Qt::WindowStaysOnBottomHint) != (flags & Qt::WindowStaysOnBottomHint))
+ m_recreationReasons |= WindowStaysOnBottomHintChanged;
+
const quint32 mask = XCB_CW_OVERRIDE_REDIRECT | XCB_CW_EVENT_MASK;
const quint32 values[] = {
// XCB_CW_OVERRIDE_REDIRECT
@@ -927,9 +956,9 @@ void QXcbWindow::setWindowFlags(Qt::WindowFlags flags)
xcb_change_window_attributes(xcb_connection(), xcb_window(), mask, values);
- QXcbWindowFunctions::WmWindowTypes wmWindowTypes;
+ WindowTypes wmWindowTypes;
if (window()->dynamicPropertyNames().contains(wm_window_type_property_id)) {
- wmWindowTypes = static_cast<QXcbWindowFunctions::WmWindowTypes>(
+ wmWindowTypes = static_cast<WindowTypes>(
qvariant_cast<int>(window()->property(wm_window_type_property_id)));
}
@@ -1008,13 +1037,13 @@ void QXcbWindow::setMotifWmHints(Qt::WindowFlags flags)
xcb_change_property(xcb_connection(),
XCB_PROP_MODE_REPLACE,
m_window,
- atom(QXcbAtom::_MOTIF_WM_HINTS),
- atom(QXcbAtom::_MOTIF_WM_HINTS),
+ atom(QXcbAtom::Atom_MOTIF_WM_HINTS),
+ atom(QXcbAtom::Atom_MOTIF_WM_HINTS),
32,
5,
&mwmhints);
} else {
- xcb_delete_property(xcb_connection(), m_window, atom(QXcbAtom::_MOTIF_WM_HINTS));
+ xcb_delete_property(xcb_connection(), m_window, atom(QXcbAtom::Atom_MOTIF_WM_HINTS));
}
}
@@ -1026,7 +1055,7 @@ void QXcbWindow::setNetWmState(bool set, xcb_atom_t one, xcb_atom_t two)
event.format = 32;
event.sequence = 0;
event.window = m_window;
- event.type = atom(QXcbAtom::_NET_WM_STATE);
+ event.type = atom(QXcbAtom::Atom_NET_WM_STATE);
event.data.data32[0] = set ? 1 : 0;
event.data.data32[1] = one;
event.data.data32[2] = two;
@@ -1042,26 +1071,26 @@ void QXcbWindow::setNetWmState(Qt::WindowStates state)
{
if ((m_windowState ^ state) & Qt::WindowMaximized) {
setNetWmState(state & Qt::WindowMaximized,
- atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_HORZ),
- atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_VERT));
+ atom(QXcbAtom::Atom_NET_WM_STATE_MAXIMIZED_HORZ),
+ atom(QXcbAtom::Atom_NET_WM_STATE_MAXIMIZED_VERT));
}
if ((m_windowState ^ state) & Qt::WindowFullScreen)
- setNetWmState(state & Qt::WindowFullScreen, atom(QXcbAtom::_NET_WM_STATE_FULLSCREEN));
+ setNetWmState(state & Qt::WindowFullScreen, atom(QXcbAtom::Atom_NET_WM_STATE_FULLSCREEN));
}
void QXcbWindow::setNetWmState(Qt::WindowFlags flags)
{
setNetWmState(flags & Qt::WindowStaysOnTopHint,
- atom(QXcbAtom::_NET_WM_STATE_ABOVE),
- atom(QXcbAtom::_NET_WM_STATE_STAYS_ON_TOP));
- setNetWmState(flags & Qt::WindowStaysOnBottomHint, atom(QXcbAtom::_NET_WM_STATE_BELOW));
+ atom(QXcbAtom::Atom_NET_WM_STATE_ABOVE),
+ atom(QXcbAtom::Atom_NET_WM_STATE_STAYS_ON_TOP));
+ setNetWmState(flags & Qt::WindowStaysOnBottomHint, atom(QXcbAtom::Atom_NET_WM_STATE_BELOW));
}
void QXcbWindow::setNetWmStateOnUnmappedWindow()
{
if (Q_UNLIKELY(m_mapped))
- qCWarning(lcQpaXcb()) << "internal error: " << Q_FUNC_INFO << "called on mapped window";
+ qCDebug(lcQpaXcb()) << "internal info: " << Q_FUNC_INFO << "called on mapped window";
NetWmStates states;
const Qt::WindowFlags flags = window()->flags();
@@ -1072,6 +1101,9 @@ void QXcbWindow::setNetWmStateOnUnmappedWindow()
states |= NetWmStateBelow;
}
+ if (window()->windowStates() & Qt::WindowMinimized)
+ states |= NetWmStateHidden;
+
if (window()->windowStates() & Qt::WindowFullScreen)
states |= NetWmStateFullScreen;
@@ -1091,9 +1123,9 @@ void QXcbWindow::setNetWmStateOnUnmappedWindow()
// we first read it and then merge our hints with the existing values, allowing a user
// to set custom hints.
- QVector<xcb_atom_t> atoms;
+ QList<xcb_atom_t> atoms;
auto reply = Q_XCB_REPLY_UNCHECKED(xcb_get_property, xcb_connection(),
- 0, m_window, atom(QXcbAtom::_NET_WM_STATE),
+ 0, m_window, atom(QXcbAtom::Atom_NET_WM_STATE),
XCB_ATOM_ATOM, 0, 1024);
if (reply && reply->format == 32 && reply->type == XCB_ATOM_ATOM && reply->value_len > 0) {
const xcb_atom_t *data = static_cast<const xcb_atom_t *>(xcb_get_property_value(reply.get()));
@@ -1101,29 +1133,31 @@ void QXcbWindow::setNetWmStateOnUnmappedWindow()
memcpy((void *)&atoms.first(), (void *)data, reply->value_len * sizeof(xcb_atom_t));
}
- if (states & NetWmStateAbove && !atoms.contains(atom(QXcbAtom::_NET_WM_STATE_ABOVE)))
- atoms.push_back(atom(QXcbAtom::_NET_WM_STATE_ABOVE));
- if (states & NetWmStateBelow && !atoms.contains(atom(QXcbAtom::_NET_WM_STATE_BELOW)))
- atoms.push_back(atom(QXcbAtom::_NET_WM_STATE_BELOW));
- if (states & NetWmStateFullScreen && !atoms.contains(atom(QXcbAtom::_NET_WM_STATE_FULLSCREEN)))
- atoms.push_back(atom(QXcbAtom::_NET_WM_STATE_FULLSCREEN));
- if (states & NetWmStateMaximizedHorz && !atoms.contains(atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_HORZ)))
- atoms.push_back(atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_HORZ));
- if (states & NetWmStateMaximizedVert && !atoms.contains(atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_VERT)))
- atoms.push_back(atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_VERT));
- if (states & NetWmStateModal && !atoms.contains(atom(QXcbAtom::_NET_WM_STATE_MODAL)))
- atoms.push_back(atom(QXcbAtom::_NET_WM_STATE_MODAL));
- if (states & NetWmStateStaysOnTop && !atoms.contains(atom(QXcbAtom::_NET_WM_STATE_STAYS_ON_TOP)))
- atoms.push_back(atom(QXcbAtom::_NET_WM_STATE_STAYS_ON_TOP));
- if (states & NetWmStateDemandsAttention && !atoms.contains(atom(QXcbAtom::_NET_WM_STATE_DEMANDS_ATTENTION)))
- atoms.push_back(atom(QXcbAtom::_NET_WM_STATE_DEMANDS_ATTENTION));
+ if (states & NetWmStateAbove && !atoms.contains(atom(QXcbAtom::Atom_NET_WM_STATE_ABOVE)))
+ atoms.push_back(atom(QXcbAtom::Atom_NET_WM_STATE_ABOVE));
+ if (states & NetWmStateBelow && !atoms.contains(atom(QXcbAtom::Atom_NET_WM_STATE_BELOW)))
+ atoms.push_back(atom(QXcbAtom::Atom_NET_WM_STATE_BELOW));
+ if (states & NetWmStateHidden && !atoms.contains(atom(QXcbAtom::Atom_NET_WM_STATE_HIDDEN)))
+ atoms.push_back(atom(QXcbAtom::Atom_NET_WM_STATE_HIDDEN));
+ if (states & NetWmStateFullScreen && !atoms.contains(atom(QXcbAtom::Atom_NET_WM_STATE_FULLSCREEN)))
+ atoms.push_back(atom(QXcbAtom::Atom_NET_WM_STATE_FULLSCREEN));
+ if (states & NetWmStateMaximizedHorz && !atoms.contains(atom(QXcbAtom::Atom_NET_WM_STATE_MAXIMIZED_HORZ)))
+ atoms.push_back(atom(QXcbAtom::Atom_NET_WM_STATE_MAXIMIZED_HORZ));
+ if (states & NetWmStateMaximizedVert && !atoms.contains(atom(QXcbAtom::Atom_NET_WM_STATE_MAXIMIZED_VERT)))
+ atoms.push_back(atom(QXcbAtom::Atom_NET_WM_STATE_MAXIMIZED_VERT));
+ if (states & NetWmStateModal && !atoms.contains(atom(QXcbAtom::Atom_NET_WM_STATE_MODAL)))
+ atoms.push_back(atom(QXcbAtom::Atom_NET_WM_STATE_MODAL));
+ if (states & NetWmStateStaysOnTop && !atoms.contains(atom(QXcbAtom::Atom_NET_WM_STATE_STAYS_ON_TOP)))
+ atoms.push_back(atom(QXcbAtom::Atom_NET_WM_STATE_STAYS_ON_TOP));
+ if (states & NetWmStateDemandsAttention && !atoms.contains(atom(QXcbAtom::Atom_NET_WM_STATE_DEMANDS_ATTENTION)))
+ atoms.push_back(atom(QXcbAtom::Atom_NET_WM_STATE_DEMANDS_ATTENTION));
if (atoms.isEmpty()) {
- xcb_delete_property(xcb_connection(), m_window, atom(QXcbAtom::_NET_WM_STATE));
+ xcb_delete_property(xcb_connection(), m_window, atom(QXcbAtom::Atom_NET_WM_STATE));
} else {
xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window,
- atom(QXcbAtom::_NET_WM_STATE), XCB_ATOM_ATOM, 32,
- atoms.count(), atoms.constData());
+ atom(QXcbAtom::Atom_NET_WM_STATE), XCB_ATOM_ATOM, 32,
+ atoms.size(), atoms.constData());
}
xcb_flush(xcb_connection());
}
@@ -1133,28 +1167,43 @@ void QXcbWindow::setWindowState(Qt::WindowStates state)
if (state == m_windowState)
return;
- if ((m_windowState & Qt::WindowMinimized) && !(state & Qt::WindowMinimized)) {
- xcb_map_window(xcb_connection(), m_window);
- } else if (!(m_windowState & Qt::WindowMinimized) && (state & Qt::WindowMinimized)) {
- xcb_client_message_event_t event;
+ Qt::WindowStates unsetState = m_windowState & ~state;
+ Qt::WindowStates newState = state & ~m_windowState;
- event.response_type = XCB_CLIENT_MESSAGE;
- event.format = 32;
- event.sequence = 0;
- event.window = m_window;
- event.type = atom(QXcbAtom::WM_CHANGE_STATE);
- event.data.data32[0] = XCB_ICCCM_WM_STATE_ICONIC;
- event.data.data32[1] = 0;
- event.data.data32[2] = 0;
- event.data.data32[3] = 0;
- event.data.data32[4] = 0;
+ // unset old state
+ if (unsetState & Qt::WindowMinimized)
+ xcb_map_window(xcb_connection(), m_window);
+ if (unsetState & Qt::WindowMaximized)
+ setNetWmState(false,
+ atom(QXcbAtom::Atom_NET_WM_STATE_MAXIMIZED_HORZ),
+ atom(QXcbAtom::Atom_NET_WM_STATE_MAXIMIZED_VERT));
+ if (unsetState & Qt::WindowFullScreen)
+ setNetWmState(false, atom(QXcbAtom::Atom_NET_WM_STATE_FULLSCREEN));
+
+ // set new state
+ if (newState & Qt::WindowMinimized) {
+ {
+ xcb_client_message_event_t event;
+
+ event.response_type = XCB_CLIENT_MESSAGE;
+ event.format = 32;
+ event.sequence = 0;
+ event.window = m_window;
+ event.type = atom(QXcbAtom::AtomWM_CHANGE_STATE);
+ event.data.data32[0] = XCB_ICCCM_WM_STATE_ICONIC;
+ event.data.data32[1] = 0;
+ event.data.data32[2] = 0;
+ event.data.data32[3] = 0;
+ event.data.data32[4] = 0;
- xcb_send_event(xcb_connection(), 0, xcbScreen()->root(),
- XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT,
- (const char *)&event);
+ xcb_send_event(xcb_connection(), 0, xcbScreen()->root(),
+ XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT,
+ (const char *)&event);
+ }
m_minimized = true;
}
+ // set Maximized && FullScreen state if need
setNetWmState(state);
xcb_get_property_cookie_t cookie = xcb_icccm_get_wm_hints_unchecked(xcb_connection(), m_window);
@@ -1180,7 +1229,7 @@ void QXcbWindow::updateNetWmUserTime(xcb_timestamp_t timestamp)
if (timestamp != 0)
connection()->setNetWmUserTime(timestamp);
- const bool isSupportedByWM = connection()->wmSupport()->isSupportedByWM(atom(QXcbAtom::_NET_WM_USER_TIME_WINDOW));
+ const bool isSupportedByWM = connection()->wmSupport()->isSupportedByWM(atom(QXcbAtom::Atom_NET_WM_USER_TIME_WINDOW));
if (m_netWmUserTimeWindow || isSupportedByWM) {
if (!m_netWmUserTimeWindow) {
m_netWmUserTimeWindow = xcb_generate_id(xcb_connection());
@@ -1193,11 +1242,11 @@ void QXcbWindow::updateNetWmUserTime(xcb_timestamp_t timestamp)
XCB_WINDOW_CLASS_INPUT_OUTPUT, // window class
m_visualId, // visual
0, // value mask
- nullptr); // value list
+ nullptr); // value list
wid = m_netWmUserTimeWindow;
- xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window, atom(QXcbAtom::_NET_WM_USER_TIME_WINDOW),
+ xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window, atom(QXcbAtom::Atom_NET_WM_USER_TIME_WINDOW),
XCB_ATOM_WINDOW, 32, 1, &m_netWmUserTimeWindow);
- xcb_delete_property(xcb_connection(), m_window, atom(QXcbAtom::_NET_WM_USER_TIME));
+ xcb_delete_property(xcb_connection(), m_window, atom(QXcbAtom::Atom_NET_WM_USER_TIME));
QXcbWindow::setWindowTitle(connection(), m_netWmUserTimeWindow,
QStringLiteral("Qt NET_WM User Time Window"));
@@ -1205,14 +1254,14 @@ void QXcbWindow::updateNetWmUserTime(xcb_timestamp_t timestamp)
} else if (!isSupportedByWM) {
// WM no longer supports it, then we should remove the
// _NET_WM_USER_TIME_WINDOW atom.
- xcb_delete_property(xcb_connection(), m_window, atom(QXcbAtom::_NET_WM_USER_TIME_WINDOW));
+ xcb_delete_property(xcb_connection(), m_window, atom(QXcbAtom::Atom_NET_WM_USER_TIME_WINDOW));
xcb_destroy_window(xcb_connection(), m_netWmUserTimeWindow);
m_netWmUserTimeWindow = XCB_NONE;
} else {
wid = m_netWmUserTimeWindow;
}
}
- xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, wid, atom(QXcbAtom::_NET_WM_USER_TIME),
+ xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, wid, atom(QXcbAtom::Atom_NET_WM_USER_TIME),
XCB_ATOM_CARDINAL, 32, 1, &timestamp);
}
@@ -1287,16 +1336,16 @@ void QXcbWindow::setWindowIconText(const QString &title)
xcb_change_property(xcb_connection(),
XCB_PROP_MODE_REPLACE,
m_window,
- atom(QXcbAtom::_NET_WM_ICON_NAME),
- atom(QXcbAtom::UTF8_STRING),
+ atom(QXcbAtom::Atom_NET_WM_ICON_NAME),
+ atom(QXcbAtom::AtomUTF8_STRING),
8,
- ba.length(),
+ ba.size(),
ba.constData());
}
void QXcbWindow::setWindowIcon(const QIcon &icon)
{
- QVector<quint32> icon_data;
+ QList<quint32> icon_data;
if (!icon.isNull()) {
QList<QSize> availableSizes = icon.availableSizes();
if (availableSizes.isEmpty()) {
@@ -1321,18 +1370,25 @@ void QXcbWindow::setWindowIcon(const QIcon &icon)
}
if (!icon_data.isEmpty()) {
+ // Ignore icon exceeding maximum xcb request length
+ if (quint64(icon_data.size()) > quint64(xcb_get_maximum_request_length(xcb_connection()))) {
+ qWarning() << "Ignoring window icon" << icon_data.size()
+ << "exceeds maximum xcb request length"
+ << xcb_get_maximum_request_length(xcb_connection());
+ return;
+ }
xcb_change_property(xcb_connection(),
XCB_PROP_MODE_REPLACE,
m_window,
- atom(QXcbAtom::_NET_WM_ICON),
- atom(QXcbAtom::CARDINAL),
+ atom(QXcbAtom::Atom_NET_WM_ICON),
+ atom(QXcbAtom::AtomCARDINAL),
32,
icon_data.size(),
(unsigned char *) icon_data.data());
} else {
xcb_delete_property(xcb_connection(),
m_window,
- atom(QXcbAtom::_NET_WM_ICON));
+ atom(QXcbAtom::Atom_NET_WM_ICON));
}
}
@@ -1389,13 +1445,14 @@ void QXcbWindow::propagateSizeHints()
qMin(XCOORD_MAX, maximumSize.height()));
if (sizeIncrement.width() > 0 || sizeIncrement.height() > 0) {
- xcb_icccm_size_hints_set_base_size(&hints, baseSize.width(), baseSize.height());
+ if (!baseSize.isNull() && baseSize.isValid())
+ xcb_icccm_size_hints_set_base_size(&hints, baseSize.width(), baseSize.height());
xcb_icccm_size_hints_set_resize_inc(&hints, sizeIncrement.width(), sizeIncrement.height());
}
xcb_icccm_set_wm_normal_hints(xcb_connection(), m_window, &hints);
- m_sizeHintsScaleFactor = QHighDpiScaling::scaleAndOrigin(screen()).factor;
+ m_sizeHintsScaleFactor = QHighDpiScaling::factor(screen());
}
void QXcbWindow::requestActivateWindow()
@@ -1407,29 +1464,37 @@ void QXcbWindow::requestActivateWindow()
return;
}
- if (!m_mapped) {
- m_deferredActivation = true;
- return;
+ {
+ QMutexLocker locker(&m_mappedMutex);
+ if (!m_mapped) {
+ m_deferredActivation = true;
+ return;
+ }
+ m_deferredActivation = false;
}
- m_deferredActivation = false;
updateNetWmUserTime(connection()->time());
QWindow *focusWindow = QGuiApplication::focusWindow();
+ xcb_window_t current = XCB_NONE;
+ if (focusWindow) {
+ if (QPlatformWindow *pw = focusWindow->handle())
+ current = pw->winId();
+ }
if (window()->isTopLevel()
&& !(window()->flags() & Qt::X11BypassWindowManagerHint)
&& (!focusWindow || !window()->isAncestorOf(focusWindow))
- && connection()->wmSupport()->isSupportedByWM(atom(QXcbAtom::_NET_ACTIVE_WINDOW))) {
+ && connection()->wmSupport()->isSupportedByWM(atom(QXcbAtom::Atom_NET_ACTIVE_WINDOW))) {
xcb_client_message_event_t event;
event.response_type = XCB_CLIENT_MESSAGE;
event.format = 32;
event.sequence = 0;
event.window = m_window;
- event.type = atom(QXcbAtom::_NET_ACTIVE_WINDOW);
+ event.type = atom(QXcbAtom::Atom_NET_ACTIVE_WINDOW);
event.data.data32[0] = 1;
event.data.data32[1] = connection()->time();
- event.data.data32[2] = focusWindow ? focusWindow->winId() : XCB_NONE;
+ event.data.data32[2] = current;
event.data.data32[3] = 0;
event.data.data32[4] = 0;
@@ -1448,41 +1513,12 @@ QSurfaceFormat QXcbWindow::format() const
return m_format;
}
-void QXcbWindow::setWmWindowTypeStatic(QWindow *window, QXcbWindowFunctions::WmWindowTypes windowTypes)
-{
- window->setProperty(wm_window_type_property_id, QVariant::fromValue(static_cast<int>(windowTypes)));
-
- if (window->handle())
- static_cast<QXcbWindow *>(window->handle())->setWmWindowType(windowTypes, window->flags());
-}
-
-void QXcbWindow::setWindowIconTextStatic(QWindow *window, const QString &text)
-{
- if (window->handle())
- static_cast<QXcbWindow *>(window->handle())->setWindowIconText(text);
-}
-
-void QXcbWindow::setWmWindowRoleStatic(QWindow *window, const QByteArray &role)
-{
- if (window->handle())
- static_cast<QXcbWindow *>(window->handle())->setWmWindowRole(role);
- else
- window->setProperty(wm_window_role_property_id, role);
-}
-
-uint QXcbWindow::visualIdStatic(QWindow *window)
-{
- if (window && window->handle())
- return static_cast<QXcbWindow *>(window->handle())->visualId();
- return UINT_MAX;
-}
-
-QXcbWindowFunctions::WmWindowTypes QXcbWindow::wmWindowTypes() const
+QXcbWindow::WindowTypes QXcbWindow::wmWindowTypes() const
{
- QXcbWindowFunctions::WmWindowTypes result;
+ WindowTypes result;
auto reply = Q_XCB_REPLY_UNCHECKED(xcb_get_property, xcb_connection(),
- 0, m_window, atom(QXcbAtom::_NET_WM_WINDOW_TYPE),
+ 0, m_window, atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE),
XCB_ATOM_ATOM, 0, 1024);
if (reply && reply->format == 32 && reply->type == XCB_ATOM_ATOM) {
const xcb_atom_t *types = static_cast<const xcb_atom_t *>(xcb_get_property_value(reply.get()));
@@ -1490,50 +1526,50 @@ QXcbWindowFunctions::WmWindowTypes QXcbWindow::wmWindowTypes() const
for (; types != types_end; types++) {
QXcbAtom::Atom type = connection()->qatom(*types);
switch (type) {
- case QXcbAtom::_NET_WM_WINDOW_TYPE_NORMAL:
- result |= QXcbWindowFunctions::Normal;
+ case QXcbAtom::Atom_NET_WM_WINDOW_TYPE_NORMAL:
+ result |= WindowType::Normal;
break;
- case QXcbAtom::_NET_WM_WINDOW_TYPE_DESKTOP:
- result |= QXcbWindowFunctions::Desktop;
+ case QXcbAtom::Atom_NET_WM_WINDOW_TYPE_DESKTOP:
+ result |= WindowType::Desktop;
break;
- case QXcbAtom::_NET_WM_WINDOW_TYPE_DOCK:
- result |= QXcbWindowFunctions::Dock;
+ case QXcbAtom::Atom_NET_WM_WINDOW_TYPE_DOCK:
+ result |= WindowType::Dock;
break;
- case QXcbAtom::_NET_WM_WINDOW_TYPE_TOOLBAR:
- result |= QXcbWindowFunctions::Toolbar;
+ case QXcbAtom::Atom_NET_WM_WINDOW_TYPE_TOOLBAR:
+ result |= WindowType::Toolbar;
break;
- case QXcbAtom::_NET_WM_WINDOW_TYPE_MENU:
- result |= QXcbWindowFunctions::Menu;
+ case QXcbAtom::Atom_NET_WM_WINDOW_TYPE_MENU:
+ result |= WindowType::Menu;
break;
- case QXcbAtom::_NET_WM_WINDOW_TYPE_UTILITY:
- result |= QXcbWindowFunctions::Utility;
+ case QXcbAtom::Atom_NET_WM_WINDOW_TYPE_UTILITY:
+ result |= WindowType::Utility;
break;
- case QXcbAtom::_NET_WM_WINDOW_TYPE_SPLASH:
- result |= QXcbWindowFunctions::Splash;
+ case QXcbAtom::Atom_NET_WM_WINDOW_TYPE_SPLASH:
+ result |= WindowType::Splash;
break;
- case QXcbAtom::_NET_WM_WINDOW_TYPE_DIALOG:
- result |= QXcbWindowFunctions::Dialog;
+ case QXcbAtom::Atom_NET_WM_WINDOW_TYPE_DIALOG:
+ result |= WindowType::Dialog;
break;
- case QXcbAtom::_NET_WM_WINDOW_TYPE_DROPDOWN_MENU:
- result |= QXcbWindowFunctions::DropDownMenu;
+ case QXcbAtom::Atom_NET_WM_WINDOW_TYPE_DROPDOWN_MENU:
+ result |= WindowType::DropDownMenu;
break;
- case QXcbAtom::_NET_WM_WINDOW_TYPE_POPUP_MENU:
- result |= QXcbWindowFunctions::PopupMenu;
+ case QXcbAtom::Atom_NET_WM_WINDOW_TYPE_POPUP_MENU:
+ result |= WindowType::PopupMenu;
break;
- case QXcbAtom::_NET_WM_WINDOW_TYPE_TOOLTIP:
- result |= QXcbWindowFunctions::Tooltip;
+ case QXcbAtom::Atom_NET_WM_WINDOW_TYPE_TOOLTIP:
+ result |= WindowType::Tooltip;
break;
- case QXcbAtom::_NET_WM_WINDOW_TYPE_NOTIFICATION:
- result |= QXcbWindowFunctions::Notification;
+ case QXcbAtom::Atom_NET_WM_WINDOW_TYPE_NOTIFICATION:
+ result |= WindowType::Notification;
break;
- case QXcbAtom::_NET_WM_WINDOW_TYPE_COMBO:
- result |= QXcbWindowFunctions::Combo;
+ case QXcbAtom::Atom_NET_WM_WINDOW_TYPE_COMBO:
+ result |= WindowType::Combo;
break;
- case QXcbAtom::_NET_WM_WINDOW_TYPE_DND:
- result |= QXcbWindowFunctions::Dnd;
+ case QXcbAtom::Atom_NET_WM_WINDOW_TYPE_DND:
+ result |= WindowType::Dnd;
break;
- case QXcbAtom::_KDE_NET_WM_WINDOW_TYPE_OVERRIDE:
- result |= QXcbWindowFunctions::KdeOverride;
+ case QXcbAtom::Atom_KDE_NET_WM_WINDOW_TYPE_OVERRIDE:
+ result |= WindowType::KdeOverride;
break;
default:
break;
@@ -1543,98 +1579,99 @@ QXcbWindowFunctions::WmWindowTypes QXcbWindow::wmWindowTypes() const
return result;
}
-void QXcbWindow::setWmWindowType(QXcbWindowFunctions::WmWindowTypes types, Qt::WindowFlags flags)
+void QXcbWindow::setWmWindowType(WindowTypes types, Qt::WindowFlags flags)
{
- QVector<xcb_atom_t> atoms;
+ QList<xcb_atom_t> atoms;
// manual selection 1 (these are never set by Qt and take precedence)
- if (types & QXcbWindowFunctions::Normal)
- atoms.append(atom(QXcbAtom::_NET_WM_WINDOW_TYPE_NORMAL));
- if (types & QXcbWindowFunctions::Desktop)
- atoms.append(atom(QXcbAtom::_NET_WM_WINDOW_TYPE_DESKTOP));
- if (types & QXcbWindowFunctions::Dock)
- atoms.append(atom(QXcbAtom::_NET_WM_WINDOW_TYPE_DOCK));
- if (types & QXcbWindowFunctions::Notification)
- atoms.append(atom(QXcbAtom::_NET_WM_WINDOW_TYPE_NOTIFICATION));
+ if (types & WindowType::Normal)
+ atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_NORMAL));
+ if (types & WindowType::Desktop)
+ atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_DESKTOP));
+ if (types & WindowType::Dock)
+ atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_DOCK));
+ if (types & WindowType::Notification)
+ atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_NOTIFICATION));
// manual selection 2 (Qt uses these during auto selection);
- if (types & QXcbWindowFunctions::Utility)
- atoms.append(atom(QXcbAtom::_NET_WM_WINDOW_TYPE_UTILITY));
- if (types & QXcbWindowFunctions::Splash)
- atoms.append(atom(QXcbAtom::_NET_WM_WINDOW_TYPE_SPLASH));
- if (types & QXcbWindowFunctions::Dialog)
- atoms.append(atom(QXcbAtom::_NET_WM_WINDOW_TYPE_DIALOG));
- if (types & QXcbWindowFunctions::Tooltip)
- atoms.append(atom(QXcbAtom::_NET_WM_WINDOW_TYPE_TOOLTIP));
- if (types & QXcbWindowFunctions::KdeOverride)
- atoms.append(atom(QXcbAtom::_KDE_NET_WM_WINDOW_TYPE_OVERRIDE));
+ if (types & WindowType::Utility)
+ atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_UTILITY));
+ if (types & WindowType::Splash)
+ atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_SPLASH));
+ if (types & WindowType::Dialog)
+ atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_DIALOG));
+ if (types & WindowType::Tooltip)
+ atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_TOOLTIP));
+ if (types & WindowType::KdeOverride)
+ atoms.append(atom(QXcbAtom::Atom_KDE_NET_WM_WINDOW_TYPE_OVERRIDE));
// manual selection 3 (these can be set by Qt, but don't have a
// corresponding Qt::WindowType). note that order of the *MENU
// atoms is important
- if (types & QXcbWindowFunctions::Menu)
- atoms.append(atom(QXcbAtom::_NET_WM_WINDOW_TYPE_MENU));
- if (types & QXcbWindowFunctions::DropDownMenu)
- atoms.append(atom(QXcbAtom::_NET_WM_WINDOW_TYPE_DROPDOWN_MENU));
- if (types & QXcbWindowFunctions::PopupMenu)
- atoms.append(atom(QXcbAtom::_NET_WM_WINDOW_TYPE_POPUP_MENU));
- if (types & QXcbWindowFunctions::Toolbar)
- atoms.append(atom(QXcbAtom::_NET_WM_WINDOW_TYPE_TOOLBAR));
- if (types & QXcbWindowFunctions::Combo)
- atoms.append(atom(QXcbAtom::_NET_WM_WINDOW_TYPE_COMBO));
- if (types & QXcbWindowFunctions::Dnd)
- atoms.append(atom(QXcbAtom::_NET_WM_WINDOW_TYPE_DND));
+ if (types & WindowType::Menu)
+ atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_MENU));
+ if (types & WindowType::DropDownMenu)
+ atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_DROPDOWN_MENU));
+ if (types & WindowType::PopupMenu)
+ atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_POPUP_MENU));
+ if (types & WindowType::Toolbar)
+ atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_TOOLBAR));
+ if (types & WindowType::Combo)
+ atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_COMBO));
+ if (types & WindowType::Dnd)
+ atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_DND));
// automatic selection
Qt::WindowType type = static_cast<Qt::WindowType>(int(flags & Qt::WindowType_Mask));
switch (type) {
case Qt::Dialog:
case Qt::Sheet:
- if (!(types & QXcbWindowFunctions::Dialog))
- atoms.append(atom(QXcbAtom::_NET_WM_WINDOW_TYPE_DIALOG));
+ if (!(types & WindowType::Dialog))
+ atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_DIALOG));
break;
case Qt::Tool:
case Qt::Drawer:
- if (!(types & QXcbWindowFunctions::Utility))
- atoms.append(atom(QXcbAtom::_NET_WM_WINDOW_TYPE_UTILITY));
+ if (!(types & WindowType::Utility))
+ atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_UTILITY));
break;
case Qt::ToolTip:
- if (!(types & QXcbWindowFunctions::Tooltip))
- atoms.append(atom(QXcbAtom::_NET_WM_WINDOW_TYPE_TOOLTIP));
+ if (!(types & WindowType::Tooltip))
+ atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_TOOLTIP));
break;
case Qt::SplashScreen:
- if (!(types & QXcbWindowFunctions::Splash))
- atoms.append(atom(QXcbAtom::_NET_WM_WINDOW_TYPE_SPLASH));
+ if (!(types & WindowType::Splash))
+ atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_SPLASH));
break;
default:
break;
}
- if ((flags & Qt::FramelessWindowHint) && !(type & QXcbWindowFunctions::KdeOverride)) {
+ if ((flags & Qt::FramelessWindowHint) && !(types & WindowType::KdeOverride)) {
// override netwm type - quick and easy for KDE noborder
- atoms.append(atom(QXcbAtom::_KDE_NET_WM_WINDOW_TYPE_OVERRIDE));
+ atoms.append(atom(QXcbAtom::Atom_KDE_NET_WM_WINDOW_TYPE_OVERRIDE));
}
- if (atoms.size() == 1 && atoms.first() == atom(QXcbAtom::_NET_WM_WINDOW_TYPE_NORMAL))
+ if (atoms.size() == 1 && atoms.first() == atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_NORMAL))
atoms.clear();
else
- atoms.append(atom(QXcbAtom::_NET_WM_WINDOW_TYPE_NORMAL));
+ atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_NORMAL));
if (atoms.isEmpty()) {
- xcb_delete_property(xcb_connection(), m_window, atom(QXcbAtom::_NET_WM_WINDOW_TYPE));
+ xcb_delete_property(xcb_connection(), m_window, atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE));
} else {
xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window,
- atom(QXcbAtom::_NET_WM_WINDOW_TYPE), XCB_ATOM_ATOM, 32,
- atoms.count(), atoms.constData());
+ atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE), XCB_ATOM_ATOM, 32,
+ atoms.size(), atoms.constData());
}
xcb_flush(xcb_connection());
}
-void QXcbWindow::setWmWindowRole(const QByteArray &role)
+void QXcbWindow::setWindowRole(const QString &role)
{
+ QByteArray roleData = role.toLatin1();
xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window,
- atom(QXcbAtom::WM_WINDOW_ROLE), XCB_ATOM_STRING, 8,
- role.size(), role.constData());
+ atom(QXcbAtom::AtomWM_WINDOW_ROLE), XCB_ATOM_STRING, 8,
+ roleData.size(), roleData.constData());
}
void QXcbWindow::setParentRelativeBackPixmap()
@@ -1655,11 +1692,7 @@ bool QXcbWindow::requestSystemTrayWindowDock()
bool QXcbWindow::handleNativeEvent(xcb_generic_event_t *event)
{
auto eventType = connection()->nativeInterface()->nativeEventType();
-#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
qintptr result = 0; // Used only by MS Windows
-#else
- long result = 0; // Used only by MS Windows
-#endif
return QWindowSystemInterface::handleNativeEvent(window(), eventType, event, &result);
}
@@ -1670,7 +1703,7 @@ void QXcbWindow::handleExposeEvent(const xcb_expose_event_t *event)
bool pending = true;
- connection()->eventQueue()->peek(QXcbEventQueue::PeekRemoveMatchContinue,
+ connection()->eventQueue()->peek(QXcbEventQueue::PeekConsumeMatchAndContinue,
[this, &pending](xcb_generic_event_t *event, int type) {
if (type != XCB_EXPOSE)
return false;
@@ -1696,15 +1729,15 @@ void QXcbWindow::handleClientMessageEvent(const xcb_client_message_event_t *even
if (event->format != 32)
return;
- if (event->type == atom(QXcbAtom::WM_PROTOCOLS)) {
+ if (event->type == atom(QXcbAtom::AtomWM_PROTOCOLS)) {
xcb_atom_t protocolAtom = event->data.data32[0];
- if (protocolAtom == atom(QXcbAtom::WM_DELETE_WINDOW)) {
+ if (protocolAtom == atom(QXcbAtom::AtomWM_DELETE_WINDOW)) {
QWindowSystemInterface::handleCloseEvent(window());
- } else if (protocolAtom == atom(QXcbAtom::WM_TAKE_FOCUS)) {
+ } else if (protocolAtom == atom(QXcbAtom::AtomWM_TAKE_FOCUS)) {
connection()->setTime(event->data.data32[1]);
relayFocusToModalWindow();
return;
- } else if (protocolAtom == atom(QXcbAtom::_NET_WM_PING)) {
+ } else if (protocolAtom == atom(QXcbAtom::Atom_NET_WM_PING)) {
if (event->window == xcbScreen()->root())
return;
@@ -1717,14 +1750,14 @@ void QXcbWindow::handleClientMessageEvent(const xcb_client_message_event_t *even
XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT,
(const char *)&reply);
xcb_flush(xcb_connection());
- } else if (protocolAtom == atom(QXcbAtom::_NET_WM_SYNC_REQUEST)) {
+ } else if (protocolAtom == atom(QXcbAtom::Atom_NET_WM_SYNC_REQUEST)) {
connection()->setTime(event->data.data32[1]);
m_syncValue.lo = event->data.data32[2];
m_syncValue.hi = event->data.data32[3];
if (connection()->hasXSync())
m_syncState = SyncReceived;
#ifndef QT_NO_WHATSTHIS
- } else if (protocolAtom == atom(QXcbAtom::_NET_WM_CONTEXT_HELP)) {
+ } else if (protocolAtom == atom(QXcbAtom::Atom_NET_WM_CONTEXT_HELP)) {
QWindowSystemInterface::handleEnterWhatsThisEvent();
#endif
} else {
@@ -1732,29 +1765,29 @@ void QXcbWindow::handleClientMessageEvent(const xcb_client_message_event_t *even
connection()->atomName(protocolAtom).constData());
}
#if QT_CONFIG(draganddrop)
- } else if (event->type == atom(QXcbAtom::XdndEnter)) {
+ } else if (event->type == atom(QXcbAtom::AtomXdndEnter)) {
connection()->drag()->handleEnter(this, event);
- } else if (event->type == atom(QXcbAtom::XdndPosition)) {
+ } else if (event->type == atom(QXcbAtom::AtomXdndPosition)) {
connection()->drag()->handlePosition(this, event);
- } else if (event->type == atom(QXcbAtom::XdndLeave)) {
+ } else if (event->type == atom(QXcbAtom::AtomXdndLeave)) {
connection()->drag()->handleLeave(this, event);
- } else if (event->type == atom(QXcbAtom::XdndDrop)) {
+ } else if (event->type == atom(QXcbAtom::AtomXdndDrop)) {
connection()->drag()->handleDrop(this, event);
#endif
- } else if (event->type == atom(QXcbAtom::_XEMBED)) {
+ } else if (event->type == atom(QXcbAtom::Atom_XEMBED)) {
handleXEmbedMessage(event);
- } else if (event->type == atom(QXcbAtom::_NET_ACTIVE_WINDOW)) {
+ } else if (event->type == atom(QXcbAtom::Atom_NET_ACTIVE_WINDOW)) {
doFocusIn();
- } else if (event->type == atom(QXcbAtom::MANAGER)
- || event->type == atom(QXcbAtom::_NET_WM_STATE)
- || event->type == atom(QXcbAtom::WM_CHANGE_STATE)) {
+ } else if (event->type == atom(QXcbAtom::AtomMANAGER)
+ || event->type == atom(QXcbAtom::Atom_NET_WM_STATE)
+ || event->type == atom(QXcbAtom::AtomWM_CHANGE_STATE)) {
// Ignore _NET_WM_STATE, MANAGER which are relate to tray icons
// and other messages.
- } else if (event->type == atom(QXcbAtom::_COMPIZ_DECOR_PENDING)
- || event->type == atom(QXcbAtom::_COMPIZ_DECOR_REQUEST)
- || event->type == atom(QXcbAtom::_COMPIZ_DECOR_DELETE_PIXMAP)
- || event->type == atom(QXcbAtom::_COMPIZ_TOOLKIT_ACTION)
- || event->type == atom(QXcbAtom::_GTK_LOAD_ICONTHEMES)) {
+ } else if (event->type == atom(QXcbAtom::Atom_COMPIZ_DECOR_PENDING)
+ || event->type == atom(QXcbAtom::Atom_COMPIZ_DECOR_REQUEST)
+ || event->type == atom(QXcbAtom::Atom_COMPIZ_DECOR_DELETE_PIXMAP)
+ || event->type == atom(QXcbAtom::Atom_COMPIZ_TOOLKIT_ACTION)
+ || event->type == atom(QXcbAtom::Atom_GTK_LOAD_ICONTHEMES)) {
//silence the _COMPIZ and _GTK messages for now
} else {
qCWarning(lcQpaXcb) << "Unhandled client message: " << connection()->atomName(event->type);
@@ -1765,7 +1798,7 @@ void QXcbWindow::handleConfigureNotifyEvent(const xcb_configure_notify_event_t *
{
bool fromSendEvent = (event->response_type & 0x80);
QPoint pos(event->x, event->y);
- if (!parent() && !fromSendEvent) {
+ if (!QPlatformWindow::parent() && !fromSendEvent) {
// Do not trust the position, query it instead.
auto reply = Q_XCB_REPLY(xcb_translate_coordinates, xcb_connection(),
xcb_window(), xcbScreen()->root(), 0, 0);
@@ -1776,7 +1809,7 @@ void QXcbWindow::handleConfigureNotifyEvent(const xcb_configure_notify_event_t *
}
const QRect actualGeometry = QRect(pos, QSize(event->width, event->height));
- QPlatformScreen *newScreen = parent() ? parent()->screen() : screenForGeometry(actualGeometry);
+ QPlatformScreen *newScreen = QPlatformWindow::parent() ? QPlatformWindow::parent()->screen() : screenForGeometry(actualGeometry);
if (!newScreen)
return;
@@ -1787,10 +1820,10 @@ void QXcbWindow::handleConfigureNotifyEvent(const xcb_configure_notify_event_t *
// will make the comparison later.
QWindowSystemInterface::handleWindowScreenChanged(window(), newScreen->screen());
- if (!qFuzzyCompare(QHighDpiScaling::scaleAndOrigin(newScreen).factor, m_sizeHintsScaleFactor))
+ if (!qFuzzyCompare(QHighDpiScaling::factor(newScreen), m_sizeHintsScaleFactor))
propagateSizeHints();
- // Send the synthetic expose event on resize only when the window is shrinked,
+ // Send the synthetic expose event on resize only when the window is shrunk,
// because the "XCB_GRAVITY_NORTH_WEST" flag doesn't send it automatically.
if (!m_oldWindowSize.isEmpty()
&& (actualGeometry.width() < m_oldWindowSize.width()
@@ -1852,8 +1885,11 @@ QPoint QXcbWindow::mapFromGlobal(const QPoint &pos) const
void QXcbWindow::handleMapNotifyEvent(const xcb_map_notify_event_t *event)
{
if (event->window == m_window) {
+ m_mappedMutex.lock();
m_mapped = true;
- if (m_deferredActivation)
+ const bool deferredActivation = m_deferredActivation;
+ m_mappedMutex.unlock();
+ if (deferredActivation)
requestActivateWindow();
QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(), geometry().size()));
@@ -1863,7 +1899,9 @@ void QXcbWindow::handleMapNotifyEvent(const xcb_map_notify_event_t *event)
void QXcbWindow::handleUnmapNotifyEvent(const xcb_unmap_notify_event_t *event)
{
if (event->window == m_window) {
+ m_mappedMutex.lock();
m_mapped = false;
+ m_mappedMutex.unlock();
QWindowSystemInterface::handleExposeEvent(window(), QRegion());
}
}
@@ -1886,7 +1924,7 @@ void QXcbWindow::handleButtonPressEvent(int event_x, int event_y, int root_x, in
if (m_embedded && !m_trayIconWindow) {
if (window() != QGuiApplication::focusWindow()) {
- const QXcbWindow *container = static_cast<const QXcbWindow *>(parent());
+ const QXcbWindow *container = static_cast<const QXcbWindow *>(QPlatformWindow::parent());
Q_ASSERT(container != nullptr);
sendXEmbedMessage(container->xcb_window(), XEMBED_REQUEST_FOCUS);
@@ -1930,8 +1968,10 @@ void QXcbWindow::handleButtonReleaseEvent(int event_x, int event_y, int root_x,
return;
}
- if (connection()->buttonState() == Qt::NoButton)
+ if (connection()->buttonState() == Qt::NoButton) {
connection()->setMousePressWindow(nullptr);
+ m_ignorePressedWindowOnMouseLeave = false;
+ }
handleMouseEvent(timestamp, local, global, modifiers, type, source);
}
@@ -1946,15 +1986,15 @@ static inline bool doCheckUnGrabAncestor(QXcbConnection *conn)
*/
if (conn) {
const bool mouseButtonsPressed = (conn->buttonState() != Qt::NoButton);
- return mouseButtonsPressed || (conn->hasXInput2() && !conn->xi2MouseEventsDisabled());
+ return mouseButtonsPressed || conn->hasXInput2();
}
return true;
}
-static bool ignoreLeaveEvent(quint8 mode, quint8 detail, QXcbConnection *conn = nullptr)
+static bool ignoreLeaveEvent(quint8 mode, quint8 detail, QXcbConnection *conn)
{
return ((doCheckUnGrabAncestor(conn)
- && mode == XCB_NOTIFY_MODE_GRAB && detail == XCB_NOTIFY_DETAIL_ANCESTOR)
+ && mode == XCB_NOTIFY_MODE_GRAB && detail == XCB_NOTIFY_DETAIL_ANCESTOR)
|| (mode == XCB_NOTIFY_MODE_UNGRAB && detail == XCB_NOTIFY_DETAIL_INFERIOR)
|| detail == XCB_NOTIFY_DETAIL_VIRTUAL
|| detail == XCB_NOTIFY_DETAIL_NONLINEAR_VIRTUAL);
@@ -1974,14 +2014,18 @@ void QXcbWindow::handleEnterNotifyEvent(int event_x, int event_y, int root_x, in
{
connection()->setTime(timestamp);
- const QPoint global = QPoint(root_x, root_y);
-
- if (ignoreEnterEvent(mode, detail, connection()) || connection()->mousePressWindow())
+ if (ignoreEnterEvent(mode, detail, connection())
+ || (connection()->mousePressWindow() && !m_ignorePressedWindowOnMouseLeave)) {
return;
+ }
// Updates scroll valuators, as user might have done some scrolling outside our X client.
connection()->xi2UpdateScrollingDevices();
+ if (mode == XCB_NOTIFY_MODE_UNGRAB && connection()->queryMouseButtons() != Qt::NoButton)
+ m_ignorePressedWindowOnMouseLeave = true;
+
+ const QPoint global = QPoint(root_x, root_y);
const QPoint local(event_x, event_y);
QWindowSystemInterface::handleEnterEvent(window(), local, global);
}
@@ -1991,8 +2035,11 @@ void QXcbWindow::handleLeaveNotifyEvent(int root_x, int root_y,
{
connection()->setTime(timestamp);
- if (ignoreLeaveEvent(mode, detail, connection()) || connection()->mousePressWindow())
+ QXcbWindow *mousePressWindow = connection()->mousePressWindow();
+ if (ignoreLeaveEvent(mode, detail, connection())
+ || (mousePressWindow && !m_ignorePressedWindowOnMouseLeave)) {
return;
+ }
// check if enter event is buffered
auto event = connection()->eventQueue()->peek([](xcb_generic_event_t *event, int type) {
@@ -2010,6 +2057,8 @@ void QXcbWindow::handleLeaveNotifyEvent(int root_x, int root_y,
QWindowSystemInterface::handleEnterLeaveEvent(enterWindow->window(), window(), local, global);
} else {
QWindowSystemInterface::handleLeaveEvent(window());
+ if (m_ignorePressedWindowOnMouseLeave)
+ connection()->setMousePressWindow(nullptr);
}
free(enter);
@@ -2162,6 +2211,7 @@ void QXcbWindow::handleMouseEvent(xcb_timestamp_t time, const QPoint &local, con
Qt::KeyboardModifiers modifiers, QEvent::Type type, Qt::MouseEventSource source)
{
m_lastPointerPosition = local;
+ m_lastPointerGlobalPosition = global;
connection()->setTime(time);
Qt::MouseButton button = type == QEvent::MouseMove ? Qt::NoButton : connection()->button();
QWindowSystemInterface::handleMouseEvent(window(), time, local, global,
@@ -2185,27 +2235,33 @@ void QXcbWindow::handlePropertyNotifyEvent(const xcb_property_notify_event_t *ev
const bool propertyDeleted = event->state == XCB_PROPERTY_DELETE;
- if (event->atom == atom(QXcbAtom::_NET_WM_STATE) || event->atom == atom(QXcbAtom::WM_STATE)) {
+ if (event->atom == atom(QXcbAtom::Atom_NET_WM_STATE) || event->atom == atom(QXcbAtom::AtomWM_STATE)) {
if (propertyDeleted)
return;
Qt::WindowStates newState = Qt::WindowNoState;
- if (event->atom == atom(QXcbAtom::WM_STATE)) { // WM_STATE: Quick check for 'Minimize'.
+ if (event->atom == atom(QXcbAtom::AtomWM_STATE)) { // WM_STATE: Quick check for 'Minimize'.
auto reply = Q_XCB_REPLY(xcb_get_property, xcb_connection(),
- 0, m_window, atom(QXcbAtom::WM_STATE),
+ 0, m_window, atom(QXcbAtom::AtomWM_STATE),
XCB_ATOM_ANY, 0, 1024);
- if (reply && reply->format == 32 && reply->type == atom(QXcbAtom::WM_STATE)) {
+ if (reply && reply->format == 32 && reply->type == atom(QXcbAtom::AtomWM_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));
}
}
- if (m_minimized)
- newState = Qt::WindowMinimized;
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
+ // within the screen bounds. The canonical example is that minimized windows should be in
+ // the _NET_WM_STATE_HIDDEN state.
+ if (m_minimized && (!connection()->wmSupport()->isSupportedByWM(NetWmStateHidden)
+ || states.testFlag(NetWmStateHidden)))
+ newState = Qt::WindowMinimized;
+
if (states & NetWmStateFullScreen)
newState |= Qt::WindowFullScreen;
if ((states & NetWmStateMaximizedHorz) && (states & NetWmStateMaximizedVert))
@@ -2219,7 +2275,7 @@ void QXcbWindow::handlePropertyNotifyEvent(const xcb_property_notify_event_t *ev
connection()->setMouseGrabber(nullptr);
}
return;
- } else if (event->atom == atom(QXcbAtom::_NET_FRAME_EXTENTS)) {
+ } else if (event->atom == atom(QXcbAtom::Atom_NET_FRAME_EXTENTS)) {
m_dirtyFrameMargins = true;
}
}
@@ -2291,7 +2347,7 @@ bool QXcbWindow::setMouseGrabEnabled(bool grab)
if (grab && !connection()->canGrab())
return false;
- if (connection()->hasXInput2() && !connection()->xi2MouseEventsDisabled()) {
+ if (connection()->hasXInput2()) {
bool result = connection()->xi2SetMouseGrabEnabled(m_window, grab);
if (grab && result)
connection()->setMouseGrabber(this);
@@ -2328,7 +2384,7 @@ bool QXcbWindow::windowEvent(QEvent *event)
case Qt::BacktabFocusReason:
{
const QXcbWindow *container =
- static_cast<const QXcbWindow *>(parent());
+ static_cast<const QXcbWindow *>(QPlatformWindow::parent());
sendXEmbedMessage(container->xcb_window(),
focusEvent->reason() == Qt::TabFocusReason ?
XEMBED_FOCUS_NEXT : XEMBED_FOCUS_PREV);
@@ -2358,23 +2414,22 @@ bool QXcbWindow::startSystemMove()
bool QXcbWindow::startSystemMoveResize(const QPoint &pos, int edges)
{
- const xcb_atom_t moveResize = connection()->atom(QXcbAtom::_NET_WM_MOVERESIZE);
+ const xcb_atom_t moveResize = connection()->atom(QXcbAtom::Atom_NET_WM_MOVERESIZE);
if (!connection()->wmSupport()->isSupportedByWM(moveResize))
return false;
// ### FIXME QTBUG-53389
bool startedByTouch = connection()->startSystemMoveResizeForTouch(m_window, edges);
if (startedByTouch) {
- if (connection()->isUnity()) {
- // Unity fails to move/resize via _NET_WM_MOVERESIZE (WM bug?).
- connection()->abortSystemMoveResizeForTouch();
+ const QString wmname = connection()->windowManagerName();
+ if (wmname != "kwin"_L1 && wmname != "openbox"_L1) {
+ qCDebug(lcQpaXInputDevices) << "only KDE and OpenBox support startSystemMove/Resize which is triggered from touch events: XDG_CURRENT_DESKTOP="
+ << qgetenv("XDG_CURRENT_DESKTOP");
+ connection()->abortSystemMoveResize(m_window);
return false;
}
// KWin, Openbox, AwesomeWM and Gnome have been tested to work with _NET_WM_MOVERESIZE.
} else { // Started by mouse press.
- if (connection()->isUnity())
- return false; // _NET_WM_MOVERESIZE on this WM is bouncy (WM bug?).
-
doStartSystemMoveResize(mapToGlobal(pos), edges);
}
@@ -2406,7 +2461,8 @@ static uint qtEdgesToXcbMoveResizeDirection(Qt::Edges edges)
void QXcbWindow::doStartSystemMoveResize(const QPoint &globalPos, int edges)
{
- const xcb_atom_t moveResize = connection()->atom(QXcbAtom::_NET_WM_MOVERESIZE);
+ qCDebug(lcQpaXInputDevices) << "triggered system move or resize via sending _NET_WM_MOVERESIZE client message";
+ const xcb_atom_t moveResize = connection()->atom(QXcbAtom::Atom_NET_WM_MOVERESIZE);
xcb_client_message_event_t xev;
xev.response_type = XCB_CLIENT_MESSAGE;
xev.type = moveResize;
@@ -2425,6 +2481,8 @@ void QXcbWindow::doStartSystemMoveResize(const QPoint &globalPos, int edges)
xcb_send_event(connection()->xcb_connection(), false, xcbScreen()->root(),
XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY,
(const char *)&xev);
+
+ connection()->setDuringSystemMoveResize(true);
}
// Sends an XEmbed message.
@@ -2437,7 +2495,7 @@ void QXcbWindow::sendXEmbedMessage(xcb_window_t window, quint32 message,
event.format = 32;
event.sequence = 0;
event.window = window;
- event.type = atom(QXcbAtom::_XEMBED);
+ event.type = atom(QXcbAtom::Atom_XEMBED);
event.data.data32[0] = connection()->time();
event.data.data32[1] = message;
event.data.data32[2] = detail;
@@ -2446,15 +2504,15 @@ void QXcbWindow::sendXEmbedMessage(xcb_window_t window, quint32 message,
xcb_send_event(xcb_connection(), false, window, XCB_EVENT_MASK_NO_EVENT, (const char *)&event);
}
-static bool activeWindowChangeQueued(const QWindow *window)
+static bool focusWindowChangeQueued(const QWindow *window)
{
/* Check from window system event queue if the next queued activation
* targets a window other than @window.
*/
- QWindowSystemInterfacePrivate::ActivatedWindowEvent *systemEvent =
- static_cast<QWindowSystemInterfacePrivate::ActivatedWindowEvent *>
- (QWindowSystemInterfacePrivate::peekWindowSystemEvent(QWindowSystemInterfacePrivate::ActivatedWindow));
- return systemEvent && systemEvent->activated != window;
+ QWindowSystemInterfacePrivate::FocusWindowEvent *systemEvent =
+ static_cast<QWindowSystemInterfacePrivate::FocusWindowEvent *>
+ (QWindowSystemInterfacePrivate::peekWindowSystemEvent(QWindowSystemInterfacePrivate::FocusWindow));
+ return systemEvent && systemEvent->focused != window;
}
void QXcbWindow::handleXEmbedMessage(const xcb_client_message_event_t *event)
@@ -2484,13 +2542,13 @@ void QXcbWindow::handleXEmbedMessage(const xcb_client_message_event_t *event)
break;
}
connection()->setFocusWindow(window());
- QWindowSystemInterface::handleWindowActivated(window(), reason);
+ QWindowSystemInterface::handleFocusWindowChanged(window(), reason);
break;
case XEMBED_FOCUS_OUT:
if (window() == QGuiApplication::focusWindow()
- && !activeWindowChangeQueued(window())) {
+ && !focusWindowChangeQueued(window())) {
connection()->setFocusWindow(nullptr);
- QWindowSystemInterface::handleWindowActivated(nullptr);
+ QWindowSystemInterface::handleFocusWindowChanged(nullptr);
}
break;
}
@@ -2516,16 +2574,16 @@ void QXcbWindow::setOpacity(qreal level)
xcb_change_property(xcb_connection(),
XCB_PROP_MODE_REPLACE,
m_window,
- atom(QXcbAtom::_NET_WM_WINDOW_OPACITY),
+ atom(QXcbAtom::Atom_NET_WM_WINDOW_OPACITY),
XCB_ATOM_CARDINAL,
32,
1,
(uchar *)&value);
}
-QVector<xcb_rectangle_t> qRegionToXcbRectangleList(const QRegion &region)
+QList<xcb_rectangle_t> qRegionToXcbRectangleList(const QRegion &region)
{
- QVector<xcb_rectangle_t> rects;
+ QList<xcb_rectangle_t> rects;
rects.reserve(region.rectCount());
for (const QRect &r : region)
rects.push_back(qRectToXCBRectangle(r));
@@ -2554,7 +2612,7 @@ void QXcbWindow::setAlertState(bool enabled)
m_alertState = enabled;
- setNetWmState(enabled, atom(QXcbAtom::_NET_WM_STATE_DEMANDS_ATTENTION));
+ setNetWmState(enabled, atom(QXcbAtom::Atom_NET_WM_STATE_DEMANDS_ATTENTION));
}
uint QXcbWindow::visualId() const
@@ -2588,10 +2646,10 @@ void QXcbWindow::setWindowTitle(const QXcbConnection *conn, xcb_window_t window,
xcb_change_property(conn->xcb_connection(),
XCB_PROP_MODE_REPLACE,
window,
- conn->atom(QXcbAtom::_NET_WM_NAME),
- conn->atom(QXcbAtom::UTF8_STRING),
+ conn->atom(QXcbAtom::Atom_NET_WM_NAME),
+ conn->atom(QXcbAtom::AtomUTF8_STRING),
8,
- ba.length(),
+ ba.size(),
ba.constData());
#if QT_CONFIG(xcb_xlib)
@@ -2605,9 +2663,9 @@ void QXcbWindow::setWindowTitle(const QXcbConnection *conn, xcb_window_t window,
QString QXcbWindow::windowTitle(const QXcbConnection *conn, xcb_window_t window)
{
- const xcb_atom_t utf8Atom = conn->atom(QXcbAtom::UTF8_STRING);
+ const xcb_atom_t utf8Atom = conn->atom(QXcbAtom::AtomUTF8_STRING);
auto reply = Q_XCB_REPLY_UNCHECKED(xcb_get_property, conn->xcb_connection(),
- false, window, conn->atom(QXcbAtom::_NET_WM_NAME),
+ false, window, conn->atom(QXcbAtom::Atom_NET_WM_NAME),
utf8Atom, 0, 1024);
if (reply && reply->format == 8 && reply->type == utf8Atom) {
const char *name = reinterpret_cast<const char *>(xcb_get_property_value(reply.get()));
@@ -2615,7 +2673,7 @@ QString QXcbWindow::windowTitle(const QXcbConnection *conn, xcb_window_t window)
}
reply = Q_XCB_REPLY_UNCHECKED(xcb_get_property, conn->xcb_connection(),
- false, window, conn->atom(QXcbAtom::WM_NAME),
+ false, window, conn->atom(QXcbAtom::AtomWM_NAME),
XCB_ATOM_STRING, 0, 1024);
if (reply && reply->format == 8 && reply->type == XCB_ATOM_STRING) {
const char *name = reinterpret_cast<const char *>(xcb_get_property_value(reply.get()));
diff --git a/src/plugins/platforms/xcb/qxcbwindow.h b/src/plugins/platforms/xcb/qxcbwindow.h
index d6f370eebe..0c047d569b 100644
--- a/src/plugins/platforms/xcb/qxcbwindow.h
+++ b/src/plugins/platforms/xcb/qxcbwindow.h
@@ -1,46 +1,13 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QXCBWINDOW_H
#define QXCBWINDOW_H
#include <qpa/qplatformwindow.h>
+#include <qpa/qplatformwindow_p.h>
+#include <QtCore/QObject>
+#include <QtCore/QPointer>
#include <QtGui/QSurfaceFormat>
#include <QtGui/QImage>
@@ -49,16 +16,16 @@
#include "qxcbobject.h"
-#include <QtPlatformHeaders/qxcbwindowfunctions.h>
-
QT_BEGIN_NAMESPACE
class QXcbScreen;
class QXcbSyncWindowRequest;
class QIcon;
-class Q_XCB_EXPORT QXcbWindow : public QXcbObject, public QXcbWindowEventListener, public QPlatformWindow
+class Q_XCB_EXPORT QXcbWindow : public QObject, public QXcbObject, public QXcbWindowEventListener, public QPlatformWindow
+ , public QNativeInterface::Private::QXcbWindow
{
+ Q_OBJECT
public:
enum NetWmState {
NetWmStateAbove = 0x1,
@@ -68,11 +35,19 @@ public:
NetWmStateMaximizedVert = 0x10,
NetWmStateModal = 0x20,
NetWmStateStaysOnTop = 0x40,
- NetWmStateDemandsAttention = 0x80
+ NetWmStateDemandsAttention = 0x80,
+ NetWmStateHidden = 0x100
};
Q_DECLARE_FLAGS(NetWmStates, NetWmState)
+ enum RecreationReason {
+ RecreationNotNeeded = 0,
+ WindowStaysOnTopHintChanged = 0x1,
+ WindowStaysOnBottomHintChanged = 0x2
+ };
+ Q_DECLARE_FLAGS(RecreationReasons, RecreationReason)
+
QXcbWindow(QWindow *window);
~QXcbWindow();
@@ -92,7 +67,7 @@ public:
QPoint mapFromGlobal(const QPoint &pos) const override;
void setWindowTitle(const QString &title) override;
- void setWindowIconText(const QString &title);
+ void setWindowIconText(const QString &title) override;
void setWindowIcon(const QIcon &icon) override;
void raise() override;
void lower() override;
@@ -146,20 +121,17 @@ public:
Qt::KeyboardModifiers modifiers, QEvent::Type type, Qt::MouseEventSource source);
void updateNetWmUserTime(xcb_timestamp_t timestamp);
+ void updateWmTransientFor();
+ void registerWmTransientForChild(QXcbWindow *);
- static void setWmWindowTypeStatic(QWindow *window, QXcbWindowFunctions::WmWindowTypes windowTypes);
- static void setWmWindowRoleStatic(QWindow *window, const QByteArray &role);
- static uint visualIdStatic(QWindow *window);
-
- QXcbWindowFunctions::WmWindowTypes wmWindowTypes() const;
- void setWmWindowType(QXcbWindowFunctions::WmWindowTypes types, Qt::WindowFlags flags);
- void setWmWindowRole(const QByteArray &role);
-
- static void setWindowIconTextStatic(QWindow *window, const QString &text);
+ WindowTypes wmWindowTypes() const;
+ void setWmWindowType(WindowTypes types, Qt::WindowFlags flags);
+ void setWindowType(WindowTypes windowTypes) override { setWmWindowType(windowTypes, window()->flags()); }
+ void setWindowRole(const QString &role) override;
void setParentRelativeBackPixmap();
bool requestSystemTrayWindowDock();
- uint visualId() const;
+ uint visualId() const override;
bool needsSync() const;
@@ -168,12 +140,15 @@ public:
QXcbScreen *xcbScreen() const;
+ QPoint lastPointerPosition() const { return m_lastPointerPosition; }
+ QPoint lastPointerGlobalPosition() const { return m_lastPointerGlobalPosition; }
+
bool startSystemMoveResize(const QPoint &pos, int edges);
void doStartSystemMoveResize(const QPoint &globalPos, int edges);
static bool isTrayIconWindow(QWindow *window)
{
- return window->objectName() == QLatin1String("QSystemTrayIconSysWindow");
+ return window->objectName() == QLatin1StringView("QSystemTrayIconSysWindow");
}
virtual void create();
@@ -237,7 +212,6 @@ protected:
quint8 mode, quint8 detail, xcb_timestamp_t timestamp);
xcb_window_t m_window = 0;
- xcb_colormap_t m_cmap = 0;
uint m_depth = 0;
QImage::Format m_imageFormat = QImage::Format_ARGB32_Premultiplied;
@@ -248,6 +222,7 @@ protected:
Qt::WindowStates m_windowState = Qt::WindowNoState;
+ QMutex m_mappedMutex;
bool m_mapped = false;
bool m_transparent = false;
bool m_deferredActivation = false;
@@ -255,6 +230,7 @@ protected:
bool m_alertState = false;
bool m_minimized = false;
bool m_trayIconWindow = false;
+ bool m_ignorePressedWindowOnMouseLeave = false;
xcb_window_t m_netWmUserTimeWindow = XCB_NONE;
QSurfaceFormat m_format;
@@ -265,6 +241,7 @@ protected:
QRegion m_exposeRegion;
QSize m_oldWindowSize;
QPoint m_lastPointerPosition;
+ QPoint m_lastPointerGlobalPosition;
xcb_visualid_t m_visualId = 0;
// Last sent state. Initialized to an invalid state, on purpose.
@@ -281,13 +258,16 @@ protected:
int m_swapInterval = -1;
qreal m_sizeHintsScaleFactor = 1.0;
+
+ RecreationReasons m_recreationReasons = RecreationNotNeeded;
+
+ QList<QPointer<QXcbWindow>> m_wmTransientForChildren;
};
class QXcbForeignWindow : public QXcbWindow
{
public:
- QXcbForeignWindow(QWindow *window, WId nativeHandle)
- : QXcbWindow(window) { m_window = nativeHandle; }
+ QXcbForeignWindow(QWindow *window, WId nativeHandle);
~QXcbForeignWindow();
bool isForeignWindow() const override { return true; }
@@ -295,7 +275,7 @@ protected:
void create() override {} // No-op
};
-QVector<xcb_rectangle_t> qRegionToXcbRectangleList(const QRegion &region);
+QList<xcb_rectangle_t> qRegionToXcbRectangleList(const QRegion &region);
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/xcb/qxcbwmsupport.cpp b/src/plugins/platforms/xcb/qxcbwmsupport.cpp
index 2619892b19..0e3c470c89 100644
--- a/src/plugins/platforms/xcb/qxcbwmsupport.cpp
+++ b/src/plugins/platforms/xcb/qxcbwmsupport.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qxcbwmsupport.h"
#include "qxcbscreen.h"
@@ -66,7 +30,7 @@ void QXcbWMSupport::updateNetWMAtoms()
int offset = 0;
int remaining = 0;
do {
- auto reply = Q_XCB_REPLY(xcb_get_property, xcb_connection(), false, root, atom(QXcbAtom::_NET_SUPPORTED), XCB_ATOM_ATOM, offset, 1024);
+ auto reply = Q_XCB_REPLY(xcb_get_property, xcb_connection(), false, root, atom(QXcbAtom::Atom_NET_SUPPORTED), XCB_ATOM_ATOM, offset, 1024);
if (!reply)
break;
@@ -90,7 +54,7 @@ void QXcbWMSupport::updateVirtualRoots()
{
net_virtual_roots.clear();
- if (!isSupportedByWM(atom(QXcbAtom::_NET_VIRTUAL_ROOTS)))
+ if (!isSupportedByWM(atom(QXcbAtom::Atom_NET_VIRTUAL_ROOTS)))
return;
xcb_window_t root = connection()->primaryScreen()->root();
@@ -98,7 +62,7 @@ void QXcbWMSupport::updateVirtualRoots()
int remaining = 0;
do {
auto reply = Q_XCB_REPLY(xcb_get_property, xcb_connection(),
- false, root, atom(QXcbAtom::_NET_VIRTUAL_ROOTS), XCB_ATOM_WINDOW, offset, 1024);
+ false, root, atom(QXcbAtom::Atom_NET_VIRTUAL_ROOTS), XCB_ATOM_WINDOW, offset, 1024);
if (!reply)
break;
diff --git a/src/plugins/platforms/xcb/qxcbwmsupport.h b/src/plugins/platforms/xcb/qxcbwmsupport.h
index b5de5b7e5b..77ad55c402 100644
--- a/src/plugins/platforms/xcb/qxcbwmsupport.h
+++ b/src/plugins/platforms/xcb/qxcbwmsupport.h
@@ -1,47 +1,11 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QXCBWMSUPPORT_H
#define QXCBWMSUPPORT_H
#include "qxcbobject.h"
#include "qxcbconnection.h"
-#include <qvector.h>
+#include <qlist.h>
QT_BEGIN_NAMESPACE
@@ -52,15 +16,15 @@ public:
bool isSupportedByWM(xcb_atom_t atom) const;
- const QVector<xcb_window_t> &virtualRoots() const { return net_virtual_roots; }
+ const QList<xcb_window_t> &virtualRoots() const { return net_virtual_roots; }
private:
friend class QXcbConnection;
void updateNetWMAtoms();
void updateVirtualRoots();
- QVector<xcb_atom_t> net_wm_atoms;
- QVector<xcb_window_t> net_virtual_roots;
+ QList<xcb_atom_t> net_wm_atoms;
+ QList<xcb_window_t> net_virtual_roots;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/xcb/qxcbxsettings.cpp b/src/plugins/platforms/xcb/qxcbxsettings.cpp
index 902f196ba9..6b62864add 100644
--- a/src/plugins/platforms/xcb/qxcbxsettings.cpp
+++ b/src/plugins/platforms/xcb/qxcbxsettings.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qxcbxsettings.h"
@@ -104,7 +68,7 @@ public:
int offset = 0;
QByteArray settings;
- xcb_atom_t _xsettings_atom = screen->connection()->atom(QXcbAtom::_XSETTINGS_SETTINGS);
+ xcb_atom_t _xsettings_atom = screen->connection()->atom(QXcbAtom::Atom_XSETTINGS_SETTINGS);
while (1) {
auto reply = Q_XCB_REPLY_UNCHECKED(xcb_get_property,
screen->xcb_connection(),
@@ -140,7 +104,7 @@ public:
void populateSettings(const QByteArray &xSettings)
{
- if (xSettings.length() < 12)
+ if (xSettings.size() < 12)
return;
char byteOrder = xSettings.at(0);
if (byteOrder != XCB_IMAGE_ORDER_LSB_FIRST && byteOrder != XCB_IMAGE_ORDER_MSB_FIRST) {
@@ -228,19 +192,18 @@ QXcbXSettings::QXcbXSettings(QXcbVirtualDesktop *screen)
auto atom_reply = Q_XCB_REPLY(xcb_intern_atom,
screen->xcb_connection(),
true,
- settings_atom_for_screen.length(),
+ settings_atom_for_screen.size(),
settings_atom_for_screen.constData());
if (!atom_reply)
return;
xcb_atom_t selection_owner_atom = atom_reply->atom;
- auto selection_result = Q_XCB_REPLY(xcb_get_selection_owner,
- screen->xcb_connection(), selection_owner_atom);
- if (!selection_result)
+ xcb_window_t owner = screen->connection()->selectionOwner(selection_owner_atom);
+ if (owner == XCB_NONE)
return;
- d_ptr->x_settings_window = selection_result->owner;
+ d_ptr->x_settings_window = owner;
if (!d_ptr->x_settings_window)
return;
diff --git a/src/plugins/platforms/xcb/qxcbxsettings.h b/src/plugins/platforms/xcb/qxcbxsettings.h
index ab1f784274..efcaae8a20 100644
--- a/src/plugins/platforms/xcb/qxcbxsettings.h
+++ b/src/plugins/platforms/xcb/qxcbxsettings.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QXCBXSETTINGS_H
#define QXCBXSETTINGS_H
diff --git a/src/plugins/platforms/xcb/xcb-plugin.pro b/src/plugins/platforms/xcb/xcb-plugin.pro
deleted file mode 100644
index 4c646d42c6..0000000000
--- a/src/plugins/platforms/xcb/xcb-plugin.pro
+++ /dev/null
@@ -1,17 +0,0 @@
-TARGET = qxcb
-
-QT += core-private gui-private xcb_qpa_lib-private
-
-DEFINES += QT_NO_FOREACH
-
-macos: CONFIG += no_app_extension_api_only
-
-SOURCES = \
- qxcbmain.cpp
-
-OTHER_FILES += xcb.json README
-
-PLUGIN_TYPE = platforms
-PLUGIN_CLASS_NAME = QXcbIntegrationPlugin
-!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = -
-load(qt_plugin)
diff --git a/src/plugins/platforms/xcb/xcb.pro b/src/plugins/platforms/xcb/xcb.pro
deleted file mode 100644
index 1c43c5ca04..0000000000
--- a/src/plugins/platforms/xcb/xcb.pro
+++ /dev/null
@@ -1,7 +0,0 @@
-TEMPLATE = subdirs
-CONFIG += ordered
-QT_FOR_CONFIG += gui-private
-
-SUBDIRS += xcb_qpa_lib.pro
-SUBDIRS += xcb-plugin.pro
-SUBDIRS += gl_integrations
diff --git a/src/plugins/platforms/xcb/xcb_qpa_lib.pro b/src/plugins/platforms/xcb/xcb_qpa_lib.pro
deleted file mode 100644
index 1f651e7697..0000000000
--- a/src/plugins/platforms/xcb/xcb_qpa_lib.pro
+++ /dev/null
@@ -1,118 +0,0 @@
-TARGET = QtXcbQpa
-CONFIG += no_module_headers internal_module
-DEFINES += QT_NO_FOREACH
-
-QT += \
- core-private gui-private \
- service_support-private theme_support-private \
- fontdatabase_support-private \
- edid_support-private \
- xkbcommon_support-private
-
-qtHaveModule(platformcompositor_support-private): \
- QT += platformcompositor_support-private
-
-qtHaveModule(linuxaccessibility_support-private): \
- QT += linuxaccessibility_support-private
-
-qtConfig(vulkan): QT += vulkan_support-private
-
-qtConfig(glib) : QMAKE_USE_PRIVATE += glib
-
-SOURCES = \
- qxcbclipboard.cpp \
- qxcbconnection.cpp \
- qxcbintegration.cpp \
- qxcbkeyboard.cpp \
- qxcbmime.cpp \
- qxcbscreen.cpp \
- qxcbwindow.cpp \
- qxcbbackingstore.cpp \
- qxcbwmsupport.cpp \
- qxcbnativeinterface.cpp \
- qxcbcursor.cpp \
- qxcbimage.cpp \
- qxcbxsettings.cpp \
- qxcbsystemtraytracker.cpp \
- qxcbeventqueue.cpp \
- qxcbeventdispatcher.cpp \
- qxcbconnection_basic.cpp \
- qxcbconnection_screens.cpp \
- qxcbconnection_xi2.cpp \
- qxcbatom.cpp
-
-HEADERS = \
- qxcbclipboard.h \
- qxcbconnection.h \
- qxcbintegration.h \
- qxcbkeyboard.h \
- qxcbmime.h \
- qxcbobject.h \
- qxcbscreen.h \
- qxcbwindow.h \
- qxcbbackingstore.h \
- qxcbwmsupport.h \
- qxcbnativeinterface.h \
- qxcbcursor.h \
- qxcbimage.h \
- qxcbxsettings.h \
- qxcbsystemtraytracker.h \
- qxcbeventqueue.h \
- qxcbeventdispatcher.h \
- qxcbconnection_basic.h \
- qxcbatom.h
-
-qtConfig(draganddrop) {
- SOURCES += qxcbdrag.cpp
- HEADERS += qxcbdrag.h
-}
-
-load(qt_build_paths)
-
-DEFINES += QT_BUILD_XCB_PLUGIN
-
-qtConfig(xcb-xlib) {
- QMAKE_USE += xcb_xlib
-}
-
-qtConfig(xcb-sm) {
- QMAKE_USE += x11sm
- SOURCES += qxcbsessionmanager.cpp
- HEADERS += qxcbsessionmanager.h
-}
-
-include(gl_integrations/gl_integrations.pri)
-include(nativepainting/nativepainting.pri)
-
-qtConfig(vulkan) {
- SOURCES += \
- qxcbvulkaninstance.cpp \
- qxcbvulkanwindow.cpp
-
- HEADERS += \
- qxcbvulkaninstance.h \
- qxcbvulkanwindow.h
-}
-
-QMAKE_USE += \
- xcb xcb_icccm xcb_image xcb_keysyms xcb_randr xcb_render xcb_renderutil \
- xcb_shape xcb_shm xcb_sync xcb_xfixes xcb_xinerama xcb_xkb xkbcommon xkbcommon_x11
-
-qtConfig(system-xcb-xinput) {
- QMAKE_USE += xcb_xinput
-} else {
- # Use bundled xcb-xinput sources.
- XCB_DIR = $$QT_SOURCE_TREE/src/3rdparty/xcb
- INCLUDEPATH += $$XCB_DIR/include/
- SOURCES += $$XCB_DIR/libxcb/xinput.c
- # Ignore compiler warnings in 3rdparty C code.
- QMAKE_CFLAGS+=-w
-}
-
-qtConfig(dlopen): QMAKE_USE += libdl
-
-# qxcbkeyboard.cpp's KeyTbl has more than 256 levels of expansion and older
-# Clang uses that as a limit (it's 1024 in current versions).
-clang:!intel_icc: QMAKE_CXXFLAGS += -ftemplate-depth=1024
-
-load(qt_module)
diff --git a/src/plugins/platformthemes/CMakeLists.txt b/src/plugins/platformthemes/CMakeLists.txt
index 6aa17c234c..e5abcd1a11 100644
--- a/src/plugins/platformthemes/CMakeLists.txt
+++ b/src/plugins/platformthemes/CMakeLists.txt
@@ -1,6 +1,8 @@
-# Generated from platformthemes.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
-if(QT_FEATURE_dbus AND QT_FEATURE_mimetype AND QT_FEATURE_regularexpression)
+
+if(QT_FEATURE_dbus AND QT_FEATURE_mimetype AND QT_FEATURE_regularexpression AND UNIX AND NOT APPLE)
add_subdirectory(xdgdesktopportal)
endif()
if(QT_FEATURE_gtk3 AND TARGET Qt::Widgets)
diff --git a/src/plugins/platformthemes/gtk3/.prev_CMakeLists.txt b/src/plugins/platformthemes/gtk3/.prev_CMakeLists.txt
deleted file mode 100644
index 0784de2ca8..0000000000
--- a/src/plugins/platformthemes/gtk3/.prev_CMakeLists.txt
+++ /dev/null
@@ -1,27 +0,0 @@
-# Generated from gtk3.pro.
-
-#####################################################################
-## QGtk3ThemePlugin Plugin:
-#####################################################################
-
-qt_add_plugin(QGtk3ThemePlugin
- OUTPUT_NAME qgtk3
- TYPE platformthemes
- SOURCES
- main.cpp
- qgtk3dialoghelpers.cpp qgtk3dialoghelpers.h
- qgtk3menu.cpp qgtk3menu.h
- qgtk3theme.cpp qgtk3theme.h
- DEFINES
- GDK_VERSION_MIN_REQUIRED=GDK_VERSION_3_6
- PUBLIC_LIBRARIES
- PkgConfig::GTK3
- Qt::Core
- Qt::CorePrivate
- Qt::Gui
- Qt::GuiPrivate
- Qt::ThemeSupportPrivate
-)
-
-#### Keys ignored in scope 1:.:.:gtk3.pro:<TRUE>:
-# PLUGIN_EXTENDS = "-"
diff --git a/src/plugins/platformthemes/gtk3/CMakeLists.txt b/src/plugins/platformthemes/gtk3/CMakeLists.txt
index 4e56e4a6b3..becfcccd35 100644
--- a/src/plugins/platformthemes/gtk3/CMakeLists.txt
+++ b/src/plugins/platformthemes/gtk3/CMakeLists.txt
@@ -1,32 +1,41 @@
-# Generated from gtk3.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
-qt_find_package(GTK3) # special case
-qt_find_package(X11) # special case
+qt_find_package(GTK3)
+
+if(QT_FEATURE_xlib)
+ qt_find_package(X11)
+endif()
#####################################################################
## QGtk3ThemePlugin Plugin:
#####################################################################
-qt_add_plugin(QGtk3ThemePlugin
+qt_internal_add_plugin(QGtk3ThemePlugin
OUTPUT_NAME qgtk3
- TYPE platformthemes
+ PLUGIN_TYPE platformthemes
+ DEFAULT_IF FALSE
SOURCES
main.cpp
qgtk3dialoghelpers.cpp qgtk3dialoghelpers.h
qgtk3menu.cpp qgtk3menu.h
qgtk3theme.cpp qgtk3theme.h
+ qgtk3interface.cpp qgtk3interface_p.h
+ qgtk3storage.cpp qgtk3storage_p.h
+ qgtk3json.cpp qgtk3json_p.h
+ NO_PCH_SOURCES
+ qgtk3dialoghelpers.cpp # undef QT_NO_FOREACH
DEFINES
GDK_VERSION_MIN_REQUIRED=GDK_VERSION_3_6
- LIBRARIES # special case
- X11::X11 # special case
- PUBLIC_LIBRARIES
+ LIBRARIES
PkgConfig::GTK3
Qt::Core
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
- Qt::ThemeSupportPrivate
)
-#### Keys ignored in scope 1:.:.:gtk3.pro:<TRUE>:
-# PLUGIN_EXTENDS = "-"
+qt_internal_extend_target(QGtk3ThemePlugin CONDITION QT_FEATURE_xlib
+ LIBRARIES
+ X11::X11
+)
diff --git a/src/plugins/platformthemes/gtk3/gtk3.pro b/src/plugins/platformthemes/gtk3/gtk3.pro
deleted file mode 100644
index cac6f7054d..0000000000
--- a/src/plugins/platformthemes/gtk3/gtk3.pro
+++ /dev/null
@@ -1,23 +0,0 @@
-TARGET = qgtk3
-
-PLUGIN_TYPE = platformthemes
-PLUGIN_EXTENDS = -
-PLUGIN_CLASS_NAME = QGtk3ThemePlugin
-load(qt_plugin)
-
-QT += core-private gui-private theme_support-private
-
-CONFIG += X11
-QMAKE_USE += gtk3
-DEFINES += GDK_VERSION_MIN_REQUIRED=GDK_VERSION_3_6
-
-HEADERS += \
- qgtk3dialoghelpers.h \
- qgtk3menu.h \
- qgtk3theme.h
-
-SOURCES += \
- main.cpp \
- qgtk3dialoghelpers.cpp \
- qgtk3menu.cpp \
- qgtk3theme.cpp
diff --git a/src/plugins/platformthemes/gtk3/main.cpp b/src/plugins/platformthemes/gtk3/main.cpp
index 860fc3a26e..569c2d8744 100644
--- a/src/plugins/platformthemes/gtk3/main.cpp
+++ b/src/plugins/platformthemes/gtk3/main.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <qpa/qplatformthemeplugin.h>
#include "qgtk3theme.h"
@@ -54,7 +18,7 @@ public:
QPlatformTheme *QGtk3ThemePlugin::create(const QString &key, const QStringList &params)
{
Q_UNUSED(params);
- if (!key.compare(QLatin1String(QGtk3Theme::name), Qt::CaseInsensitive))
+ if (!key.compare(QLatin1StringView(QGtk3Theme::name), Qt::CaseInsensitive))
return new QGtk3Theme;
return nullptr;
diff --git a/src/plugins/platformthemes/gtk3/qgtk3dialoghelpers.cpp b/src/plugins/platformthemes/gtk3/qgtk3dialoghelpers.cpp
index 65564b59a1..08419ec7dc 100644
--- a/src/plugins/platformthemes/gtk3/qgtk3dialoghelpers.cpp
+++ b/src/plugins/platformthemes/gtk3/qgtk3dialoghelpers.cpp
@@ -1,41 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#undef QT_NO_FOREACH // this file contains unported legacy Q_FOREACH uses
#include "qgtk3dialoghelpers.h"
#include "qgtk3theme.h"
@@ -45,24 +11,42 @@
#include <qcolor.h>
#include <qdebug.h>
#include <qfont.h>
+#include <qfileinfo.h>
#include <private/qguiapplication_p.h>
+#include <private/qgenericunixservices_p.h>
+#include <qpa/qplatformintegration.h>
#include <qpa/qplatformfontdatabase.h>
#undef signals
#include <gtk/gtk.h>
#include <gdk/gdk.h>
-#include <gdk/gdkx.h>
#include <pango/pango.h>
+#if QT_CONFIG(xlib) && defined(GDK_WINDOWING_X11)
+#include <gdk/gdkx.h>
+#endif
+
+#ifdef GDK_WINDOWING_WAYLAND
+#include <gdk/gdkwayland.h>
+#endif
+
+// The size of the preview we display for selected image files. We set height
+// larger than width because generally there is more free space vertically
+// than horizontally (setting the preview image will always expand the width of
+// the dialog, but usually not the height). The image's aspect ratio will always
+// be preserved.
+#define PREVIEW_WIDTH 256
+#define PREVIEW_HEIGHT 512
+
QT_BEGIN_NAMESPACE
-class QGtk3Dialog : public QWindow
-{
- Q_OBJECT
+using namespace Qt::StringLiterals;
+class QGtk3Dialog
+{
public:
- QGtk3Dialog(GtkWidget *gtkWidget);
+ QGtk3Dialog(GtkWidget *gtkWidget, QPlatformDialogHelper *helper);
~QGtk3Dialog();
GtkDialog *gtkDialog() const;
@@ -71,23 +55,20 @@ public:
bool show(Qt::WindowFlags flags, Qt::WindowModality modality, QWindow *parent);
void hide();
-Q_SIGNALS:
- void accept();
- void reject();
-
protected:
- static void onResponse(QGtk3Dialog *dialog, int response);
-
-private slots:
- void onParentWindowDestroyed();
+ static void onResponse(QPlatformDialogHelper *helper, int response);
private:
GtkWidget *gtkWidget;
+ QPlatformDialogHelper *helper;
+ Qt::WindowModality modality;
};
-QGtk3Dialog::QGtk3Dialog(GtkWidget *gtkWidget) : gtkWidget(gtkWidget)
+QGtk3Dialog::QGtk3Dialog(GtkWidget *gtkWidget, QPlatformDialogHelper *helper)
+ : gtkWidget(gtkWidget)
+ , helper(helper)
{
- g_signal_connect_swapped(G_OBJECT(gtkWidget), "response", G_CALLBACK(onResponse), this);
+ g_signal_connect_swapped(G_OBJECT(gtkWidget), "response", G_CALLBACK(onResponse), helper);
g_signal_connect(G_OBJECT(gtkWidget), "delete-event", G_CALLBACK(gtk_widget_hide_on_delete), NULL);
}
@@ -104,43 +85,52 @@ GtkDialog *QGtk3Dialog::gtkDialog() const
void QGtk3Dialog::exec()
{
- if (modality() == Qt::ApplicationModal) {
+ if (modality == Qt::ApplicationModal) {
// block input to the whole app, including other GTK dialogs
gtk_dialog_run(gtkDialog());
} else {
// block input to the window, allow input to other GTK dialogs
QEventLoop loop;
- connect(this, SIGNAL(accept()), &loop, SLOT(quit()));
- connect(this, SIGNAL(reject()), &loop, SLOT(quit()));
+ loop.connect(helper, SIGNAL(accept()), SLOT(quit()));
+ loop.connect(helper, SIGNAL(reject()), SLOT(quit()));
loop.exec();
}
}
bool QGtk3Dialog::show(Qt::WindowFlags flags, Qt::WindowModality modality, QWindow *parent)
{
- if (parent) {
- connect(parent, &QWindow::destroyed, this, &QGtk3Dialog::onParentWindowDestroyed,
- Qt::UniqueConnection);
- }
- setParent(parent);
- setFlags(flags);
- setModality(modality);
+ Q_UNUSED(flags);
+ this->modality = modality;
gtk_widget_realize(gtkWidget); // creates X window
GdkWindow *gdkWindow = gtk_widget_get_window(gtkWidget);
if (parent) {
- if (GDK_IS_X11_WINDOW(gdkWindow)) {
+ if (false) {
+#if defined(GDK_WINDOWING_WAYLAND) && GTK_CHECK_VERSION(3, 22, 0)
+ } else if (GDK_IS_WAYLAND_WINDOW(gdkWindow)) {
+ const auto unixServices = dynamic_cast<QGenericUnixServices *>(
+ QGuiApplicationPrivate::platformIntegration()->services());
+ if (unixServices) {
+ const auto handle = unixServices->portalWindowIdentifier(parent);
+ if (handle.startsWith("wayland:"_L1)) {
+ auto handleBa = handle.sliced(8).toUtf8();
+ gdk_wayland_window_set_transient_for_exported(gdkWindow, handleBa.data());
+ }
+ }
+#endif
+#if QT_CONFIG(xlib) && defined(GDK_WINDOWING_X11)
+ } else if (GDK_IS_X11_WINDOW(gdkWindow)) {
GdkDisplay *gdkDisplay = gdk_window_get_display(gdkWindow);
XSetTransientForHint(gdk_x11_display_get_xdisplay(gdkDisplay),
gdk_x11_window_get_xid(gdkWindow),
parent->winId());
+#endif
}
}
if (modality != Qt::NonModal) {
gdk_window_set_modal_hint(gdkWindow, true);
- QGuiApplicationPrivate::showModalWindow(this);
}
gtk_widget_show(gtkWidget);
@@ -150,30 +140,20 @@ bool QGtk3Dialog::show(Qt::WindowFlags flags, Qt::WindowModality modality, QWind
void QGtk3Dialog::hide()
{
- QGuiApplicationPrivate::hideModalWindow(this);
gtk_widget_hide(gtkWidget);
}
-void QGtk3Dialog::onResponse(QGtk3Dialog *dialog, int response)
+void QGtk3Dialog::onResponse(QPlatformDialogHelper *helper, int response)
{
if (response == GTK_RESPONSE_OK)
- emit dialog->accept();
+ emit helper->accept();
else
- emit dialog->reject();
-}
-
-void QGtk3Dialog::onParentWindowDestroyed()
-{
- // The QGtk3*DialogHelper classes own this object. Make sure the parent doesn't delete it.
- setParent(nullptr);
+ emit helper->reject();
}
QGtk3ColorDialogHelper::QGtk3ColorDialogHelper()
{
- d.reset(new QGtk3Dialog(gtk_color_chooser_dialog_new("", nullptr)));
- connect(d.data(), SIGNAL(accept()), this, SLOT(onAccepted()));
- connect(d.data(), SIGNAL(reject()), this, SIGNAL(reject()));
-
+ d.reset(new QGtk3Dialog(gtk_color_chooser_dialog_new("", nullptr), this));
g_signal_connect_swapped(d->gtkDialog(), "notify::rgba", G_CALLBACK(onColorChanged), this);
}
@@ -218,11 +198,6 @@ QColor QGtk3ColorDialogHelper::currentColor() const
return QColor::fromRgbF(gdkColor.red, gdkColor.green, gdkColor.blue, gdkColor.alpha);
}
-void QGtk3ColorDialogHelper::onAccepted()
-{
- emit accept();
-}
-
void QGtk3ColorDialogHelper::onColorChanged(QGtk3ColorDialogHelper *dialog)
{
emit dialog->currentColorChanged(dialog->currentColor());
@@ -242,14 +217,15 @@ QGtk3FileDialogHelper::QGtk3FileDialogHelper()
GTK_FILE_CHOOSER_ACTION_OPEN,
qUtf8Printable(QGtk3Theme::defaultStandardButtonText(QPlatformDialogHelper::Cancel)), GTK_RESPONSE_CANCEL,
qUtf8Printable(QGtk3Theme::defaultStandardButtonText(QPlatformDialogHelper::Ok)), GTK_RESPONSE_OK,
- NULL)));
-
- connect(d.data(), SIGNAL(accept()), this, SLOT(onAccepted()));
- connect(d.data(), SIGNAL(reject()), this, SIGNAL(reject()));
+ NULL), this));
g_signal_connect(GTK_FILE_CHOOSER(d->gtkDialog()), "selection-changed", G_CALLBACK(onSelectionChanged), this);
g_signal_connect_swapped(GTK_FILE_CHOOSER(d->gtkDialog()), "current-folder-changed", G_CALLBACK(onCurrentFolderChanged), this);
g_signal_connect_swapped(GTK_FILE_CHOOSER(d->gtkDialog()), "notify::filter", G_CALLBACK(onFilterChanged), this);
+
+ previewWidget = gtk_image_new();
+ g_signal_connect(G_OBJECT(d->gtkDialog()), "update-preview", G_CALLBACK(onUpdatePreview), this);
+ gtk_file_chooser_set_preview_widget(GTK_FILE_CHOOSER(d->gtkDialog()), previewWidget);
}
QGtk3FileDialogHelper::~QGtk3FileDialogHelper()
@@ -364,11 +340,6 @@ QString QGtk3FileDialogHelper::selectedNameFilter() const
return _filterNames.value(gtkFilter);
}
-void QGtk3FileDialogHelper::onAccepted()
-{
- emit accept();
-}
-
void QGtk3FileDialogHelper::onSelectionChanged(GtkDialog *gtkDialog, QGtk3FileDialogHelper *helper)
{
QString selection;
@@ -390,6 +361,33 @@ void QGtk3FileDialogHelper::onFilterChanged(QGtk3FileDialogHelper *dialog)
emit dialog->filterSelected(dialog->selectedNameFilter());
}
+void QGtk3FileDialogHelper::onUpdatePreview(GtkDialog *gtkDialog, QGtk3FileDialogHelper *helper)
+{
+ gchar *filename = gtk_file_chooser_get_preview_filename(GTK_FILE_CHOOSER(gtkDialog));
+ if (!filename) {
+ gtk_file_chooser_set_preview_widget_active(GTK_FILE_CHOOSER(gtkDialog), false);
+ return;
+ }
+
+ // Don't attempt to open anything which isn't a regular file. If a named pipe,
+ // this may hang.
+ QFileInfo fileinfo(filename);
+ if (!fileinfo.exists() || !fileinfo.isFile()) {
+ g_free(filename);
+ gtk_file_chooser_set_preview_widget_active(GTK_FILE_CHOOSER(gtkDialog), false);
+ return;
+ }
+
+ // This will preserve the image's aspect ratio.
+ GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file_at_size(filename, PREVIEW_WIDTH, PREVIEW_HEIGHT, 0);
+ g_free(filename);
+ if (pixbuf) {
+ gtk_image_set_from_pixbuf(GTK_IMAGE(helper->previewWidget), pixbuf);
+ g_object_unref(pixbuf);
+ }
+ gtk_file_chooser_set_preview_widget_active(GTK_FILE_CHOOSER(gtkDialog), pixbuf ? true : false);
+}
+
static GtkFileChooserAction gtkFileChooserAction(const QSharedPointer<QFileDialogOptions> &options)
{
switch (options->fileMode()) {
@@ -481,10 +479,10 @@ void QGtk3FileDialogHelper::setNameFilters(const QStringList &filters)
foreach (const QString &filter, filters) {
GtkFileFilter *gtkFilter = gtk_file_filter_new();
- const QString name = filter.left(filter.indexOf(QLatin1Char('(')));
+ const QString name = filter.left(filter.indexOf(u'('));
const QStringList extensions = cleanFilterList(filter);
- gtk_file_filter_set_name(gtkFilter, qUtf8Printable(name.isEmpty() ? extensions.join(QLatin1String(", ")) : name));
+ gtk_file_filter_set_name(gtkFilter, qUtf8Printable(name.isEmpty() ? extensions.join(", "_L1) : name));
foreach (const QString &ext, extensions)
gtk_file_filter_add_pattern(gtkFilter, qUtf8Printable(ext));
@@ -497,10 +495,7 @@ void QGtk3FileDialogHelper::setNameFilters(const QStringList &filters)
QGtk3FontDialogHelper::QGtk3FontDialogHelper()
{
- d.reset(new QGtk3Dialog(gtk_font_chooser_dialog_new("", nullptr)));
- connect(d.data(), SIGNAL(accept()), this, SLOT(onAccepted()));
- connect(d.data(), SIGNAL(reject()), this, SIGNAL(reject()));
-
+ d.reset(new QGtk3Dialog(gtk_font_chooser_dialog_new("", nullptr), this));
g_signal_connect_swapped(d->gtkDialog(), "notify::font", G_CALLBACK(onFontChanged), this);
}
@@ -573,10 +568,9 @@ static QFont qt_fontFromString(const QString &name)
QString family = QString::fromUtf8(pango_font_description_get_family(desc));
if (!family.isEmpty())
- font.setFamily(family);
+ font.setFamilies(QStringList{family});
- const int weight = pango_font_description_get_weight(desc);
- font.setWeight(QPlatformFontDatabase::weightFromInteger(weight));
+ font.setWeight(QFont::Weight(pango_font_description_get_weight(desc)));
PangoStyle style = pango_font_description_get_style(desc);
if (style == PANGO_STYLE_ITALIC)
@@ -605,11 +599,6 @@ QFont QGtk3FontDialogHelper::currentFont() const
return font;
}
-void QGtk3FontDialogHelper::onAccepted()
-{
- emit accept();
-}
-
void QGtk3FontDialogHelper::onFontChanged(QGtk3FontDialogHelper *dialog)
{
emit dialog->currentFontChanged(dialog->currentFont());
@@ -625,4 +614,4 @@ void QGtk3FontDialogHelper::applyOptions()
QT_END_NAMESPACE
-#include "qgtk3dialoghelpers.moc"
+#include "moc_qgtk3dialoghelpers.cpp"
diff --git a/src/plugins/platformthemes/gtk3/qgtk3dialoghelpers.h b/src/plugins/platformthemes/gtk3/qgtk3dialoghelpers.h
index e78a7fc6d1..89f48d8b01 100644
--- a/src/plugins/platformthemes/gtk3/qgtk3dialoghelpers.h
+++ b/src/plugins/platformthemes/gtk3/qgtk3dialoghelpers.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QGTK3DIALOGHELPERS_H
#define QGTK3DIALOGHELPERS_H
@@ -47,6 +11,7 @@
#include <QtCore/qstring.h>
#include <qpa/qplatformdialoghelper.h>
+typedef struct _GtkWidget GtkWidget;
typedef struct _GtkDialog GtkDialog;
typedef struct _GtkFileFilter GtkFileFilter;
@@ -70,9 +35,6 @@ public:
void setCurrentColor(const QColor &color) override;
QColor currentColor() const override;
-private Q_SLOTS:
- void onAccepted();
-
private:
static void onColorChanged(QGtk3ColorDialogHelper *helper);
void applyOptions();
@@ -101,13 +63,11 @@ public:
void selectNameFilter(const QString &filter) override;
QString selectedNameFilter() const override;
-private Q_SLOTS:
- void onAccepted();
-
private:
static void onSelectionChanged(GtkDialog *dialog, QGtk3FileDialogHelper *helper);
static void onCurrentFolderChanged(QGtk3FileDialogHelper *helper);
static void onFilterChanged(QGtk3FileDialogHelper *helper);
+ static void onUpdatePreview(GtkDialog *dialog, QGtk3FileDialogHelper *helper);
void applyOptions();
void setNameFilters(const QStringList &filters);
void selectFileInternal(const QUrl &filename);
@@ -118,6 +78,7 @@ private:
QHash<QString, GtkFileFilter*> _filters;
QHash<GtkFileFilter*, QString> _filterNames;
QScopedPointer<QGtk3Dialog> d;
+ GtkWidget *previewWidget;
};
class QGtk3FontDialogHelper : public QPlatformFontDialogHelper
@@ -135,9 +96,6 @@ public:
void setCurrentFont(const QFont &font) override;
QFont currentFont() const override;
-private Q_SLOTS:
- void onAccepted();
-
private:
static void onFontChanged(QGtk3FontDialogHelper *helper);
void applyOptions();
diff --git a/src/plugins/platformthemes/gtk3/qgtk3interface.cpp b/src/plugins/platformthemes/gtk3/qgtk3interface.cpp
new file mode 100644
index 0000000000..a35e211fbf
--- /dev/null
+++ b/src/plugins/platformthemes/gtk3/qgtk3interface.cpp
@@ -0,0 +1,702 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+//
+// 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 "qgtk3interface_p.h"
+#include "qgtk3storage_p.h"
+#include <QtCore/QMetaEnum>
+#include <QtCore/QFileInfo>
+#include <QtGui/QFontDatabase>
+
+QT_BEGIN_NAMESPACE
+Q_LOGGING_CATEGORY(lcQGtk3Interface, "qt.qpa.gtk");
+
+
+// Callback for gnome event loop has to be static
+static QGtk3Storage *m_storage = nullptr;
+
+QGtk3Interface::QGtk3Interface(QGtk3Storage *s)
+{
+ initColorMap();
+
+ if (!s) {
+ qCDebug(lcQGtk3Interface) << "QGtk3Interface instantiated without QGtk3Storage."
+ << "No reaction to runtime theme changes.";
+ return;
+ }
+
+ // Connect to the GTK settings changed signal
+ auto handleThemeChange = [] {
+ if (m_storage)
+ m_storage->handleThemeChange();
+ };
+
+ GtkSettings *settings = gtk_settings_get_default();
+ const gboolean success = g_signal_connect(settings, "notify::gtk-theme-name",
+ G_CALLBACK(handleThemeChange), nullptr);
+ if (success == FALSE) {
+ qCDebug(lcQGtk3Interface) << "Connection to theme change signal failed."
+ << "No reaction to runtime theme changes.";
+ } else {
+ m_storage = s;
+ }
+}
+
+QGtk3Interface::~QGtk3Interface()
+{
+ // Ignore theme changes when destructor is reached
+ m_storage = nullptr;
+
+ // QGtkWidgets have to be destroyed manually
+ for (auto v : cache)
+ gtk_widget_destroy(v.second);
+}
+
+/*!
+ \internal
+ \brief Converts a string into the GtkStateFlags enum.
+
+ Converts a string formatted GTK color \param state into an enum value.
+ Returns an integer corresponding to GtkStateFlags.
+ Returns -1 if \param state does not correspond to a valid enum key.
+ */
+int QGtk3Interface::toGtkState(const QString &state)
+{
+#define CASE(x) \
+ if (QLatin1String(QByteArray(state.toLatin1())) == #x ##_L1) \
+ return GTK_STATE_FLAG_ ##x
+
+#define CONVERT\
+ CASE(NORMAL);\
+ CASE(ACTIVE);\
+ CASE(PRELIGHT);\
+ CASE(SELECTED);\
+ CASE(INSENSITIVE);\
+ CASE(INCONSISTENT);\
+ CASE(FOCUSED);\
+ CASE(BACKDROP);\
+ CASE(DIR_LTR);\
+ CASE(DIR_RTL);\
+ CASE(LINK);\
+ CASE(VISITED);\
+ CASE(CHECKED);\
+ CASE(DROP_ACTIVE)
+
+ CONVERT;
+ return -1;
+#undef CASE
+}
+
+/*!
+ \internal
+ \brief Returns \param state converted into a string.
+ */
+const QLatin1String QGtk3Interface::fromGtkState(GtkStateFlags state)
+{
+#define CASE(x) case GTK_STATE_FLAG_ ##x: return QLatin1String(#x)
+ switch (state) {
+ CONVERT;
+ }
+ Q_UNREACHABLE();
+#undef CASE
+#undef CONVERT
+}
+
+/*!
+ \internal
+ \brief Populates the internal map used to find a GTK color's source and fallback generic color.
+ */
+void QGtk3Interface::initColorMap()
+{
+ #define SAVE(src, state, prop, def)\
+ {ColorKey({QGtkColorSource::src, GTK_STATE_FLAG_ ##state}), ColorValue({#prop ##_L1, QGtkColorDefault::def})}
+
+ gtkColorMap = ColorMap {
+ SAVE(Foreground, NORMAL, theme_fg_color, Foreground),
+ SAVE(Foreground, BACKDROP, theme_unfocused_selected_fg_color, Foreground),
+ SAVE(Foreground, INSENSITIVE, insensitive_fg_color, Foreground),
+ SAVE(Foreground, SELECTED, theme_selected_fg_color, Foreground),
+ SAVE(Foreground, ACTIVE, theme_unfocused_fg_color, Foreground),
+ SAVE(Text, NORMAL, theme_text_color, Foreground),
+ SAVE(Text, ACTIVE, theme_unfocused_text_color, Foreground),
+ SAVE(Base, NORMAL, theme_base_color, Background),
+ SAVE(Base, INSENSITIVE, insensitive_base_color, Background),
+ SAVE(Background, NORMAL, theme_bg_color, Background),
+ SAVE(Background, SELECTED, theme_selected_bg_color, Background),
+ SAVE(Background, INSENSITIVE, insensitive_bg_color, Background),
+ SAVE(Background, ACTIVE, theme_unfocused_bg_color, Background),
+ SAVE(Background, BACKDROP, theme_unfocused_selected_bg_color, Background),
+ SAVE(Border, NORMAL, borders, Border),
+ SAVE(Border, ACTIVE, unfocused_borders, Border)
+ };
+#undef SAVE
+
+ qCDebug(lcQGtk3Interface) << "Color map populated from defaults.";
+}
+
+/*!
+ \internal
+ \brief Returns a QImage corresponding to \param standardPixmap.
+
+ A QImage (not a QPixmap) is returned so it can be cached and re-scaled in case the pixmap is
+ requested multiple times with different resolutions.
+
+ \note Rather than defaulting to a QImage(), all QPlatformTheme::StandardPixmap enum values have
+ been mentioned explicitly.
+ That way they can be covered more easily in case additional icons are provided by GTK.
+ */
+QImage QGtk3Interface::standardPixmap(QPlatformTheme::StandardPixmap standardPixmap) const
+{
+ switch (standardPixmap) {
+ case QPlatformTheme::DialogDiscardButton:
+ return qt_gtk_get_icon(GTK_STOCK_DELETE);
+ case QPlatformTheme::DialogOkButton:
+ return qt_gtk_get_icon(GTK_STOCK_OK);
+ case QPlatformTheme::DialogCancelButton:
+ return qt_gtk_get_icon(GTK_STOCK_CANCEL);
+ case QPlatformTheme::DialogYesButton:
+ return qt_gtk_get_icon(GTK_STOCK_YES);
+ case QPlatformTheme::DialogNoButton:
+ return qt_gtk_get_icon(GTK_STOCK_NO);
+ case QPlatformTheme::DialogOpenButton:
+ return qt_gtk_get_icon(GTK_STOCK_OPEN);
+ case QPlatformTheme::DialogCloseButton:
+ return qt_gtk_get_icon(GTK_STOCK_CLOSE);
+ case QPlatformTheme::DialogApplyButton:
+ return qt_gtk_get_icon(GTK_STOCK_APPLY);
+ case QPlatformTheme::DialogSaveButton:
+ return qt_gtk_get_icon(GTK_STOCK_SAVE);
+ case QPlatformTheme::MessageBoxWarning:
+ return qt_gtk_get_icon(GTK_STOCK_DIALOG_WARNING);
+ case QPlatformTheme::MessageBoxQuestion:
+ return qt_gtk_get_icon(GTK_STOCK_DIALOG_QUESTION);
+ case QPlatformTheme::MessageBoxInformation:
+ return qt_gtk_get_icon(GTK_STOCK_DIALOG_INFO);
+ case QPlatformTheme::MessageBoxCritical:
+ return qt_gtk_get_icon(GTK_STOCK_DIALOG_ERROR);
+ case QPlatformTheme::CustomBase:
+ case QPlatformTheme::TitleBarMenuButton:
+ case QPlatformTheme::TitleBarMinButton:
+ case QPlatformTheme::TitleBarMaxButton:
+ case QPlatformTheme::TitleBarCloseButton:
+ case QPlatformTheme::TitleBarNormalButton:
+ case QPlatformTheme::TitleBarShadeButton:
+ case QPlatformTheme::TitleBarUnshadeButton:
+ case QPlatformTheme::TitleBarContextHelpButton:
+ case QPlatformTheme::DockWidgetCloseButton:
+ case QPlatformTheme::DesktopIcon:
+ case QPlatformTheme::TrashIcon:
+ case QPlatformTheme::ComputerIcon:
+ case QPlatformTheme::DriveFDIcon:
+ case QPlatformTheme::DriveHDIcon:
+ case QPlatformTheme::DriveCDIcon:
+ case QPlatformTheme::DriveDVDIcon:
+ case QPlatformTheme::DriveNetIcon:
+ case QPlatformTheme::DirOpenIcon:
+ case QPlatformTheme::DirClosedIcon:
+ case QPlatformTheme::DirLinkIcon:
+ case QPlatformTheme::DirLinkOpenIcon:
+ case QPlatformTheme::FileIcon:
+ case QPlatformTheme::FileLinkIcon:
+ case QPlatformTheme::ToolBarHorizontalExtensionButton:
+ case QPlatformTheme::ToolBarVerticalExtensionButton:
+ case QPlatformTheme::FileDialogStart:
+ case QPlatformTheme::FileDialogEnd:
+ case QPlatformTheme::FileDialogToParent:
+ case QPlatformTheme::FileDialogNewFolder:
+ case QPlatformTheme::FileDialogDetailedView:
+ case QPlatformTheme::FileDialogInfoView:
+ case QPlatformTheme::FileDialogContentsView:
+ case QPlatformTheme::FileDialogListView:
+ case QPlatformTheme::FileDialogBack:
+ case QPlatformTheme::DirIcon:
+ case QPlatformTheme::DialogHelpButton:
+ case QPlatformTheme::DialogResetButton:
+ case QPlatformTheme::ArrowUp:
+ case QPlatformTheme::ArrowDown:
+ case QPlatformTheme::ArrowLeft:
+ case QPlatformTheme::ArrowRight:
+ case QPlatformTheme::ArrowBack:
+ case QPlatformTheme::ArrowForward:
+ case QPlatformTheme::DirHomeIcon:
+ case QPlatformTheme::CommandLink:
+ case QPlatformTheme::VistaShield:
+ case QPlatformTheme::BrowserReload:
+ case QPlatformTheme::BrowserStop:
+ case QPlatformTheme::MediaPlay:
+ case QPlatformTheme::MediaStop:
+ case QPlatformTheme::MediaPause:
+ case QPlatformTheme::MediaSkipForward:
+ case QPlatformTheme::MediaSkipBackward:
+ case QPlatformTheme::MediaSeekForward:
+ case QPlatformTheme::MediaSeekBackward:
+ case QPlatformTheme::MediaVolume:
+ case QPlatformTheme::MediaVolumeMuted:
+ case QPlatformTheme::LineEditClearButton:
+ case QPlatformTheme::DialogYesToAllButton:
+ case QPlatformTheme::DialogNoToAllButton:
+ case QPlatformTheme::DialogSaveAllButton:
+ case QPlatformTheme::DialogAbortButton:
+ case QPlatformTheme::DialogRetryButton:
+ case QPlatformTheme::DialogIgnoreButton:
+ case QPlatformTheme::RestoreDefaultsButton:
+ case QPlatformTheme::TabCloseButton:
+ case QPlatformTheme::NStandardPixmap:
+ return QImage();
+ }
+ Q_UNREACHABLE();
+}
+
+/*!
+ \internal
+ \brief Returns a QImage for a given GTK \param iconName.
+ */
+QImage QGtk3Interface::qt_gtk_get_icon(const char* iconName) const
+{
+ GtkIconSet* iconSet = gtk_icon_factory_lookup_default (iconName);
+ GdkPixbuf* icon = gtk_icon_set_render_icon_pixbuf(iconSet, context(), GTK_ICON_SIZE_DIALOG);
+ return qt_convert_gdk_pixbuf(icon);
+}
+
+/*!
+ \internal
+ \brief Returns a QImage converted from the GDK pixel buffer \param buf.
+
+ The ability to convert GdkPixbuf to QImage relies on the following assumptions:
+ \list
+ \li QImage uses uchar as a data container (unasserted)
+ \li the types guint8 and uchar are identical (statically asserted)
+ \li GDK pixel buffer uses 8 bits per sample (assumed at runtime)
+ \li GDK pixel buffer has 4 channels (assumed at runtime)
+ \endlist
+ */
+QImage QGtk3Interface::qt_convert_gdk_pixbuf(GdkPixbuf *buf) const
+{
+ if (!buf)
+ return QImage();
+
+ const guint8 *gdata = gdk_pixbuf_read_pixels(buf);
+ static_assert(std::is_same<decltype(gdata), const uchar *>::value,
+ "guint8 has diverted from uchar. Code needs fixing.");
+ Q_ASSERT(gdk_pixbuf_get_bits_per_sample(buf) == 8);
+ Q_ASSERT(gdk_pixbuf_get_n_channels(buf) == 4);
+ const uchar *data = static_cast<const uchar *>(gdata);
+
+ const int width = gdk_pixbuf_get_width(buf);
+ const int height = gdk_pixbuf_get_height(buf);
+ const int bpl = gdk_pixbuf_get_rowstride(buf);
+ QImage converted(data, width, height, bpl, QImage::Format_RGBA8888);
+
+ // convert to more optimal format and detach to survive lifetime of buf
+ return converted.convertToFormat(QImage::Format_ARGB32_Premultiplied);
+}
+
+/*!
+ \internal
+ \brief Instantiate a new GTK widget.
+
+ Returns a pointer to a new GTK widget of \param type, allocated on the heap.
+ Returns nullptr of gtk_Default has is passed.
+ */
+GtkWidget *QGtk3Interface::qt_new_gtkWidget(QGtkWidget type) const
+{
+#define CASE(Type)\
+ case QGtkWidget::Type: return Type ##_new();
+#define CASEN(Type)\
+ case QGtkWidget::Type: return Type ##_new(nullptr);
+
+ switch (type) {
+ CASE(gtk_menu_bar)
+ CASE(gtk_menu)
+ CASE(gtk_button)
+ case QGtkWidget::gtk_button_box: return gtk_button_box_new(GtkOrientation::GTK_ORIENTATION_HORIZONTAL);
+ CASE(gtk_check_button)
+ CASEN(gtk_radio_button)
+ CASEN(gtk_frame)
+ CASE(gtk_statusbar)
+ CASE(gtk_entry)
+ case QGtkWidget::gtk_popup: return gtk_window_new(GTK_WINDOW_POPUP);
+ CASE(gtk_notebook)
+ CASE(gtk_toolbar)
+ CASE(gtk_tree_view)
+ CASE(gtk_combo_box)
+ CASE(gtk_combo_box_text)
+ CASE(gtk_progress_bar)
+ CASE(gtk_fixed)
+ CASE(gtk_separator_menu_item)
+ CASE(gtk_offscreen_window)
+ case QGtkWidget::gtk_Default: return nullptr;
+ }
+#undef CASE
+#undef CASEN
+ Q_UNREACHABLE();
+}
+
+/*!
+ \internal
+ \brief Read a GTK widget's color from a generic color getter.
+
+ This method returns a generic color of \param con, a given GTK style context.
+ The requested color is defined by \param def and the GTK color-state \param state.
+ The return type is GDK color in RGBA format.
+ */
+GdkRGBA QGtk3Interface::genericColor(GtkStyleContext *con, GtkStateFlags state, QGtkColorDefault def) const
+{
+ GdkRGBA color;
+
+#define CASE(def, call)\
+ case QGtkColorDefault::def:\
+ gtk_style_context_get_ ##call(con, state, &color);\
+ break;
+
+ switch (def) {
+ CASE(Foreground, color)
+ CASE(Background, background_color)
+ CASE(Border, border_color)
+ }
+ return color;
+#undef CASE
+}
+
+/*!
+ \internal
+ \brief Read a GTK widget's color from a property.
+
+ Returns a color of GTK-widget \param widget, defined by \param source and \param state.
+ The return type is GDK color in RGBA format.
+
+ \note If no corresponding property can be found for \param source, the method falls back to a
+ suitable generic color.
+ */
+QColor QGtk3Interface::color(GtkWidget *widget, QGtkColorSource source, GtkStateFlags state) const
+{
+ GdkRGBA col;
+ GtkStyleContext *con = context(widget);
+
+#define CASE(src, def)\
+ case QGtkColorSource::src: {\
+ const ColorKey key = ColorKey({QGtkColorSource::src, state});\
+ if (gtkColorMap.contains(key)) {\
+ const ColorValue val = gtkColorMap.value(key);\
+ if (!gtk_style_context_lookup_color(con, val.propertyName.toUtf8().constData(), &col)) {\
+ col = genericColor(con, state, val.genericSource);\
+ qCDebug(lcQGtk3Interface) << "Property name" << val.propertyName << "not found.\n"\
+ << "Falling back to " << val.genericSource;\
+ }\
+ } else {\
+ col = genericColor(con, state, QGtkColorDefault::def);\
+ qCDebug(lcQGtk3Interface) << "No color source found for" << QGtkColorSource::src\
+ << fromGtkState(state) << "\n Falling back to"\
+ << QGtkColorDefault::def;\
+ }\
+ }\
+ break;
+
+ switch (source) {
+ CASE(Foreground, Foreground)
+ CASE(Background, Background)
+ CASE(Text, Foreground)
+ CASE(Base, Background)
+ CASE(Border, Border)
+ }
+
+ return fromGdkColor(col);
+#undef CASE
+}
+
+/*!
+ \internal
+ \brief Get pointer to a GTK widget by \param type.
+
+ Returns the pointer to a GTK widget, specified by \param type.
+ GTK widgets are cached, so that only one instance of each type is created.
+ \note
+ The method returns nullptr for the enum value gtk_Default.
+ */
+GtkWidget *QGtk3Interface::widget(QGtkWidget type) const
+{
+ if (type == QGtkWidget::gtk_Default)
+ return nullptr;
+
+ // Return from cache
+ if (GtkWidget *w = cache.value(type))
+ return w;
+
+ // Create new item and cache it
+ GtkWidget *w = qt_new_gtkWidget(type);
+ cache.insert(type, w);
+ return w;
+}
+
+/*!
+ \internal
+ \brief Access a GTK widget's style context.
+
+ Returns the pointer to the style context of GTK widget \param w.
+
+ \note If \param w is nullptr, the GTK default style context (entry style) is returned.
+ */
+GtkStyleContext *QGtk3Interface::context(GtkWidget *w) const
+{
+ if (w)
+ return gtk_widget_get_style_context(w);
+
+ return gtk_widget_get_style_context(widget(QGtkWidget::gtk_entry));
+}
+
+/*!
+ \internal
+ \brief Create a QBrush from a GTK widget.
+
+ Returns a QBrush corresponding to GTK widget type \param wtype, \param source and \param state.
+
+ Brush height and width is ignored in GTK3, because brush assets (e.g. 9-patches)
+ can't be accessed by the GTK3 API. It's therefore unknown, if the brush relates only to colors,
+ or to a pixmap based style.
+
+ */
+QBrush QGtk3Interface::brush(QGtkWidget wtype, QGtkColorSource source, GtkStateFlags state) const
+{
+ // FIXME: When a color's pixmap can be accessed via the GTK API,
+ // read it and set it in the brush.
+ return QBrush(color(widget(wtype), source, state));
+}
+
+/*!
+ \internal
+ \brief Returns the name of the current GTK theme.
+ */
+QString QGtk3Interface::themeName() const
+{
+ QString name;
+
+ if (GtkSettings *settings = gtk_settings_get_default()) {
+ gchar *theme_name;
+ g_object_get(settings, "gtk-theme-name", &theme_name, nullptr);
+ name = QLatin1StringView(theme_name);
+ g_free(theme_name);
+ }
+
+ return name;
+}
+
+/*!
+ \internal
+ \brief Determine color scheme by colors.
+
+ Returns the color scheme of the current GTK theme, heuristically determined by the
+ lightness difference between default background and foreground colors.
+
+ \note Returns Unknown in the unlikely case that both colors have the same lightness.
+ */
+Qt::ColorScheme QGtk3Interface::colorSchemeByColors() const
+{
+ const QColor background = color(widget(QGtkWidget::gtk_Default),
+ QGtkColorSource::Background,
+ GTK_STATE_FLAG_ACTIVE);
+ const QColor foreground = color(widget(QGtkWidget::gtk_Default),
+ QGtkColorSource::Foreground,
+ GTK_STATE_FLAG_ACTIVE);
+
+ if (foreground.lightness() > background.lightness())
+ return Qt::ColorScheme::Dark;
+ if (foreground.lightness() < background.lightness())
+ return Qt::ColorScheme::Light;
+ return Qt::ColorScheme::Unknown;
+}
+
+/*!
+ \internal
+ \brief Map font type to GTK widget type.
+
+ Returns the GTK widget type corresponding to the given QPlatformTheme::Font \param type.
+ */
+inline constexpr QGtk3Interface::QGtkWidget QGtk3Interface::toWidgetType(QPlatformTheme::Font type)
+{
+ switch (type) {
+ case QPlatformTheme::SystemFont: return QGtkWidget::gtk_Default;
+ case QPlatformTheme::MenuFont: return QGtkWidget::gtk_menu;
+ case QPlatformTheme::MenuBarFont: return QGtkWidget::gtk_menu_bar;
+ case QPlatformTheme::MenuItemFont: return QGtkWidget::gtk_menu;
+ case QPlatformTheme::MessageBoxFont: return QGtkWidget::gtk_popup;
+ case QPlatformTheme::LabelFont: return QGtkWidget::gtk_popup;
+ case QPlatformTheme::TipLabelFont: return QGtkWidget::gtk_Default;
+ case QPlatformTheme::StatusBarFont: return QGtkWidget::gtk_statusbar;
+ case QPlatformTheme::TitleBarFont: return QGtkWidget::gtk_Default;
+ case QPlatformTheme::MdiSubWindowTitleFont: return QGtkWidget::gtk_Default;
+ case QPlatformTheme::DockWidgetTitleFont: return QGtkWidget::gtk_Default;
+ case QPlatformTheme::PushButtonFont: return QGtkWidget::gtk_button;
+ case QPlatformTheme::CheckBoxFont: return QGtkWidget::gtk_check_button;
+ case QPlatformTheme::RadioButtonFont: return QGtkWidget::gtk_radio_button;
+ case QPlatformTheme::ToolButtonFont: return QGtkWidget::gtk_button;
+ case QPlatformTheme::ItemViewFont: return QGtkWidget::gtk_entry;
+ case QPlatformTheme::ListViewFont: return QGtkWidget::gtk_tree_view;
+ case QPlatformTheme::HeaderViewFont: return QGtkWidget::gtk_combo_box;
+ case QPlatformTheme::ListBoxFont: return QGtkWidget::gtk_Default;
+ case QPlatformTheme::ComboMenuItemFont: return QGtkWidget::gtk_combo_box;
+ case QPlatformTheme::ComboLineEditFont: return QGtkWidget::gtk_combo_box_text;
+ case QPlatformTheme::SmallFont: return QGtkWidget::gtk_Default;
+ case QPlatformTheme::MiniFont: return QGtkWidget::gtk_Default;
+ case QPlatformTheme::FixedFont: return QGtkWidget::gtk_Default;
+ case QPlatformTheme::GroupBoxTitleFont: return QGtkWidget::gtk_Default;
+ case QPlatformTheme::TabButtonFont: return QGtkWidget::gtk_button;
+ case QPlatformTheme::EditorFont: return QGtkWidget::gtk_entry;
+ case QPlatformTheme::NFonts: return QGtkWidget::gtk_Default;
+ }
+ Q_UNREACHABLE();
+}
+
+/*!
+ \internal
+ \brief Convert pango \param style to QFont::Style.
+ */
+inline constexpr QFont::Style QGtk3Interface::toFontStyle(PangoStyle style)
+{
+ switch (style) {
+ case PANGO_STYLE_ITALIC: return QFont::StyleItalic;
+ case PANGO_STYLE_OBLIQUE: return QFont::StyleOblique;
+ case PANGO_STYLE_NORMAL: return QFont::StyleNormal;
+ }
+ // This is reached when GTK has introduced a new font style
+ Q_UNREACHABLE();
+}
+
+/*!
+ \internal
+ \brief Convert pango font \param weight to an int, representing font weight in Qt.
+
+ Compatibility of PangoWeight is statically asserted.
+ The minimum (1) and maximum (1000) weight in Qt is respeced.
+ */
+inline constexpr int QGtk3Interface::toFontWeight(PangoWeight weight)
+{
+ // GTK PangoWeight can be directly converted to QFont::Weight
+ // unless one of the enums changes.
+ static_assert(PANGO_WEIGHT_THIN == 100 && PANGO_WEIGHT_ULTRAHEAVY == 1000,
+ "Pango font weight enum changed. Fix conversion.");
+
+ static_assert(QFont::Thin == 100 && QFont::Black == 900,
+ "QFont::Weight enum changed. Fix conversion.");
+
+ return qBound(1, static_cast<int>(weight), 1000);
+}
+
+/*!
+ \internal
+ \brief Return a GTK styled font.
+
+ Returns the QFont corresponding to \param type by reading the corresponding
+ GTK widget type's font.
+
+ \note GTK allows to specify a non fixed font as the system's fixed font.
+ If a fixed font is requested, the method fixes the pitch and falls back to monospace,
+ unless a suitable fixed pitch font is found.
+ */
+QFont QGtk3Interface::font(QPlatformTheme::Font type) const
+{
+ GtkStyleContext *con = context(widget(toWidgetType(type)));
+ if (!con)
+ return QFont();
+
+ // explicitly add provider for fixed font
+ GtkCssProvider *cssProvider = nullptr;
+ if (type == QPlatformTheme::FixedFont) {
+ cssProvider = gtk_css_provider_new();
+ gtk_style_context_add_class (con, GTK_STYLE_CLASS_MONOSPACE);
+ const char *fontSpec = "* {font-family: monospace;}";
+ gtk_css_provider_load_from_data(cssProvider, fontSpec, -1, NULL);
+ gtk_style_context_add_provider(con, GTK_STYLE_PROVIDER(cssProvider),
+ GTK_STYLE_PROVIDER_PRIORITY_USER);
+ }
+
+ // remove monospace provider from style context and unref it
+ QScopeGuard guard([&](){
+ if (cssProvider) {
+ gtk_style_context_remove_provider(con, GTK_STYLE_PROVIDER(cssProvider));
+ g_object_unref(cssProvider);
+ }
+ });
+
+ const PangoFontDescription *gtkFont = gtk_style_context_get_font(con, GTK_STATE_FLAG_NORMAL);
+ if (!gtkFont)
+ return QFont();
+
+ const QString family = QString::fromLatin1(pango_font_description_get_family(gtkFont));
+ if (family.isEmpty())
+ return QFont();
+
+ const int weight = toFontWeight(pango_font_description_get_weight(gtkFont));
+
+ // Creating a QFont() creates a futex lockup on a theme change
+ // QFont doesn't have a constructor with float point size
+ // => create a dummy point size and set it later.
+ QFont font(family, 1, weight);
+ font.setPointSizeF(static_cast<float>(pango_font_description_get_size(gtkFont)/PANGO_SCALE));
+ font.setStyle(toFontStyle(pango_font_description_get_style(gtkFont)));
+
+ if (type == QPlatformTheme::FixedFont) {
+ font.setFixedPitch(true);
+ if (!QFontInfo(font).fixedPitch()) {
+ qCDebug(lcQGtk3Interface) << "No fixed pitch font found in font family"
+ << font.family() << ". falling back to a default"
+ << "fixed pitch font";
+ font.setFamily("monospace"_L1);
+ }
+ }
+
+ return font;
+}
+
+/*!
+ \internal
+ \brief Returns a GTK styled file icon for \param fileInfo.
+ */
+QIcon QGtk3Interface::fileIcon(const QFileInfo &fileInfo) const
+{
+ GFile *file = g_file_new_for_path(fileInfo.absoluteFilePath().toLatin1().constData());
+ if (!file)
+ return QIcon();
+
+ GFileInfo *info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_ICON,
+ G_FILE_QUERY_INFO_NONE, nullptr, nullptr);
+ if (!info) {
+ g_object_unref(file);
+ return QIcon();
+ }
+
+ GIcon *icon = g_file_info_get_icon(info);
+ if (!icon) {
+ g_object_unref(file);
+ g_object_unref(info);
+ return QIcon();
+ }
+
+ GtkIconTheme *theme = gtk_icon_theme_get_default();
+ GtkIconInfo *iconInfo = gtk_icon_theme_lookup_by_gicon(theme, icon, 16,
+ GTK_ICON_LOOKUP_FORCE_SIZE);
+ if (!iconInfo) {
+ g_object_unref(file);
+ g_object_unref(info);
+ return QIcon();
+ }
+
+ GdkPixbuf *buf = gtk_icon_info_load_icon(iconInfo, nullptr);
+ QImage image = qt_convert_gdk_pixbuf(buf);
+ g_object_unref(file);
+ g_object_unref(info);
+ g_object_unref(buf);
+ return QIcon(QPixmap::fromImage(image));
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platformthemes/gtk3/qgtk3interface_p.h b/src/plugins/platformthemes/gtk3/qgtk3interface_p.h
new file mode 100644
index 0000000000..c43932a4fa
--- /dev/null
+++ b/src/plugins/platformthemes/gtk3/qgtk3interface_p.h
@@ -0,0 +1,211 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QGTK3INTERFACE_H
+#define QGTK3INTERFACE_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/QString>
+#include <QtCore/QCache>
+#include <private/qflatmap_p.h>
+#include <QtCore/QObject>
+#include <QtGui/QIcon>
+#include <QtGui/QPalette>
+#include <QtWidgets/QWidget>
+#include <QtCore/QLoggingCategory>
+#include <QtGui/QPixmap>
+#include <qpa/qplatformtheme.h>
+
+#undef signals // Collides with GTK symbols
+#include <gtk/gtk.h>
+#include <gdk/gdk.h>
+#include <glib.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_LOGGING_CATEGORY(lcQGtk3Interface);
+
+using namespace Qt::StringLiterals;
+
+class QGtk3Storage;
+
+/*!
+ \internal
+ \brief The QGtk3Interface class centralizes communication with the GTK3 library.
+
+ By encapsulating all GTK version specific syntax and conversions, it makes Qt's GTK theme
+ independent from GTK versions.
+
+ \note
+ Including GTK3 headers requires #undef signals, which disables Qt signal/slot handling.
+ */
+
+class QGtk3Interface
+{
+ Q_GADGET
+public:
+ QGtk3Interface(QGtk3Storage *);
+ ~QGtk3Interface();
+
+ /*!
+ * \internal
+ \enum QGtk3Interface::QGtkWidget
+ \brief Represents GTK widget types used to obtain color information.
+
+ \note The enum value gtk_Default refers to the GTK default style, rather than to a specific widget.
+ */
+ enum class QGtkWidget {
+ gtk_menu_bar,
+ gtk_menu,
+ gtk_button,
+ gtk_button_box,
+ gtk_check_button,
+ gtk_radio_button,
+ gtk_frame,
+ gtk_statusbar,
+ gtk_entry,
+ gtk_popup,
+ gtk_notebook,
+ gtk_toolbar,
+ gtk_tree_view,
+ gtk_combo_box,
+ gtk_combo_box_text,
+ gtk_progress_bar,
+ gtk_fixed,
+ gtk_separator_menu_item,
+ gtk_Default,
+ gtk_offscreen_window
+ };
+ Q_ENUM(QGtkWidget)
+
+ /*!
+ \internal
+ \enum QGtk3Interface::QGtkColorSource
+ \brief The QGtkColorSource enum represents the source of a color within a GTK widgets style context.
+
+ If the current GTK theme provides such a color for a given widget, the color can be read
+ from the style context by passing the enum's key as a property name to the GTK method
+ gtk_style_context_lookup_color. The method will return false, if no color has been found.
+ */
+ enum class QGtkColorSource {
+ Foreground,
+ Background,
+ Text,
+ Base,
+ Border
+ };
+ Q_ENUM(QGtkColorSource)
+
+ /*!
+ \internal
+ \enum QGtk3Interface::QGtkColorDefault
+ \brief The QGtkColorDefault enum represents generic GTK colors.
+
+ The GTK3 methods gtk_style_context_get_color, gtk_style_context_get_background_color, and
+ gtk_style_context_get_foreground_color always return the respective colors with a widget's
+ style context. Unless set as a property by the current GTK theme, GTK's default colors will
+ be returned.
+ These generic default colors, represented by the GtkColorDefault enum, are used as a
+ back, if a specific color property is requested but not defined in the current GTK theme.
+ */
+ enum class QGtkColorDefault {
+ Foreground,
+ Background,
+ Border
+ };
+ Q_ENUM(QGtkColorDefault)
+
+ // Create a brush from GTK widget type, color source and color state
+ QBrush brush(QGtkWidget wtype, QGtkColorSource source, GtkStateFlags state) const;
+
+ // Font & icon getters
+ QImage standardPixmap(QPlatformTheme::StandardPixmap standardPixmap) const;
+ QFont font(QPlatformTheme::Font type) const;
+ QIcon fileIcon(const QFileInfo &fileInfo) const;
+
+ // Return current GTK theme name
+ QString themeName() const;
+
+ // Derive color scheme from default colors
+ Qt::ColorScheme colorSchemeByColors() const;
+
+ // Convert GTK state to/from string
+ static int toGtkState(const QString &state);
+ static const QLatin1String fromGtkState(GtkStateFlags state);
+
+private:
+
+ // Map colors to GTK property names and default to generic color getters
+ struct ColorKey {
+ QGtkColorSource colorSource = QGtkColorSource::Background;
+ GtkStateFlags state = GTK_STATE_FLAG_NORMAL;
+
+ // struct becomes key of a map, so operator< is needed
+ bool operator<(const ColorKey& other) const {
+ return std::tie(colorSource, state) <
+ std::tie(other.colorSource, other.state);
+ }
+
+ QDebug operator<<(QDebug dbg)
+ {
+ return dbg << "QGtk3Interface::ColorKey(colorSource=" << colorSource << ", GTK state=" << fromGtkState(state) << ")";
+ }
+ };
+
+ struct ColorValue {
+ QString propertyName = QString();
+ QGtkColorDefault genericSource = QGtkColorDefault::Background;
+
+ QDebug operator<<(QDebug dbg)
+ {
+ return dbg << "QGtk3Interface::ColorValue(propertyName=" << propertyName << ", genericSource=" << genericSource << ")";
+ }
+ };
+
+ typedef QFlatMap<ColorKey, ColorValue> ColorMap;
+ ColorMap gtkColorMap;
+ void initColorMap();
+
+ GdkRGBA genericColor(GtkStyleContext *con, GtkStateFlags state, QGtkColorDefault def) const;
+
+ // Cache for GTK widgets
+ mutable QFlatMap<QGtkWidget, GtkWidget *> cache;
+
+ // Converters for GTK icon and GDK pixbuf
+ QImage qt_gtk_get_icon(const char *iconName) const;
+ QImage qt_convert_gdk_pixbuf(GdkPixbuf *buf) const;
+
+ // Create new GTK widget object
+ GtkWidget *qt_new_gtkWidget(QGtkWidget type) const;
+
+ // Deliver GTK Widget from cache or create new
+ GtkWidget *widget(QGtkWidget type) const;
+
+ // Get a GTK widget's style context. Default settings style context if nullptr
+ GtkStyleContext *context(GtkWidget *widget = nullptr) const;
+
+ // Convert GTK color into QColor
+ static inline QColor fromGdkColor (const GdkRGBA &c)
+ { return QColor::fromRgbF(c.red, c.green, c.blue, c.alpha); }
+
+ // get a QColor of a GTK widget (default settings style if nullptr)
+ QColor color (GtkWidget *widget, QGtkColorSource source, GtkStateFlags state) const;
+
+ // Mappings for GTK fonts
+ inline static constexpr QGtkWidget toWidgetType(QPlatformTheme::Font);
+ inline static constexpr QFont::Style toFontStyle(PangoStyle style);
+ inline static constexpr int toFontWeight(PangoWeight weight);
+
+};
+QT_END_NAMESPACE
+#endif // QGTK3INTERFACE_H
diff --git a/src/plugins/platformthemes/gtk3/qgtk3json.cpp b/src/plugins/platformthemes/gtk3/qgtk3json.cpp
new file mode 100644
index 0000000000..eb81e563be
--- /dev/null
+++ b/src/plugins/platformthemes/gtk3/qgtk3json.cpp
@@ -0,0 +1,404 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+//
+// 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 "qgtk3json_p.h"
+#include <QtCore/QFile>
+#include <QMetaEnum>
+
+QT_BEGIN_NAMESPACE
+
+QLatin1String QGtk3Json::fromPalette(QPlatformTheme::Palette palette)
+{
+ return QLatin1String(QMetaEnum::fromType<QPlatformTheme::Palette>().valueToKey(static_cast<int>(palette)));
+}
+
+QLatin1String QGtk3Json::fromGtkState(GtkStateFlags state)
+{
+ return QGtk3Interface::fromGtkState(state);
+}
+
+QLatin1String fromColor(const QColor &color)
+{
+ return QLatin1String(QByteArray(color.name(QColor::HexRgb).toLatin1()));
+}
+
+QLatin1String QGtk3Json::fromColorRole(QPalette::ColorRole role)
+{
+ return QLatin1String(QMetaEnum::fromType<QPalette::ColorRole>().valueToKey(static_cast<int>(role)));
+}
+
+QLatin1String QGtk3Json::fromColorGroup(QPalette::ColorGroup group)
+{
+ return QLatin1String(QMetaEnum::fromType<QPalette::ColorGroup>().valueToKey(static_cast<int>(group)));
+}
+
+QLatin1String QGtk3Json::fromGdkSource(QGtk3Interface::QGtkColorSource source)
+{
+ return QLatin1String(QMetaEnum::fromType<QGtk3Interface::QGtkColorSource>().valueToKey(static_cast<int>(source)));
+}
+
+QLatin1String QGtk3Json::fromWidgetType(QGtk3Interface::QGtkWidget widgetType)
+{
+ return QLatin1String(QMetaEnum::fromType<QGtk3Interface::QGtkWidget>().valueToKey(static_cast<int>(widgetType)));
+}
+
+QLatin1String QGtk3Json::fromColorScheme(Qt::ColorScheme app)
+{
+ return QLatin1String(QMetaEnum::fromType<Qt::ColorScheme>().valueToKey(static_cast<int>(app)));
+}
+
+#define CONVERT(type, key, def)\
+ bool ok;\
+ const int intVal = QMetaEnum::fromType<type>().keyToValue(key.toLatin1().constData(), &ok);\
+ return ok ? static_cast<type>(intVal) : type::def
+
+Qt::ColorScheme QGtk3Json::toColorScheme(const QString &colorScheme)
+{
+ CONVERT(Qt::ColorScheme, colorScheme, Unknown);
+}
+
+QPlatformTheme::Palette QGtk3Json::toPalette(const QString &palette)
+{
+ CONVERT(QPlatformTheme::Palette, palette, NPalettes);
+}
+
+GtkStateFlags QGtk3Json::toGtkState(const QString &type)
+{
+ int i = QGtk3Interface::toGtkState(type);
+ if (i < 0)
+ return GTK_STATE_FLAG_NORMAL;
+ return static_cast<GtkStateFlags>(i);
+}
+
+QColor toColor(const QStringView &color)
+{
+ return QColor::fromString(color);
+}
+
+QPalette::ColorRole QGtk3Json::toColorRole(const QString &role)
+{
+ CONVERT(QPalette::ColorRole, role, NColorRoles);
+}
+
+QPalette::ColorGroup QGtk3Json::toColorGroup(const QString &group)
+{
+ CONVERT(QPalette::ColorGroup, group, NColorGroups);
+}
+
+QGtk3Interface::QGtkColorSource QGtk3Json::toGdkSource(const QString &source)
+{
+ CONVERT(QGtk3Interface::QGtkColorSource, source, Background);
+}
+
+QLatin1String QGtk3Json::fromSourceType(QGtk3Storage::SourceType sourceType)
+{
+ return QLatin1String(QMetaEnum::fromType<QGtk3Storage::SourceType>().valueToKey(static_cast<int>(sourceType)));
+}
+
+QGtk3Storage::SourceType QGtk3Json::toSourceType(const QString &sourceType)
+{
+ CONVERT(QGtk3Storage::SourceType, sourceType, Invalid);
+}
+
+QGtk3Interface::QGtkWidget QGtk3Json::toWidgetType(const QString &widgetType)
+{
+ CONVERT(QGtk3Interface::QGtkWidget, widgetType, gtk_offscreen_window);
+}
+
+#undef CONVERT
+
+bool QGtk3Json::save(const QGtk3Storage::PaletteMap &map, const QString &fileName,
+ QJsonDocument::JsonFormat format)
+{
+ QJsonDocument doc = save(map);
+ if (doc.isEmpty()) {
+ qWarning() << "Nothing to save to" << fileName;
+ return false;
+ }
+
+ QFile file(fileName);
+ if (!file.open(QIODevice::WriteOnly)) {
+ qWarning() << "Unable to open file" << fileName << "for writing.";
+ return false;
+ }
+
+ if (!file.write(doc.toJson(format))) {
+ qWarning() << "Unable to serialize Json document.";
+ return false;
+ }
+
+ file.close();
+ qInfo() << "Saved mapping data to" << fileName;
+ return true;
+}
+
+const QJsonDocument QGtk3Json::save(const QGtk3Storage::PaletteMap &map)
+{
+ QJsonObject paletteObject;
+ for (auto paletteIterator = map.constBegin(); paletteIterator != map.constEnd();
+ ++paletteIterator) {
+ const QGtk3Storage::BrushMap &bm = paletteIterator.value();
+ QFlatMap<QPalette::ColorRole, QGtk3Storage::BrushMap> brushMaps;
+ for (auto brushIterator = bm.constBegin(); brushIterator != bm.constEnd();
+ ++brushIterator) {
+ const QPalette::ColorRole role = brushIterator.key().colorRole;
+ if (brushMaps.contains(role)) {
+ brushMaps.value(role).insert(brushIterator.key(), brushIterator.value());
+ } else {
+ QGtk3Storage::BrushMap newMap;
+ newMap.insert(brushIterator.key(), brushIterator.value());
+ brushMaps.insert(role, newMap);
+ }
+ }
+
+ QJsonObject brushArrayObject;
+ for (auto brushMapIterator = brushMaps.constBegin();
+ brushMapIterator != brushMaps.constEnd(); ++brushMapIterator) {
+
+ QJsonArray brushArray;
+ int brushIndex = 0;
+ const QGtk3Storage::BrushMap &bm = brushMapIterator.value();
+ for (auto brushIterator = bm.constBegin(); brushIterator != bm.constEnd();
+ ++brushIterator) {
+ QJsonObject brushObject;
+ const QGtk3Storage::TargetBrush tb = brushIterator.key();
+ QGtk3Storage::Source s = brushIterator.value();
+ brushObject.insert(ceColorGroup, fromColorGroup(tb.colorGroup));
+ brushObject.insert(ceColorScheme, fromColorScheme(tb.colorScheme));
+ brushObject.insert(ceSourceType, fromSourceType(s.sourceType));
+
+ QJsonObject sourceObject;
+ switch (s.sourceType) {
+ case QGtk3Storage::SourceType::Gtk: {
+ sourceObject.insert(ceGtkWidget, fromWidgetType(s.gtk3.gtkWidgetType));
+ sourceObject.insert(ceGdkSource, fromGdkSource(s.gtk3.source));
+ sourceObject.insert(ceGtkState, fromGtkState(s.gtk3.state));
+ sourceObject.insert(ceWidth, s.gtk3.width);
+ sourceObject.insert(ceHeight, s.gtk3.height);
+ }
+ break;
+
+ case QGtk3Storage::SourceType::Fixed: {
+ QJsonObject fixedObject;
+ fixedObject.insert(ceColor, s.fix.fixedBrush.color().name());
+ fixedObject.insert(ceWidth, s.fix.fixedBrush.texture().width());
+ fixedObject.insert(ceHeight, s.fix.fixedBrush.texture().height());
+ sourceObject.insert(ceBrush, fixedObject);
+ }
+ break;
+
+ case QGtk3Storage::SourceType::Modified:{
+ sourceObject.insert(ceColorGroup, fromColorGroup(s.rec.colorGroup));
+ sourceObject.insert(ceColorRole, fromColorRole(s.rec.colorRole));
+ sourceObject.insert(ceColorScheme, fromColorScheme(s.rec.colorScheme));
+ sourceObject.insert(ceRed, s.rec.deltaRed);
+ sourceObject.insert(ceGreen, s.rec.deltaGreen);
+ sourceObject.insert(ceBlue, s.rec.deltaBlue);
+ sourceObject.insert(ceWidth, s.rec.width);
+ sourceObject.insert(ceHeight, s.rec.height);
+ sourceObject.insert(ceLighter, s.rec.lighter);
+ }
+ break;
+
+ case QGtk3Storage::SourceType::Invalid:
+ break;
+ }
+
+ brushObject.insert(ceData, sourceObject);
+ brushArray.insert(brushIndex, brushObject);
+ ++brushIndex;
+ }
+ brushArrayObject.insert(fromColorRole(brushMapIterator.key()), brushArray);
+ }
+ paletteObject.insert(fromPalette(paletteIterator.key()), brushArrayObject);
+ }
+
+ QJsonObject top;
+ top.insert(cePalettes, paletteObject);
+ return paletteObject.keys().isEmpty() ? QJsonDocument() : QJsonDocument(top);
+}
+
+bool QGtk3Json::load(QGtk3Storage::PaletteMap &map, const QString &fileName)
+{
+ QFile file(fileName);
+ if (!file.open(QIODevice::ReadOnly)) {
+ qCWarning(lcQGtk3Interface) << "Unable to open file:" << fileName;
+ return false;
+ }
+
+ QJsonParseError err;
+ QJsonDocument doc = QJsonDocument::fromJson(file.readAll(), &err);
+ if (err.error != QJsonParseError::NoError) {
+ qWarning(lcQGtk3Interface) << "Unable to parse Json document from" << fileName
+ << err.error << err.errorString();
+ return false;
+ }
+
+ if (Q_LIKELY(load(map, doc))) {
+ qInfo() << "GTK mapping successfully imported from" << fileName;
+ return true;
+ }
+
+ qWarning() << "File" << fileName << "could not be loaded.";
+ return false;
+}
+
+bool QGtk3Json::load(QGtk3Storage::PaletteMap &map, const QJsonDocument &doc)
+{
+#define GETSTR(obj, key)\
+ if (!obj.contains(key)) {\
+ qCInfo(lcQGtk3Interface) << key << "missing for palette" << paletteName\
+ << ", Brush" << colorRoleName;\
+ return false;\
+ }\
+ value = obj[key].toString()
+
+#define GETINT(obj, key, var) GETSTR(obj, key);\
+ if (!obj[key].isDouble()) {\
+ qCInfo(lcQGtk3Interface) << key << "type mismatch" << value\
+ << "is not an integer!"\
+ << "(Palette" << paletteName << "), Brush" << colorRoleName;\
+ return false;\
+ }\
+ const int var = obj[key].toInt()
+
+ map.clear();
+ const QJsonObject top(doc.object());
+ if (doc.isEmpty() || top.isEmpty() || !top.contains(cePalettes)) {
+ qCInfo(lcQGtk3Interface) << "Document does not contain Palettes.";
+ return false;
+ }
+
+ const QStringList &paletteList = top[cePalettes].toObject().keys();
+ for (const QString &paletteName : paletteList) {
+ bool ok;
+ const int intVal = QMetaEnum::fromType<QPlatformTheme::Palette>().keyToValue(paletteName
+ .toLatin1().constData(), &ok);
+ if (!ok) {
+ qCInfo(lcQGtk3Interface) << "Invalid Palette name:" << paletteName;
+ return false;
+ }
+ const QJsonObject &paletteObject = top[cePalettes][paletteName].toObject();
+ const QStringList &brushList = paletteObject.keys();
+ if (brushList.isEmpty()) {
+ qCInfo(lcQGtk3Interface) << "Palette" << paletteName << "does not contain brushes";
+ return false;
+ }
+
+ const QPlatformTheme::Palette paletteType = static_cast<QPlatformTheme::Palette>(intVal);
+ QGtk3Storage::BrushMap brushes;
+ const QStringList &colorRoles = paletteObject.keys();
+ for (const QString &colorRoleName : colorRoles) {
+ const int intVal = QMetaEnum::fromType<QPalette::ColorRole>().keyToValue(colorRoleName
+ .toLatin1().constData(), &ok);
+ if (!ok) {
+ qCInfo(lcQGtk3Interface) << "Palette" << paletteName
+ << "contains invalid color role" << colorRoleName;
+ return false;
+ }
+ const QPalette::ColorRole colorRole = static_cast<QPalette::ColorRole>(intVal);
+ const QJsonArray &brushArray = paletteObject[colorRoleName].toArray();
+ for (int brushIndex = 0; brushIndex < brushArray.size(); ++brushIndex) {
+ const QJsonObject brushObject = brushArray.at(brushIndex).toObject();
+ if (brushObject.isEmpty()) {
+ qCInfo(lcQGtk3Interface) << "Brush specification missing at for palette"
+ << paletteName << ", Brush" << colorRoleName;
+ return false;
+ }
+
+ QString value;
+ GETSTR(brushObject, ceSourceType);
+ const QGtk3Storage::SourceType sourceType = toSourceType(value);
+ GETSTR(brushObject, ceColorGroup);
+ const QPalette::ColorGroup colorGroup = toColorGroup(value);
+ GETSTR(brushObject, ceColorScheme);
+ const Qt::ColorScheme colorScheme = toColorScheme(value);
+ QGtk3Storage::TargetBrush tb(colorGroup, colorRole, colorScheme);
+ QGtk3Storage::Source s;
+
+ if (!brushObject.contains(ceData) || !brushObject[ceData].isObject()) {
+ qCInfo(lcQGtk3Interface) << "Source specification missing for palette" << paletteName
+ << "Brush" << colorRoleName;
+ return false;
+ }
+ const QJsonObject &sourceObject = brushObject[ceData].toObject();
+
+ switch (sourceType) {
+ case QGtk3Storage::SourceType::Gtk: {
+ GETSTR(sourceObject, ceGdkSource);
+ const QGtk3Interface::QGtkColorSource gtkSource = toGdkSource(value);
+ GETSTR(sourceObject, ceGtkState);
+ const GtkStateFlags gtkState = toGtkState(value);
+ GETSTR(sourceObject, ceGtkWidget);
+ const QGtk3Interface::QGtkWidget widgetType = toWidgetType(value);
+ GETINT(sourceObject, ceHeight, height);
+ GETINT(sourceObject, ceWidth, width);
+ s = QGtk3Storage::Source(widgetType, gtkSource, gtkState, width, height);
+ }
+ break;
+
+ case QGtk3Storage::SourceType::Fixed: {
+ if (!sourceObject.contains(ceBrush)) {
+ qCInfo(lcQGtk3Interface) << "Fixed brush specification missing for palette" << paletteName
+ << "Brush" << colorRoleName;
+ return false;
+ }
+ const QJsonObject &fixedSource = sourceObject[ceBrush].toObject();
+ GETINT(fixedSource, ceWidth, width);
+ GETINT(fixedSource, ceHeight, height);
+ GETSTR(fixedSource, ceColor);
+ const QColor color(value);
+ if (!color.isValid()) {
+ qCInfo(lcQGtk3Interface) << "Color" << value << "can't be parsed for:" << paletteName
+ << "Brush" << colorRoleName;
+ return false;
+ }
+ const QBrush fixedBrush = (width < 0 && height < 0)
+ ? QBrush(color, QPixmap(width, height))
+ : QBrush(color);
+ s = QGtk3Storage::Source(fixedBrush);
+ }
+ break;
+
+ case QGtk3Storage::SourceType::Modified: {
+ GETSTR(sourceObject, ceColorGroup);
+ const QPalette::ColorGroup colorGroup = toColorGroup(value);
+ GETSTR(sourceObject, ceColorRole);
+ const QPalette::ColorRole colorRole = toColorRole(value);
+ GETSTR(sourceObject, ceColorScheme);
+ const Qt::ColorScheme colorScheme = toColorScheme(value);
+ GETINT(sourceObject, ceLighter, lighter);
+ GETINT(sourceObject, ceRed, red);
+ GETINT(sourceObject, ceBlue, blue);
+ GETINT(sourceObject, ceGreen, green);
+ s = QGtk3Storage::Source(colorGroup, colorRole, colorScheme,
+ lighter, red, green, blue);
+ }
+ break;
+
+ case QGtk3Storage::SourceType::Invalid:
+ qInfo(lcQGtk3Interface) << "Invalid source type for palette" << paletteName
+ << "Brush." << colorRoleName;
+ return false;
+ }
+ brushes.insert(tb, s);
+ }
+ }
+ map.insert(paletteType, brushes);
+ }
+ return true;
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/plugins/platformthemes/gtk3/qgtk3json_p.h b/src/plugins/platformthemes/gtk3/qgtk3json_p.h
new file mode 100644
index 0000000000..daf280612c
--- /dev/null
+++ b/src/plugins/platformthemes/gtk3/qgtk3json_p.h
@@ -0,0 +1,102 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+#ifndef QGTK3JSON_P_H
+#define QGTK3JSON_P_H
+
+#include <QtCore/QCache>
+#include <QtCore/QJsonArray>
+#include <QtCore/QJsonDocument>
+#include <QtCore/QJsonObject>
+#include <QtCore/QMap>
+#include <QtCore/QString>
+#include <QtGui/QGuiApplication>
+#include <QtGui/QPalette>
+
+#include <qpa/qplatformtheme.h>
+#include "qgtk3interface_p.h"
+#include "qgtk3storage_p.h"
+
+#undef signals // Collides with GTK symbols
+#include <gtk/gtk.h>
+#include <gdk/gdk.h>
+#include <glib.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.
+//
+
+QT_BEGIN_NAMESPACE
+
+class QGtk3Json
+{
+ Q_GADGET
+private:
+ QGtk3Json(){};
+
+public:
+ // Convert enums to strings
+ static QLatin1String fromPalette(QPlatformTheme::Palette palette);
+ static QLatin1String fromGtkState(GtkStateFlags type);
+ static QLatin1String fromColor(const QColor &Color);
+ static QLatin1String fromColorRole(QPalette::ColorRole role);
+ static QLatin1String fromColorGroup(QPalette::ColorGroup group);
+ static QLatin1String fromGdkSource(QGtk3Interface::QGtkColorSource source);
+ static QLatin1String fromSourceType(QGtk3Storage::SourceType sourceType);
+ static QLatin1String fromWidgetType(QGtk3Interface::QGtkWidget widgetType);
+ static QLatin1String fromColorScheme(Qt::ColorScheme colorScheme);
+
+ // Convert strings to enums
+ static QPlatformTheme::Palette toPalette(const QString &palette);
+ static GtkStateFlags toGtkState(const QString &type);
+ static QColor toColor(const QString &Color);
+ static QPalette::ColorRole toColorRole(const QString &role);
+ static QPalette::ColorGroup toColorGroup(const QString &group);
+ static QGtk3Interface::QGtkColorSource toGdkSource(const QString &source);
+ static QGtk3Storage::SourceType toSourceType(const QString &sourceType);
+ static QGtk3Interface::QGtkWidget toWidgetType(const QString &widgetType);
+ static Qt::ColorScheme toColorScheme(const QString &colorScheme);
+
+ // Json keys
+ static constexpr QLatin1StringView cePalettes = "QtGtk3Palettes"_L1;
+ static constexpr QLatin1StringView cePalette = "PaletteType"_L1;
+ static constexpr QLatin1StringView ceGtkState = "GtkStateType"_L1;
+ static constexpr QLatin1StringView ceGtkWidget = "GtkWidgetType"_L1;
+ static constexpr QLatin1StringView ceColor = "Color"_L1;
+ static constexpr QLatin1StringView ceColorRole = "ColorRole"_L1;
+ static constexpr QLatin1StringView ceColorGroup = "ColorGroup"_L1;
+ static constexpr QLatin1StringView ceGdkSource = "GdkSource"_L1;
+ static constexpr QLatin1StringView ceSourceType = "SourceType"_L1;
+ static constexpr QLatin1StringView ceLighter = "Lighter"_L1;
+ static constexpr QLatin1StringView ceRed = "DeltaRed"_L1;
+ static constexpr QLatin1StringView ceGreen = "DeltaGreen"_L1;
+ static constexpr QLatin1StringView ceBlue = "DeltaBlue"_L1;
+ static constexpr QLatin1StringView ceWidth = "Width"_L1;
+ static constexpr QLatin1StringView ceHeight = "Height"_L1;
+ static constexpr QLatin1StringView ceBrush = "FixedBrush"_L1;
+ static constexpr QLatin1StringView ceData = "SourceData"_L1;
+ static constexpr QLatin1StringView ceBrushes = "Brushes"_L1;
+ static constexpr QLatin1StringView ceColorScheme = "ColorScheme"_L1;
+
+ // Save to a file
+ static bool save(const QGtk3Storage::PaletteMap &map, const QString &fileName,
+ QJsonDocument::JsonFormat format = QJsonDocument::Indented);
+
+ // Save to a Json document
+ static const QJsonDocument save(const QGtk3Storage::PaletteMap &map);
+
+ // Load from a file
+ static bool load(QGtk3Storage::PaletteMap &map, const QString &fileName);
+
+ // Load from a Json document
+ static bool load(QGtk3Storage::PaletteMap &map, const QJsonDocument &doc);
+};
+
+QT_END_NAMESPACE
+#endif // QGTK3JSON_P_H
diff --git a/src/plugins/platformthemes/gtk3/qgtk3menu.cpp b/src/plugins/platformthemes/gtk3/qgtk3menu.cpp
index d9d117faeb..c4ea0e5e33 100644
--- a/src/plugins/platformthemes/gtk3/qgtk3menu.cpp
+++ b/src/plugins/platformthemes/gtk3/qgtk3menu.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qgtk3menu.h"
@@ -56,7 +20,7 @@ static guint qt_gdkKey(const QKeySequence &shortcut)
// TODO: proper mapping
Qt::KeyboardModifiers mods = Qt::ShiftModifier | Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier;
- return (shortcut[0] ^ mods) & shortcut[0];
+ return (shortcut[0].toCombined() ^ mods) & shortcut[0].toCombined();
}
static GdkModifierType qt_gdkModifiers(const QKeySequence &shortcut)
@@ -65,7 +29,7 @@ static GdkModifierType qt_gdkModifiers(const QKeySequence &shortcut)
return GdkModifierType(0);
guint mods = 0;
- int m = shortcut[0];
+ Qt::KeyboardModifiers m = shortcut[0].keyboardModifiers();
if (m & Qt::ShiftModifier)
mods |= GDK_SHIFT_MASK;
if (m & Qt::ControlModifier)
@@ -85,6 +49,7 @@ QGtk3MenuItem::QGtk3MenuItem()
m_checkable(false),
m_checked(false),
m_enabled(true),
+ m_exclusive(false),
m_underline(false),
m_invalid(true),
m_menu(nullptr),
@@ -158,23 +123,23 @@ static QString convertMnemonics(QString text, bool *found)
{
*found = false;
- int i = text.length() - 1;
+ qsizetype i = text.size() - 1;
while (i >= 0) {
const QChar c = text.at(i);
- if (c == QLatin1Char('&')) {
- if (i == 0 || text.at(i - 1) != QLatin1Char('&')) {
+ if (c == u'&') {
+ if (i == 0 || text.at(i - 1) != u'&') {
// convert Qt to GTK mnemonic
- if (i < text.length() - 1 && !text.at(i + 1).isSpace()) {
- text.replace(i, 1, QLatin1Char('_'));
+ if (i < text.size() - 1 && !text.at(i + 1).isSpace()) {
+ text.replace(i, 1, u'_');
*found = true;
}
- } else if (text.at(i - 1) == QLatin1Char('&')) {
+ } else if (text.at(i - 1) == u'&') {
// unescape ampersand
- text.replace(--i, 2, QLatin1Char('&'));
+ text.replace(--i, 2, u'&');
}
- } else if (c == QLatin1Char('_')) {
+ } else if (c == u'_') {
// escape GTK mnemonic
- text.insert(i, QLatin1Char('_'));
+ text.insert(i, u'_');
}
--i;
}
@@ -364,7 +329,7 @@ void QGtk3Menu::insertMenuItem(QPlatformMenuItem *item, QPlatformMenuItem *befor
GtkWidget *handle = gitem->create();
int index = m_items.indexOf(static_cast<QGtk3MenuItem *>(before));
if (index < 0)
- index = m_items.count();
+ index = m_items.size();
m_items.insert(index, gitem);
gtk_menu_shell_insert(GTK_MENU_SHELL(m_menu), handle, index);
}
@@ -483,3 +448,5 @@ void QGtk3Menu::onHide(GtkWidget *, void *data)
}
QT_END_NAMESPACE
+
+#include "moc_qgtk3menu.cpp"
diff --git a/src/plugins/platformthemes/gtk3/qgtk3menu.h b/src/plugins/platformthemes/gtk3/qgtk3menu.h
index cce800fbd8..4eb432c69b 100644
--- a/src/plugins/platformthemes/gtk3/qgtk3menu.h
+++ b/src/plugins/platformthemes/gtk3/qgtk3menu.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QGTK3MENU_H
#define QGTK3MENU_H
@@ -156,7 +120,7 @@ protected:
private:
GtkWidget *m_menu;
QPoint m_targetPos;
- QVector<QGtk3MenuItem *> m_items;
+ QList<QGtk3MenuItem *> m_items;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platformthemes/gtk3/qgtk3storage.cpp b/src/plugins/platformthemes/gtk3/qgtk3storage.cpp
new file mode 100644
index 0000000000..90c0282651
--- /dev/null
+++ b/src/plugins/platformthemes/gtk3/qgtk3storage.cpp
@@ -0,0 +1,673 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+//
+// 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 "qgtk3json_p.h"
+#include "qgtk3storage_p.h"
+#include <qpa/qwindowsysteminterface.h>
+
+QT_BEGIN_NAMESPACE
+
+QGtk3Storage::QGtk3Storage()
+{
+ m_interface.reset(new QGtk3Interface(this));
+ populateMap();
+}
+
+/*!
+ \internal
+ \enum QGtk3Storage::SourceType
+ \brief This enum represents the type of a color source.
+
+ \value Gtk Color is read from a GTK widget
+ \value Fixed A fixed brush is specified
+ \value Modified The color is a modification of another color (fixed or read from GTK)
+ \omitvalue Invalid
+ */
+
+/*!
+ \internal
+ \brief Find a brush from a source.
+
+ Returns a QBrush from a given \param source and a \param map of available brushes
+ to search from.
+
+ A null QBrush is returned, if no brush corresponding to the source has been found.
+ */
+QBrush QGtk3Storage::brush(const Source &source, const BrushMap &map) const
+{
+ switch (source.sourceType) {
+ case SourceType::Gtk:
+ return m_interface ? QBrush(m_interface->brush(source.gtk3.gtkWidgetType,
+ source.gtk3.source, source.gtk3.state))
+ : QBrush();
+
+ case SourceType::Modified: {
+ // don't loop through modified sources, break if modified source not found
+ Source recSource = brush(TargetBrush(source.rec.colorGroup, source.rec.colorRole,
+ source.rec.colorScheme), map);
+
+ if (!recSource.isValid() || (recSource.sourceType == SourceType::Modified))
+ return QBrush();
+
+ // Set brush and alter color
+ QBrush b = brush(recSource, map);
+ if (source.rec.width > 0 && source.rec.height > 0)
+ b.setTexture(QPixmap(source.rec.width, source.rec.height));
+ QColor c = b.color().lighter(source.rec.lighter);
+ c = QColor((c.red() + source.rec.deltaRed),
+ (c.green() + source.rec.deltaGreen),
+ (c.blue() + source.rec.deltaBlue));
+ b.setColor(c);
+ return b;
+ }
+
+ case SourceType::Fixed:
+ return source.fix.fixedBrush;
+
+ case SourceType::Invalid:
+ return QBrush();
+ }
+
+ // needed because of the scope after recursive
+ Q_UNREACHABLE();
+}
+
+/*!
+ \internal
+ \brief Recurse to find a source brush for modification.
+
+ Returns the source specified by the target brush \param b in the \param map of brushes.
+ Takes dark/light/unknown into consideration.
+ Returns an empty brush if no suitable one can be found.
+ */
+QGtk3Storage::Source QGtk3Storage::brush(const TargetBrush &b, const BrushMap &map) const
+{
+#define FIND(brush) if (map.contains(brush))\
+ return map.value(brush)
+
+ // Return exact match
+ FIND(b);
+
+ // unknown color scheme can find anything
+ if (b.colorScheme == Qt::ColorScheme::Unknown) {
+ FIND(TargetBrush(b, Qt::ColorScheme::Dark));
+ FIND(TargetBrush(b, Qt::ColorScheme::Light));
+ }
+
+ // Color group All can always be found
+ if (b.colorGroup != QPalette::All)
+ return brush(TargetBrush(QPalette::All, b.colorRole, b.colorScheme), map);
+
+ // Brush not found
+ return Source();
+#undef FIND
+}
+
+/*!
+ \internal
+ \brief Returns a simple, hard coded base palette.
+
+ Create a hard coded palette with default colors as a fallback for any color that can't be
+ obtained from GTK.
+
+ \note This palette will be used as a default baseline for the system palette, which then
+ will be used as a default baseline for any other palette type.
+ */
+QPalette QGtk3Storage::standardPalette()
+{
+ QColor backgroundColor(0xd4, 0xd0, 0xc8);
+ QColor lightColor(backgroundColor.lighter());
+ QColor darkColor(backgroundColor.darker());
+ const QBrush darkBrush(darkColor);
+ QColor midColor(Qt::gray);
+ QPalette palette(Qt::black, backgroundColor, lightColor, darkColor,
+ midColor, Qt::black, Qt::white);
+ palette.setBrush(QPalette::Disabled, QPalette::WindowText, darkBrush);
+ palette.setBrush(QPalette::Disabled, QPalette::Text, darkBrush);
+ palette.setBrush(QPalette::Disabled, QPalette::ButtonText, darkBrush);
+ palette.setBrush(QPalette::Disabled, QPalette::Base, QBrush(backgroundColor));
+ return palette;
+}
+
+/*!
+ \internal
+ \brief Return a GTK styled QPalette.
+
+ Returns the pointer to a (cached) QPalette for \param type, with its brushes
+ populated according to the current GTK theme.
+ */
+const QPalette *QGtk3Storage::palette(QPlatformTheme::Palette type) const
+{
+ if (type >= QPlatformTheme::NPalettes)
+ return nullptr;
+
+ if (m_paletteCache[type].has_value()) {
+ qCDebug(lcQGtk3Interface) << "Returning palette from cache:"
+ << QGtk3Json::fromPalette(type);
+
+ return &m_paletteCache[type].value();
+ }
+
+ // Read system palette as a baseline first
+ if (!m_paletteCache[QPlatformTheme::SystemPalette].has_value() && type != QPlatformTheme::SystemPalette)
+ palette();
+
+ // Fall back to system palette for unknown types
+ if (!m_palettes.contains(type) && type != QPlatformTheme::SystemPalette) {
+ qCDebug(lcQGtk3Interface) << "Returning system palette for unknown type"
+ << QGtk3Json::fromPalette(type);
+ return palette();
+ }
+
+ BrushMap brushes = m_palettes.value(type);
+
+ // Standard palette is base for system palette. System palette is base for all others.
+ QPalette p = QPalette( type == QPlatformTheme::SystemPalette ? standardPalette()
+ : m_paletteCache[QPlatformTheme::SystemPalette].value());
+
+ qCDebug(lcQGtk3Interface) << "Creating palette:" << QGtk3Json::fromPalette(type);
+ for (auto i = brushes.begin(); i != brushes.end(); ++i) {
+ Source source = i.value();
+
+ // Brush is set if
+ // - theme and source color scheme match
+ // - or either of them is unknown
+ const auto appSource = i.key().colorScheme;
+ const auto appTheme = colorScheme();
+ const bool setBrush = (appSource == appTheme) ||
+ (appSource == Qt::ColorScheme::Unknown) ||
+ (appTheme == Qt::ColorScheme::Unknown);
+
+ if (setBrush) {
+ p.setBrush(i.key().colorGroup, i.key().colorRole, brush(source, brushes));
+ }
+ }
+
+ m_paletteCache[type].emplace(p);
+ if (type == QPlatformTheme::SystemPalette)
+ qCDebug(lcQGtk3Interface) << "System Palette defined" << themeName() << colorScheme() << p;
+
+ return &m_paletteCache[type].value();
+}
+
+/*!
+ \internal
+ \brief Return a GTK styled font.
+
+ Returns a QFont of \param type, styled according to the current GTK theme.
+*/
+const QFont *QGtk3Storage::font(QPlatformTheme::Font type) const
+{
+ if (m_fontCache[type].has_value())
+ return &m_fontCache[type].value();
+
+ m_fontCache[type].emplace(m_interface->font(type));
+ return &m_fontCache[type].value();
+}
+
+/*!
+ \internal
+ \brief Return a GTK styled standard pixmap if available.
+
+ Returns a pixmap specified by \param standardPixmap and \param size.
+ Returns an empty pixmap if GTK doesn't support the requested one.
+ */
+QPixmap QGtk3Storage::standardPixmap(QPlatformTheme::StandardPixmap standardPixmap,
+ const QSizeF &size) const
+{
+ if (m_pixmapCache.contains(standardPixmap))
+ return QPixmap::fromImage(m_pixmapCache.object(standardPixmap)->scaled(size.toSize()));
+
+ if (!m_interface)
+ return QPixmap();
+
+ QImage image = m_interface->standardPixmap(standardPixmap);
+ if (image.isNull())
+ return QPixmap();
+
+ m_pixmapCache.insert(standardPixmap, new QImage(image));
+ return QPixmap::fromImage(image.scaled(size.toSize()));
+}
+
+/*!
+ \internal
+ \brief Returns a GTK styled file icon corresponding to \param fileInfo.
+ */
+QIcon QGtk3Storage::fileIcon(const QFileInfo &fileInfo) const
+{
+ return m_interface ? m_interface->fileIcon(fileInfo) : QIcon();
+}
+
+/*!
+ \internal
+ \brief Clears all caches.
+ */
+void QGtk3Storage::clear()
+{
+ m_colorScheme = Qt::ColorScheme::Unknown;
+ m_palettes.clear();
+ for (auto &cache : m_paletteCache)
+ cache.reset();
+
+ for (auto &cache : m_fontCache)
+ cache.reset();
+}
+
+/*!
+ \internal
+ \brief Handles a theme change at runtime.
+
+ Clear all caches, re-populate with current GTK theme and notify the window system interface.
+ This method is a callback for the theme change signal sent from GTK.
+ */
+void QGtk3Storage::handleThemeChange()
+{
+ clear();
+ populateMap();
+ QWindowSystemInterface::handleThemeChange();
+}
+
+/*!
+ \internal
+ \brief Populates a map with information about how to locate colors in GTK.
+
+ This method creates a data structure to locate color information for each brush of a QPalette
+ within GTK. The structure can hold mapping information for each QPlatformTheme::Palette
+ enum value. If no specific mapping is stored for an enum value, the system palette is returned
+ instead of a specific one. If no mapping is stored for the system palette, it will fall back to
+ QGtk3Storage::standardPalette.
+
+ The method will populate the data structure with a standard mapping, covering the following
+ palette types:
+ \list
+ \li QPlatformTheme::SystemPalette
+ \li QPlatformTheme::CheckBoxPalette
+ \li QPlatformTheme::RadioButtonPalette
+ \li QPlatformTheme::ComboBoxPalette
+ \li QPlatformTheme::GroupBoxPalette
+ \li QPlatformTheme::MenuPalette
+ \li QPlatformTheme::TextLineEditPalette
+ \endlist
+
+ The method will check the environment variable {{QT_GUI_GTK_JSON_SAVE}}. If it points to a
+ valid path with write access, it will write the standard mapping into a Json file.
+ That Json file can be modified and/or extended.
+ The Json syntax is
+ - "QGtk3Palettes" (top level value)
+ - QPlatformTheme::Palette
+ - QPalette::ColorRole
+ - Qt::ColorScheme
+ - Qt::ColorGroup
+ - Source data
+ - Source Type
+ - [source data]
+
+ If the environment variable {{QT_GUI_GTK_JSON_HARDCODED}} contains the keyword \c true,
+ all sources are converted to fixed sources. In that case, they contain the hard coded HexRGBA
+ values read from GTK.
+
+ The method will also check the environment variable {{QT_GUI_GTK_JSON}}. If it points to a valid
+ Json file with read access, it will be parsed instead of creating a standard mapping.
+ Parsing errors will be printed out with qCInfo if the logging category {{qt.qpa.gtk}} is activated.
+ In case of a parsing error, the method will fall back to creating a standard mapping.
+
+ \note
+ If a Json file contains only fixed brushes (e.g. exported with {{QT_GUI_GTK_JSON_HARDCODED=true}}),
+ no colors will be imported from GTK.
+ */
+void QGtk3Storage::populateMap()
+{
+ static QString m_themeName;
+
+ // Distiguish initialization, theme change or call without theme change
+ const QString newThemeName = themeName();
+ if (m_themeName == newThemeName)
+ return;
+
+ clear();
+
+ // Derive color scheme from theme name
+ m_colorScheme = newThemeName.contains("dark"_L1, Qt::CaseInsensitive)
+ ? Qt::ColorScheme::Dark : m_interface->colorSchemeByColors();
+
+ if (m_themeName.isEmpty()) {
+ qCDebug(lcQGtk3Interface) << "GTK theme initialized:" << newThemeName << m_colorScheme;
+ } else {
+ qCDebug(lcQGtk3Interface) << "GTK theme changed to:" << newThemeName << m_colorScheme;
+ }
+ m_themeName = newThemeName;
+
+ // create standard mapping or load from Json file?
+ const QString jsonInput = qEnvironmentVariable("QT_GUI_GTK_JSON");
+ if (!jsonInput.isEmpty()) {
+ if (load(jsonInput)) {
+ return;
+ } else {
+ qWarning() << "Falling back to standard GTK mapping.";
+ }
+ }
+
+ createMapping();
+
+ const QString jsonOutput = qEnvironmentVariable("QT_GUI_GTK_JSON_SAVE");
+ if (!jsonOutput.isEmpty() && !save(jsonOutput))
+ qWarning() << "File" << jsonOutput << "could not be saved.\n";
+}
+
+/*!
+ \internal
+ \brief Return a palette map for saving.
+
+ This method returns the existing palette map, if the environment variable
+ {{QT_GUI_GTK_JSON_HARDCODED}} is not set or does not contain the keyword \c true.
+ If it contains the keyword \c true, it returns a palette map with all brush
+ sources converted to fixed sources.
+ */
+const QGtk3Storage::PaletteMap QGtk3Storage::savePalettes() const
+{
+ const QString hard = qEnvironmentVariable("QT_GUI_GTK_JSON_HARDCODED");
+ if (!hard.contains("true"_L1, Qt::CaseInsensitive))
+ return m_palettes;
+
+ // Json output is supposed to be readable without GTK connection
+ // convert palette map into hard coded brushes
+ PaletteMap map = m_palettes;
+ for (auto paletteIterator = map.begin(); paletteIterator != map.end();
+ ++paletteIterator) {
+ QGtk3Storage::BrushMap &bm = paletteIterator.value();
+ for (auto brushIterator = bm.begin(); brushIterator != bm.end();
+ ++brushIterator) {
+ QGtk3Storage::Source &s = brushIterator.value();
+ switch (s.sourceType) {
+
+ // Read the brush and convert it into a fixed brush
+ case SourceType::Gtk: {
+ const QBrush fixedBrush = brush(s, bm);
+ s.fix.fixedBrush = fixedBrush;
+ s.sourceType = SourceType::Fixed;
+ }
+ break;
+ case SourceType::Fixed:
+ case SourceType::Modified:
+ case SourceType::Invalid:
+ break;
+ }
+ }
+ }
+ return map;
+}
+
+/*!
+ \internal
+ \brief Saves current palette mapping to a \param filename with Json format \param f.
+
+ Saves the current palette mapping into a QJson file,
+ taking {{QT_GUI_GTK_JSON_HARDCODED}} into consideration.
+ Returns \c true if saving was successful and \c false otherwise.
+ */
+bool QGtk3Storage::save(const QString &filename, QJsonDocument::JsonFormat f) const
+{
+ return QGtk3Json::save(savePalettes(), filename, f);
+}
+
+/*!
+ \internal
+ \brief Returns a QJsonDocument with current palette mapping.
+
+ Saves the current palette mapping into a QJsonDocument,
+ taking {{QT_GUI_GTK_JSON_HARDCODED}} into consideration.
+ Returns \c true if saving was successful and \c false otherwise.
+ */
+QJsonDocument QGtk3Storage::save() const
+{
+ return QGtk3Json::save(savePalettes());
+}
+
+/*!
+ \internal
+ \brief Loads palette mapping from Json file \param filename.
+
+ Returns \c true if the file was successfully parsed and \c false otherwise.
+ */
+bool QGtk3Storage::load(const QString &filename)
+{
+ return QGtk3Json::load(m_palettes, filename);
+}
+
+/*!
+ \internal
+ \brief Creates a standard palette mapping.
+
+ The method creates a hard coded standard mapping, used if no external Json file
+ containing a valid mapping has been specified in the environment variable {{QT_GUI_GTK_JSON}}.
+ */
+void QGtk3Storage::createMapping()
+{
+ // Hard code standard mapping
+ BrushMap map;
+ Source source;
+
+ // Define a GTK source
+#define GTK(wtype, colorSource, state)\
+ source = Source(QGtk3Interface::QGtkWidget::gtk_ ##wtype,\
+ QGtk3Interface::QGtkColorSource::colorSource, GTK_STATE_FLAG_ ##state)
+
+ // Define a modified source
+#define LIGHTER(group, role, lighter)\
+ source = Source(QPalette::group, QPalette::role,\
+ Qt::ColorScheme::Unknown, lighter)
+#define MODIFY(group, role, red, green, blue)\
+ source = Source(QPalette::group, QPalette::role,\
+ Qt::ColorScheme::Unknown, red, green, blue)
+
+ // Define fixed source
+#define FIX(color) source = FixedSource(color);
+
+ // Add the source to a target brush
+ // Use default Qt::ColorScheme::Unknown, if no color scheme was specified
+#define ADD_2(group, role) map.insert(TargetBrush(QPalette::group, QPalette::role), source);
+#define ADD_3(group, role, app) map.insert(TargetBrush(QPalette::group, QPalette::role,\
+ Qt::ColorScheme::app), source);
+#define ADD_X(x, group, role, app, FUNC, ...) FUNC
+#define ADD(...) ADD_X(,##__VA_ARGS__, ADD_3(__VA_ARGS__), ADD_2(__VA_ARGS__))
+ // Save target brushes to a palette type
+#define SAVE(palette) m_palettes.insert(QPlatformTheme::palette, map)
+ // Clear brushes to start next palette
+#define CLEAR map.clear()
+
+ /*
+ Macro usage:
+
+ 1. Define a source
+ GTK(QGtkWidget, QGtkColorSource, GTK_STATE_FLAG)
+ Fetch the color from a GtkWidget, related to a source and a state.
+
+ LIGHTER(ColorGroup, ColorROle, lighter)
+ Use a color of the same QPalette related to ColorGroup and ColorRole.
+ Make the color lighter (if lighter >100) or darker (if lighter < 100)
+
+ MODIFY(ColorGroup, ColorRole, red, green, blue)
+ Use a color of the same QPalette related to ColorGroup and ColorRole.
+ Modify it by adding red, green, blue.
+
+ FIX(const QBrush &)
+ Use a fixed brush without querying GTK
+
+ 2. Define the target
+ Use ADD(ColorGroup, ColorRole) to use the defined source for the
+ color group / role in the current palette.
+
+ Use ADD(ColorGroup, ColorRole, ColorScheme) to use the defined source
+ only for a specific color scheme
+
+ 3. Save mapping
+ Save the defined mappings for a specific palette.
+ If a mapping entry does not cover all color groups and roles of a palette,
+ the system palette will be used for the remaining values.
+ If the system palette does not have all combination of color groups and roles,
+ the remaining ones will be populated by a hard coded fusion-style like palette.
+
+ 4. Clear mapping
+ Use CLEAR to clear the mapping and begin a new one.
+ */
+
+
+ // System palette
+ {
+ // background color and calculate derivates
+ GTK(Default, Background, INSENSITIVE);
+ ADD(All, Window);
+ ADD(All, Button);
+ ADD(All, Base);
+ LIGHTER(Normal, Window, 125);
+ ADD(Normal, Light);
+ ADD(Inactive, Light);
+ LIGHTER(Normal, Window, 70);
+ ADD(Normal, Shadow);
+ LIGHTER(Normal, Window, 80);
+ ADD(Normal, Dark);
+ ADD(Inactive, Dark)
+
+ GTK(button, Foreground, ACTIVE);
+ ADD(Inactive, WindowText);
+ LIGHTER(Normal, WindowText, 50);
+ ADD(Disabled, Text);
+ ADD(Disabled, WindowText);
+ ADD(Disabled, ButtonText);
+
+ GTK(button, Text, NORMAL);
+ ADD(Inactive, ButtonText);
+
+ // special background colors
+ GTK(Default, Background, SELECTED);
+ ADD(Disabled, Highlight);
+ ADD(Normal, Highlight);
+ ADD(Inactive, Highlight);
+
+ GTK(entry, Foreground, SELECTED);
+ ADD(Normal, HighlightedText);
+ ADD(Inactive, HighlightedText);
+
+ // text color and friends
+ GTK(entry, Text, NORMAL);
+ ADD(Normal, ButtonText);
+ ADD(Normal, WindowText);
+ ADD(Disabled, HighlightedText);
+
+ GTK(Default, Text, NORMAL);
+ ADD(Normal, Text);
+ ADD(Inactive, Text);
+ ADD(Normal, HighlightedText);
+ LIGHTER(Normal, Base, 93);
+ ADD(All, AlternateBase);
+
+ GTK(Default, Foreground, NORMAL);
+ MODIFY(Normal, Text, 100, 100, 100);
+ ADD(All, PlaceholderText, Light);
+ MODIFY(Normal, Text, -100, -100, -100);
+ ADD(All, PlaceholderText, Dark);
+
+ // Light, midlight, dark, mid, shadow colors
+ LIGHTER(Normal, Button, 125);
+ ADD(All, Light)
+ LIGHTER(Normal, Button, 113);
+ ADD(All, Midlight)
+ LIGHTER(Normal, Button, 113);
+ ADD(All, Mid)
+ LIGHTER(Normal, Button, 87);
+ ADD(All, Dark)
+ LIGHTER(Normal, Button, 5);
+ ADD(All, Shadow)
+
+ SAVE(SystemPalette);
+ CLEAR;
+ }
+
+ // Label and TabBar Palette
+ {
+ GTK(entry, Text, NORMAL);
+ ADD(Normal, WindowText);
+ ADD(Inactive, WindowText);
+
+ SAVE(LabelPalette);
+ SAVE(TabBarPalette);
+ CLEAR;
+ }
+
+ // Checkbox and RadioButton Palette
+ {
+ GTK(button, Text, ACTIVE);
+ ADD(Normal, Base, Dark);
+ ADD(Inactive, WindowText, Dark);
+
+ GTK(Default, Foreground, NORMAL);
+ ADD(All, Text);
+
+ GTK(Default, Background, NORMAL);
+ ADD(All, Base);
+
+ GTK(button, Text, NORMAL);
+ ADD(Normal, Base, Light);
+ ADD(Inactive, WindowText, Light);
+
+ SAVE(CheckBoxPalette);
+ SAVE(RadioButtonPalette);
+ CLEAR;
+ }
+
+ // ComboBox, GroupBox & Frame Palette
+ {
+ GTK(combo_box, Text, NORMAL);
+ ADD(Normal, ButtonText, Dark);
+ ADD(Normal, Text, Dark);
+ ADD(Inactive, WindowText, Dark);
+
+ GTK(combo_box, Text, ACTIVE);
+ ADD(Normal, ButtonText, Light);
+ ADD(Normal, Text, Light);
+ ADD(Inactive, WindowText, Light);
+
+ SAVE(ComboBoxPalette);
+ SAVE(GroupBoxPalette);
+ CLEAR;
+ }
+
+ // MenuBar Palette
+ {
+ GTK(Default, Text, ACTIVE);
+ ADD(Normal, ButtonText);
+ SAVE(MenuPalette);
+ CLEAR;
+ }
+
+ // LineEdit Palette
+ {
+ GTK(Default, Background, NORMAL);
+ ADD(All, Base);
+ SAVE(TextLineEditPalette);
+ CLEAR;
+ }
+
+#undef GTK
+#undef REC
+#undef FIX
+#undef ADD
+#undef ADD_2
+#undef ADD_3
+#undef ADD_X
+#undef SAVE
+#undef LOAD
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platformthemes/gtk3/qgtk3storage_p.h b/src/plugins/platformthemes/gtk3/qgtk3storage_p.h
new file mode 100644
index 0000000000..37c5bf57ff
--- /dev/null
+++ b/src/plugins/platformthemes/gtk3/qgtk3storage_p.h
@@ -0,0 +1,235 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QGTK3STORAGE_P_H
+#define QGTK3STORAGE_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 "qgtk3interface_p.h"
+
+#include <QtCore/QJsonDocument>
+#include <QtCore/QCache>
+#include <QtCore/QString>
+#include <QtGui/QGuiApplication>
+#include <QtGui/QPalette>
+
+#include <qpa/qplatformtheme.h>
+#include <private/qflatmap_p.h>
+
+QT_BEGIN_NAMESPACE
+class QGtk3Storage
+{
+ Q_GADGET
+public:
+ QGtk3Storage();
+
+ // Enum documented in cpp file. Please keep it in line with updates made here.
+ enum class SourceType {
+ Gtk,
+ Fixed,
+ Modified,
+ Invalid
+ };
+ Q_ENUM(SourceType)
+
+ // Standard GTK source: Populate a brush from GTK
+ struct Gtk3Source {
+ QGtk3Interface::QGtkWidget gtkWidgetType;
+ QGtk3Interface::QGtkColorSource source;
+ GtkStateFlags state;
+ int width = -1;
+ int height = -1;
+ QDebug operator<<(QDebug dbg)
+ {
+ return dbg << "QGtkStorage::Gtk3Source(gtkwidgetType=" << gtkWidgetType << ", source="
+ << source << ", state=" << state << ", width=" << width << ", height="
+ << height << ")";
+ }
+ };
+
+ // Recursive source: Populate a brush by altering another source
+ struct RecursiveSource {
+ QPalette::ColorGroup colorGroup;
+ QPalette::ColorRole colorRole;
+ Qt::ColorScheme colorScheme;
+ int lighter = 100;
+ int deltaRed = 0;
+ int deltaGreen = 0;
+ int deltaBlue = 0;
+ int width = -1;
+ int height = -1;
+ QDebug operator<<(QDebug dbg)
+ {
+ return dbg << "QGtkStorage::RecursiceSource(colorGroup=" << colorGroup << ", colorRole="
+ << colorRole << ", colorScheme=" << colorScheme << ", lighter=" << lighter
+ << ", deltaRed="<< deltaRed << "deltaBlue =" << deltaBlue << "deltaGreen="
+ << deltaGreen << ", width=" << width << ", height=" << height << ")";
+ }
+ };
+
+ // Fixed source: Populate a brush with fixed values rather than reading GTK
+ struct FixedSource {
+ QBrush fixedBrush;
+ QDebug operator<<(QDebug dbg)
+ {
+ return dbg << "QGtkStorage::FixedSource(" << fixedBrush << ")";
+ }
+ };
+
+ // Data source for brushes
+ struct Source {
+ SourceType sourceType = SourceType::Invalid;
+ Gtk3Source gtk3;
+ RecursiveSource rec;
+ FixedSource fix;
+
+ // GTK constructor
+ Source(QGtk3Interface::QGtkWidget wtype, QGtk3Interface::QGtkColorSource csource,
+ GtkStateFlags cstate, int bwidth = -1, int bheight = -1) : sourceType(SourceType::Gtk)
+ {
+ gtk3.gtkWidgetType = wtype;
+ gtk3.source = csource;
+ gtk3.state = cstate;
+ gtk3.width = bwidth;
+ gtk3.height = bheight;
+ }
+
+ // Recursive constructor for darker/lighter colors
+ Source(QPalette::ColorGroup group, QPalette::ColorRole role,
+ Qt::ColorScheme scheme, int p_lighter = 100)
+ : sourceType(SourceType::Modified)
+ {
+ rec.colorGroup = group;
+ rec.colorRole = role;
+ rec.colorScheme = scheme;
+ rec.lighter = p_lighter;
+ }
+
+ // Recursive ocnstructor for color modification
+ Source(QPalette::ColorGroup group, QPalette::ColorRole role,
+ Qt::ColorScheme scheme, int p_red, int p_green, int p_blue)
+ : sourceType(SourceType::Modified)
+ {
+ rec.colorGroup = group;
+ rec.colorRole = role;
+ rec.colorScheme = scheme;
+ rec.deltaRed = p_red;
+ rec.deltaGreen = p_green;
+ rec.deltaBlue = p_blue;
+ }
+
+ // Recursive constructor for all: color modification and darker/lighter
+ Source(QPalette::ColorGroup group, QPalette::ColorRole role,
+ Qt::ColorScheme scheme, int p_lighter,
+ int p_red, int p_green, int p_blue) : sourceType(SourceType::Modified)
+ {
+ rec.colorGroup = group;
+ rec.colorRole = role;
+ rec.colorScheme = scheme;
+ rec.lighter = p_lighter;
+ rec.deltaRed = p_red;
+ rec.deltaGreen = p_green;
+ rec.deltaBlue = p_blue;
+ }
+
+ // Fixed Source constructor
+ Source(const QBrush &brush) : sourceType(SourceType::Fixed)
+ {
+ fix.fixedBrush = brush;
+ };
+
+ // Invalid constructor and getter
+ Source() : sourceType(SourceType::Invalid) {};
+ bool isValid() const { return sourceType != SourceType::Invalid; }
+
+ // Debug
+ QDebug operator<<(QDebug dbg)
+ {
+ return dbg << "QGtk3Storage::Source(sourceType=" << sourceType << ")";
+ }
+ };
+
+ // Struct with key attributes to identify a brush: color group, color role and color scheme
+ struct TargetBrush {
+ QPalette::ColorGroup colorGroup;
+ QPalette::ColorRole colorRole;
+ Qt::ColorScheme colorScheme;
+
+ // Generic constructor
+ TargetBrush(QPalette::ColorGroup group, QPalette::ColorRole role,
+ Qt::ColorScheme scheme = Qt::ColorScheme::Unknown) :
+ colorGroup(group), colorRole(role), colorScheme(scheme) {};
+
+ // Copy constructor with color scheme modifier for dark/light aware search
+ TargetBrush(const TargetBrush &other, Qt::ColorScheme scheme) :
+ colorGroup(other.colorGroup), colorRole(other.colorRole), colorScheme(scheme) {};
+
+ // struct becomes key of a map, so operator< is needed
+ bool operator<(const TargetBrush& other) const {
+ return std::tie(colorGroup, colorRole, colorScheme) <
+ std::tie(other.colorGroup, other.colorRole, other.colorScheme);
+ }
+ };
+
+ // Mapping a palette's brushes to their GTK sources
+ typedef QFlatMap<TargetBrush, Source> BrushMap;
+
+ // Storage of palettes and their GTK sources
+ typedef QFlatMap<QPlatformTheme::Palette, BrushMap> PaletteMap;
+
+ // Public getters
+ const QPalette *palette(QPlatformTheme::Palette = QPlatformTheme::SystemPalette) const;
+ QPixmap standardPixmap(QPlatformTheme::StandardPixmap standardPixmap, const QSizeF &size) const;
+ Qt::ColorScheme colorScheme() const { return m_colorScheme; };
+ static QPalette standardPalette();
+ const QString themeName() const { return m_interface ? m_interface->themeName() : QString(); };
+ const QFont *font(QPlatformTheme::Font type) const;
+ QIcon fileIcon(const QFileInfo &fileInfo) const;
+
+ // Initialization
+ void populateMap();
+ void handleThemeChange();
+
+private:
+ // Storage for palettes and their brushes
+ PaletteMap m_palettes;
+
+ std::unique_ptr<QGtk3Interface> m_interface;
+
+
+ Qt::ColorScheme m_colorScheme = Qt::ColorScheme::Unknown;
+
+ // Caches for Pixmaps, fonts and palettes
+ mutable QCache<QPlatformTheme::StandardPixmap, QImage> m_pixmapCache;
+ mutable std::array<std::optional<QPalette>, QPlatformTheme::Palette::NPalettes> m_paletteCache;
+ mutable std::array<std::optional<QFont>, QPlatformTheme::NFonts> m_fontCache;
+
+ // Search brush with a given GTK3 source
+ QBrush brush(const Source &source, const BrushMap &map) const;
+
+ // Get GTK3 source for a target brush
+ Source brush (const TargetBrush &brush, const BrushMap &map) const;
+
+ // clear cache, palettes and color scheme
+ void clear();
+
+ // Data creation, import & export
+ void createMapping ();
+ const PaletteMap savePalettes() const;
+ bool save(const QString &filename, const QJsonDocument::JsonFormat f = QJsonDocument::Indented) const;
+ QJsonDocument save() const;
+ bool load(const QString &filename);
+};
+
+QT_END_NAMESPACE
+#endif // QGTK3STORAGE_H
diff --git a/src/plugins/platformthemes/gtk3/qgtk3theme.cpp b/src/plugins/platformthemes/gtk3/qgtk3theme.cpp
index 93520344f8..9d23ba7e48 100644
--- a/src/plugins/platformthemes/gtk3/qgtk3theme.cpp
+++ b/src/plugins/platformthemes/gtk3/qgtk3theme.cpp
@@ -1,54 +1,24 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qgtk3theme.h"
#include "qgtk3dialoghelpers.h"
#include "qgtk3menu.h"
#include <QVariant>
+#include <QGuiApplication>
+#include <qpa/qwindowsysteminterface.h>
#undef signals
#include <gtk/gtk.h>
+#if QT_CONFIG(xcb_xlib)
#include <X11/Xlib.h>
+#endif
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
const char *QGtk3Theme::name = "gtk3";
template <typename T>
@@ -84,13 +54,25 @@ void gtkMessageHandler(const gchar *log_domain,
QGtk3Theme::QGtk3Theme()
{
+ // Ensure gtk uses the same windowing system, but let it
+ // fallback in case GDK_BACKEND environment variable
+ // filters the preferred one out
+ if (QGuiApplication::platformName().startsWith("wayland"_L1))
+ gdk_set_allowed_backends("wayland,x11");
+ else if (QGuiApplication::platformName() == "xcb"_L1)
+ gdk_set_allowed_backends("x11,wayland");
+
+#if QT_CONFIG(xcb_xlib)
// gtk_init will reset the Xlib error handler, and that causes
// Qt applications to quit on X errors. Therefore, we need to manually restore it.
int (*oldErrorHandler)(Display *, XErrorEvent *) = XSetErrorHandler(nullptr);
+#endif
gtk_init(nullptr, nullptr);
+#if QT_CONFIG(xcb_xlib)
XSetErrorHandler(oldErrorHandler);
+#endif
/* Initialize some types here so that Gtk+ does not crash when reading
* the treemodel for GtkFontChooser.
@@ -100,6 +82,29 @@ QGtk3Theme::QGtk3Theme()
/* Use our custom log handler. */
g_log_set_handler("Gtk", G_LOG_LEVEL_MESSAGE, gtkMessageHandler, nullptr);
+
+#define SETTING_CONNECT(setting) g_signal_connect(settings, "notify::" setting, G_CALLBACK(notifyThemeChanged), nullptr)
+ auto notifyThemeChanged = [] {
+ QWindowSystemInterface::handleThemeChange();
+ };
+
+ GtkSettings *settings = gtk_settings_get_default();
+ SETTING_CONNECT("gtk-cursor-blink-time");
+ SETTING_CONNECT("gtk-double-click-distance");
+ SETTING_CONNECT("gtk-double-click-time");
+ SETTING_CONNECT("gtk-long-press-time");
+ SETTING_CONNECT("gtk-entry-password-hint-timeout");
+ SETTING_CONNECT("gtk-dnd-drag-threshold");
+ SETTING_CONNECT("gtk-icon-theme-name");
+ SETTING_CONNECT("gtk-fallback-icon-theme");
+ SETTING_CONNECT("gtk-font-name");
+ SETTING_CONNECT("gtk-application-prefer-dark-theme");
+ SETTING_CONNECT("gtk-theme-name");
+ SETTING_CONNECT("gtk-cursor-theme-name");
+ SETTING_CONNECT("gtk-cursor-theme-size");
+#undef SETTING_CONNECT
+
+ m_storage.reset(new QGtk3Storage);
}
static inline QVariant gtkGetLongPressTime()
@@ -134,6 +139,14 @@ QVariant QGtk3Theme::themeHint(QPlatformTheme::ThemeHint hint) const
return QVariant(gtkSetting("gtk-icon-theme-name"));
case QPlatformTheme::SystemIconFallbackThemeName:
return QVariant(gtkSetting("gtk-fallback-icon-theme"));
+ case QPlatformTheme::MouseCursorTheme:
+ return QVariant(gtkSetting("gtk-cursor-theme-name"));
+ case QPlatformTheme::MouseCursorSize: {
+ int s = gtkSetting<gint>("gtk-cursor-theme-size");
+ if (s > 0)
+ return QVariant(QSize(s, s));
+ return QGnomeTheme::themeHint(hint);
+ }
default:
return QGnomeTheme::themeHint(hint);
}
@@ -147,6 +160,12 @@ QString QGtk3Theme::gtkFontName() const
return QGnomeTheme::gtkFontName();
}
+Qt::ColorScheme QGtk3Theme::colorScheme() const
+{
+ Q_ASSERT(m_storage);
+ return m_storage->colorScheme();
+}
+
bool QGtk3Theme::usePlatformNativeDialog(DialogType type) const
{
switch (type) {
@@ -200,4 +219,30 @@ bool QGtk3Theme::useNativeFileDialog()
return gtk_check_version(3, 15, 5) == nullptr;
}
+const QPalette *QGtk3Theme::palette(Palette type) const
+{
+ Q_ASSERT(m_storage);
+ return m_storage->palette(type);
+}
+
+QPixmap QGtk3Theme::standardPixmap(StandardPixmap sp, const QSizeF &size) const
+{
+ Q_ASSERT(m_storage);
+ return m_storage->standardPixmap(sp, size);
+}
+
+const QFont *QGtk3Theme::font(Font type) const
+{
+ Q_ASSERT(m_storage);
+ return m_storage->font(type);
+}
+
+QIcon QGtk3Theme::fileIcon(const QFileInfo &fileInfo,
+ QPlatformTheme::IconOptions iconOptions) const
+{
+ Q_UNUSED(iconOptions);
+ Q_ASSERT(m_storage);
+ return m_storage->fileIcon(fileInfo);
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/platformthemes/gtk3/qgtk3theme.h b/src/plugins/platformthemes/gtk3/qgtk3theme.h
index 54296d2ff1..2828cc56e6 100644
--- a/src/plugins/platformthemes/gtk3/qgtk3theme.h
+++ b/src/plugins/platformthemes/gtk3/qgtk3theme.h
@@ -1,46 +1,12 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QGTK3THEME_H
#define QGTK3THEME_H
+#include <private/qtguiglobal_p.h>
#include <private/qgenericunixthemes_p.h>
+#include "qgtk3storage_p.h"
QT_BEGIN_NAMESPACE
@@ -52,15 +18,24 @@ public:
virtual QVariant themeHint(ThemeHint hint) const override;
virtual QString gtkFontName() const override;
+ Qt::ColorScheme colorScheme() const override;
+
bool usePlatformNativeDialog(DialogType type) const override;
QPlatformDialogHelper *createPlatformDialogHelper(DialogType type) const override;
QPlatformMenu* createPlatformMenu() const override;
QPlatformMenuItem* createPlatformMenuItem() const override;
+ const QPalette *palette(Palette type = SystemPalette) const override;
+ const QFont *font(Font type = SystemFont) const override;
+ QPixmap standardPixmap(StandardPixmap sp, const QSizeF &size) const override;
+ QIcon fileIcon(const QFileInfo &fileInfo,
+ QPlatformTheme::IconOptions iconOptions = { }) const override;
+
static const char *name;
private:
static bool useNativeFileDialog();
+ std::unique_ptr<QGtk3Storage> m_storage;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platformthemes/platformthemes.pro b/src/plugins/platformthemes/platformthemes.pro
deleted file mode 100644
index 3bcc659199..0000000000
--- a/src/plugins/platformthemes/platformthemes.pro
+++ /dev/null
@@ -1,6 +0,0 @@
-TEMPLATE = subdirs
-QT_FOR_CONFIG += widgets-private
-
-qtConfig(dbus):qtConfig(regularexpression):qtConfig(mimetype): SUBDIRS += xdgdesktopportal
-
-qtHaveModule(widgets):qtConfig(gtk3): SUBDIRS += gtk3
diff --git a/src/plugins/platformthemes/xdgdesktopportal/CMakeLists.txt b/src/plugins/platformthemes/xdgdesktopportal/CMakeLists.txt
index a9062f695f..6228e83ec7 100644
--- a/src/plugins/platformthemes/xdgdesktopportal/CMakeLists.txt
+++ b/src/plugins/platformthemes/xdgdesktopportal/CMakeLists.txt
@@ -1,24 +1,22 @@
-# Generated from xdgdesktopportal.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## QXdgDesktopPortalThemePlugin Plugin:
#####################################################################
-qt_add_plugin(QXdgDesktopPortalThemePlugin
+qt_internal_add_plugin(QXdgDesktopPortalThemePlugin
OUTPUT_NAME qxdgdesktopportal
- TYPE platformthemes
+ PLUGIN_TYPE platformthemes
+ DEFAULT_IF FALSE
SOURCES
main.cpp
qxdgdesktopportalfiledialog.cpp qxdgdesktopportalfiledialog_p.h
qxdgdesktopportaltheme.cpp qxdgdesktopportaltheme.h
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Core
Qt::CorePrivate
Qt::DBus
Qt::Gui
Qt::GuiPrivate
- Qt::ThemeSupportPrivate
)
-
-#### Keys ignored in scope 1:.:.:xdgdesktopportal.pro:<TRUE>:
-# PLUGIN_EXTENDS = "-"
diff --git a/src/plugins/platformthemes/xdgdesktopportal/main.cpp b/src/plugins/platformthemes/xdgdesktopportal/main.cpp
index 64a03d479f..efbc16b3d2 100644
--- a/src/plugins/platformthemes/xdgdesktopportal/main.cpp
+++ b/src/plugins/platformthemes/xdgdesktopportal/main.cpp
@@ -1,47 +1,13 @@
-/****************************************************************************
-**
-** Copyright (C) 2017-2018 Red Hat, Inc
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2017-2018 Red Hat, Inc
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <qpa/qplatformthemeplugin.h>
#include "qxdgdesktopportaltheme.h"
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
class QXdgDesktopPortalThemePlugin : public QPlatformThemePlugin
{
Q_OBJECT
@@ -54,9 +20,9 @@ public:
QPlatformTheme *QXdgDesktopPortalThemePlugin::create(const QString &key, const QStringList &params)
{
Q_UNUSED(params);
- if (!key.compare(QLatin1String("xdgdesktopportal"), Qt::CaseInsensitive) ||
- !key.compare(QLatin1String("flatpak"), Qt::CaseInsensitive) ||
- !key.compare(QLatin1String("snap"), Qt::CaseInsensitive))
+ if (!key.compare("xdgdesktopportal"_L1, Qt::CaseInsensitive) ||
+ !key.compare("flatpak"_L1, Qt::CaseInsensitive) ||
+ !key.compare("snap"_L1, Qt::CaseInsensitive))
return new QXdgDesktopPortalTheme;
return nullptr;
diff --git a/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportalfiledialog.cpp b/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportalfiledialog.cpp
index dcf52921aa..1c162be8fc 100644
--- a/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportalfiledialog.cpp
+++ b/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportalfiledialog.cpp
@@ -1,62 +1,33 @@
-/****************************************************************************
-**
-** Copyright (C) 2017-2018 Red Hat, Inc
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2017-2018 Red Hat, Inc
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qxdgdesktopportalfiledialog_p.h"
-#include <QtCore/qeventloop.h>
+#include <private/qgenericunixservices_p.h>
+#include <private/qguiapplication_p.h>
+#include <qpa/qplatformintegration.h>
-#include <QtDBus/QtDBus>
#include <QDBusConnection>
#include <QDBusMessage>
#include <QDBusPendingCall>
#include <QDBusPendingCallWatcher>
#include <QDBusPendingReply>
+#include <QDBusMetaType>
+#include <QEventLoop>
#include <QFile>
+#include <QFileInfo>
#include <QMetaType>
#include <QMimeType>
#include <QMimeDatabase>
#include <QRandomGenerator>
#include <QWindow>
+#include <QRegularExpression>
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
QDBusArgument &operator <<(QDBusArgument &arg, const QXdgDesktopPortalFileDialog::FilterCondition &filterCondition)
{
arg.beginStructure();
@@ -102,33 +73,43 @@ const QDBusArgument &operator >>(const QDBusArgument &arg, QXdgDesktopPortalFile
class QXdgDesktopPortalFileDialogPrivate
{
public:
- QXdgDesktopPortalFileDialogPrivate(QPlatformFileDialogHelper *nativeFileDialog)
+ QXdgDesktopPortalFileDialogPrivate(QPlatformFileDialogHelper *nativeFileDialog, uint fileChooserPortalVersion)
: nativeFileDialog(nativeFileDialog)
+ , fileChooserPortalVersion(fileChooserPortalVersion)
{ }
- WId winId = 0;
- bool modal = false;
- bool multipleFiles = false;
- bool saveFile = false;
+ QEventLoop loop;
QString acceptLabel;
QString directory;
QString title;
QStringList nameFilters;
QStringList mimeTypesFilters;
+ // maps user-visible name for portal to full name filter
+ QMap<QString, QString> userVisibleToNameFilter;
+ QString selectedMimeTypeFilter;
+ QString selectedNameFilter;
QStringList selectedFiles;
- QPlatformFileDialogHelper *nativeFileDialog = nullptr;
+ std::unique_ptr<QPlatformFileDialogHelper> nativeFileDialog;
+ uint fileChooserPortalVersion = 0;
+ bool failedToOpen = false;
+ bool directoryMode = false;
+ bool multipleFiles = false;
+ bool saveFile = false;
};
-QXdgDesktopPortalFileDialog::QXdgDesktopPortalFileDialog(QPlatformFileDialogHelper *nativeFileDialog)
+QXdgDesktopPortalFileDialog::QXdgDesktopPortalFileDialog(QPlatformFileDialogHelper *nativeFileDialog, uint fileChooserPortalVersion)
: QPlatformFileDialogHelper()
- , d_ptr(new QXdgDesktopPortalFileDialogPrivate(nativeFileDialog))
+ , d_ptr(new QXdgDesktopPortalFileDialogPrivate(nativeFileDialog, fileChooserPortalVersion))
{
Q_D(QXdgDesktopPortalFileDialog);
if (d->nativeFileDialog) {
- connect(d->nativeFileDialog, SIGNAL(accept()), this, SIGNAL(accept()));
- connect(d->nativeFileDialog, SIGNAL(reject()), this, SIGNAL(reject()));
+ connect(d->nativeFileDialog.get(), SIGNAL(accept()), this, SIGNAL(accept()));
+ connect(d->nativeFileDialog.get(), SIGNAL(reject()), this, SIGNAL(reject()));
}
+
+ d->loop.connect(this, SIGNAL(accept()), SLOT(quit()));
+ d->loop.connect(this, SIGNAL(reject()), SLOT(quit()));
}
QXdgDesktopPortalFileDialog::~QXdgDesktopPortalFileDialog()
@@ -145,6 +126,9 @@ void QXdgDesktopPortalFileDialog::initializeDialog()
if (options()->fileMode() == QFileDialogOptions::ExistingFiles)
d->multipleFiles = true;
+ if (options()->fileMode() == QFileDialogOptions::Directory || options()->fileMode() == QFileDialogOptions::DirectoryOnly)
+ d->directoryMode = true;
+
if (options()->isLabelExplicitlySet(QFileDialogOptions::Accept))
d->acceptLabel = options()->labelText(QFileDialogOptions::Accept);
@@ -160,32 +144,43 @@ void QXdgDesktopPortalFileDialog::initializeDialog()
if (!options()->mimeTypeFilters().isEmpty())
d->mimeTypesFilters = options()->mimeTypeFilters();
+ if (!options()->initiallySelectedMimeTypeFilter().isEmpty())
+ d->selectedMimeTypeFilter = options()->initiallySelectedMimeTypeFilter();
+
+ if (!options()->initiallySelectedNameFilter().isEmpty())
+ d->selectedNameFilter = options()->initiallySelectedNameFilter();
+
setDirectory(options()->initialDirectory());
}
-void QXdgDesktopPortalFileDialog::openPortal()
+void QXdgDesktopPortalFileDialog::openPortal(Qt::WindowFlags windowFlags, Qt::WindowModality windowModality, QWindow *parent)
{
- Q_D(const QXdgDesktopPortalFileDialog);
-
- QDBusMessage message = QDBusMessage::createMethodCall(QLatin1String("org.freedesktop.portal.Desktop"),
- QLatin1String("/org/freedesktop/portal/desktop"),
- QLatin1String("org.freedesktop.portal.FileChooser"),
- d->saveFile ? QLatin1String("SaveFile") : QLatin1String("OpenFile"));
- QString parentWindowId = QLatin1String("x11:") + QString::number(d->winId);
+ Q_D(QXdgDesktopPortalFileDialog);
+ QDBusMessage message = QDBusMessage::createMethodCall("org.freedesktop.portal.Desktop"_L1,
+ "/org/freedesktop/portal/desktop"_L1,
+ "org.freedesktop.portal.FileChooser"_L1,
+ d->saveFile ? "SaveFile"_L1 : "OpenFile"_L1);
QVariantMap options;
if (!d->acceptLabel.isEmpty())
- options.insert(QLatin1String("accept_label"), d->acceptLabel);
-
- options.insert(QLatin1String("modal"), d->modal);
- options.insert(QLatin1String("multiple"), d->multipleFiles);
-
- if (d->saveFile) {
- if (!d->directory.isEmpty())
- options.insert(QLatin1String("current_folder"), QFile::encodeName(d->directory).append('\0'));
-
- if (!d->selectedFiles.isEmpty())
- options.insert(QLatin1String("current_file"), QFile::encodeName(d->selectedFiles.first()).append('\0'));
+ options.insert("accept_label"_L1, d->acceptLabel);
+
+ options.insert("modal"_L1, windowModality != Qt::NonModal);
+ options.insert("multiple"_L1, d->multipleFiles);
+ options.insert("directory"_L1, d->directoryMode);
+
+ if (!d->directory.isEmpty())
+ options.insert("current_folder"_L1, QFile::encodeName(d->directory).append('\0'));
+
+ if (d->saveFile && !d->selectedFiles.isEmpty()) {
+ // current_file for the file to be pre-selected, current_name for the file name to be
+ // pre-filled current_file accepts absolute path and requires the file to exist while
+ // current_name accepts just file name
+ QFileInfo selectedFileInfo(d->selectedFiles.constFirst());
+ if (selectedFileInfo.exists())
+ options.insert("current_file"_L1,
+ QFile::encodeName(d->selectedFiles.constFirst()).append('\0'));
+ options.insert("current_name"_L1, selectedFileInfo.fileName());
}
// Insert filters
@@ -195,6 +190,9 @@ void QXdgDesktopPortalFileDialog::openPortal()
qDBusRegisterMetaType<FilterList>();
FilterList filterList;
+ auto selectedFilterIndex = filterList.size() - 1;
+
+ d->userVisibleToNameFilter.clear();
if (!d->mimeTypesFilters.isEmpty()) {
for (const QString &mimeTypefilter : d->mimeTypesFilters) {
@@ -215,17 +213,28 @@ void QXdgDesktopPortalFileDialog::openPortal()
filter.name = mimeType.comment();
filter.filterConditions = filterConditions;
+ if (filter.name.isEmpty())
+ filter.name = mimeTypefilter;
+
filterList << filter;
+
+ if (!d->selectedMimeTypeFilter.isEmpty() && d->selectedMimeTypeFilter == mimeTypefilter)
+ selectedFilterIndex = filterList.size() - 1;
}
} else if (!d->nameFilters.isEmpty()) {
- for (const QString &filter : d->nameFilters) {
+ for (const QString &nameFilter : d->nameFilters) {
// Do parsing:
// Supported format is ("Images (*.png *.jpg)")
QRegularExpression regexp(QPlatformFileDialogHelper::filterRegExp);
- QRegularExpressionMatch match = regexp.match(filter);
+ QRegularExpressionMatch match = regexp.match(nameFilter);
if (match.hasMatch()) {
QString userVisibleName = match.captured(1);
- QStringList filterStrings = match.captured(2).split(QLatin1Char(' '), QString::SkipEmptyParts);
+ QStringList filterStrings = match.captured(2).split(u' ', Qt::SkipEmptyParts);
+
+ if (filterStrings.isEmpty()) {
+ qWarning() << "Filter " << userVisibleName << " is empty and will be ignored.";
+ continue;
+ }
FilterConditionList filterConditions;
for (const QString &filterString : filterStrings) {
@@ -240,34 +249,58 @@ void QXdgDesktopPortalFileDialog::openPortal()
filter.filterConditions = filterConditions;
filterList << filter;
+
+ d->userVisibleToNameFilter.insert(userVisibleName, nameFilter);
+
+ if (!d->selectedNameFilter.isEmpty() && d->selectedNameFilter == nameFilter)
+ selectedFilterIndex = filterList.size() - 1;
}
}
}
if (!filterList.isEmpty())
- options.insert(QLatin1String("filters"), QVariant::fromValue(filterList));
+ options.insert("filters"_L1, QVariant::fromValue(filterList));
+
+ if (selectedFilterIndex != -1)
+ options.insert("current_filter"_L1, QVariant::fromValue(filterList[selectedFilterIndex]));
- options.insert(QLatin1String("handle_token"), QStringLiteral("qt%1").arg(QRandomGenerator::global()->generate()));
+ options.insert("handle_token"_L1, QStringLiteral("qt%1").arg(QRandomGenerator::global()->generate()));
// TODO choices a(ssa(ss)s)
// List of serialized combo boxes to add to the file chooser.
- message << parentWindowId << d->title << options;
+ auto unixServices = dynamic_cast<QGenericUnixServices *>(
+ QGuiApplicationPrivate::platformIntegration()->services());
+ if (parent && unixServices)
+ message << unixServices->portalWindowIdentifier(parent);
+ else
+ message << QString();
+
+ message << d->title << options;
QDBusPendingCall pendingCall = QDBusConnection::sessionBus().asyncCall(message);
QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pendingCall);
- connect(watcher, &QDBusPendingCallWatcher::finished, this, [this] (QDBusPendingCallWatcher *watcher) {
+ connect(watcher, &QDBusPendingCallWatcher::finished, this, [this, d, windowFlags, windowModality, parent] (QDBusPendingCallWatcher *watcher) {
QDBusPendingReply<QDBusObjectPath> reply = *watcher;
- if (reply.isError()) {
- Q_EMIT reject();
+ // Any error means the dialog is not shown and we need to fallback
+ d->failedToOpen = reply.isError();
+ if (d->failedToOpen) {
+ if (d->nativeFileDialog) {
+ d->nativeFileDialog->show(windowFlags, windowModality, parent);
+ if (d->loop.isRunning())
+ d->nativeFileDialog->exec();
+ } else {
+ Q_EMIT reject();
+ }
} else {
QDBusConnection::sessionBus().connect(nullptr,
reply.value().path(),
- QLatin1String("org.freedesktop.portal.Request"),
- QLatin1String("Response"),
+ "org.freedesktop.portal.Request"_L1,
+ "Response"_L1,
this,
SLOT(gotResponse(uint,QVariantMap)));
}
+ watcher->deleteLater();
});
}
@@ -292,7 +325,7 @@ QUrl QXdgDesktopPortalFileDialog::directory() const
{
Q_D(const QXdgDesktopPortalFileDialog);
- if (d->nativeFileDialog && (options()->fileMode() == QFileDialogOptions::Directory || options()->fileMode() == QFileDialogOptions::DirectoryOnly))
+ if (d->nativeFileDialog && useNativeFileDialog())
return d->nativeFileDialog->directory();
return d->directory;
@@ -314,7 +347,7 @@ QList<QUrl> QXdgDesktopPortalFileDialog::selectedFiles() const
{
Q_D(const QXdgDesktopPortalFileDialog);
- if (d->nativeFileDialog && (options()->fileMode() == QFileDialogOptions::Directory || options()->fileMode() == QFileDialogOptions::DirectoryOnly))
+ if (d->nativeFileDialog && useNativeFileDialog())
return d->nativeFileDialog->selectedFiles();
QList<QUrl> files;
@@ -334,6 +367,21 @@ void QXdgDesktopPortalFileDialog::setFilter()
}
}
+void QXdgDesktopPortalFileDialog::selectMimeTypeFilter(const QString &filter)
+{
+ Q_D(QXdgDesktopPortalFileDialog);
+ if (d->nativeFileDialog) {
+ d->nativeFileDialog->setOptions(options());
+ d->nativeFileDialog->selectMimeTypeFilter(filter);
+ }
+}
+
+QString QXdgDesktopPortalFileDialog::selectedMimeTypeFilter() const
+{
+ Q_D(const QXdgDesktopPortalFileDialog);
+ return d->selectedMimeTypeFilter;
+}
+
void QXdgDesktopPortalFileDialog::selectNameFilter(const QString &filter)
{
Q_D(QXdgDesktopPortalFileDialog);
@@ -346,24 +394,21 @@ void QXdgDesktopPortalFileDialog::selectNameFilter(const QString &filter)
QString QXdgDesktopPortalFileDialog::selectedNameFilter() const
{
- // TODO
- return QString();
+ Q_D(const QXdgDesktopPortalFileDialog);
+ return d->selectedNameFilter;
}
void QXdgDesktopPortalFileDialog::exec()
{
Q_D(QXdgDesktopPortalFileDialog);
- if (d->nativeFileDialog && (options()->fileMode() == QFileDialogOptions::Directory || options()->fileMode() == QFileDialogOptions::DirectoryOnly)) {
+ if (d->nativeFileDialog && useNativeFileDialog()) {
d->nativeFileDialog->exec();
return;
}
// HACK we have to avoid returning until we emit that the dialog was accepted or rejected
- QEventLoop loop;
- loop.connect(this, SIGNAL(accept()), SLOT(quit()));
- loop.connect(this, SIGNAL(reject()), SLOT(quit()));
- loop.exec();
+ d->loop.exec();
}
void QXdgDesktopPortalFileDialog::hide()
@@ -380,13 +425,10 @@ bool QXdgDesktopPortalFileDialog::show(Qt::WindowFlags windowFlags, Qt::WindowMo
initializeDialog();
- d->modal = windowModality != Qt::NonModal;
- d->winId = parent ? parent->winId() : 0;
-
- if (d->nativeFileDialog && (options()->fileMode() == QFileDialogOptions::Directory || options()->fileMode() == QFileDialogOptions::DirectoryOnly))
+ if (d->nativeFileDialog && useNativeFileDialog(OpenFallback))
return d->nativeFileDialog->show(windowFlags, windowModality, parent);
- openPortal();
+ openPortal(windowFlags, windowModality, parent);
return true;
}
@@ -396,13 +438,43 @@ void QXdgDesktopPortalFileDialog::gotResponse(uint response, const QVariantMap &
Q_D(QXdgDesktopPortalFileDialog);
if (!response) {
- if (results.contains(QLatin1String("uris")))
- d->selectedFiles = results.value(QLatin1String("uris")).toStringList();
-
+ if (results.contains("uris"_L1))
+ d->selectedFiles = results.value("uris"_L1).toStringList();
+
+ if (results.contains("current_filter"_L1)) {
+ const Filter selectedFilter = qdbus_cast<Filter>(results.value(QStringLiteral("current_filter")));
+ if (!selectedFilter.filterConditions.empty() && selectedFilter.filterConditions[0].type == MimeType) {
+ // s.a. QXdgDesktopPortalFileDialog::openPortal which basically does the inverse
+ d->selectedMimeTypeFilter = selectedFilter.filterConditions[0].pattern;
+ d->selectedNameFilter.clear();
+ } else {
+ d->selectedNameFilter = d->userVisibleToNameFilter.value(selectedFilter.name);
+ d->selectedMimeTypeFilter.clear();
+ }
+ }
Q_EMIT accept();
} else {
Q_EMIT reject();
}
}
+bool QXdgDesktopPortalFileDialog::useNativeFileDialog(QXdgDesktopPortalFileDialog::FallbackType fallbackType) const
+{
+ Q_D(const QXdgDesktopPortalFileDialog);
+
+ if (d->failedToOpen && fallbackType != OpenFallback)
+ return true;
+
+ if (d->fileChooserPortalVersion < 3) {
+ if (options()->fileMode() == QFileDialogOptions::Directory)
+ return true;
+ else if (options()->fileMode() == QFileDialogOptions::DirectoryOnly)
+ return true;
+ }
+
+ return false;
+}
+
QT_END_NAMESPACE
+
+#include "moc_qxdgdesktopportalfiledialog_p.cpp"
diff --git a/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportalfiledialog_p.h b/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportalfiledialog_p.h
index c1f1a2c005..f309307cd6 100644
--- a/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportalfiledialog_p.h
+++ b/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportalfiledialog_p.h
@@ -1,46 +1,10 @@
-/****************************************************************************
-**
-** Copyright (C) 2017-2018 Red Hat, Inc
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2017-2018 Red Hat, Inc
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QXDGDESKTOPPORTALFILEDIALOG_P_H
#define QXDGDESKTOPPORTALFILEDIALOG_P_H
#include <qpa/qplatformdialoghelper.h>
-#include <QVector>
+#include <QList>
QT_BEGIN_NAMESPACE
@@ -51,6 +15,11 @@ class QXdgDesktopPortalFileDialog : public QPlatformFileDialogHelper
Q_OBJECT
Q_DECLARE_PRIVATE(QXdgDesktopPortalFileDialog)
public:
+ enum FallbackType {
+ GenericFallback,
+ OpenFallback
+ };
+
enum ConditionType : uint {
GlobalPattern = 0,
MimeType = 1
@@ -61,15 +30,15 @@ public:
ConditionType type;
QString pattern; // E.g. '*ico' or 'image/png'
};
- typedef QVector<FilterCondition> FilterConditionList;
+ typedef QList<FilterCondition> FilterConditionList;
struct Filter {
QString name; // E.g. 'Images' or 'Text
FilterConditionList filterConditions;; // E.g. [(0, '*.ico'), (1, 'image/png')] or [(0, '*.txt')]
};
- typedef QVector<Filter> FilterList;
+ typedef QList<Filter> FilterList;
- QXdgDesktopPortalFileDialog(QPlatformFileDialogHelper *nativeFileDialog = nullptr);
+ QXdgDesktopPortalFileDialog(QPlatformFileDialogHelper *nativeFileDialog = nullptr, uint fileChooserPortalVersion = 0);
~QXdgDesktopPortalFileDialog();
bool defaultNameFilterDisables() const override;
@@ -80,6 +49,8 @@ public:
void setFilter() override;
void selectNameFilter(const QString &filter) override;
QString selectedNameFilter() const override;
+ void selectMimeTypeFilter(const QString &filter) override;
+ QString selectedMimeTypeFilter() const override;
void exec() override;
bool show(Qt::WindowFlags windowFlags, Qt::WindowModality windowModality, QWindow *parent) override;
@@ -90,7 +61,8 @@ private Q_SLOTS:
private:
void initializeDialog();
- void openPortal();
+ void openPortal(Qt::WindowFlags windowFlags, Qt::WindowModality windowModality, QWindow *parent);
+ bool useNativeFileDialog(FallbackType fallbackType = GenericFallback) const;
QScopedPointer<QXdgDesktopPortalFileDialogPrivate> d_ptr;
};
diff --git a/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportaltheme.cpp b/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportaltheme.cpp
index fb65f6d909..7e2a9daacb 100644
--- a/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportaltheme.cpp
+++ b/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportaltheme.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qxdgdesktopportaltheme.h"
#include "qxdgdesktopportalfiledialog_p.h"
@@ -45,11 +9,26 @@
#include <qpa/qplatformthemefactory_p.h>
#include <qpa/qplatformintegration.h>
+#include <QDBusConnection>
+#include <QDBusMessage>
+#include <QDBusPendingCall>
+#include <QDBusPendingCallWatcher>
+#include <QDBusPendingReply>
+#include <QDBusReply>
+
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
class QXdgDesktopPortalThemePrivate : public QPlatformThemePrivate
{
public:
+ enum XdgColorschemePref {
+ None,
+ PreferDark,
+ PreferLight
+ };
+
QXdgDesktopPortalThemePrivate()
: QPlatformThemePrivate()
{ }
@@ -59,7 +38,33 @@ public:
delete baseTheme;
}
- QPlatformTheme *baseTheme;
+ /*! \internal
+
+ Converts the given Freedesktop color scheme setting \a colorschemePref to a Qt::ColorScheme value.
+ Specification: https://github.com/flatpak/xdg-desktop-portal/blob/d7a304a00697d7d608821253cd013f3b97ac0fb6/data/org.freedesktop.impl.portal.Settings.xml#L33-L45
+
+ Unfortunately the enum numerical values are not defined identically, so we have to convert them.
+
+ The mapping is as follows:
+
+ Enum Index: Freedesktop definition | Qt definition
+ ----------------------------------- | -------------
+ 0: No preference | 0: Unknown
+ 1: Prefer dark appearance | 2: Dark
+ 2: Prefer light appearance | 1: Light
+ */
+ static Qt::ColorScheme colorSchemeFromXdgPref(const XdgColorschemePref colorschemePref)
+ {
+ switch (colorschemePref) {
+ case PreferDark: return Qt::ColorScheme::Dark;
+ case PreferLight: return Qt::ColorScheme::Light;
+ default: return Qt::ColorScheme::Unknown;
+ }
+ }
+
+ QPlatformTheme *baseTheme = nullptr;
+ uint fileChooserPortalVersion = 0;
+ Qt::ColorScheme colorScheme = Qt::ColorScheme::Unknown;
};
QXdgDesktopPortalTheme::QXdgDesktopPortalTheme()
@@ -70,7 +75,7 @@ QXdgDesktopPortalTheme::QXdgDesktopPortalTheme()
QStringList themeNames;
themeNames += QGuiApplicationPrivate::platform_integration->themeNames();
// 1) Look for a theme plugin.
- for (const QString &themeName : qAsConst(themeNames)) {
+ for (const QString &themeName : std::as_const(themeNames)) {
d->baseTheme = QPlatformThemeFactory::create(themeName, nullptr);
if (d->baseTheme)
break;
@@ -79,7 +84,7 @@ QXdgDesktopPortalTheme::QXdgDesktopPortalTheme()
// 2) If no theme plugin was found ask the platform integration to
// create a theme
if (!d->baseTheme) {
- for (const QString &themeName : qAsConst(themeNames)) {
+ for (const QString &themeName : std::as_const(themeNames)) {
d->baseTheme = QGuiApplicationPrivate::platform_integration->createPlatformTheme(themeName);
if (d->baseTheme)
break;
@@ -90,6 +95,37 @@ QXdgDesktopPortalTheme::QXdgDesktopPortalTheme()
// 3) Fall back on the built-in "null" platform theme.
if (!d->baseTheme)
d->baseTheme = new QPlatformTheme;
+
+ // Get information about portal version
+ QDBusMessage message = QDBusMessage::createMethodCall("org.freedesktop.portal.Desktop"_L1,
+ "/org/freedesktop/portal/desktop"_L1,
+ "org.freedesktop.DBus.Properties"_L1,
+ "Get"_L1);
+ message << "org.freedesktop.portal.FileChooser"_L1 << "version"_L1;
+ QDBusPendingCall pendingCall = QDBusConnection::sessionBus().asyncCall(message);
+ QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pendingCall);
+ QObject::connect(watcher, &QDBusPendingCallWatcher::finished, watcher, [d] (QDBusPendingCallWatcher *watcher) {
+ QDBusPendingReply<QVariant> reply = *watcher;
+ if (reply.isValid()) {
+ d->fileChooserPortalVersion = reply.value().toUInt();
+ }
+ watcher->deleteLater();
+ });
+
+ // Get information about system theme preference
+ message = QDBusMessage::createMethodCall("org.freedesktop.portal.Desktop"_L1,
+ "/org/freedesktop/portal/desktop"_L1,
+ "org.freedesktop.portal.Settings"_L1,
+ "Read"_L1);
+ message << "org.freedesktop.appearance"_L1 << "color-scheme"_L1;
+
+ // this must not be asyncCall() because we have to set appearance now
+ QDBusReply<QVariant> reply = QDBusConnection::sessionBus().call(message);
+ if (reply.isValid()) {
+ const QDBusVariant dbusVariant = qvariant_cast<QDBusVariant>(reply.value());
+ const QXdgDesktopPortalThemePrivate::XdgColorschemePref xdgPref = static_cast<QXdgDesktopPortalThemePrivate::XdgColorschemePref>(dbusVariant.variant().toUInt());
+ d->colorScheme = QXdgDesktopPortalThemePrivate::colorSchemeFromXdgPref(xdgPref);
+ }
}
QPlatformMenuItem* QXdgDesktopPortalTheme::createPlatformMenuItem() const
@@ -130,9 +166,12 @@ QPlatformDialogHelper* QXdgDesktopPortalTheme::createPlatformDialogHelper(Dialog
{
Q_D(const QXdgDesktopPortalTheme);
- if (type == FileDialog) {
+ if (type == FileDialog && d->fileChooserPortalVersion) {
+ // Older versions of FileChooser portal don't support opening directories, therefore we fallback
+ // to native file dialog opened inside the sandbox to open a directory.
if (d->baseTheme->usePlatformNativeDialog(type))
- return new QXdgDesktopPortalFileDialog(static_cast<QPlatformFileDialogHelper*>(d->baseTheme->createPlatformDialogHelper(type)));
+ return new QXdgDesktopPortalFileDialog(static_cast<QPlatformFileDialogHelper*>(d->baseTheme->createPlatformDialogHelper(type)),
+ d->fileChooserPortalVersion);
return new QXdgDesktopPortalFileDialog;
}
@@ -166,6 +205,14 @@ QVariant QXdgDesktopPortalTheme::themeHint(ThemeHint hint) const
return d->baseTheme->themeHint(hint);
}
+Qt::ColorScheme QXdgDesktopPortalTheme::colorScheme() const
+{
+ Q_D(const QXdgDesktopPortalTheme);
+ if (d->colorScheme == Qt::ColorScheme::Unknown)
+ return d->baseTheme->colorScheme();
+ return d->colorScheme;
+}
+
QPixmap QXdgDesktopPortalTheme::standardPixmap(StandardPixmap sp, const QSizeF &size) const
{
Q_D(const QXdgDesktopPortalTheme);
diff --git a/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportaltheme.h b/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportaltheme.h
index d38b3ddda3..1ac04c45e6 100644
--- a/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportaltheme.h
+++ b/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportaltheme.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QXDGDESKTOPPORTALTHEME_H
#define QXDGDESKTOPPORTALTHEME_H
@@ -70,6 +34,8 @@ public:
QVariant themeHint(ThemeHint hint) const override;
+ Qt::ColorScheme colorScheme() const override;
+
QPixmap standardPixmap(StandardPixmap sp, const QSizeF &size) const override;
QIcon fileIcon(const QFileInfo &fileInfo,
QPlatformTheme::IconOptions iconOptions = { }) const override;
diff --git a/src/plugins/platformthemes/xdgdesktopportal/xdgdesktopportal.pro b/src/plugins/platformthemes/xdgdesktopportal/xdgdesktopportal.pro
deleted file mode 100644
index 0a71484cf9..0000000000
--- a/src/plugins/platformthemes/xdgdesktopportal/xdgdesktopportal.pro
+++ /dev/null
@@ -1,17 +0,0 @@
-TARGET = qxdgdesktopportal
-
-PLUGIN_TYPE = platformthemes
-PLUGIN_EXTENDS = -
-PLUGIN_CLASS_NAME = QXdgDesktopPortalThemePlugin
-load(qt_plugin)
-
-QT += core-private dbus gui-private theme_support-private
-
-HEADERS += \
- qxdgdesktopportaltheme.h \
- qxdgdesktopportalfiledialog_p.h
-
-SOURCES += \
- main.cpp \
- qxdgdesktopportaltheme.cpp \
- qxdgdesktopportalfiledialog.cpp
diff --git a/src/plugins/plugins.pro b/src/plugins/plugins.pro
deleted file mode 100644
index cd4d301194..0000000000
--- a/src/plugins/plugins.pro
+++ /dev/null
@@ -1,14 +0,0 @@
-TEMPLATE = subdirs
-QT_FOR_CONFIG += network
-
-qtHaveModule(sql): SUBDIRS += sqldrivers
-qtHaveModule(network):qtConfig(bearermanagement): SUBDIRS += bearer
-qtHaveModule(gui) {
- SUBDIRS *= platforms platforminputcontexts platformthemes
- qtConfig(imageformatplugin): SUBDIRS *= imageformats
- !android:qtConfig(library): SUBDIRS *= generic
-}
-qtHaveModule(widgets): SUBDIRS += styles
-
-!winrt:qtHaveModule(printsupport): \
- SUBDIRS += printsupport
diff --git a/src/plugins/printsupport/.prev_CMakeLists.txt b/src/plugins/printsupport/.prev_CMakeLists.txt
deleted file mode 100644
index 5853d82c6a..0000000000
--- a/src/plugins/printsupport/.prev_CMakeLists.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-# Generated from printsupport.pro.
-
-if(APPLE_OSX)
- add_subdirectory(cocoa)
-endif()
-if(WIN32)
- add_subdirectory(windows)
-endif()
-if(QT_FEATURE_cups AND UNIX AND NOT APPLE)
- add_subdirectory(cups)
-endif()
diff --git a/src/plugins/printsupport/CMakeLists.txt b/src/plugins/printsupport/CMakeLists.txt
index 22b753f5c0..7736684762 100644
--- a/src/plugins/printsupport/CMakeLists.txt
+++ b/src/plugins/printsupport/CMakeLists.txt
@@ -1,11 +1,6 @@
-# Generated from printsupport.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
-if(APPLE_OSX)
- add_subdirectory(cocoa)
-endif()
-if(WIN32)
- # add_subdirectory(windows) # special case TODO
-endif()
if(QT_FEATURE_cups AND UNIX AND NOT APPLE)
add_subdirectory(cups)
endif()
diff --git a/src/plugins/printsupport/cocoa/CMakeLists.txt b/src/plugins/printsupport/cocoa/CMakeLists.txt
deleted file mode 100644
index 72660dc173..0000000000
--- a/src/plugins/printsupport/cocoa/CMakeLists.txt
+++ /dev/null
@@ -1,22 +0,0 @@
-# Generated from cocoa.pro.
-
-#####################################################################
-## QCocoaPrinterSupportPlugin Plugin:
-#####################################################################
-
-qt_add_plugin(QCocoaPrinterSupportPlugin
- OUTPUT_NAME cocoaprintersupport
- TYPE printsupport
- SOURCES
- main.cpp
- PUBLIC_LIBRARIES
- ${FWAppKit}
- Qt::Core
- Qt::Gui
- Qt::GuiPrivate
- Qt::PrintSupportPrivate
-)
-
-#### Keys ignored in scope 1:.:.:cocoa.pro:<TRUE>:
-# MODULE = "cocoaprintersupport"
-# OTHER_FILES = "cocoa.json"
diff --git a/src/plugins/printsupport/cocoa/cocoa.json b/src/plugins/printsupport/cocoa/cocoa.json
deleted file mode 100644
index 85c38c42be..0000000000
--- a/src/plugins/printsupport/cocoa/cocoa.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "Keys": [ "cocoaprintersupport" ]
-}
diff --git a/src/plugins/printsupport/cocoa/cocoa.pro b/src/plugins/printsupport/cocoa/cocoa.pro
deleted file mode 100644
index 242c596bcd..0000000000
--- a/src/plugins/printsupport/cocoa/cocoa.pro
+++ /dev/null
@@ -1,13 +0,0 @@
-TARGET = cocoaprintersupport
-MODULE = cocoaprintersupport
-
-QT += gui-private printsupport-private
-LIBS += -framework AppKit
-
-SOURCES += main.cpp
-
-OTHER_FILES += cocoa.json
-
-PLUGIN_TYPE = printsupport
-PLUGIN_CLASS_NAME = QCocoaPrinterSupportPlugin
-load(qt_plugin)
diff --git a/src/plugins/printsupport/cocoa/main.cpp b/src/plugins/printsupport/cocoa/main.cpp
deleted file mode 100644
index b6830c88d4..0000000000
--- a/src/plugins/printsupport/cocoa/main.cpp
+++ /dev/null
@@ -1,76 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtPrintSupport module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and 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 <QtCore/QMetaMethod>
-#include <QtGui/QGuiApplication>
-#include <qpa/qplatformnativeinterface.h>
-#include <qpa/qplatformprintplugin.h>
-
-QT_BEGIN_NAMESPACE
-
-class QCocoaPrinterSupportPlugin : public QPlatformPrinterSupportPlugin
-{
- Q_OBJECT
- Q_PLUGIN_METADATA(IID QPlatformPrinterSupportFactoryInterface_iid FILE "cocoa.json")
-
-public:
- QPlatformPrinterSupport *create(const QString &);
-};
-
-QPlatformPrinterSupport *QCocoaPrinterSupportPlugin::create(const QString &key)
-{
- if (key.compare(key, QLatin1String("cocoaprintersupport"), Qt::CaseInsensitive) != 0)
- return 0;
- QGuiApplication *app = qobject_cast<QGuiApplication *>(QCoreApplication::instance());
- if (!app)
- return 0;
- QPlatformNativeInterface *platformNativeInterface = app->platformNativeInterface();
- int at = platformNativeInterface->metaObject()->indexOfMethod("createPlatformPrinterSupport()");
- if (at == -1)
- return 0;
- QMetaMethod createPlatformPrinterSupport = platformNativeInterface->metaObject()->method(at);
- QPlatformPrinterSupport *platformPrinterSupport = 0;
- if (!createPlatformPrinterSupport.invoke(platformNativeInterface, Q_RETURN_ARG(QPlatformPrinterSupport *, platformPrinterSupport)))
- return 0;
- return platformPrinterSupport;
-}
-
-QT_END_NAMESPACE
-
-#include "main.moc"
diff --git a/src/plugins/printsupport/cups/.prev_CMakeLists.txt b/src/plugins/printsupport/cups/.prev_CMakeLists.txt
deleted file mode 100644
index c65ffb89c7..0000000000
--- a/src/plugins/printsupport/cups/.prev_CMakeLists.txt
+++ /dev/null
@@ -1,30 +0,0 @@
-# Generated from cups.pro.
-
-#####################################################################
-## QCupsPrinterSupportPlugin Plugin:
-#####################################################################
-
-qt_add_plugin(QCupsPrinterSupportPlugin
- OUTPUT_NAME cupsprintersupport
- TYPE printsupport
- SOURCES
- main.cpp
- qcupsprintengine.cpp qcupsprintengine_p.h
- qcupsprintersupport.cpp qcupsprintersupport_p.h
- qppdprintdevice.cpp qppdprintdevice.h
- INCLUDE_DIRECTORIES
- ../../../printsupport/kernel
- LIBRARIES
- Cups::Cups
- PUBLIC_LIBRARIES
- Qt::Core
- Qt::CorePrivate
- Qt::Gui
- Qt::GuiPrivate
- Qt::PrintSupport
- Qt::PrintSupportPrivate
-)
-
-#### Keys ignored in scope 1:.:.:cups.pro:<TRUE>:
-# MODULE = "cupsprintersupport"
-# OTHER_FILES = "cups.json"
diff --git a/src/plugins/printsupport/cups/CMakeLists.txt b/src/plugins/printsupport/cups/CMakeLists.txt
index 5c920443ea..b6400d2d36 100644
--- a/src/plugins/printsupport/cups/CMakeLists.txt
+++ b/src/plugins/printsupport/cups/CMakeLists.txt
@@ -1,14 +1,15 @@
-# Generated from cups.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
-qt_find_package(Cups PROVIDED_TARGETS Cups::Cups) # special case
+qt_find_package(Cups PROVIDED_TARGETS Cups::Cups)
#####################################################################
## QCupsPrinterSupportPlugin Plugin:
#####################################################################
-qt_add_plugin(QCupsPrinterSupportPlugin
+qt_internal_add_plugin(QCupsPrinterSupportPlugin
OUTPUT_NAME cupsprintersupport
- TYPE printsupport
+ PLUGIN_TYPE printsupport
SOURCES
main.cpp
qcupsprintengine.cpp qcupsprintengine_p.h
@@ -18,7 +19,6 @@ qt_add_plugin(QCupsPrinterSupportPlugin
../../../printsupport/kernel
LIBRARIES
Cups::Cups
- PUBLIC_LIBRARIES
Qt::Core
Qt::CorePrivate
Qt::Gui
@@ -26,7 +26,3 @@ qt_add_plugin(QCupsPrinterSupportPlugin
Qt::PrintSupport
Qt::PrintSupportPrivate
)
-
-#### Keys ignored in scope 1:.:.:cups.pro:<TRUE>:
-# MODULE = "cupsprintersupport"
-# OTHER_FILES = "cups.json"
diff --git a/src/plugins/printsupport/cups/cups.pro b/src/plugins/printsupport/cups/cups.pro
deleted file mode 100644
index 58bc11606b..0000000000
--- a/src/plugins/printsupport/cups/cups.pro
+++ /dev/null
@@ -1,23 +0,0 @@
-TARGET = cupsprintersupport
-MODULE = cupsprintersupport
-
-QT += core-private gui-private printsupport printsupport-private
-
-QMAKE_USE_PRIVATE += cups
-
-INCLUDEPATH += ../../../printsupport/kernel
-
-SOURCES += main.cpp \
- qppdprintdevice.cpp \
- qcupsprintersupport.cpp \
- qcupsprintengine.cpp
-
-HEADERS += qcupsprintersupport_p.h \
- qppdprintdevice.h \
- qcupsprintengine_p.h
-
-OTHER_FILES += cups.json
-
-PLUGIN_TYPE = printsupport
-PLUGIN_CLASS_NAME = QCupsPrinterSupportPlugin
-load(qt_plugin)
diff --git a/src/plugins/printsupport/cups/main.cpp b/src/plugins/printsupport/cups/main.cpp
index cf263a7f52..1d0ee5d8e5 100644
--- a/src/plugins/printsupport/cups/main.cpp
+++ b/src/plugins/printsupport/cups/main.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qcupsprintersupport_p.h"
@@ -45,6 +9,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
class QCupsPrinterSupportPlugin : public QPlatformPrinterSupportPlugin
{
Q_OBJECT
@@ -62,7 +28,7 @@ QStringList QCupsPrinterSupportPlugin::keys() const
QPlatformPrinterSupport *QCupsPrinterSupportPlugin::create(const QString &key)
{
- if (key.compare(key, QLatin1String("cupsprintersupport"), Qt::CaseInsensitive) == 0)
+ if (key.compare(key, "cupsprintersupport"_L1, Qt::CaseInsensitive) == 0)
return new QCupsPrinterSupport;
return 0;
}
diff --git a/src/plugins/printsupport/cups/qcupsprintengine.cpp b/src/plugins/printsupport/cups/qcupsprintengine.cpp
index 43d5e119ad..6c50c11c0f 100644
--- a/src/plugins/printsupport/cups/qcupsprintengine.cpp
+++ b/src/plugins/printsupport/cups/qcupsprintengine.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qcupsprintengine_p.h"
@@ -89,8 +53,10 @@ void QCupsPrintEngine::setProperty(PrintEnginePropertyKey key, const QVariant &v
break;
case PPK_Duplex: {
QPrint::DuplexMode mode = QPrint::DuplexMode(value.toInt());
- if (mode != d->duplex && d->m_printDevice.supportedDuplexModes().contains(mode))
+ if (d->m_printDevice.supportedDuplexModes().contains(mode)) {
d->duplex = mode;
+ d->duplexRequestedExplicitly = true;
+ }
break;
}
case PPK_PrinterName:
@@ -178,7 +144,20 @@ bool QCupsPrintEnginePrivate::openPrintDevice()
}
cupsTempFile = QString::fromLocal8Bit(filename);
outDevice = new QFile();
- static_cast<QFile *>(outDevice)->open(fd, QIODevice::WriteOnly);
+ if (!static_cast<QFile *>(outDevice)->open(fd, QIODevice::WriteOnly)) {
+ qWarning("QPdfPrinter: Could not open CUPS temporary file descriptor: %s",
+ qPrintable(outDevice->errorString()));
+ delete outDevice;
+ outDevice = nullptr;
+
+#if defined(Q_OS_WIN) && defined(Q_CC_MSVC)
+ ::_close(fd);
+#else
+ ::close(fd);
+#endif
+ fd = -1;
+ return false;
+ }
}
return true;
@@ -201,7 +180,7 @@ void QCupsPrintEnginePrivate::closePrintDevice()
// Set up print options.
QList<QPair<QByteArray, QByteArray> > options;
- QVector<cups_option_t> cupsOptStruct;
+ QList<cups_option_t> cupsOptStruct;
options.append(QPair<QByteArray, QByteArray>("media", m_pageLayout.pageSize().key().toLocal8Bit()));
@@ -249,7 +228,7 @@ void QCupsPrintEnginePrivate::closePrintDevice()
// Print the file
// Cups expect the printer original name without instance, the full name is used only to retrieve the configuration
- const auto parts = printerName.splitRef(QLatin1Char('/'));
+ const auto parts = QStringView{printerName}.split(u'/');
const auto printerOriginalName = parts.at(0);
cups_option_t* optPtr = cupsOptStruct.size() ? &cupsOptStruct.first() : 0;
cupsPrintFile(printerOriginalName.toLocal8Bit().constData(), tempFile.toLocal8Bit().constData(),
@@ -277,12 +256,18 @@ void QCupsPrintEnginePrivate::changePrinter(const QString &newPrinter)
m_printDevice.swap(printDevice);
printerName = m_printDevice.id();
- // Check if new printer supports current settings, otherwise us defaults
- if (duplex != QPrint::DuplexAuto && !m_printDevice.supportedDuplexModes().contains(duplex))
+ // in case a duplex value was explicitly set, check if new printer supports current value,
+ // otherwise use device default
+ if (!duplexRequestedExplicitly || !m_printDevice.supportedDuplexModes().contains(duplex)) {
duplex = m_printDevice.defaultDuplexMode();
- QPrint::ColorMode colorMode = grayscale ? QPrint::GrayScale : QPrint::Color;
- if (!m_printDevice.supportedColorModes().contains(colorMode))
- grayscale = m_printDevice.defaultColorMode() == QPrint::GrayScale;
+ duplexRequestedExplicitly = false;
+ }
+ QPrint::ColorMode colorMode = static_cast<QPrint::ColorMode>(printerColorMode());
+ if (!m_printDevice.supportedColorModes().contains(colorMode)) {
+ colorModel = (m_printDevice.defaultColorMode() == QPrint::GrayScale)
+ ? QPdfEngine::ColorModel::Grayscale
+ : QPdfEngine::ColorModel::RGB;
+ }
// Get the equivalent page size for this printer as supported names may be different
if (m_printDevice.supportedPageSize(m_pageLayout.pageSize()).isValid())
diff --git a/src/plugins/printsupport/cups/qcupsprintengine_p.h b/src/plugins/printsupport/cups/qcupsprintengine_p.h
index c021b0c643..d17b3aaedd 100644
--- a/src/plugins/printsupport/cups/qcupsprintengine_p.h
+++ b/src/plugins/printsupport/cups/qcupsprintengine_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QCUPSPRINTENGINE_P_H
#define QCUPSPRINTENGINE_P_H
@@ -100,6 +64,7 @@ private:
QStringList cupsOptions;
QString cupsTempFile;
QPrint::DuplexMode duplex;
+ bool duplexRequestedExplicitly = false;
};
QT_END_NAMESPACE
diff --git a/src/plugins/printsupport/cups/qcupsprintersupport.cpp b/src/plugins/printsupport/cups/qcupsprintersupport.cpp
index 42a7a821f2..6578d8a558 100644
--- a/src/plugins/printsupport/cups/qcupsprintersupport.cpp
+++ b/src/plugins/printsupport/cups/qcupsprintersupport.cpp
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2014 John Layt <jlayt@kde.org>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2014 John Layt <jlayt@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qcupsprintersupport_p.h"
@@ -47,14 +11,14 @@
#include <QtPrintSupport/QPrinterInfo>
-#if QT_CONFIG(dialogbuttonbox)
+#if QT_CONFIG(cupspassworddialog)
#include <QGuiApplication>
#include <QDialog>
#include <QDialogButtonBox>
#include <QFormLayout>
#include <QLabel>
#include <QLineEdit>
-#endif // QT_CONFIG(dialogbuttonbox)
+#endif // QT_CONFIG(cupspassworddialog)
#include <cups/ppd.h>
#ifndef QT_LINUXBASE // LSB merges everything into cups.h
@@ -63,7 +27,7 @@
QT_BEGIN_NAMESPACE
-#if QT_CONFIG(dialogbuttonbox)
+#if QT_CONFIG(cupspassworddialog)
static const char *getPasswordCB(const char */*prompt*/, http_t *http, const char */*method*/, const char *resource, void */*user_data*/)
{
// cups doesn't free the const char * we return so keep around
@@ -93,7 +57,7 @@ static const char *getPasswordCB(const char */*prompt*/, http_t *http, const cha
QString resourceString = QString::fromLocal8Bit(resource);
if (resourceString.startsWith(QStringLiteral("/printers/")))
- resourceString = resourceString.mid(QStringLiteral("/printers/").length());
+ resourceString = resourceString.mid(QStringLiteral("/printers/").size());
QLabel *label = new QLabel();
if (hostname == QStringLiteral("localhost")) {
@@ -125,16 +89,16 @@ static const char *getPasswordCB(const char */*prompt*/, http_t *http, const cha
return password.constData();
}
-#endif // QT_CONFIG(dialogbuttonbox)
+#endif // QT_CONFIG(cupspassworddialog)
QCupsPrinterSupport::QCupsPrinterSupport()
: QPlatformPrinterSupport()
{
-#if QT_CONFIG(dialogbuttonbox)
+#if QT_CONFIG(cupspassworddialog)
// Only show password dialog if GUI application
if (qobject_cast<QGuiApplication*>(QCoreApplication::instance()))
cupsSetPasswordCB2(getPasswordCB, nullptr /* user_data */ );
-#endif // QT_CONFIG(dialogbuttonbox)
+#endif // QT_CONFIG(cupspassworddialog)
}
QCupsPrinterSupport::~QCupsPrinterSupport()
@@ -148,7 +112,7 @@ QPrintEngine *QCupsPrinterSupport::createNativePrintEngine(QPrinter::PrinterMode
QPaintEngine *QCupsPrinterSupport::createPaintEngine(QPrintEngine *engine, QPrinter::PrinterMode printerMode)
{
- Q_UNUSED(printerMode)
+ Q_UNUSED(printerMode);
return static_cast<QCupsPrintEngine *>(engine);
}
@@ -166,7 +130,7 @@ QStringList QCupsPrinterSupport::availablePrintDeviceIds() const
for (int i = 0; i < count; ++i) {
QString printerId = QString::fromLocal8Bit(dests[i].name);
if (dests[i].instance)
- printerId += QLatin1Char('/') + QString::fromLocal8Bit(dests[i].instance);
+ printerId += u'/' + QString::fromLocal8Bit(dests[i].instance);
list.append(printerId);
}
cupsFreeDests(count, dests);
@@ -187,7 +151,7 @@ QString QCupsPrinterSupport::staticDefaultPrintDeviceId()
if (dests[i].is_default) {
printerId = QString::fromLocal8Bit(dests[i].name);
if (dests[i].instance) {
- printerId += QLatin1Char('/') + QString::fromLocal8Bit(dests[i].instance);
+ printerId += u'/' + QString::fromLocal8Bit(dests[i].instance);
break;
}
}
diff --git a/src/plugins/printsupport/cups/qcupsprintersupport_p.h b/src/plugins/printsupport/cups/qcupsprintersupport_p.h
index c2b4895c7f..bc70bae048 100644
--- a/src/plugins/printsupport/cups/qcupsprintersupport_p.h
+++ b/src/plugins/printsupport/cups/qcupsprintersupport_p.h
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2014 John Layt <jlayt@kde.org>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2014 John Layt <jlayt@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QCUPSPRINTERSUPPORT_H
#define QCUPSPRINTERSUPPORT_H
diff --git a/src/plugins/printsupport/cups/qppdprintdevice.cpp b/src/plugins/printsupport/cups/qppdprintdevice.cpp
index 8bfa239dbe..95813c90fa 100644
--- a/src/plugins/printsupport/cups/qppdprintdevice.cpp
+++ b/src/plugins/printsupport/cups/qppdprintdevice.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 John Layt <jlayt@kde.org>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2014 John Layt <jlayt@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qppdprintdevice.h"
@@ -52,6 +16,10 @@
QT_BEGIN_NAMESPACE
+// avoid all the warnings about using deprecated API from CUPS (as there is no real replacement)
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
+
QPpdPrintDevice::QPpdPrintDevice(const QString &id)
: QPlatformPrintDevice(id),
m_cupsDest(0),
@@ -60,7 +28,7 @@ QPpdPrintDevice::QPpdPrintDevice(const QString &id)
if (!id.isEmpty()) {
// TODO For now each dest is an individual device
- const auto parts = id.splitRef(QLatin1Char('/'));
+ const auto parts = QStringView{id}.split(u'/');
m_cupsName = parts.at(0).toUtf8();
if (parts.size() > 1)
m_cupsInstance = parts.at(1).toUtf8();
@@ -189,8 +157,8 @@ QMarginsF QPpdPrintDevice::printableMargins(const QPageSize &pageSize,
QPageLayout::Orientation orientation,
int resolution) const
{
- Q_UNUSED(orientation)
- Q_UNUSED(resolution)
+ Q_UNUSED(orientation);
+ Q_UNUSED(resolution);
if (!m_havePageSizes)
loadPageSizes();
// TODO Orientation?
@@ -460,7 +428,7 @@ bool QPpdPrintDevice::setProperty(QPrintDevice::PrintDevicePropertyKey key, cons
{
if (key == PDPK_PpdOption) {
const QStringList values = value.toStringList();
- if (values.count() == 2) {
+ if (values.size() == 2) {
ppdMarkOption(m_ppd, values[0].toLatin1(), values[1].toLatin1());
return true;
}
@@ -473,7 +441,7 @@ bool QPpdPrintDevice::isFeatureAvailable(QPrintDevice::PrintDevicePropertyKey ke
{
if (key == PDPK_PpdChoiceIsInstallableConflict) {
const QStringList values = params.toStringList();
- if (values.count() == 2)
+ if (values.size() == 2)
return ppdInstallableConflict(m_ppd, values[0].toLatin1(), values[1].toLatin1());
}
@@ -508,4 +476,6 @@ cups_ptype_e QPpdPrintDevice::printerTypeFlags() const
return static_cast<cups_ptype_e>(printerOption("printer-type").toUInt());
}
+QT_WARNING_POP
+
QT_END_NAMESPACE
diff --git a/src/plugins/printsupport/cups/qppdprintdevice.h b/src/plugins/printsupport/cups/qppdprintdevice.h
index 3baf8b771b..ea8f5f2768 100644
--- a/src/plugins/printsupport/cups/qppdprintdevice.h
+++ b/src/plugins/printsupport/cups/qppdprintdevice.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 John Layt <jlayt@kde.org>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2014 John Layt <jlayt@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QPPDPRINTDEVICE_H
#define QPPDPRINTDEVICE_H
diff --git a/src/plugins/printsupport/printsupport.pro b/src/plugins/printsupport/printsupport.pro
deleted file mode 100644
index 05cf1bc0b2..0000000000
--- a/src/plugins/printsupport/printsupport.pro
+++ /dev/null
@@ -1,6 +0,0 @@
-TEMPLATE = subdirs
-QT_FOR_CONFIG += printsupport-private
-
-osx: SUBDIRS += cocoa
-win32: SUBDIRS += windows
-unix:!darwin:qtConfig(cups): SUBDIRS += cups
diff --git a/src/plugins/printsupport/windows/main.cpp b/src/plugins/printsupport/windows/main.cpp
deleted file mode 100644
index 7575006569..0000000000
--- a/src/plugins/printsupport/windows/main.cpp
+++ /dev/null
@@ -1,66 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 <qpa/qplatformprintplugin.h>
-#include <QtCore/QStringList>
-
-#include "qwindowsprintersupport.h"
-
-QT_BEGIN_NAMESPACE
-
-class QWindowsPrinterSupportPlugin : public QPlatformPrinterSupportPlugin
-{
- Q_OBJECT
- Q_PLUGIN_METADATA(IID QPlatformPrinterSupportFactoryInterface_iid FILE "windows.json")
-
-public:
- QPlatformPrinterSupport *create(const QString &);
-};
-
-QPlatformPrinterSupport *QWindowsPrinterSupportPlugin::create(const QString &key)
-{
- if (key.compare(key, QLatin1String("windowsprintsupport"), Qt::CaseInsensitive) == 0)
- return new QWindowsPrinterSupport;
- return 0;
-}
-
-QT_END_NAMESPACE
-
-#include "main.moc"
diff --git a/src/plugins/printsupport/windows/qwindowsprintdevice.cpp b/src/plugins/printsupport/windows/qwindowsprintdevice.cpp
deleted file mode 100644
index f01e93d611..0000000000
--- a/src/plugins/printsupport/windows/qwindowsprintdevice.cpp
+++ /dev/null
@@ -1,571 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 John Layt <jlayt@kde.org>
-** Copyright (C) 2018 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 "qwindowsprintdevice.h"
-
-#include <qdebug.h>
-
-#ifndef DC_COLLATE
-# define DC_COLLATE 22
-#endif
-
-QT_BEGIN_NAMESPACE
-
-QT_WARNING_DISABLE_GCC("-Wsign-compare")
-typedef QVector<QWindowsPrinterInfo> WindowsPrinterLookup;
-Q_GLOBAL_STATIC(WindowsPrinterLookup, windowsDeviceLookup);
-
-extern qreal qt_pointMultiplier(QPageLayout::Unit unit);
-
-static inline uint qwcsnlen(const wchar_t *str, uint maxlen)
-{
- uint length = 0;
- if (str) {
- while (length < maxlen && *str++)
- length++;
- }
- return length;
-}
-
-static QPrint::InputSlot paperBinToInputSlot(int windowsId, const QString &name)
-{
- QPrint::InputSlot slot;
- slot.name = name;
- int i;
- for (i = 0; inputSlotMap[i].id != QPrint::CustomInputSlot; ++i) {
- if (inputSlotMap[i].windowsId == windowsId) {
- slot.key = inputSlotMap[i].key;
- slot.id = inputSlotMap[i].id;
- slot.windowsId = inputSlotMap[i].windowsId;
- return slot;
- }
- }
- slot.key = inputSlotMap[i].key;
- slot.id = inputSlotMap[i].id;
- slot.windowsId = windowsId;
- return slot;
-}
-
-static LPDEVMODE getDevmode(HANDLE hPrinter, const QString &printerId)
-{
- LPWSTR printerIdUtf16 = const_cast<LPWSTR>(reinterpret_cast<LPCWSTR>(printerId.utf16()));
- // Allocate the required DEVMODE buffer
- LONG dmSize = DocumentProperties(NULL, hPrinter, printerIdUtf16, NULL, NULL, 0);
- if (dmSize <= 0)
- return nullptr;
- LPDEVMODE pDevMode = reinterpret_cast<LPDEVMODE>(malloc(dmSize));
- // Get the default DevMode
- LONG result = DocumentProperties(NULL, hPrinter, printerIdUtf16, pDevMode, NULL, DM_OUT_BUFFER);
- if (result != IDOK) {
- free(pDevMode);
- pDevMode = nullptr;
- }
- return pDevMode;
-}
-
-QWindowsPrintDevice::QWindowsPrintDevice()
- : QPlatformPrintDevice(),
- m_hPrinter(0)
-{
-}
-
-QWindowsPrintDevice::QWindowsPrintDevice(const QString &id)
- : QPlatformPrintDevice(id),
- m_hPrinter(0)
-{
- // First do a fast lookup to see if printer exists, if it does then open it
- if (!id.isEmpty() && QWindowsPrintDevice::availablePrintDeviceIds().contains(id)) {
- if (OpenPrinter(const_cast<LPWSTR>(wcharId()), &m_hPrinter, nullptr)) {
- DWORD needed = 0;
- GetPrinter(m_hPrinter, 2, 0, 0, &needed);
- QScopedArrayPointer<BYTE> buffer(new BYTE[needed]);
- if (GetPrinter(m_hPrinter, 2, buffer.data(), needed, &needed)) {
- PPRINTER_INFO_2 info = reinterpret_cast<PPRINTER_INFO_2>(buffer.data());
- m_name = QString::fromWCharArray(info->pPrinterName);
- m_location = QString::fromWCharArray(info->pLocation);
- m_makeAndModel = QString::fromWCharArray(info->pDriverName); // TODO Check is not available elsewhere
- m_isRemote = info->Attributes & PRINTER_ATTRIBUTE_NETWORK;
- }
- QWindowsPrinterInfo m_info;
- m_info.m_id = m_id;
- m_info.m_name = m_name;
- m_info.m_location = m_location;
- m_info.m_makeAndModel = m_makeAndModel;
- m_info.m_isRemote = m_isRemote;
- m_infoIndex = windowsDeviceLookup()->indexOf(m_info);
- if (m_infoIndex != -1) {
- m_info = windowsDeviceLookup()->at(m_infoIndex);
- m_havePageSizes = m_info.m_havePageSizes;
- m_pageSizes = m_info.m_pageSizes;
- m_haveResolutions = m_info.m_haveResolutions;
- m_resolutions = m_info.m_resolutions;
- m_haveCopies = m_info.m_haveCopies;
- m_supportsMultipleCopies = m_info.m_supportsMultipleCopies;
- m_supportsCollateCopies = m_info.m_supportsCollateCopies;
- m_haveMinMaxPageSizes = m_info.m_haveMinMaxPageSizes;
- m_minimumPhysicalPageSize = m_info.m_minimumPhysicalPageSize;
- m_maximumPhysicalPageSize = m_info.m_maximumPhysicalPageSize;
- m_supportsCustomPageSizes = m_info.m_supportsCustomPageSizes;
- m_haveInputSlots = m_info.m_haveInputSlots;
- m_inputSlots = m_info.m_inputSlots;
- m_haveOutputBins = m_info.m_haveOutputBins;
- m_outputBins = m_info.m_outputBins;
- m_haveDuplexModes = m_info.m_haveDuplexModes;
- m_duplexModes = m_info.m_duplexModes;
- m_haveColorModes = m_info.m_haveColorModes;
- m_colorModes = m_info.m_colorModes;
- m_infoIndex = windowsDeviceLookup()->indexOf(m_info);
- } else {
- windowsDeviceLookup()->append(m_info);
- m_infoIndex = windowsDeviceLookup()->count() - 1;
- }
- }
- }
-}
-
-QWindowsPrintDevice::~QWindowsPrintDevice()
-{
- ClosePrinter(m_hPrinter);
-}
-
-bool QWindowsPrintDevice::isValid() const
-{
- return m_hPrinter;
-}
-
-bool QWindowsPrintDevice::isDefault() const
-{
- return m_id == defaultPrintDeviceId();
-}
-
-QPrint::DeviceState QWindowsPrintDevice::state() const
-{
- DWORD needed = 0;
- GetPrinter(m_hPrinter, 6, 0, 0, &needed);
- QScopedArrayPointer<BYTE> buffer(new BYTE[needed]);
-
- if (GetPrinter(m_hPrinter, 6, buffer.data(), needed, &needed)) {
- PPRINTER_INFO_6 info = reinterpret_cast<PPRINTER_INFO_6>(buffer.data());
- // TODO Check mapping
- if (info->dwStatus == 0
- || (info->dwStatus & PRINTER_STATUS_WAITING) == PRINTER_STATUS_WAITING
- || (info->dwStatus & PRINTER_STATUS_POWER_SAVE) == PRINTER_STATUS_POWER_SAVE) {
- return QPrint::Idle;
- } else if ((info->dwStatus & PRINTER_STATUS_PRINTING) == PRINTER_STATUS_PRINTING
- || (info->dwStatus & PRINTER_STATUS_BUSY) == PRINTER_STATUS_BUSY
- || (info->dwStatus & PRINTER_STATUS_INITIALIZING) == PRINTER_STATUS_INITIALIZING
- || (info->dwStatus & PRINTER_STATUS_IO_ACTIVE) == PRINTER_STATUS_IO_ACTIVE
- || (info->dwStatus & PRINTER_STATUS_PROCESSING) == PRINTER_STATUS_PROCESSING
- || (info->dwStatus & PRINTER_STATUS_WARMING_UP) == PRINTER_STATUS_WARMING_UP) {
- return QPrint::Active;
- }
- }
-
- return QPrint::Error;
-}
-
-void QWindowsPrintDevice::loadPageSizes() const
-{
- // Get the number of paper sizes and check all 3 attributes have same count
- DWORD paperCount = DeviceCapabilities((LPWSTR)m_id.utf16(), NULL, DC_PAPERNAMES, NULL, NULL);
- if (int(paperCount) > 0
- && DeviceCapabilities((LPWSTR)m_id.utf16(), NULL, DC_PAPERSIZE, NULL, NULL) == paperCount
- && DeviceCapabilities((LPWSTR)m_id.utf16(), NULL, DC_PAPERS, NULL, NULL) == paperCount) {
-
- QScopedArrayPointer<wchar_t> paperNames(new wchar_t[paperCount*64]);
- QScopedArrayPointer<POINT> winSizes(new POINT[paperCount]);
- QScopedArrayPointer<wchar_t> papers(new wchar_t[paperCount]);
-
- // Get the details and match the default paper size
- if (DeviceCapabilities((LPWSTR)m_id.utf16(), NULL, DC_PAPERNAMES, paperNames.data(), NULL) == paperCount
- && DeviceCapabilities((LPWSTR)m_id.utf16(), NULL, DC_PAPERSIZE, (wchar_t *)winSizes.data(), NULL) == paperCount
- && DeviceCapabilities((LPWSTR)m_id.utf16(), NULL, DC_PAPERS, papers.data(), NULL) == paperCount) {
-
- // Returned size is in tenths of a millimeter
- const qreal multiplier = qt_pointMultiplier(QPageLayout::Millimeter);
- for (int i = 0; i < int(paperCount); ++i) {
- QSize size = QSize(qRound((winSizes[i].x / 10.0) * multiplier), qRound((winSizes[i].y / 10.0) * multiplier));
- wchar_t *paper = paperNames.data() + (i * 64);
- QString name = QString::fromWCharArray(paper, qwcsnlen(paper, 64));
- m_pageSizes.append(createPageSize(papers[i], size, name));
- }
-
- }
- }
-
- m_havePageSizes = true;
- QWindowsPrinterInfo *info = windowsDeviceLookup()->data();
- info[m_infoIndex].m_havePageSizes = true;
- info[m_infoIndex].m_pageSizes = m_pageSizes;
-}
-
-QPageSize QWindowsPrintDevice::defaultPageSize() const
-{
- if (!m_havePageSizes)
- loadPageSizes();
-
- QPageSize pageSize;
-
- if (LPDEVMODE pDevMode = getDevmode(m_hPrinter, m_id)) {
- // Get the default paper size
- if (pDevMode->dmFields & DM_PAPERSIZE) {
- // Find the supported page size that matches, in theory default should be one of them
- foreach (const QPageSize &ps, m_pageSizes) {
- if (ps.windowsId() == pDevMode->dmPaperSize) {
- pageSize = ps;
- break;
- }
- }
- }
- // Clean-up
- free(pDevMode);
- }
-
- return pageSize;
-}
-
-QMarginsF QWindowsPrintDevice::printableMargins(const QPageSize &pageSize,
- QPageLayout::Orientation orientation,
- int resolution) const
-{
- // TODO This is slow, need to cache values or find better way!
- // Modify the DevMode to get the DC printable margins in device pixels
- QMarginsF margins = QMarginsF(0, 0, 0, 0);
- DWORD needed = 0;
- GetPrinter(m_hPrinter, 2, 0, 0, &needed);
- QScopedArrayPointer<BYTE> buffer(new BYTE[needed]);
- if (GetPrinter(m_hPrinter, 2, buffer.data(), needed, &needed)) {
- PPRINTER_INFO_2 info = reinterpret_cast<PPRINTER_INFO_2>(buffer.data());
- LPDEVMODE devMode = info->pDevMode;
- bool separateDevMode = false;
- if (!devMode) {
- // GetPrinter() didn't include the DEVMODE. Get it a different way.
- devMode = getDevmode(m_hPrinter, m_id);
- if (!devMode)
- return margins;
- separateDevMode = true;
- }
-
- HDC pDC = CreateDC(NULL, (LPWSTR)m_id.utf16(), NULL, devMode);
- if (pageSize.id() == QPageSize::Custom || pageSize.windowsId() <= 0 || pageSize.windowsId() > DMPAPER_LAST) {
- devMode->dmPaperSize = 0;
- devMode->dmPaperWidth = pageSize.size(QPageSize::Millimeter).width() * 10.0;
- devMode->dmPaperLength = pageSize.size(QPageSize::Millimeter).height() * 10.0;
- } else {
- devMode->dmPaperSize = pageSize.windowsId();
- }
- devMode->dmPrintQuality = resolution;
- devMode->dmOrientation = orientation == QPageLayout::Portrait ? DMORIENT_PORTRAIT : DMORIENT_LANDSCAPE;
- ResetDC(pDC, devMode);
- const int dpiWidth = GetDeviceCaps(pDC, LOGPIXELSX);
- const int dpiHeight = GetDeviceCaps(pDC, LOGPIXELSY);
- const qreal wMult = 72.0 / dpiWidth;
- const qreal hMult = 72.0 / dpiHeight;
- const qreal physicalWidth = GetDeviceCaps(pDC, PHYSICALWIDTH) * wMult;
- const qreal physicalHeight = GetDeviceCaps(pDC, PHYSICALHEIGHT) * hMult;
- const qreal printableWidth = GetDeviceCaps(pDC, HORZRES) * wMult;
- const qreal printableHeight = GetDeviceCaps(pDC, VERTRES) * hMult;
- const qreal leftMargin = GetDeviceCaps(pDC, PHYSICALOFFSETX)* wMult;
- const qreal topMargin = GetDeviceCaps(pDC, PHYSICALOFFSETY) * hMult;
- const qreal rightMargin = physicalWidth - leftMargin - printableWidth;
- const qreal bottomMargin = physicalHeight - topMargin - printableHeight;
- margins = QMarginsF(leftMargin, topMargin, rightMargin, bottomMargin);
- if (separateDevMode)
- free(devMode);
- DeleteDC(pDC);
- }
- return margins;
-}
-
-void QWindowsPrintDevice::loadResolutions() const
-{
- DWORD resCount = DeviceCapabilities((LPWSTR)m_id.utf16(), NULL, DC_ENUMRESOLUTIONS, NULL, NULL);
- if (int(resCount) > 0) {
- QScopedArrayPointer<LONG> resolutions(new LONG[resCount*2]);
- // Get the details and match the default paper size
- if (DeviceCapabilities((LPWSTR)m_id.utf16(), NULL, DC_ENUMRESOLUTIONS, (LPWSTR)resolutions.data(), NULL) == resCount) {
- for (int i = 0; i < int(resCount * 2); i += 2)
- m_resolutions.append(resolutions[i+1]);
- }
- }
- m_haveResolutions = true;
- QWindowsPrinterInfo *info = windowsDeviceLookup()->data();
- info[m_infoIndex].m_haveResolutions = true;
- info[m_infoIndex].m_resolutions = m_resolutions;
-}
-
-int QWindowsPrintDevice::defaultResolution() const
-{
- int resolution = 72; // TODO Set a sensible default?
-
- if (LPDEVMODE pDevMode = getDevmode(m_hPrinter, m_id)) {
- // Get the default resolution
- if (pDevMode->dmFields & DM_YRESOLUTION) {
- if (pDevMode->dmPrintQuality > 0)
- resolution = pDevMode->dmPrintQuality;
- else
- resolution = pDevMode->dmYResolution;
- }
- // Clean-up
- free(pDevMode);
- }
- return resolution;
-}
-
-void QWindowsPrintDevice::loadInputSlots() const
-{
- const auto printerId = wcharId();
- DWORD binCount = DeviceCapabilities(printerId, nullptr, DC_BINS, nullptr, nullptr);
- if (int(binCount) > 0
- && DeviceCapabilities(printerId, nullptr, DC_BINNAMES, nullptr, nullptr) == binCount) {
-
- QScopedArrayPointer<WORD> bins(new WORD[binCount]);
- QScopedArrayPointer<wchar_t> binNames(new wchar_t[binCount*24]);
-
- // Get the details and match the default paper size
- if (DeviceCapabilities(printerId, nullptr, DC_BINS,
- reinterpret_cast<LPWSTR>(bins.data()), nullptr) == binCount
- && DeviceCapabilities(printerId, nullptr, DC_BINNAMES, binNames.data(),
- nullptr) == binCount) {
-
- for (int i = 0; i < int(binCount); ++i) {
- wchar_t *binName = binNames.data() + (i * 24);
- QString name = QString::fromWCharArray(binName, qwcsnlen(binName, 24));
- m_inputSlots.append(paperBinToInputSlot(bins[i], name));
- }
-
- }
- }
-
- m_haveInputSlots = true;
- QWindowsPrinterInfo *info = windowsDeviceLookup()->data();
- info[m_infoIndex].m_haveInputSlots = true;
- info[m_infoIndex].m_inputSlots = m_inputSlots;
-}
-
-QPrint::InputSlot QWindowsPrintDevice::defaultInputSlot() const
-{
- QPrint::InputSlot inputSlot = QPlatformPrintDevice::defaultInputSlot();;
-
- if (LPDEVMODE pDevMode = getDevmode(m_hPrinter, m_id)) {
- // Get the default input slot
- if (pDevMode->dmFields & DM_DEFAULTSOURCE) {
- QPrint::InputSlot tempSlot = paperBinToInputSlot(pDevMode->dmDefaultSource, QString());
- foreach (const QPrint::InputSlot &slot, supportedInputSlots()) {
- if (slot.key == tempSlot.key) {
- inputSlot = slot;
- break;
- }
- }
- }
- // Clean-up
- free(pDevMode);
- }
- return inputSlot;
-}
-
-void QWindowsPrintDevice::loadOutputBins() const
-{
- m_outputBins.append(QPlatformPrintDevice::defaultOutputBin());
- m_haveOutputBins = true;
- QWindowsPrinterInfo *info = windowsDeviceLookup()->data();
- info[m_infoIndex].m_haveOutputBins = true;
- info[m_infoIndex].m_outputBins = m_outputBins;
-}
-
-void QWindowsPrintDevice::loadDuplexModes() const
-{
- m_duplexModes.append(QPrint::DuplexNone);
- DWORD duplex = DeviceCapabilities(wcharId(), nullptr, DC_DUPLEX, nullptr, nullptr);
- if (int(duplex) == 1) {
- // TODO Assume if duplex flag supports both modes
- m_duplexModes.append(QPrint::DuplexAuto);
- m_duplexModes.append(QPrint::DuplexLongSide);
- m_duplexModes.append(QPrint::DuplexShortSide);
- }
- m_haveDuplexModes = true;
- QWindowsPrinterInfo *info = windowsDeviceLookup()->data();
- info[m_infoIndex].m_haveDuplexModes = true;
- info[m_infoIndex].m_duplexModes = m_duplexModes;
-}
-
-QPrint::DuplexMode QWindowsPrintDevice::defaultDuplexMode() const
-{
- QPrint::DuplexMode duplexMode = QPrint::DuplexNone;
-
- if (LPDEVMODE pDevMode = getDevmode(m_hPrinter, m_id)) {
- // Get the default duplex mode
- if (pDevMode->dmFields & DM_DUPLEX) {
- if (pDevMode->dmDuplex == DMDUP_VERTICAL)
- duplexMode = QPrint::DuplexLongSide;
- else if (pDevMode->dmDuplex == DMDUP_HORIZONTAL)
- duplexMode = QPrint::DuplexShortSide;
- }
- // Clean-up
- free(pDevMode);
- }
- return duplexMode;
-}
-
-void QWindowsPrintDevice::loadColorModes() const
-{
- m_colorModes.append(QPrint::GrayScale);
- DWORD color = DeviceCapabilities(wcharId(), nullptr, DC_COLORDEVICE, nullptr, nullptr);
- if (int(color) == 1)
- m_colorModes.append(QPrint::Color);
- m_haveColorModes = true;
- QWindowsPrinterInfo *info = windowsDeviceLookup()->data();
- info[m_infoIndex].m_haveColorModes = true;
- info[m_infoIndex].m_colorModes = m_colorModes;
-}
-
-QPrint::ColorMode QWindowsPrintDevice::defaultColorMode() const
-{
- if (!m_haveColorModes)
- loadColorModes();
- if (!m_colorModes.contains(QPrint::Color))
- return QPrint::GrayScale;
-
- QPrint::ColorMode colorMode = QPrint::GrayScale;
-
- if (LPDEVMODE pDevMode = getDevmode(m_hPrinter, m_id)) {
- // Get the default color mode
- if (pDevMode->dmFields & DM_COLOR && pDevMode->dmColor == DMCOLOR_COLOR)
- colorMode = QPrint::Color;
- // Clean-up
- free(pDevMode);
- }
- return colorMode;
-}
-
-QStringList QWindowsPrintDevice::availablePrintDeviceIds()
-{
- QStringList list;
- DWORD needed = 0;
- DWORD returned = 0;
- if ((!EnumPrinters(PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS, NULL, 4, 0, 0, &needed, &returned) && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
- || !needed) {
- return list;
- }
- QScopedArrayPointer<BYTE> buffer(new BYTE[needed]);
- if (!EnumPrinters(PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS, NULL, 4, buffer.data(), needed, &needed, &returned))
- return list;
- PPRINTER_INFO_4 infoList = reinterpret_cast<PPRINTER_INFO_4>(buffer.data());
- for (uint i = 0; i < returned; ++i)
- list.append(QString::fromWCharArray(infoList[i].pPrinterName));
- return list;
-}
-
-QString QWindowsPrintDevice::defaultPrintDeviceId()
-{
- DWORD size = 0;
- if (GetDefaultPrinter(NULL, &size) == ERROR_FILE_NOT_FOUND)
- return QString();
-
- QScopedArrayPointer<wchar_t> name(new wchar_t[size]);
- GetDefaultPrinter(name.data(), &size);
- return QString::fromWCharArray(name.data());
-}
-
-void QWindowsPrintDevice::loadCopiesSupport() const
-{
- auto printerId = wcharId();
- m_supportsMultipleCopies = (DeviceCapabilities(printerId, NULL, DC_COPIES, NULL, NULL) > 1);
- m_supportsCollateCopies = DeviceCapabilities(printerId, NULL, DC_COLLATE, NULL, NULL);
- m_haveCopies = true;
- QWindowsPrinterInfo *info = windowsDeviceLookup()->data();
- info[m_infoIndex].m_haveCopies = true;
- info[m_infoIndex].m_supportsMultipleCopies = m_supportsMultipleCopies;
- info[m_infoIndex].m_supportsCollateCopies = m_supportsCollateCopies;
-}
-
-bool QWindowsPrintDevice::supportsCollateCopies() const
-{
- if (!m_haveCopies)
- loadCopiesSupport();
- return m_supportsCollateCopies;
-}
-
-bool QWindowsPrintDevice::supportsMultipleCopies() const
-{
- if (!m_haveCopies)
- loadCopiesSupport();
- return m_supportsMultipleCopies;
-}
-
-bool QWindowsPrintDevice::supportsCustomPageSizes() const
-{
- if (!m_haveMinMaxPageSizes)
- loadMinMaxPageSizes();
- return m_supportsCustomPageSizes;
-}
-
-QSize QWindowsPrintDevice::minimumPhysicalPageSize() const
-{
- if (!m_haveMinMaxPageSizes)
- loadMinMaxPageSizes();
- return m_minimumPhysicalPageSize;
-}
-
-QSize QWindowsPrintDevice::maximumPhysicalPageSize() const
-{
- if (!m_haveMinMaxPageSizes)
- loadMinMaxPageSizes();
- return m_maximumPhysicalPageSize;
-}
-
-void QWindowsPrintDevice::loadMinMaxPageSizes() const
-{
- // Min/Max custom size is in tenths of a millimeter
- const qreal multiplier = qt_pointMultiplier(QPageLayout::Millimeter);
- auto printerId = wcharId();
- DWORD min = DeviceCapabilities(printerId, NULL, DC_MINEXTENT, NULL, NULL);
- m_minimumPhysicalPageSize = QSize((LOWORD(min) / 10.0) * multiplier, (HIWORD(min) / 10.0) * multiplier);
- DWORD max = DeviceCapabilities(printerId, NULL, DC_MAXEXTENT, NULL, NULL);
- m_maximumPhysicalPageSize = QSize((LOWORD(max) / 10.0) * multiplier, (HIWORD(max) / 10.0) * multiplier);
- m_supportsCustomPageSizes = (m_maximumPhysicalPageSize.width() > 0 && m_maximumPhysicalPageSize.height() > 0);
- m_haveMinMaxPageSizes = true;
- QWindowsPrinterInfo *info = windowsDeviceLookup()->data();
- info[m_infoIndex].m_haveCopies = true;
- info[m_infoIndex].m_supportsMultipleCopies = m_supportsMultipleCopies;
- info[m_infoIndex].m_supportsCollateCopies = m_supportsCollateCopies;
-}
-
-QT_END_NAMESPACE
diff --git a/src/plugins/printsupport/windows/qwindowsprintdevice.h b/src/plugins/printsupport/windows/qwindowsprintdevice.h
deleted file mode 100644
index 166f0f65b2..0000000000
--- a/src/plugins/printsupport/windows/qwindowsprintdevice.h
+++ /dev/null
@@ -1,153 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 John Layt <jlayt@kde.org>
-** Copyright (C) 2018 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 QWINDOWSPRINTDEVICE_H
-#define QWINDOWSPRINTDEVICE_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists for the convenience
-// of internal files. This header file may change from version to version
-// without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <qpa/qplatformprintdevice.h>
-
-#include <QtCore/qt_windows.h>
-
-QT_BEGIN_NAMESPACE
-
-class QWindowsPrinterInfo
-{
-public:
- bool operator==(const QWindowsPrinterInfo &other) const
- {
- // We only need to check if these are the same for matching up
- return m_id == other.m_id && m_name == other.m_name &&
- m_location == other.m_location &&
- m_makeAndModel == other.m_makeAndModel &&
- m_isRemote == other.m_isRemote;
- }
- QString m_id;
- QString m_name;
- QString m_location;
- QString m_makeAndModel;
- QList<QPageSize> m_pageSizes;
- QList<int> m_resolutions;
- QVector<QPrint::InputSlot> m_inputSlots;
- QVector<QPrint::OutputBin> m_outputBins;
- QVector<QPrint::DuplexMode> m_duplexModes;
- QVector<QPrint::ColorMode> m_colorModes;
- QSize m_minimumPhysicalPageSize;
- QSize m_maximumPhysicalPageSize;
- bool m_isRemote = false;
- bool m_havePageSizes = false;
- bool m_haveResolutions = false;
- bool m_haveCopies = false;
- bool m_supportsMultipleCopies = false;
- bool m_supportsCollateCopies = false;
- bool m_haveMinMaxPageSizes = false;
- bool m_supportsCustomPageSizes = false;
- bool m_haveInputSlots = false;
- bool m_haveOutputBins = false;
- bool m_haveDuplexModes = false;
- bool m_haveColorModes = false;
-};
-
-class QWindowsPrintDevice : public QPlatformPrintDevice
-{
-public:
- QWindowsPrintDevice();
- explicit QWindowsPrintDevice(const QString &id);
- virtual ~QWindowsPrintDevice();
-
- bool isValid() const override;
- bool isDefault() const override;
-
- QPrint::DeviceState state() const override;
-
- QPageSize defaultPageSize() const override;
-
- QMarginsF printableMargins(const QPageSize &pageSize, QPageLayout::Orientation orientation,
- int resolution) const override;
-
- int defaultResolution() const override;
-
- QPrint::InputSlot defaultInputSlot() const override;
-
- QPrint::DuplexMode defaultDuplexMode() const override;
-
- QPrint::ColorMode defaultColorMode() const override;
-
- static QStringList availablePrintDeviceIds();
- static QString defaultPrintDeviceId();
-
- bool supportsCollateCopies() const override;
- bool supportsMultipleCopies() const override;
- bool supportsCustomPageSizes() const override;
- QSize minimumPhysicalPageSize() const override;
- QSize maximumPhysicalPageSize() const override;
-
-protected:
- void loadPageSizes() const override;
- void loadResolutions() const override;
- void loadInputSlots() const override;
- void loadOutputBins() const override;
- void loadDuplexModes() const override;
- void loadColorModes() const override;
- void loadCopiesSupport() const;
- void loadMinMaxPageSizes() const;
-
-private:
- LPCWSTR wcharId() const { return reinterpret_cast<LPCWSTR>(m_id.utf16()); }
-
- HANDLE m_hPrinter;
- mutable bool m_haveCopies;
- mutable bool m_haveMinMaxPageSizes;
- int m_infoIndex;
-};
-
-QT_END_NAMESPACE
-
-#endif // QWINDOWSPRINTDEVICE_H
diff --git a/src/plugins/printsupport/windows/qwindowsprinterinfo.cpp b/src/plugins/printsupport/windows/qwindowsprinterinfo.cpp
deleted file mode 100644
index e416dd7a21..0000000000
--- a/src/plugins/printsupport/windows/qwindowsprinterinfo.cpp
+++ /dev/null
@@ -1,120 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and 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 "qprinterinfo.h"
-#include "qprinterinfo_p.h"
-
-#include <qstringlist.h>
-
-#include <qt_windows.h>
-
-QT_BEGIN_NAMESPACE
-
-#ifndef QT_NO_PRINTER
-
-extern QPrinter::PaperSize mapDevmodePaperSize(int s);
-
-//QList<QPrinterInfo> QPrinterInfo::availablePrinters()
-//{
-// QList<QPrinterInfo> printers;
-
-// DWORD needed = 0;
-// DWORD returned = 0;
-// if (!EnumPrinters(PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS, NULL, 4, 0, 0, &needed, &returned)) {
-// LPBYTE buffer = new BYTE[needed];
-// if (EnumPrinters(PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS, NULL, 4, buffer, needed, &needed, &returned)) {
-// PPRINTER_INFO_4 infoList = reinterpret_cast<PPRINTER_INFO_4>(buffer);
-// QPrinterInfo defPrn = defaultPrinter();
-// for (uint i = 0; i < returned; ++i) {
-// QString printerName(QString::fromWCharArray(infoList[i].pPrinterName));
-
-// QPrinterInfo printerInfo(printerName);
-// if (printerInfo.printerName() == defPrn.printerName())
-// printerInfo.d_ptr->isDefault = true;
-// printers.append(printerInfo);
-// }
-// }
-// delete [] buffer;
-// }
-
-// return printers;
-//}
-
-//QPrinterInfo QPrinterInfo::defaultPrinter()
-//{
-// QString noPrinters(QLatin1String("qt_no_printers"));
-// wchar_t buffer[256];
-// GetProfileString(L"windows", L"device", (wchar_t*)noPrinters.utf16(), buffer, 256);
-// QString output = QString::fromWCharArray(buffer);
-// if (output != noPrinters) {
-// // Filter out the name of the printer, which should be everything before a comma.
-// QString printerName = output.split(QLatin1Char(',')).value(0);
-// QPrinterInfo printerInfo(printerName);
-// printerInfo.d_ptr->isDefault = true;
-// return printerInfo;
-// }
-
-// return QPrinterInfo();
-//}
-
-//QList<QPrinter::PaperSize> QPrinterInfo::supportedPaperSizes() const
-//{
-// const Q_D(QPrinterInfo);
-
-// QList<QPrinter::PaperSize> paperSizes;
-// if (isNull())
-// return paperSizes;
-
-// DWORD size = DeviceCapabilities(reinterpret_cast<const wchar_t*>(d->name.utf16()),
-// NULL, DC_PAPERS, NULL, NULL);
-// if ((int)size != -1) {
-// wchar_t *papers = new wchar_t[size];
-// size = DeviceCapabilities(reinterpret_cast<const wchar_t*>(d->name.utf16()),
-// NULL, DC_PAPERS, papers, NULL);
-// for (int c = 0; c < (int)size; ++c)
-// paperSizes.append(mapDevmodePaperSize(papers[c]));
-// delete [] papers;
-// }
-
-// return paperSizes;
-//}
-
-#endif // QT_NO_PRINTER
-
-QT_END_NAMESPACE
diff --git a/src/plugins/printsupport/windows/qwindowsprintersupport.cpp b/src/plugins/printsupport/windows/qwindowsprintersupport.cpp
deleted file mode 100644
index a7eabc2622..0000000000
--- a/src/plugins/printsupport/windows/qwindowsprintersupport.cpp
+++ /dev/null
@@ -1,84 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 "qwindowsprintersupport.h"
-#include "qwindowsprintdevice.h"
-
-#include <QtCore/QStringList>
-#include <qprintengine_win_p.h>
-#include <private/qprintdevice_p.h>
-
-QT_BEGIN_NAMESPACE
-
-QWindowsPrinterSupport::QWindowsPrinterSupport()
- : QPlatformPrinterSupport()
-{
-}
-
-QWindowsPrinterSupport::~QWindowsPrinterSupport()
-{
-}
-
-QPrintEngine *QWindowsPrinterSupport::createNativePrintEngine(QPrinter::PrinterMode printerMode, const QString &deviceId)
-{
- return new QWin32PrintEngine(printerMode, deviceId);
-}
-
-QPaintEngine *QWindowsPrinterSupport::createPaintEngine(QPrintEngine *engine, QPrinter::PrinterMode printerMode)
-{
- Q_UNUSED(printerMode)
- return static_cast<QWin32PrintEngine *>(engine);
-}
-
-QPrintDevice QWindowsPrinterSupport::createPrintDevice(const QString &id)
-{
- return QPlatformPrinterSupport::createPrintDevice(new QWindowsPrintDevice(id));
-}
-
-QStringList QWindowsPrinterSupport::availablePrintDeviceIds() const
-{
- return QWindowsPrintDevice::availablePrintDeviceIds();
-}
-
-QString QWindowsPrinterSupport::defaultPrintDeviceId() const
-{
- return QWindowsPrintDevice::defaultPrintDeviceId();
-}
-
-QT_END_NAMESPACE
diff --git a/src/plugins/printsupport/windows/qwindowsprintersupport.h b/src/plugins/printsupport/windows/qwindowsprintersupport.h
deleted file mode 100644
index 400701628e..0000000000
--- a/src/plugins/printsupport/windows/qwindowsprintersupport.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 WINDOWSPRINTERSUPPORT_H
-#define WINDOWSPRINTERSUPPORT_H
-
-#include <qpa/qplatformprintersupport.h>
-
-QT_BEGIN_NAMESPACE
-
-class QWindowsPrinterSupport : public QPlatformPrinterSupport
-{
- Q_DISABLE_COPY_MOVE(QWindowsPrinterSupport)
-public:
- QWindowsPrinterSupport();
- ~QWindowsPrinterSupport() override;
-
- QPrintEngine *createNativePrintEngine(QPrinter::PrinterMode printerMode, const QString &deviceId = QString()) override;
- QPaintEngine *createPaintEngine(QPrintEngine *printEngine, QPrinter::PrinterMode) override;
-
- QPrintDevice createPrintDevice(const QString &id) override;
- QStringList availablePrintDeviceIds() const override;
- QString defaultPrintDeviceId() const override;
-};
-
-QT_END_NAMESPACE
-
-#endif // WINDOWSPRINTERSUPPORT_H
diff --git a/src/plugins/printsupport/windows/windows.json b/src/plugins/printsupport/windows/windows.json
deleted file mode 100644
index 803052854e..0000000000
--- a/src/plugins/printsupport/windows/windows.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "Keys": [ "windowsprintsupport" ]
-}
diff --git a/src/plugins/printsupport/windows/windows.pro b/src/plugins/printsupport/windows/windows.pro
deleted file mode 100644
index 6ca601b2a4..0000000000
--- a/src/plugins/printsupport/windows/windows.pro
+++ /dev/null
@@ -1,26 +0,0 @@
-TARGET = windowsprintersupport
-MODULE = windowsprintersupport
-
-QT *= core-private
-QT *= gui-private
-QT *= printsupport-private
-
-INCLUDEPATH *= $$QT_SOURCE_TREE/src/printsupport/kernel
-
-SOURCES += \
- main.cpp \
- qwindowsprintersupport.cpp \
- qwindowsprintdevice.cpp \
-
-HEADERS += \
- qwindowsprintersupport.h \
- qwindowsprintdevice.h \
-
-OTHER_FILES += windows.json
-
-LIBS += -lwinspool -lcomdlg32
-QMAKE_USE_PRIVATE += user32 gdi32
-
-PLUGIN_TYPE = printsupport
-PLUGIN_CLASS_NAME = QWindowsPrinterSupportPlugin
-load(qt_plugin)
diff --git a/src/plugins/sqldrivers/.cmake.conf b/src/plugins/sqldrivers/.cmake.conf
new file mode 100644
index 0000000000..10bc1fd407
--- /dev/null
+++ b/src/plugins/sqldrivers/.cmake.conf
@@ -0,0 +1 @@
+set(QT_REPO_MODULE_VERSION "6.8.0")
diff --git a/src/plugins/sqldrivers/.prev_CMakeLists.txt b/src/plugins/sqldrivers/.prev_CMakeLists.txt
deleted file mode 100644
index 8752cf701f..0000000000
--- a/src/plugins/sqldrivers/.prev_CMakeLists.txt
+++ /dev/null
@@ -1,15 +0,0 @@
-# Generated from sqldrivers.pro.
-
-cmake_minimum_required(VERSION 3.15.0)
-
-project(ldrivers_FIXME
- VERSION 6.0.0
- DESCRIPTION "Qt ldrivers_FIXME Libraries"
- HOMEPAGE_URL "https://qt.io/"
- LANGUAGES CXX C
-)
-
-find_package(Qt6 ${PROJECT_VERSION} CONFIG REQUIRED COMPONENTS BuildInternals Core SET_ME_TO_SOMETHING_USEFUL)
-find_package(Qt6 ${PROJECT_VERSION} CONFIG OPTIONAL_COMPONENTS SET_ME_TO_SOMETHING_USEFUL)
-
-qt_build_repo()
diff --git a/src/plugins/sqldrivers/CMakeLists.txt b/src/plugins/sqldrivers/CMakeLists.txt
index d45f5712a8..43abb00ad1 100644
--- a/src/plugins/sqldrivers/CMakeLists.txt
+++ b/src/plugins/sqldrivers/CMakeLists.txt
@@ -1,6 +1,33 @@
-# Generated from sqldrivers.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.16)
+if (NOT CMAKE_PROJECT_NAME STREQUAL "QtBase" AND NOT CMAKE_PROJECT_NAME STREQUAL "Qt")
+ include(.cmake.conf)
+ # Store initial build type (if any is specified) to be read by
+ # qt_internal_set_cmake_build_type().
+ # See qt_internal_set_cmake_build_type() for details.
+ if(DEFINED CACHE{CMAKE_BUILD_TYPE})
+ set(__qt_internal_standalone_project_cmake_build_type_before_project_call
+ "${CMAKE_BUILD_TYPE}")
+ endif()
+
+ project(QSQLiteDriverPlugins
+ VERSION "${QT_REPO_MODULE_VERSION}"
+ DESCRIPTION "Qt6 SQL driver plugins"
+ HOMEPAGE_URL "https://qt.io/"
+ LANGUAGES CXX C ASM
+ )
+ find_package(Qt6 ${PROJECT_VERSION} CONFIG REQUIRED COMPONENTS
+ BuildInternals
+ Core
+ Sql
+ )
+ qt_prepare_standalone_project()
+else()
+ qt_internal_upgrade_cmake_policies()
+endif()
-# special case begin
# Currently handled completely manually.
# TODO sqldrivers_standalone {
@@ -17,7 +44,7 @@ include(configure.cmake)
qt_feature_module_end(NO_MODULE)
-if(QT_FEATURE_sql_psql)
+if(QT_FEATURE_sql_psql AND QT_FEATURE_regularexpression)
add_subdirectory(psql)
endif()
@@ -29,10 +56,6 @@ if(QT_FEATURE_sql_odbc)
add_subdirectory(odbc)
endif()
-if(QT_FEATURE_sql_tds)
-# TODO add_subdirectory(tds)
-endif()
-
if(QT_FEATURE_sql_oci)
add_subdirectory(oci)
endif()
@@ -45,11 +68,14 @@ if(QT_FEATURE_sql_sqlite)
add_subdirectory(sqlite)
endif()
-if(QT_FEATURE_sql_sqlite2)
-# TODO add_subdirectory(sqlite2)
+if(QT_FEATURE_sql_ibase)
+ add_subdirectory(ibase)
endif()
-if(QT_FEATURE_sql_ibase)
-# TODO add_subdirectory(ibase)
+if(QT_FEATURE_sql_mimer)
+ add_subdirectory(mimer)
+endif()
+
+if(NOT CMAKE_PROJECT_NAME STREQUAL "QtBase" AND NOT CMAKE_PROJECT_NAME STREQUAL "Qt")
+ qt_print_feature_summary()
endif()
-# special case end
diff --git a/src/plugins/sqldrivers/configure.cmake b/src/plugins/sqldrivers/configure.cmake
index 7cf0763da1..534ac020d8 100644
--- a/src/plugins/sqldrivers/configure.cmake
+++ b/src/plugins/sqldrivers/configure.cmake
@@ -1,17 +1,29 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
#### Inputs
+# input sqlite
+set(INPUT_sqlite "undefined" CACHE STRING "")
+set_property(CACHE INPUT_sqlite PROPERTY STRINGS undefined qt system)
+
#### Libraries
-qt_find_package(DB2 PROVIDED_TARGETS DB2::DB2)
-qt_find_package(MySQL PROVIDED_TARGETS MySQL::MySQL)
-qt_find_package(PostgreSQL PROVIDED_TARGETS PostgreSQL::PostgreSQL)
-qt_find_package(Oracle PROVIDED_TARGETS Oracle::OCI)
-qt_find_package(ODBC PROVIDED_TARGETS ODBC::ODBC)
-qt_find_package(SQLite3 PROVIDED_TARGETS SQLite::SQLite3)
+qt_find_package(DB2 PROVIDED_TARGETS DB2::DB2 MODULE_NAME sqldrivers QMAKE_LIB db2)
+qt_find_package(MySQL PROVIDED_TARGETS MySQL::MySQL MODULE_NAME sqldrivers QMAKE_LIB mysql)
+qt_find_package(PostgreSQL PROVIDED_TARGETS PostgreSQL::PostgreSQL MODULE_NAME sqldrivers QMAKE_LIB psql)
+qt_find_package(Oracle PROVIDED_TARGETS Oracle::OCI MODULE_NAME sqldrivers QMAKE_LIB oci)
+qt_find_package(ODBC PROVIDED_TARGETS ODBC::ODBC MODULE_NAME sqldrivers QMAKE_LIB odbc)
+qt_find_package(SQLite3 PROVIDED_TARGETS SQLite::SQLite3 MODULE_NAME sqldrivers QMAKE_LIB sqlite3)
+qt_find_package(Interbase PROVIDED_TARGETS Interbase::Interbase MODULE_NAME sqldrivers QMAKE_LIB ibase) # special case
+qt_find_package(Mimer PROVIDED_TARGETS MimerSQL::MimerSQL MODULE_NAME sqldrivers QMAKE_LIB mimer)
+if(NOT WIN32 AND QT_FEATURE_system_zlib)
+ qt_add_qmake_lib_dependency(sqlite3 zlib)
+endif()
#### Tests
@@ -26,7 +38,7 @@ qt_feature("sql-db2" PRIVATE
)
qt_feature("sql-ibase" PRIVATE
LABEL "InterBase"
- CONDITION libs.ibase OR FIXME
+ CONDITION Interbase_FOUND # special case
)
qt_feature("sql-mysql" PRIVATE
LABEL "MySql"
@@ -46,5 +58,31 @@ qt_feature("sql-psql" PRIVATE
)
qt_feature("sql-sqlite" PRIVATE
LABEL "SQLite"
- CONDITION QT_FEATURE_datestring AND SQLite3_FOUND
+ CONDITION QT_FEATURE_datestring
+)
+qt_feature("system-sqlite" PRIVATE
+ LABEL " Using system provided SQLite"
+ AUTODETECT OFF
+ CONDITION QT_FEATURE_sql_sqlite AND SQLite3_FOUND
+)
+qt_feature("sql-mimer" PRIVATE
+ LABEL "Mimer"
+ CONDITION Mimer_FOUND
+)
+
+qt_configure_add_summary_section(NAME "Qt Sql Drivers")
+qt_configure_add_summary_entry(ARGS "sql-db2")
+qt_configure_add_summary_entry(ARGS "sql-ibase")
+qt_configure_add_summary_entry(ARGS "sql-mysql")
+qt_configure_add_summary_entry(ARGS "sql-oci")
+qt_configure_add_summary_entry(ARGS "sql-odbc")
+qt_configure_add_summary_entry(ARGS "sql-psql")
+qt_configure_add_summary_entry(ARGS "sql-sqlite")
+qt_configure_add_summary_entry(ARGS "system-sqlite")
+qt_configure_add_summary_entry(ARGS "sql-mimer")
+qt_configure_end_summary_section() # end of "Qt Sql Drivers" section
+qt_configure_add_report_entry(
+ TYPE WARNING
+ MESSAGE "Qt does not support compiling the Oracle database driver with MinGW, due to lack of such support from Oracle. Consider disabling the Oracle driver, as the current build will most likely fail."
+ CONDITION WIN32 AND NOT MSVC AND QT_FEATURE_sql_oci
)
diff --git a/src/plugins/sqldrivers/configure.json b/src/plugins/sqldrivers/configure.json
deleted file mode 100644
index f738e58a00..0000000000
--- a/src/plugins/sqldrivers/configure.json
+++ /dev/null
@@ -1,201 +0,0 @@
-{
- "module": "sqldrivers",
- "depends": [
- "core"
- ],
- "testDir": "../../../config.tests",
-
- "commandline": {
- "assignments": {
- "MYSQL_PATH": "mysql.prefix"
- },
- "options": {
- "mysql_config": "string",
- "psql_config": "string",
- "sqlite": { "type": "enum", "name": "system-sqlite", "values": { "qt": "no", "system": "yes" } },
- "sql-db2": "boolean",
- "sql-ibase": "boolean",
- "sql-mysql": "boolean",
- "sql-oci": "boolean",
- "sql-odbc": "boolean",
- "sql-psql": "boolean",
- "sql-sqlite": "boolean",
- "plugin-sql-db2": { "type": "void", "name": "sql-db2" },
- "plugin-sql-ibase": { "type": "void", "name": "sql-ibase" },
- "plugin-sql-mysql": { "type": "void", "name": "sql-mysql" },
- "plugin-sql-oci": { "type": "void", "name": "sql-oci" },
- "plugin-sql-odbc": { "type": "void", "name": "sql-odbc" },
- "plugin-sql-psql": { "type": "void", "name": "sql-psql" },
- "plugin-sql-sqlite": { "type": "void", "name": "sql-sqlite" }
- }
- },
-
- "libraries": {
- "db2": {
- "label": "DB2 (IBM)",
- "test": {},
- "headers": [ "sqlcli.h", "sqlcli1.h" ],
- "sources": [
- { "libs": "-ldb2cli", "condition": "config.win32" },
- { "libs": "-ldb2", "condition": "!config.win32" }
- ]
- },
- "ibase": {
- "label": "InterBase",
- "test": {},
- "headers": "ibase.h",
- "sources": [
- { "libs": "-lgds32_ms", "condition": "config.win32" },
- { "libs": "-lgds", "condition": "!config.win32" }
- ]
- },
- "mysql": {
- "label": "MySQL",
- "test": {
- "head": [
- "#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(WIN64) || defined(_WIN64) || defined(__WIN64__)",
- "# include <windows.h>",
- "#endif"
- ],
- "main": "mysql_get_client_version();"
- },
- "headers": "mysql.h",
- "sources": [
- { "type": "mysqlConfig", "query": "--libs_r", "cleanlibs": true },
- { "type": "mysqlConfig", "query": "--libs", "cleanlibs": true },
- { "type": "mysqlConfig", "query": "--libs_r", "cleanlibs": false },
- { "type": "mysqlConfig", "query": "--libs", "cleanlibs": false },
- { "libs": "-lmysqlclient_r", "condition": "!config.win32" },
- { "libs": "-llibmariadb", "condition": "config.win32" },
- { "libs": "-llibmysql", "condition": "config.win32" },
- { "libs": "-lmariadb", "condition": "!config.win32" },
- { "libs": "-lmysqlclient", "condition": "!config.win32" }
- ]
- },
- "psql": {
- "label": "PostgreSQL",
- "test": {
- "main": [
- "PQescapeBytea(0, 0, 0);",
- "PQunescapeBytea(0, 0);"
- ]
- },
- "headers": "libpq-fe.h",
- "sources": [
- { "type": "pkgConfig", "args": "libpq" },
- { "type": "psqlConfig" },
- { "type": "psqlEnv", "libs": "-llibpq -lws2_32 -ladvapi32", "condition": "config.win32" },
- { "type": "psqlEnv", "libs": "-lpq", "condition": "!config.win32" }
- ]
- },
- "oci": {
- "label": "OCI (Oracle)",
- "test": {},
- "headers": "oci.h",
- "sources": [
- { "libs": "-loci", "condition": "config.win32" },
- { "libs": "-lclntsh", "condition": "!config.win32" }
- ]
- },
- "odbc": {
- "label": "ODBC",
- "test": {
- "head": [
- "#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(WIN64) || defined(_WIN64) || defined(__WIN64__)",
- "# include <windows.h>",
- "#endif"
- ],
- "main": [
- "SQLHANDLE env;",
- "SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env);"
- ]
- },
- "headers": [ "sql.h", "sqlext.h" ],
- "sources": [
- { "libs": "-lodbc32", "condition": "config.win32" },
- { "libs": "-liodbc", "condition": "config.darwin" },
- { "libs": "-lodbc", "condition": "!config.win32 && !config.darwin" }
- ]
- },
- "sqlite3": {
- "label": "SQLite (version 3)",
- "export": "sqlite",
- "test": {
- "main": "sqlite3_open_v2(0, 0, 0, 0);"
- },
- "headers": "sqlite3.h",
- "sources": [
- { "type": "pkgConfig", "args": "sqlite3" },
- "-lsqlite3"
- ],
- "use": [
- { "lib": "zlib", "condition": "!config.win32 && features.system-zlib" }
- ]
- }
- },
-
- "tests": {
- },
-
- "features": {
- "sql-db2": {
- "label": "DB2 (IBM)",
- "condition": "libs.db2",
- "output": [ "privateFeature" ]
- },
- "sql-ibase": {
- "label": "InterBase",
- "condition": "libs.ibase",
- "output": [ "privateFeature" ]
- },
- "sql-mysql": {
- "label": "MySql",
- "condition": "libs.mysql",
- "output": [ "privateFeature" ]
- },
- "sql-oci": {
- "label": "OCI (Oracle)",
- "condition": "libs.oci",
- "output": [ "privateFeature" ]
- },
- "sql-odbc": {
- "label": "ODBC",
- "condition": "features.datestring && libs.odbc",
- "output": [ "privateFeature" ]
- },
- "sql-psql": {
- "label": "PostgreSQL",
- "condition": "libs.psql",
- "output": [ "privateFeature" ]
- },
- "sql-sqlite": {
- "label": "SQLite",
- "condition": "features.datestring",
- "output": [ "privateFeature" ]
- },
- "system-sqlite": {
- "label": " Using system provided SQLite",
- "autoDetect": false,
- "condition": "features.sql-sqlite && libs.sqlite3",
- "output": [ "privateFeature" ]
- }
- },
-
- "report": [
- {
- "type": "warning",
- "condition": "config.win32 && !config.msvc && features.sql-oci",
- "message": "Qt does not support compiling the Oracle database driver with MinGW, due to lack of such support from Oracle. Consider disabling the Oracle driver, as the current build will most likely fail."
- }
- ],
-
- "summary": [
- {
- "section": "Qt Sql Drivers",
- "entries": [
- "sql-db2", "sql-ibase", "sql-mysql", "sql-oci", "sql-odbc", "sql-psql",
- "sql-sqlite", "system-sqlite"
- ]
- }
- ]
-}
diff --git a/src/plugins/sqldrivers/configure.pri b/src/plugins/sqldrivers/configure.pri
deleted file mode 100644
index be6a930e52..0000000000
--- a/src/plugins/sqldrivers/configure.pri
+++ /dev/null
@@ -1,85 +0,0 @@
-# custom tests
-
-defineTest(qtConfLibrary_psqlConfig) {
- pg_config = $$config.input.psql_config
- isEmpty(pg_config):!cross_compile: \
- pg_config = $$qtConfFindInPath("pg_config")
- !win32:!isEmpty(pg_config) {
- qtRunLoggedCommand("$$pg_config --libdir", libdir)|return(false)
- !qtConfResolvePathLibs($${1}.libs, $$libdir, -lpq): \
- return(false)
- qtRunLoggedCommand("$$pg_config --includedir", includedir)|return(false)
- !qtConfResolvePathIncs($${1}.includedir, $$includedir, $$2): \
- return(false)
- return(true)
- }
- qtLog("pg_config not found.")
- return(false)
-}
-
-defineTest(qtConfLibrary_psqlEnv) {
- # Respect PSQL_LIBS if set
- PSQL_LIBS = $$getenv(PSQL_LIBS)
- !isEmpty(PSQL_LIBS) {
- eval(libs = $$PSQL_LIBS)
- !qtConfResolveLibs($${1}.libs, $$libs): \
- return(false)
- } else {
- !qtConfLibrary_inline($$1, $$2): \
- return(false)
- }
- return(true)
-}
-
-defineTest(qtConfLibrary_mysqlConfig) {
- mysql_config = $$config.input.mysql_config
- isEmpty(mysql_config):!cross_compile: \
- mysql_config = $$qtConfFindInPath("mysql_config")
- !isEmpty(mysql_config) {
- qtRunLoggedCommand("$$mysql_config --version", version)|return(false)
- version = $$split(version, '.')
- version = $$first(version)
- isEmpty(version)|lessThan(version, 4): return(false)]
-
- # query is either --libs or --libs_r
- query = $$eval($${1}.query)
- qtRunLoggedCommand("$$mysql_config $$query", libs)|return(false)
- qtRunLoggedCommand("$$mysql_config --include", includedir)|return(false)
- eval(libs = $$libs)
- # -rdynamic should not be returned by mysql_config, but is on RHEL 6.6
- libs -= -rdynamic
- equals($${1}.cleanlibs, true) {
- for(l, libs) {
- # Drop all options besides the -L one and the -lmysqlclient one
- # so we don't unnecessarily link to libs like OpenSSL
- contains(l, "^(-L|-lmysqlclient).*"): cleanlibs += $$l
- }
- libs = $$cleanlibs
- }
- !qtConfResolveLibs($${1}.libs, $$libs): \
- return(false)
- eval(rawincludedir = $$includedir)
- rawincludedir ~= s/^-I//g
- includedir =
- for (id, rawincludedir): \
- includedir += $$clean_path($$id)
- !qtConfResolvePathIncs($${1}.includedir, $$includedir, $$2): \
- return(false)
- return(true)
- }
- qtLog("mysql_config not found.")
- return(false)
-}
-
-defineTest(qtConfLibrary_sybaseEnv) {
- libdir =
- sybase = $$getenv(SYBASE)
- !isEmpty(sybase): \
- libdir += $${sybase}/lib
- eval(libs = $$getenv(SYBASE_LIBS))
- isEmpty(libs): \
- libs = $$eval($${1}.libs)
- !qtConfResolvePathLibs($${1}.libs, $$libdir, $$libs): \
- return(false)
- return(true)
-}
diff --git a/src/plugins/sqldrivers/db2/CMakeLists.txt b/src/plugins/sqldrivers/db2/CMakeLists.txt
index 637461e168..119a5b53c9 100644
--- a/src/plugins/sqldrivers/db2/CMakeLists.txt
+++ b/src/plugins/sqldrivers/db2/CMakeLists.txt
@@ -1,32 +1,32 @@
-# Generated from db2.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## QDB2DriverPlugin Plugin:
#####################################################################
-qt_add_plugin(QDB2DriverPlugin
+qt_internal_add_plugin(QDB2DriverPlugin
OUTPUT_NAME qsqldb2
- TYPE sqldrivers
+ PLUGIN_TYPE sqldrivers
SOURCES
main.cpp
qsql_db2.cpp qsql_db2_p.h
DEFINES
QT_NO_CAST_FROM_ASCII
QT_NO_CAST_TO_ASCII
- PUBLIC_LIBRARIES
+ LIBRARIES
DB2::DB2
Qt::Core
Qt::CorePrivate
Qt::SqlPrivate
)
-#### Keys ignored in scope 1:.:.:db2.pro:<TRUE>:
-# OTHER_FILES = "db2.json"
-
## Scopes:
#####################################################################
-qt_extend_target(QDB2DriverPlugin CONDITION (TEST_architecture_arch STREQUAL "x86_64")
+qt_internal_extend_target(QDB2DriverPlugin CONDITION (TEST_architecture_arch STREQUAL "x86_64")
DEFINES
ODBC64
)
+
+qt_internal_force_macos_intel_arch(QDB2DriverPlugin)
diff --git a/src/plugins/sqldrivers/db2/db2.pro b/src/plugins/sqldrivers/db2/db2.pro
deleted file mode 100644
index b99fe91fe3..0000000000
--- a/src/plugins/sqldrivers/db2/db2.pro
+++ /dev/null
@@ -1,13 +0,0 @@
-TARGET = qsqldb2
-
-HEADERS += $$PWD/qsql_db2_p.h
-SOURCES += $$PWD/qsql_db2.cpp $$PWD/main.cpp
-
-QMAKE_USE += db2
-
-OTHER_FILES += db2.json
-
-equals(QT_ARCH, x86_64): DEFINES += ODBC64
-
-PLUGIN_CLASS_NAME = QDB2DriverPlugin
-include(../qsqldriverbase.pri)
diff --git a/src/plugins/sqldrivers/db2/main.cpp b/src/plugins/sqldrivers/db2/main.cpp
index 97338b8eef..b5aa5a6492 100644
--- a/src/plugins/sqldrivers/db2/main.cpp
+++ b/src/plugins/sqldrivers/db2/main.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <qsqldriverplugin.h>
#include <qstringlist.h>
@@ -43,6 +7,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
class QDB2DriverPlugin : public QSqlDriverPlugin
{
Q_OBJECT
@@ -61,7 +27,7 @@ QDB2DriverPlugin::QDB2DriverPlugin()
QSqlDriver* QDB2DriverPlugin::create(const QString &name)
{
- if (name == QLatin1String("QDB2")) {
+ if (name == "QDB2"_L1) {
QDB2Driver* driver = new QDB2Driver();
return driver;
}
diff --git a/src/plugins/sqldrivers/db2/qsql_db2.cpp b/src/plugins/sqldrivers/db2/qsql_db2.cpp
index 1d7e985731..9b6a06c378 100644
--- a/src/plugins/sqldrivers/db2/qsql_db2.cpp
+++ b/src/plugins/sqldrivers/db2/qsql_db2.cpp
@@ -1,55 +1,20 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtSql module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qsql_db2_p.h"
#include <qcoreapplication.h>
#include <qdatetime.h>
-#include <qsqlfield.h>
+#include <qlist.h>
#include <qsqlerror.h>
+#include <qsqlfield.h>
#include <qsqlindex.h>
#include <qsqlrecord.h>
#include <qstringlist.h>
#include <qvarlengtharray.h>
-#include <qvector.h>
#include <QDebug>
#include <QtSql/private/qsqldriver_p.h>
#include <QtSql/private/qsqlresult_p.h>
+#include "private/qtools_p.h"
#if defined(Q_CC_BOR)
// DB2's sqlsystm.h (included through sqlcli1.h) defines the SQL_BIGINT_TYPE
@@ -65,6 +30,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
static const int COLNAMESIZE = 255;
// Based on what is mentioned in the documentation here:
// https://www.ibm.com/support/knowledgecenter/en/SSEPEK_10.0.0/sqlref/src/tpc/db2z_limits.html
@@ -77,10 +44,13 @@ class QDB2DriverPrivate : public QSqlDriverPrivate
Q_DECLARE_PUBLIC(QDB2Driver)
public:
- QDB2DriverPrivate() : QSqlDriverPrivate(), hEnv(0), hDbc(0) { dbmsType = QSqlDriver::DB2; }
- SQLHANDLE hEnv;
- SQLHANDLE hDbc;
+ QDB2DriverPrivate() : QSqlDriverPrivate(QSqlDriver::DB2) {}
+ SQLHANDLE hEnv = 0;
+ SQLHANDLE hDbc = 0;
QString user;
+
+ void qSplitTableQualifier(const QString &qualifier, QString &catalog,
+ QString &schema, QString &table) const;
};
class QDB2ResultPrivate;
@@ -141,7 +111,7 @@ public:
SQLHANDLE hStmt;
QSqlRecord recInf;
- QVector<QVariant*> valueCache;
+ QList<QVariant*> valueCache;
};
static QString qFromTChar(SQLTCHAR* str)
@@ -188,7 +158,7 @@ static QString qDB2Warn(const QDB2DriverPrivate* d, QStringList *errorCodes = nu
errorCode = 0;
}
if (!error.isEmpty())
- error += QLatin1Char(' ');
+ error += u' ';
error += qWarnDB2Handle(SQL_HANDLE_DBC, d->hDbc, &errorCode);
if (errorCodes && errorCode != 0)
*errorCodes << QString::number(errorCode);
@@ -204,14 +174,14 @@ static QString qDB2Warn(const QDB2ResultPrivate* d, QStringList *errorCodes = nu
errorCode = 0;
}
if (!error.isEmpty())
- error += QLatin1Char(' ');
+ error += u' ';
error += qWarnDB2Handle(SQL_HANDLE_DBC, d->drv_d_func()->hDbc, &errorCode);
if (errorCodes && errorCode != 0) {
*errorCodes << QString::number(errorCode);
errorCode = 0;
}
if (!error.isEmpty())
- error += QLatin1Char(' ');
+ error += u' ';
error += qWarnDB2Handle(SQL_HANDLE_STMT, d->hStmt, &errorCode);
if (errorCodes && errorCode != 0)
*errorCodes << QString::number(errorCode);
@@ -236,7 +206,7 @@ static QSqlError qMakeError(const QString& err, QSqlError::ErrorType type,
QStringList errorCodes;
const QString error = qDB2Warn(p, &errorCodes);
return QSqlError(QStringLiteral("QDB2: ") + err, error, type,
- errorCodes.join(QLatin1Char(';')));
+ errorCodes.join(u';'));
}
static QSqlError qMakeError(const QString& err, QSqlError::ErrorType type,
@@ -245,28 +215,28 @@ static QSqlError qMakeError(const QString& err, QSqlError::ErrorType type,
QStringList errorCodes;
const QString error = qDB2Warn(p, &errorCodes);
return QSqlError(QStringLiteral("QDB2: ") + err, error, type,
- errorCodes.join(QLatin1Char(';')));
+ errorCodes.join(u';'));
}
-static QVariant::Type qDecodeDB2Type(SQLSMALLINT sqltype)
+static QMetaType qDecodeDB2Type(SQLSMALLINT sqltype)
{
- QVariant::Type type = QVariant::Invalid;
+ int type = QMetaType::UnknownType;
switch (sqltype) {
case SQL_REAL:
case SQL_FLOAT:
case SQL_DOUBLE:
case SQL_DECIMAL:
case SQL_NUMERIC:
- type = QVariant::Double;
+ type = QMetaType::Double;
break;
case SQL_SMALLINT:
case SQL_INTEGER:
case SQL_BIT:
case SQL_TINYINT:
- type = QVariant::Int;
+ type = QMetaType::Int;
break;
case SQL_BIGINT:
- type = QVariant::LongLong;
+ type = QMetaType::LongLong;
break;
case SQL_BLOB:
case SQL_BINARY:
@@ -274,19 +244,19 @@ static QVariant::Type qDecodeDB2Type(SQLSMALLINT sqltype)
case SQL_LONGVARBINARY:
case SQL_CLOB:
case SQL_DBCLOB:
- type = QVariant::ByteArray;
+ type = QMetaType::QByteArray;
break;
case SQL_DATE:
case SQL_TYPE_DATE:
- type = QVariant::Date;
+ type = QMetaType::QDate;
break;
case SQL_TIME:
case SQL_TYPE_TIME:
- type = QVariant::Time;
+ type = QMetaType::QTime;
break;
case SQL_TIMESTAMP:
case SQL_TYPE_TIMESTAMP:
- type = QVariant::DateTime;
+ type = QMetaType::QDateTime;
break;
case SQL_WCHAR:
case SQL_WVARCHAR:
@@ -294,13 +264,13 @@ static QVariant::Type qDecodeDB2Type(SQLSMALLINT sqltype)
case SQL_CHAR:
case SQL_VARCHAR:
case SQL_LONGVARCHAR:
- type = QVariant::String;
+ type = QMetaType::QString;
break;
default:
- type = QVariant::ByteArray;
+ type = QMetaType::QByteArray;
break;
}
- return type;
+ return QMetaType(type);
}
static QSqlField qMakeFieldInfo(const QDB2ResultPrivate* d, int i)
@@ -335,7 +305,6 @@ static QSqlField qMakeFieldInfo(const QDB2ResultPrivate* d, int i)
// else required is unknown
f.setLength(colSize == 0 ? -1 : int(colSize));
f.setPrecision(colScale == 0 ? -1 : int(colScale));
- f.setSqlType(int(colType));
SQLTCHAR tableName[TABLENAMESIZE];
SQLSMALLINT tableNameLen;
r = SQLColAttribute(d->hStmt, i + 1, SQL_DESC_BASE_TABLE_NAME, tableName,
@@ -495,34 +464,27 @@ static QByteArray qGetBinaryData(SQLHANDLE hStmt, int column, SQLLEN& lengthIndi
return fieldVal;
}
-static void qSplitTableQualifier(const QString & qualifier, QString * catalog,
- QString * schema, QString * table)
+void QDB2DriverPrivate::qSplitTableQualifier(const QString &qualifier, QString &catalog,
+ QString &schema, QString &table) const
{
- if (!catalog || !schema || !table)
- return;
- QStringList l = qualifier.split(QLatin1Char('.'));
- if (l.count() > 3)
- return; // can't possibly be a valid table qualifier
- int i = 0, n = l.count();
- if (n == 1) {
- *table = qualifier;
- } else {
- for (QStringList::Iterator it = l.begin(); it != l.end(); ++it) {
- if (n == 3) {
- if (i == 0)
- *catalog = *it;
- else if (i == 1)
- *schema = *it;
- else if (i == 2)
- *table = *it;
- } else if (n == 2) {
- if (i == 0)
- *schema = *it;
- else if (i == 1)
- *table = *it;
- }
- i++;
- }
+ const QList<QStringView> l = QStringView(qualifier).split(u'.');
+ switch (l.count()) {
+ case 1:
+ table = qualifier;
+ break;
+ case 2:
+ schema = l.at(0).toString();
+ table = l.at(1).toString();
+ break;
+ case 3:
+ catalog = l.at(0).toString();
+ schema = l.at(1).toString();
+ table = l.at(2).toString();
+ break;
+ default:
+ qSqlWarning(QString::fromLatin1("QODBCDriver::splitTableQualifier: Unable to split table qualifier '%1'")
+ .arg(qualifier), this);
+ break;
}
}
@@ -542,7 +504,6 @@ static QSqlField qMakeFieldInfo(const SQLHANDLE hStmt)
// else we don't know.
f.setLength(qGetIntData(hStmt, 6, isNull)); // column size
f.setPrecision(qGetIntData(hStmt, 8, isNull)); // precision
- f.setSqlType(type);
return f;
}
@@ -554,13 +515,13 @@ static bool qMakeStatement(QDB2ResultPrivate* d, bool forwardOnly, bool setForwa
d->drv_d_func()->hDbc,
&d->hStmt);
if (r != SQL_SUCCESS) {
- qSqlWarning(QLatin1String("QDB2Result::reset: Unable to allocate statement handle"), d);
+ qSqlWarning("QDB2Result::reset: Unable to allocate statement handle"_L1, d);
return false;
}
} else {
r = SQLFreeStmt(d->hStmt, SQL_CLOSE);
if (r != SQL_SUCCESS) {
- qSqlWarning(QLatin1String("QDB2Result::reset: Unable to close statement handle"), d);
+ qSqlWarning("QDB2Result::reset: Unable to close statement handle"_L1, d);
return false;
}
}
@@ -581,8 +542,8 @@ static bool qMakeStatement(QDB2ResultPrivate* d, bool forwardOnly, bool setForwa
}
if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) {
qSqlWarning(QString::fromLatin1("QDB2Result::reset: Unable to set %1 attribute.").arg(
- forwardOnly ? QLatin1String("SQL_CURSOR_FORWARD_ONLY")
- : QLatin1String("SQL_CURSOR_STATIC")), d);
+ forwardOnly ? "SQL_CURSOR_FORWARD_ONLY"_L1
+ : "SQL_CURSOR_STATIC"_L1), d);
return false;
}
return true;
@@ -591,7 +552,7 @@ static bool qMakeStatement(QDB2ResultPrivate* d, bool forwardOnly, bool setForwa
QVariant QDB2Result::handle() const
{
Q_D(const QDB2Result);
- return QVariant(qRegisterMetaType<SQLHANDLE>("SQLHANDLE"), &d->hStmt);
+ return QVariant(QMetaType::fromType<SQLHANDLE>(), &d->hStmt);
}
/************************************/
@@ -607,8 +568,7 @@ QDB2Result::~QDB2Result()
if (d->hStmt) {
SQLRETURN r = SQLFreeHandle(SQL_HANDLE_STMT, d->hStmt);
if (r != SQL_SUCCESS)
- qSqlWarning(QLatin1String("QDB2Driver: Unable to free statement handle ")
- + QString::number(r), d);
+ qSqlWarning("QDB2Driver: Unable to free statement handle "_L1 + QString::number(r), d);
}
}
@@ -692,18 +652,18 @@ bool QDB2Result::exec()
return false;
- QVector<QVariant> &values = boundValues();
+ QList<QVariant> &values = boundValues();
int i;
for (i = 0; i < values.count(); ++i) {
// bind parameters - only positional binding allowed
SQLLEN *ind = &indicators[i];
- if (values.at(i).isNull())
+ if (QSqlResultPrivate::isVariantNull(values.at(i)))
*ind = SQL_NULL_DATA;
if (bindValueType(i) & QSql::Out)
values[i].detach();
- switch (values.at(i).type()) {
- case QVariant::Date: {
+ switch (values.at(i).metaType().id()) {
+ case QMetaType::QDate: {
QByteArray ba;
ba.resize(sizeof(DATE_STRUCT));
DATE_STRUCT *dt = (DATE_STRUCT *)ba.constData();
@@ -723,7 +683,7 @@ bool QDB2Result::exec()
*ind == SQL_NULL_DATA ? ind : NULL);
tmpStorage.append(ba);
break; }
- case QVariant::Time: {
+ case QMetaType::QTime: {
QByteArray ba;
ba.resize(sizeof(TIME_STRUCT));
TIME_STRUCT *dt = (TIME_STRUCT *)ba.constData();
@@ -743,7 +703,7 @@ bool QDB2Result::exec()
*ind == SQL_NULL_DATA ? ind : NULL);
tmpStorage.append(ba);
break; }
- case QVariant::DateTime: {
+ case QMetaType::QDateTime: {
QByteArray ba;
ba.resize(sizeof(TIMESTAMP_STRUCT));
TIMESTAMP_STRUCT * dt = (TIMESTAMP_STRUCT *)ba.constData();
@@ -767,7 +727,7 @@ bool QDB2Result::exec()
*ind == SQL_NULL_DATA ? ind : NULL);
tmpStorage.append(ba);
break; }
- case QVariant::Int:
+ case QMetaType::Int:
r = SQLBindParameter(d->hStmt,
i + 1,
qParamType[bindValueType(i) & 3],
@@ -779,7 +739,7 @@ bool QDB2Result::exec()
0,
*ind == SQL_NULL_DATA ? ind : NULL);
break;
- case QVariant::Double:
+ case QMetaType::Double:
r = SQLBindParameter(d->hStmt,
i + 1,
qParamType[bindValueType(i) & 3],
@@ -791,7 +751,7 @@ bool QDB2Result::exec()
0,
*ind == SQL_NULL_DATA ? ind : NULL);
break;
- case QVariant::ByteArray: {
+ case QMetaType::QByteArray: {
int len = values.at(i).toByteArray().size();
if (*ind != SQL_NULL_DATA)
*ind = len;
@@ -806,13 +766,13 @@ bool QDB2Result::exec()
len,
ind);
break; }
- case QVariant::String:
+ case QMetaType::QString:
{
- QString str(values.at(i).toString());
+ const QString str(values.at(i).toString());
if (*ind != SQL_NULL_DATA)
*ind = str.length() * sizeof(QChar);
if (bindValueType(i) & QSql::Out) {
- QByteArray ba((char*)str.utf16(), str.capacity() * sizeof(QChar));
+ QByteArray ba((char *)str.data(), str.capacity() * sizeof(QChar));
r = SQLBindParameter(d->hStmt,
i + 1,
qParamType[bindValueType(i) & 3],
@@ -894,25 +854,25 @@ bool QDB2Result::exec()
return true;
for (i = 0; i < values.count(); ++i) {
- switch (values[i].type()) {
- case QVariant::Date: {
+ switch (values[i].metaType().id()) {
+ case QMetaType::QDate: {
DATE_STRUCT ds = *((DATE_STRUCT *)tmpStorage.takeFirst().constData());
values[i] = QVariant(QDate(ds.year, ds.month, ds.day));
break; }
- case QVariant::Time: {
+ case QMetaType::QTime: {
TIME_STRUCT dt = *((TIME_STRUCT *)tmpStorage.takeFirst().constData());
values[i] = QVariant(QTime(dt.hour, dt.minute, dt.second));
break; }
- case QVariant::DateTime: {
+ case QMetaType::QDateTime: {
TIMESTAMP_STRUCT dt = *((TIMESTAMP_STRUCT *)tmpStorage.takeFirst().constData());
values[i] = QVariant(QDateTime(QDate(dt.year, dt.month, dt.day),
QTime(dt.hour, dt.minute, dt.second, dt.fraction / 1000000)));
break; }
- case QVariant::Int:
- case QVariant::Double:
- case QVariant::ByteArray:
+ case QMetaType::Int:
+ case QMetaType::Double:
+ case QMetaType::QByteArray:
break;
- case QVariant::String:
+ case QMetaType::QString:
if (bindValueType(i) & QSql::Out)
values[i] = QString((const QChar *)tmpStorage.takeFirst().constData());
break;
@@ -921,7 +881,7 @@ bool QDB2Result::exec()
break; }
}
if (indicators[i] == SQL_NULL_DATA)
- values[i] = QVariant(values[i].type());
+ values[i] = QVariant(values[i].metaType());
}
return true;
}
@@ -992,7 +952,7 @@ bool QDB2Result::fetchFirst()
SQL_FETCH_FIRST,
0);
if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) {
- if(r!= SQL_NO_DATA)
+ if (r!= SQL_NO_DATA)
setLastError(qMakeError(QCoreApplication::translate("QDB2Result", "Unable to fetch first"),
QSqlError::StatementError, d));
return false;
@@ -1052,15 +1012,15 @@ QVariant QDB2Result::data(int field)
return *d->valueCache[field];
- QVariant* v = 0;
- switch (info.type()) {
- case QVariant::LongLong:
+ QVariant *v = nullptr;
+ switch (info.metaType().id()) {
+ case QMetaType::LongLong:
v = new QVariant((qint64) qGetBigIntData(d->hStmt, field, isNull));
break;
- case QVariant::Int:
+ case QMetaType::Int:
v = new QVariant(qGetIntData(d->hStmt, field, isNull));
break;
- case QVariant::Date: {
+ case QMetaType::QDate: {
DATE_STRUCT dbuf;
r = SQLGetData(d->hStmt,
field + 1,
@@ -1075,7 +1035,7 @@ QVariant QDB2Result::data(int field)
isNull = true;
}
break; }
- case QVariant::Time: {
+ case QMetaType::QTime: {
TIME_STRUCT tbuf;
r = SQLGetData(d->hStmt,
field + 1,
@@ -1090,7 +1050,7 @@ QVariant QDB2Result::data(int field)
isNull = true;
}
break; }
- case QVariant::DateTime: {
+ case QMetaType::QDateTime: {
TIMESTAMP_STRUCT dtbuf;
r = SQLGetData(d->hStmt,
field + 1,
@@ -1106,10 +1066,10 @@ QVariant QDB2Result::data(int field)
isNull = true;
}
break; }
- case QVariant::ByteArray:
+ case QMetaType::QByteArray:
v = new QVariant(qGetBinaryData(d->hStmt, field, lengthIndicator, isNull));
break;
- case QVariant::Double:
+ case QMetaType::Double:
{
switch(numericalPrecisionPolicy()) {
case QSql::LowPrecisionInt32:
@@ -1129,13 +1089,13 @@ QVariant QDB2Result::data(int field)
}
break;
}
- case QVariant::String:
+ case QMetaType::QString:
default:
v = new QVariant(qGetStringData(d->hStmt, field, info.length(), isNull));
break;
}
if (isNull)
- *v = QVariant(info.type());
+ *v = QVariant(info.metaType());
d->valueCache[field] = v;
return *v;
}
@@ -1159,7 +1119,7 @@ int QDB2Result::numRowsAffected()
if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO)
return affectedRowCount;
else
- qSqlWarning(QLatin1String("QDB2Result::numRowsAffected: Unable to count affected rows"), d);
+ qSqlWarning("QDB2Result::numRowsAffected: Unable to count affected rows"_L1, d);
return -1;
}
@@ -1254,7 +1214,7 @@ bool QDB2Driver::open(const QString& db, const QString& user, const QString& pas
SQL_NULL_HANDLE,
&d->hEnv);
if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) {
- qSqlWarning(QLatin1String("QDB2Driver::open: Unable to allocate environment"), d);
+ qSqlWarning("QDB2Driver::open: Unable to allocate environment"_L1, d);
setOpenError(true);
return false;
}
@@ -1263,18 +1223,18 @@ bool QDB2Driver::open(const QString& db, const QString& user, const QString& pas
d->hEnv,
&d->hDbc);
if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) {
- qSqlWarning(QLatin1String("QDB2Driver::open: Unable to allocate connection"), d);
+ qSqlWarning("QDB2Driver::open: Unable to allocate connection"_L1, d);
setOpenError(true);
return false;
}
QString protocol;
// Set connection attributes
- const QStringList opts(connOpts.split(QLatin1Char(';'), QString::SkipEmptyParts));
+ const QStringList opts(connOpts.split(u';', Qt::SkipEmptyParts));
for (int i = 0; i < opts.count(); ++i) {
const QString tmp(opts.at(i));
int idx;
- if ((idx = tmp.indexOf(QLatin1Char('='))) == -1) {
+ if ((idx = tmp.indexOf(u'=')) == -1) {
qWarning("QDB2Driver::open: Illegal connect option value '%s'",
tmp.toLocal8Bit().constData());
continue;
@@ -1285,10 +1245,10 @@ bool QDB2Driver::open(const QString& db, const QString& user, const QString& pas
SQLULEN v = 0;
r = SQL_SUCCESS;
- if (opt == QLatin1String("SQL_ATTR_ACCESS_MODE")) {
- if (val == QLatin1String("SQL_MODE_READ_ONLY")) {
+ if (opt == "SQL_ATTR_ACCESS_MODE"_L1) {
+ if (val == "SQL_MODE_READ_ONLY"_L1) {
v = SQL_MODE_READ_ONLY;
- } else if (val == QLatin1String("SQL_MODE_READ_WRITE")) {
+ } else if (val == "SQL_MODE_READ_WRITE"_L1) {
v = SQL_MODE_READ_WRITE;
} else {
qWarning("QDB2Driver::open: Unknown option value '%s'",
@@ -1296,10 +1256,10 @@ bool QDB2Driver::open(const QString& db, const QString& user, const QString& pas
continue;
}
r = SQLSetConnectAttr(d->hDbc, SQL_ATTR_ACCESS_MODE, reinterpret_cast<SQLPOINTER>(v), 0);
- } else if (opt == QLatin1String("SQL_ATTR_LOGIN_TIMEOUT")) {
+ } else if (opt == "SQL_ATTR_LOGIN_TIMEOUT"_L1) {
v = val.toUInt();
r = SQLSetConnectAttr(d->hDbc, SQL_ATTR_LOGIN_TIMEOUT, reinterpret_cast<SQLPOINTER>(v), 0);
- } else if (opt.compare(QLatin1String("PROTOCOL"), Qt::CaseInsensitive) == 0) {
+ } else if (opt.compare("PROTOCOL"_L1, Qt::CaseInsensitive) == 0) {
protocol = tmp;
}
else {
@@ -1312,15 +1272,15 @@ bool QDB2Driver::open(const QString& db, const QString& user, const QString& pas
}
if (protocol.isEmpty())
- protocol = QLatin1String("PROTOCOL=TCPIP");
+ protocol = "PROTOCOL=TCPIP"_L1;
if (port < 0 )
port = 50000;
QString connQStr;
- connQStr = protocol + QLatin1String(";DATABASE=") + db + QLatin1String(";HOSTNAME=") + host
- + QLatin1String(";PORT=") + QString::number(port) + QLatin1String(";UID=") + user
- + QLatin1String(";PWD=") + password;
+ connQStr = protocol + ";DATABASE="_L1 + db + ";HOSTNAME="_L1 + host
+ + ";PORT="_L1 + QString::number(port) + ";UID="_L1 + user
+ + ";PWD="_L1 + password;
SQLTCHAR connOut[SQL_MAX_OPTION_STRING_LENGTH];
@@ -1356,18 +1316,18 @@ void QDB2Driver::close()
if (isOpen()) {
r = SQLDisconnect(d->hDbc);
if (r != SQL_SUCCESS)
- qSqlWarning(QLatin1String("QDB2Driver::close: Unable to disconnect datasource"), d);
+ qSqlWarning("QDB2Driver::close: Unable to disconnect datasource"_L1, d);
}
r = SQLFreeHandle(SQL_HANDLE_DBC, d->hDbc);
if (r != SQL_SUCCESS)
- qSqlWarning(QLatin1String("QDB2Driver::close: Unable to free connection handle"), d);
+ qSqlWarning("QDB2Driver::close: Unable to free connection handle"_L1, d);
d->hDbc = 0;
}
if (d->hEnv) {
r = SQLFreeHandle(SQL_HANDLE_ENV, d->hEnv);
if (r != SQL_SUCCESS)
- qSqlWarning(QLatin1String("QDB2Driver::close: Unable to free environment handle"), d);
+ qSqlWarning("QDB2Driver::close: Unable to free environment handle"_L1, d);
d->hEnv = 0;
}
setOpen(false);
@@ -1388,7 +1348,7 @@ QSqlRecord QDB2Driver::record(const QString& tableName) const
SQLHANDLE hStmt;
QString catalog, schema, table;
- qSplitTableQualifier(tableName, &catalog, &schema, &table);
+ d->qSplitTableQualifier(tableName, catalog, schema, table);
if (schema.isEmpty())
schema = d->user;
@@ -1411,7 +1371,7 @@ QSqlRecord QDB2Driver::record(const QString& tableName) const
d->hDbc,
&hStmt);
if (r != SQL_SUCCESS) {
- qSqlWarning(QLatin1String("QDB2Driver::record: Unable to allocate handle"), d);
+ qSqlWarning("QDB2Driver::record: Unable to allocate handle"_L1, d);
return fil;
}
@@ -1434,7 +1394,7 @@ QSqlRecord QDB2Driver::record(const QString& tableName) const
0);
if (r != SQL_SUCCESS)
- qSqlWarning(QLatin1String("QDB2Driver::record: Unable to execute column list"), d);
+ qSqlWarning("QDB2Driver::record: Unable to execute column list"_L1, d);
r = SQLFetchScroll(hStmt,
SQL_FETCH_NEXT,
0);
@@ -1449,7 +1409,7 @@ QSqlRecord QDB2Driver::record(const QString& tableName) const
r = SQLFreeHandle(SQL_HANDLE_STMT, hStmt);
if (r != SQL_SUCCESS)
- qSqlWarning(QLatin1String("QDB2Driver: Unable to free statement handle ")
+ qSqlWarning("QDB2Driver: Unable to free statement handle "_L1
+ QString::number(r), d);
return fil;
@@ -1468,7 +1428,7 @@ QStringList QDB2Driver::tables(QSql::TableType type) const
d->hDbc,
&hStmt);
if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) {
- qSqlWarning(QLatin1String("QDB2Driver::tables: Unable to allocate handle"), d);
+ qSqlWarning("QDB2Driver::tables: Unable to allocate handle"_L1, d);
return tl;
}
r = SQLSetStmtAttr(hStmt,
@@ -1478,11 +1438,11 @@ QStringList QDB2Driver::tables(QSql::TableType type) const
QString tableType;
if (type & QSql::Tables)
- tableType += QLatin1String("TABLE,");
+ tableType += "TABLE,"_L1;
if (type & QSql::Views)
- tableType += QLatin1String("VIEW,");
+ tableType += "VIEW,"_L1;
if (type & QSql::SystemTables)
- tableType += QLatin1String("SYSTEM TABLE,");
+ tableType += "SYSTEM TABLE,"_L1;
if (tableType.isEmpty())
return tl;
tableType.chop(1);
@@ -1498,7 +1458,7 @@ QStringList QDB2Driver::tables(QSql::TableType type) const
tableType.length());
if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO)
- qSqlWarning(QLatin1String("QDB2Driver::tables: Unable to execute table list"), d);
+ qSqlWarning("QDB2Driver::tables: Unable to execute table list"_L1, d);
r = SQLFetchScroll(hStmt,
SQL_FETCH_NEXT,
0);
@@ -1513,7 +1473,7 @@ QStringList QDB2Driver::tables(QSql::TableType type) const
user = user.toUpper();
if (userVal != user)
- fieldVal = userVal + QLatin1Char('.') + fieldVal;
+ fieldVal = userVal + u'.' + fieldVal;
tl.append(fieldVal);
r = SQLFetchScroll(hStmt,
SQL_FETCH_NEXT,
@@ -1522,7 +1482,7 @@ QStringList QDB2Driver::tables(QSql::TableType type) const
r = SQLFreeHandle(SQL_HANDLE_STMT, hStmt);
if (r != SQL_SUCCESS)
- qSqlWarning(QLatin1String("QDB2Driver::tables: Unable to free statement handle ")
+ qSqlWarning("QDB2Driver::tables: Unable to free statement handle "_L1
+ QString::number(r), d);
return tl;
}
@@ -1540,11 +1500,11 @@ QSqlIndex QDB2Driver::primaryIndex(const QString& tablename) const
d->hDbc,
&hStmt);
if (r != SQL_SUCCESS) {
- qSqlWarning(QLatin1String("QDB2Driver::primaryIndex: Unable to list primary key"), d);
+ qSqlWarning("QDB2Driver::primaryIndex: Unable to list primary key"_L1, d);
return index;
}
QString catalog, schema, table;
- qSplitTableQualifier(tablename, &catalog, &schema, &table);
+ d->qSplitTableQualifier(tablename, catalog, schema, table);
if (isIdentifierEscaped(catalog, QSqlDriver::TableName))
catalog = stripDelimiters(catalog, QSqlDriver::TableName);
@@ -1591,7 +1551,7 @@ QSqlIndex QDB2Driver::primaryIndex(const QString& tablename) const
}
r = SQLFreeHandle(SQL_HANDLE_STMT, hStmt);
if (r!= SQL_SUCCESS)
- qSqlWarning(QLatin1String("QDB2Driver: Unable to free statement handle ")
+ qSqlWarning("QDB2Driver: Unable to free statement handle "_L1
+ QString::number(r), d);
return index;
}
@@ -1685,41 +1645,41 @@ bool QDB2Driver::setAutoCommit(bool autoCommit)
QString QDB2Driver::formatValue(const QSqlField &field, bool trimStrings) const
{
if (field.isNull())
- return QLatin1String("NULL");
+ return "NULL"_L1;
- switch (field.type()) {
- case QVariant::DateTime: {
+ switch (field.metaType().id()) {
+ case QMetaType::QDateTime: {
// Use an escape sequence for the datetime fields
if (field.value().toDateTime().isValid()) {
QDate dt = field.value().toDateTime().date();
QTime tm = field.value().toDateTime().time();
// Dateformat has to be "yyyy-MM-dd hh:mm:ss", with leading zeroes if month or day < 10
- return QLatin1Char('\'') + QString::number(dt.year()) + QLatin1Char('-')
- + QString::number(dt.month()) + QLatin1Char('-')
- + QString::number(dt.day()) + QLatin1Char('-')
- + QString::number(tm.hour()) + QLatin1Char('.')
- + QString::number(tm.minute()).rightJustified(2, QLatin1Char('0'), true)
- + QLatin1Char('.')
- + QString::number(tm.second()).rightJustified(2, QLatin1Char('0'), true)
- + QLatin1Char('.')
- + QString::number(tm.msec() * 1000).rightJustified(6, QLatin1Char('0'), true)
- + QLatin1Char('\'');
+ return u'\'' + QString::number(dt.year()) + u'-'
+ + QString::number(dt.month()) + u'-'
+ + QString::number(dt.day()) + u'-'
+ + QString::number(tm.hour()) + u'.'
+ + QString::number(tm.minute()).rightJustified(2, u'0', true)
+ + u'.'
+ + QString::number(tm.second()).rightJustified(2, u'0', true)
+ + u'.'
+ + QString::number(tm.msec() * 1000).rightJustified(6, u'0', true)
+ + u'\'';
} else {
- return QLatin1String("NULL");
+ return "NULL"_L1;
}
}
- case QVariant::ByteArray: {
- QByteArray ba = field.value().toByteArray();
- QString res;
- res += QLatin1String("BLOB(X'");
- static const char hexchars[] = "0123456789abcdef";
- for (int i = 0; i < ba.size(); ++i) {
- uchar s = (uchar) ba[i];
- res += QLatin1Char(hexchars[s >> 4]);
- res += QLatin1Char(hexchars[s & 0x0f]);
+ case QMetaType::QByteArray: {
+ const QByteArray ba = field.value().toByteArray();
+ QString r;
+ r.reserve(ba.size() * 2 + 9);
+ r += "BLOB(X'"_L1;
+ for (const char c : ba) {
+ const uchar s = uchar(c);
+ r += QLatin1Char(QtMiscUtils::toHexLower(s >> 4));
+ r += QLatin1Char(QtMiscUtils::toHexLower(s & 0x0f));
}
- res += QLatin1String("')");
- return res;
+ r += "')"_L1;
+ return r;
}
default:
return QSqlDriver::formatValue(field, trimStrings);
@@ -1729,18 +1689,20 @@ QString QDB2Driver::formatValue(const QSqlField &field, bool trimStrings) const
QVariant QDB2Driver::handle() const
{
Q_D(const QDB2Driver);
- return QVariant(qRegisterMetaType<SQLHANDLE>("SQLHANDLE"), &d->hDbc);
+ return QVariant(QMetaType::fromType<SQLHANDLE>(), &d->hDbc);
}
QString QDB2Driver::escapeIdentifier(const QString &identifier, IdentifierType) const
{
QString res = identifier;
- if(!identifier.isEmpty() && !identifier.startsWith(QLatin1Char('"')) && !identifier.endsWith(QLatin1Char('"')) ) {
- res.replace(QLatin1Char('"'), QLatin1String("\"\""));
- res.prepend(QLatin1Char('"')).append(QLatin1Char('"'));
- res.replace(QLatin1Char('.'), QLatin1String("\".\""));
+ if (!identifier.isEmpty() && !identifier.startsWith(u'"') && !identifier.endsWith(u'"') ) {
+ res.replace(u'"', "\"\""_L1);
+ res.replace(u'.', "\".\""_L1);
+ res = u'"' + res + u'"';
}
return res;
}
QT_END_NAMESPACE
+
+#include "moc_qsql_db2_p.cpp"
diff --git a/src/plugins/sqldrivers/db2/qsql_db2_p.h b/src/plugins/sqldrivers/db2/qsql_db2_p.h
index 79ae54ab2d..9e580352b2 100644
--- a/src/plugins/sqldrivers/db2/qsql_db2_p.h
+++ b/src/plugins/sqldrivers/db2/qsql_db2_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtSql module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QSQL_DB2_H
#define QSQL_DB2_H
@@ -72,8 +36,8 @@ class Q_EXPORT_SQLDRIVER_DB2 QDB2Driver : public QSqlDriver
friend class QDB2ResultPrivate;
public:
- explicit QDB2Driver(QObject* parent = 0);
- QDB2Driver(Qt::HANDLE env, Qt::HANDLE con, QObject* parent = 0);
+ explicit QDB2Driver(QObject *parent = nullptr);
+ QDB2Driver(Qt::HANDLE env, Qt::HANDLE con, QObject *parent = nullptr);
~QDB2Driver();
bool hasFeature(DriverFeature) const override;
void close() override;
diff --git a/src/plugins/sqldrivers/ibase/CMakeLists.txt b/src/plugins/sqldrivers/ibase/CMakeLists.txt
new file mode 100644
index 0000000000..b8f2d2561f
--- /dev/null
+++ b/src/plugins/sqldrivers/ibase/CMakeLists.txt
@@ -0,0 +1,20 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+qt_internal_add_plugin(QIBaseDriverPlugin
+ OUTPUT_NAME qsqlibase
+ PLUGIN_TYPE sqldrivers
+ SOURCES
+ main.cpp
+ qsql_ibase.cpp qsql_ibase_p.h
+ DEFINES
+ QT_NO_CAST_FROM_ASCII
+ QT_NO_CAST_TO_ASCII
+ QT_NO_CONTEXTLESS_CONNECT
+ LIBRARIES
+ Interbase::Interbase
+ Qt::Core
+ Qt::CorePrivate
+ Qt::SqlPrivate)
+
+qt_internal_force_macos_intel_arch(QIBaseDriverPlugin)
diff --git a/src/plugins/sqldrivers/ibase/ibase.pro b/src/plugins/sqldrivers/ibase/ibase.pro
deleted file mode 100644
index e5709207d1..0000000000
--- a/src/plugins/sqldrivers/ibase/ibase.pro
+++ /dev/null
@@ -1,12 +0,0 @@
-TARGET = qsqlibase
-
-HEADERS += $$PWD/qsql_ibase_p.h
-SOURCES += $$PWD/qsql_ibase.cpp $$PWD/main.cpp
-
-# FIXME: ignores libfb (unix)/fbclient (win32) - but that's for the test anyway
-QMAKE_USE += ibase
-
-OTHER_FILES += ibase.json
-
-PLUGIN_CLASS_NAME = QIBaseDriverPlugin
-include(../qsqldriverbase.pri)
diff --git a/src/plugins/sqldrivers/ibase/main.cpp b/src/plugins/sqldrivers/ibase/main.cpp
index 8d462afcdc..24e9dc0864 100644
--- a/src/plugins/sqldrivers/ibase/main.cpp
+++ b/src/plugins/sqldrivers/ibase/main.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <qsqldriverplugin.h>
#include <qstringlist.h>
@@ -43,6 +7,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
class QIBaseDriverPlugin : public QSqlDriverPlugin
{
Q_OBJECT
@@ -51,7 +17,7 @@ class QIBaseDriverPlugin : public QSqlDriverPlugin
public:
QIBaseDriverPlugin();
- QSqlDriver* create(const QString &);
+ QSqlDriver* create(const QString &) override;
};
QIBaseDriverPlugin::QIBaseDriverPlugin()
@@ -61,7 +27,7 @@ QIBaseDriverPlugin::QIBaseDriverPlugin()
QSqlDriver* QIBaseDriverPlugin::create(const QString &name)
{
- if (name == QLatin1String("QIBASE")) {
+ if (name == "QIBASE"_L1) {
QIBaseDriver* driver = new QIBaseDriver();
return driver;
}
diff --git a/src/plugins/sqldrivers/ibase/qsql_ibase.cpp b/src/plugins/sqldrivers/ibase/qsql_ibase.cpp
index 09c0655f3d..28361e250d 100644
--- a/src/plugins/sqldrivers/ibase/qsql_ibase.cpp
+++ b/src/plugins/sqldrivers/ibase/qsql_ibase.cpp
@@ -1,78 +1,57 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtSql module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and 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$
-**
-****************************************************************************/
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qsql_ibase_p.h"
-#include <qcoreapplication.h>
-#include <qdatetime.h>
-#include <qdeadlinetimer.h>
-#include <qvariant.h>
-#include <qsqlerror.h>
-#include <qsqlfield.h>
-#include <qsqlindex.h>
-#include <qsqlquery.h>
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qdatetime.h>
+#include <QtCore/qtimezone.h>
+#include <QtCore/qdeadlinetimer.h>
+#include <QtCore/qdebug.h>
+#include <QtCore/qlist.h>
+#include <QtCore/qloggingcategory.h>
+#include <QtCore/qmap.h>
+#include <QtCore/qmutex.h>
+#include <QtCore/qvariant.h>
+#include <QtCore/qvarlengtharray.h>
+#include <QtSql/qsqlerror.h>
+#include <QtSql/qsqlfield.h>
+#include <QtSql/qsqlindex.h>
+#include <QtSql/qsqlquery.h>
#include <QtSql/private/qsqlcachedresult_p.h>
#include <QtSql/private/qsqldriver_p.h>
-#include <qlist.h>
-#include <qvector.h>
-#include <qtextcodec.h>
-#include <qmutex.h>
#include <stdlib.h>
#include <limits.h>
#include <math.h>
-#include <qdebug.h>
-#include <QVarLengthArray>
+#include <mutex>
QT_BEGIN_NAMESPACE
+static Q_LOGGING_CATEGORY(lcIbase, "qt.sql.ibase")
+
+using namespace Qt::StringLiterals;
+
#define FBVERSION SQL_DIALECT_V6
#ifndef SQLDA_CURRENT_VERSION
#define SQLDA_CURRENT_VERSION SQLDA_VERSION1
#endif
-enum { QIBaseChunkSize = SHRT_MAX / 2 };
+// Firebird uses blr_bool and not blr_boolean_dtype which is what Interbase uses
+#ifndef blr_boolean_dtype
+#define blr_boolean_dtype blr_bool
+#endif
+
+constexpr qsizetype QIBaseChunkSize = SHRT_MAX / 2;
-#if defined(FB_API_VER) && FB_API_VER >= 20
-static bool getIBaseError(QString& msg, const ISC_STATUS* status, ISC_LONG &sqlcode, QTextCodec *tc)
-#else
-static bool getIBaseError(QString& msg, ISC_STATUS* status, ISC_LONG &sqlcode, QTextCodec *tc)
+#if (FB_API_VER >= 40)
+typedef QMap<quint16, QByteArray> QFbTzIdToIanaIdMap;
+typedef QMap<QByteArray, quint16> QIanaIdToFbTzIdMap;
+Q_GLOBAL_STATIC(QFbTzIdToIanaIdMap, qFbTzIdToIanaIdMap)
+Q_GLOBAL_STATIC(QIanaIdToFbTzIdMap, qIanaIdToFbTzIdMap)
+std::once_flag initTZMappingFlag;
#endif
+
+static bool getIBaseError(QString& msg, const ISC_STATUS* status, ISC_LONG &sqlcode)
{
if (status[0] != 1 || status[1] <= 0)
return false;
@@ -80,17 +59,10 @@ static bool getIBaseError(QString& msg, ISC_STATUS* status, ISC_LONG &sqlcode, Q
msg.clear();
sqlcode = isc_sqlcode(status);
char buf[512];
-#if defined(FB_API_VER) && FB_API_VER >= 20
while(fb_interpret(buf, 512, &status)) {
-#else
- while(isc_interprete(buf, &status)) {
-#endif
- if(!msg.isEmpty())
- msg += QLatin1String(" - ");
- if (tc)
- msg += tc->toUnicode(buf);
- else
- msg += QString::fromUtf8(buf);
+ if (!msg.isEmpty())
+ msg += " - "_L1;
+ msg += QString::fromUtf8(buf);
}
return true;
}
@@ -126,10 +98,14 @@ static void initDA(XSQLDA *sqlda)
case SQL_FLOAT:
case SQL_DOUBLE:
case SQL_TIMESTAMP:
+#if (FB_API_VER >= 40)
+ case SQL_TIMESTAMP_TZ:
+#endif
case SQL_TYPE_TIME:
case SQL_TYPE_DATE:
case SQL_TEXT:
case SQL_BLOB:
+ case SQL_BOOLEAN:
sqlda->sqlvar[i].sqldata = new char[sqlda->sqlvar[i].sqllen];
break;
case SQL_ARRAY:
@@ -162,10 +138,10 @@ static void delDA(XSQLDA *&sqlda)
delete [] sqlda->sqlvar[i].sqldata;
}
free(sqlda);
- sqlda = 0;
+ sqlda = nullptr;
}
-static QVariant::Type qIBaseTypeName(int iType, bool hasScale)
+static QMetaType::Type qIBaseTypeName(int iType, bool hasScale)
{
switch (iType) {
case blr_varying:
@@ -173,56 +149,66 @@ static QVariant::Type qIBaseTypeName(int iType, bool hasScale)
case blr_text:
case blr_cstring:
case blr_cstring2:
- return QVariant::String;
+ return QMetaType::QString;
case blr_sql_time:
- return QVariant::Time;
+ return QMetaType::QTime;
case blr_sql_date:
- return QVariant::Date;
+ return QMetaType::QDate;
case blr_timestamp:
- return QVariant::DateTime;
+#if (FB_API_VER >= 40)
+ case blr_timestamp_tz:
+#endif
+ return QMetaType::QDateTime;
case blr_blob:
- return QVariant::ByteArray;
+ return QMetaType::QByteArray;
case blr_quad:
case blr_short:
case blr_long:
- return (hasScale ? QVariant::Double : QVariant::Int);
+ return (hasScale ? QMetaType::Double : QMetaType::Int);
case blr_int64:
- return (hasScale ? QVariant::Double : QVariant::LongLong);
+ return (hasScale ? QMetaType::Double : QMetaType::LongLong);
case blr_float:
case blr_d_float:
case blr_double:
- return QVariant::Double;
+ return QMetaType::Double;
+ case blr_boolean_dtype:
+ return QMetaType::Bool;
}
- qWarning("qIBaseTypeName: unknown datatype: %d", iType);
- return QVariant::Invalid;
+ qCWarning(lcIbase, "qIBaseTypeName: unknown datatype: %d", iType);
+ return QMetaType::UnknownType;
}
-static QVariant::Type qIBaseTypeName2(int iType, bool hasScale)
+static QMetaType::Type qIBaseTypeName2(int iType, bool hasScale)
{
switch(iType & ~1) {
case SQL_VARYING:
case SQL_TEXT:
- return QVariant::String;
+ return QMetaType::QString;
case SQL_LONG:
case SQL_SHORT:
- return (hasScale ? QVariant::Double : QVariant::Int);
+ return (hasScale ? QMetaType::Double : QMetaType::Int);
case SQL_INT64:
- return (hasScale ? QVariant::Double : QVariant::LongLong);
+ return (hasScale ? QMetaType::Double : QMetaType::LongLong);
case SQL_FLOAT:
case SQL_DOUBLE:
- return QVariant::Double;
+ return QMetaType::Double;
case SQL_TIMESTAMP:
- return QVariant::DateTime;
+#if (FB_API_VER >= 40)
+ case SQL_TIMESTAMP_TZ:
+#endif
+ return QMetaType::QDateTime;
case SQL_TYPE_TIME:
- return QVariant::Time;
+ return QMetaType::QTime;
case SQL_TYPE_DATE:
- return QVariant::Date;
+ return QMetaType::QDate;
case SQL_ARRAY:
- return QVariant::List;
+ return QMetaType::QVariantList;
case SQL_BLOB:
- return QVariant::ByteArray;
+ return QMetaType::QByteArray;
+ case SQL_BOOLEAN:
+ return QMetaType::Bool;
default:
- return QVariant::Invalid;
+ return QMetaType::UnknownType;
}
}
@@ -244,12 +230,45 @@ static QDateTime fromTimeStamp(char *buffer)
// have to demangle the structure ourselves because isc_decode_time
// strips the msecs
- t = t.addMSecs(int(((ISC_TIMESTAMP*)buffer)->timestamp_time / 10));
- d = bd.addDays(int(((ISC_TIMESTAMP*)buffer)->timestamp_date));
-
+ auto timebuf = reinterpret_cast<ISC_TIMESTAMP*>(buffer);
+ t = t.addMSecs(static_cast<int>(timebuf->timestamp_time / 10));
+ d = bd.addDays(timebuf->timestamp_date);
return QDateTime(d, t);
}
+#if (FB_API_VER >= 40)
+QDateTime fromTimeStampTz(char *buffer)
+{
+ static const QDate bd(1858, 11, 17);
+ QTime t(0, 0);
+ QDate d;
+
+ // have to demangle the structure ourselves because isc_decode_time
+ // strips the msecs
+ auto timebuf = reinterpret_cast<ISC_TIMESTAMP_TZ*>(buffer);
+ t = t.addMSecs(static_cast<int>(timebuf->utc_timestamp.timestamp_time / 10));
+ d = bd.addDays(timebuf->utc_timestamp.timestamp_date);
+ quint16 fpTzID = timebuf->time_zone;
+
+ QByteArray timeZoneName = qFbTzIdToIanaIdMap()->value(fpTzID);
+ if (!timeZoneName.isEmpty())
+ return QDateTime(d, t, QTimeZone(timeZoneName));
+ else
+ return {};
+}
+
+ISC_TIMESTAMP_TZ toTimeStampTz(const QDateTime &dt)
+{
+ static const QTime midnight(0, 0, 0, 0);
+ static const QDate basedate(1858, 11, 17);
+ ISC_TIMESTAMP_TZ ts;
+ ts.utc_timestamp.timestamp_time = midnight.msecsTo(dt.time()) * 10;
+ ts.utc_timestamp.timestamp_date = basedate.daysTo(dt.date());
+ ts.time_zone = qIanaIdToFbTzIdMap()->value(dt.timeZone().id().simplified(), 0);
+ return ts;
+}
+#endif
+
static ISC_TIME toTime(QTime t)
{
static const QTime midnight(0, 0, 0, 0);
@@ -287,21 +306,9 @@ static QDate fromDate(char *buffer)
return d;
}
-static QByteArray encodeString(QTextCodec *tc, const QString &str)
-{
- if (tc)
- return tc->fromUnicode(str);
- return str.toUtf8();
-}
-
struct QIBaseEventBuffer {
-#if defined(FB_API_VER) && FB_API_VER >= 20
ISC_UCHAR *eventBuffer;
ISC_UCHAR *resultBuffer;
-#else
- char *eventBuffer;
- char *resultBuffer;
-#endif
ISC_LONG bufferLength;
ISC_LONG eventId;
@@ -313,14 +320,15 @@ class QIBaseDriverPrivate : public QSqlDriverPrivate
{
Q_DECLARE_PUBLIC(QIBaseDriver)
public:
- QIBaseDriverPrivate() : QSqlDriverPrivate(), ibase(0), trans(0), tc(0) { dbmsType = QSqlDriver::Interbase; }
+ QIBaseDriverPrivate() : QSqlDriverPrivate(), ibase(0), trans(0)
+ { dbmsType = QSqlDriver::Interbase; }
bool isError(const char *msg, QSqlError::ErrorType typ = QSqlError::UnknownError)
{
Q_Q(QIBaseDriver);
QString imsg;
ISC_LONG sqlcode;
- if (!getIBaseError(imsg, status, sqlcode, tc))
+ if (!getIBaseError(imsg, status, sqlcode))
return false;
q->setLastError(QSqlError(QCoreApplication::translate("QIBaseDriver", msg),
@@ -329,10 +337,37 @@ public:
return true;
}
+#if (FB_API_VER >= 40)
+ void initTZMappingCache()
+ {
+ Q_Q(QIBaseDriver);
+ QSqlQuery qry(q->createResult());
+ qry.setForwardOnly(true);
+ qry.exec(QString("select * from RDB$TIME_ZONES"_L1));
+ if (qry.lastError().type()) {
+ q->setLastError(QSqlError(
+ QCoreApplication::translate("QIBaseDriver",
+ "failed to query time zone mapping from system table"),
+ qry.lastError().databaseText(),
+ QSqlError::StatementError,
+ qry.lastError().nativeErrorCode()));
+
+ return;
+ }
+
+ while (qry.next()) {
+ auto record = qry.record();
+ quint16 fbTzId = record.value(0).value<quint16>();
+ QByteArray ianaId = record.value(1).toByteArray().simplified();
+ qFbTzIdToIanaIdMap()->insert(fbTzId, ianaId);
+ qIanaIdToFbTzIdMap()->insert(ianaId, fbTzId);
+ }
+ }
+#endif
+
public:
isc_db_handle ibase;
isc_tr_handle trans;
- QTextCodec *tc;
ISC_STATUS status[20];
QMap<QString, QIBaseEventBuffer*> eventBuffers;
};
@@ -386,7 +421,7 @@ public:
Q_Q(QIBaseResult);
QString imsg;
ISC_LONG sqlcode;
- if (!getIBaseError(imsg, status, sqlcode, tc))
+ if (!getIBaseError(imsg, status, sqlcode))
return false;
q->setLastError(QSqlError(QCoreApplication::translate("QIBaseResult", msg),
@@ -400,10 +435,9 @@ public:
bool isSelect();
QVariant fetchBlob(ISC_QUAD *bId);
- bool writeBlob(int i, const QByteArray &ba);
+ bool writeBlob(qsizetype iPos, const QByteArray &ba);
QVariant fetchArray(int pos, ISC_QUAD *arr);
- bool writeArray(int i, const QList<QVariant> &list);
-
+ bool writeArray(qsizetype i, const QList<QVariant> &list);
public:
ISC_STATUS status[20];
isc_tr_handle trans;
@@ -414,7 +448,6 @@ public:
XSQLDA *sqlda; // output sqlda
XSQLDA *inda; // input parameters
int queryType;
- QTextCodec *tc;
};
@@ -424,10 +457,9 @@ QIBaseResultPrivate::QIBaseResultPrivate(QIBaseResult *q, const QIBaseDriver *dr
localTransaction(!drv_d_func()->ibase),
stmt(0),
ibase(drv_d_func()->ibase),
- sqlda(0),
- inda(0),
- queryType(-1),
- tc(drv_d_func()->tc)
+ sqlda(nullptr),
+ inda(nullptr),
+ queryType(-1)
{
}
@@ -450,20 +482,20 @@ void QIBaseResultPrivate::cleanup()
q->cleanup();
}
-bool QIBaseResultPrivate::writeBlob(int i, const QByteArray &ba)
+bool QIBaseResultPrivate::writeBlob(qsizetype iPos, const QByteArray &ba)
{
isc_blob_handle handle = 0;
- ISC_QUAD *bId = (ISC_QUAD*)inda->sqlvar[i].sqldata;
+ ISC_QUAD *bId = (ISC_QUAD*)inda->sqlvar[iPos].sqldata;
isc_create_blob2(status, &ibase, &trans, &handle, bId, 0, 0);
if (!isError(QT_TRANSLATE_NOOP("QIBaseResult", "Unable to create BLOB"),
QSqlError::StatementError)) {
- int i = 0;
+ qsizetype i = 0;
while (i < ba.size()) {
- isc_put_segment(status, &handle, qMin(ba.size() - i, int(QIBaseChunkSize)),
- const_cast<char*>(ba.data()) + i);
+ isc_put_segment(status, &handle, qMin(ba.size() - i, QIBaseChunkSize),
+ ba.data() + i);
if (isError(QT_TRANSLATE_NOOP("QIBaseResult", "Unable to write BLOB")))
return false;
- i += qMin(ba.size() - i, int(QIBaseChunkSize));
+ i += qMin(ba.size() - i, QIBaseChunkSize);
}
}
isc_close_blob(status, &handle);
@@ -483,7 +515,7 @@ QVariant QIBaseResultPrivate::fetchBlob(ISC_QUAD *bId)
QByteArray ba;
int chunkSize = QIBaseChunkSize;
ba.resize(chunkSize);
- int read = 0;
+ qsizetype read = 0;
while (isc_get_segment(status, &handle, &len, chunkSize, ba.data() + read) == 0 || status[1] == isc_segment) {
read += len;
ba.resize(read + chunkSize);
@@ -505,7 +537,7 @@ QVariant QIBaseResultPrivate::fetchBlob(ISC_QUAD *bId)
}
template<typename T>
-static QList<QVariant> toList(char** buf, int count, T* = 0)
+static QList<QVariant> toList(char** buf, int count)
{
QList<QVariant> res;
for (int i = 0; i < count; ++i) {
@@ -514,24 +546,9 @@ static QList<QVariant> toList(char** buf, int count, T* = 0)
}
return res;
}
-/* char** ? seems like bad influence from oracle ... */
-template<>
-QList<QVariant> toList<long>(char** buf, int count, long*)
-{
- QList<QVariant> res;
- for (int i = 0; i < count; ++i) {
- if (sizeof(int) == sizeof(long))
- res.append(int((*(long*)(*buf))));
- else
- res.append((qint64)(*(long*)(*buf)));
- *buf += sizeof(long);
- }
- return res;
-}
static char* readArrayBuffer(QList<QVariant>& list, char *buffer, short curDim,
- short* numElements, ISC_ARRAY_DESC *arrayDesc,
- QTextCodec *tc)
+ short* numElements, ISC_ARRAY_DESC *arrayDesc)
{
const short dim = arrayDesc->array_desc_dimensions - 1;
const unsigned char dataType = arrayDesc->array_desc_dtype;
@@ -540,8 +557,7 @@ static char* readArrayBuffer(QList<QVariant>& list, char *buffer, short curDim,
if (curDim != dim) {
for(int i = 0; i < numElements[curDim]; ++i)
- buffer = readArrayBuffer(list, buffer, curDim + 1, numElements,
- arrayDesc, tc);
+ buffer = readArrayBuffer(list, buffer, curDim + 1, numElements, arrayDesc);
} else {
switch(dataType) {
case blr_varying:
@@ -555,16 +571,12 @@ static char* readArrayBuffer(QList<QVariant>& list, char *buffer, short curDim,
for(o = 0; o < strLen && buffer[o]!=0; ++o )
;
- if (tc)
- valList.append(tc->toUnicode(buffer, o));
- else
- valList.append(QString::fromUtf8(buffer, o));
-
+ valList.append(QString::fromUtf8(buffer, o));
buffer += strLen;
}
break; }
case blr_long:
- valList = toList<long>(&buffer, numElements[dim], static_cast<long *>(0));
+ valList = toList<int>(&buffer, numElements[dim]);
break;
case blr_short:
valList = toList<short>(&buffer, numElements[dim]);
@@ -584,8 +596,16 @@ static char* readArrayBuffer(QList<QVariant>& list, char *buffer, short curDim,
buffer += sizeof(ISC_TIMESTAMP);
}
break;
+#if (FB_API_VER >= 40)
+ case blr_timestamp_tz:
+ for (int i = 0; i < numElements[dim]; ++i) {
+ valList.append(fromTimeStampTz(buffer));
+ buffer += sizeof(ISC_TIMESTAMP_TZ);
+ }
+ break;
+#endif
case blr_sql_time:
- for(int i = 0; i < numElements[dim]; ++i) {
+ for (int i = 0; i < numElements[dim]; ++i) {
valList.append(fromTime(buffer));
buffer += sizeof(ISC_TIME);
}
@@ -596,6 +616,9 @@ static char* readArrayBuffer(QList<QVariant>& list, char *buffer, short curDim,
buffer += sizeof(ISC_DATE);
}
break;
+ case blr_boolean_dtype:
+ valList = toList<bool>(&buffer, numElements[dim]);
+ break;
}
}
if (dim > 0)
@@ -614,7 +637,7 @@ QVariant QIBaseResultPrivate::fetchArray(int pos, ISC_QUAD *arr)
return list;
QByteArray relname(sqlda->sqlvar[pos].relname, sqlda->sqlvar[pos].relname_length);
- QByteArray sqlname(sqlda->sqlvar[pos].aliasname, sqlda->sqlvar[pos].aliasname_length);
+ QByteArray sqlname(sqlda->sqlvar[pos].sqlname, sqlda->sqlvar[pos].sqlname_length);
isc_array_lookup_bounds(status, &ibase, &trans, relname.data(), sqlname.data(), &desc);
if (isError(QT_TRANSLATE_NOOP("QIBaseResult", "Could not find array"),
@@ -653,17 +676,16 @@ QVariant QIBaseResultPrivate::fetchArray(int pos, ISC_QUAD *arr)
QSqlError::StatementError))
return list;
- readArrayBuffer(list, ba.data(), 0, numElements.data(), &desc, tc);
+ readArrayBuffer(list, ba.data(), 0, numElements.data(), &desc);
return QVariant(list);
}
template<typename T>
-static char* fillList(char *buffer, const QList<QVariant> &list, T* = 0)
+static char* fillList(char *buffer, const QList<QVariant> &list, T* = nullptr)
{
- for (int i = 0; i < list.size(); ++i) {
- T val;
- val = qvariant_cast<T>(list.at(i));
+ for (const auto &elem : list) {
+ T val = qvariant_cast<T>(elem);
memcpy(buffer, &val, sizeof(T));
buffer += sizeof(T);
}
@@ -673,11 +695,9 @@ static char* fillList(char *buffer, const QList<QVariant> &list, T* = 0)
template<>
char* fillList<float>(char *buffer, const QList<QVariant> &list, float*)
{
- for (int i = 0; i < list.size(); ++i) {
- double val;
- float val2 = 0;
- val = qvariant_cast<double>(list.at(i));
- val2 = (float)val;
+ for (const auto &elem : list) {
+ double val = qvariant_cast<double>(elem);
+ float val2 = (float)val;
memcpy(buffer, &val2, sizeof(float));
buffer += sizeof(float);
}
@@ -685,10 +705,9 @@ char* fillList<float>(char *buffer, const QList<QVariant> &list, float*)
}
static char* qFillBufferWithString(char *buffer, const QString& string,
- short buflen, bool varying, bool array,
- QTextCodec *tc)
+ short buflen, bool varying, bool array)
{
- QByteArray str = encodeString(tc, string); // keep a copy of the string alive in this scope
+ QByteArray str = string.toUtf8(); // keep a copy of the string alive in this scope
if (varying) {
short tmpBuflen = buflen;
if (str.length() < buflen)
@@ -710,10 +729,9 @@ static char* qFillBufferWithString(char *buffer, const QString& string,
}
static char* createArrayBuffer(char *buffer, const QList<QVariant> &list,
- QVariant::Type type, short curDim, ISC_ARRAY_DESC *arrayDesc,
- QString& error, QTextCodec *tc)
+ QMetaType::Type type, short curDim, ISC_ARRAY_DESC *arrayDesc,
+ QString& error)
{
- int i;
ISC_ARRAY_BOUND *bounds = arrayDesc->array_desc_bounds;
short dim = arrayDesc->array_desc_dimensions - 1;
@@ -721,72 +739,86 @@ static char* createArrayBuffer(char *buffer, const QList<QVariant> &list,
bounds[curDim].array_bound_lower + 1);
if (list.size() != elements) { // size mismatch
- error = QLatin1String("Expected size: %1. Supplied size: %2");
- error = QLatin1String("Array size mismatch. Fieldname: %1 ")
+ error = "Expected size: %1. Supplied size: %2"_L1;
+ error = "Array size mismatch. Fieldname: %1 "_L1
+ error.arg(elements).arg(list.size());
return 0;
}
if (curDim != dim) {
- for(i = 0; i < list.size(); ++i) {
+ for (const auto &elem : list) {
- if (list.at(i).userType() != QVariant::List) { // dimensions mismatch
- error = QLatin1String("Array dimensons mismatch. Fieldname: %1");
+ if (elem.typeId() != QMetaType::QVariantList) { // dimensions mismatch
+ error = "Array dimensons mismatch. Fieldname: %1"_L1;
return 0;
}
- buffer = createArrayBuffer(buffer, list.at(i).toList(), type, curDim + 1,
- arrayDesc, error, tc);
+ buffer = createArrayBuffer(buffer, elem.toList(), type, curDim + 1,
+ arrayDesc, error);
if (!buffer)
return 0;
}
} else {
switch(type) {
- case QVariant::Int:
- case QVariant::UInt:
+ case QMetaType::Int:
+ case QMetaType::UInt:
if (arrayDesc->array_desc_dtype == blr_short)
buffer = fillList<short>(buffer, list);
else
buffer = fillList<int>(buffer, list);
break;
- case QVariant::Double:
+ case QMetaType::Double:
if (arrayDesc->array_desc_dtype == blr_float)
buffer = fillList<float>(buffer, list, static_cast<float *>(0));
else
buffer = fillList<double>(buffer, list);
break;
- case QVariant::LongLong:
+ case QMetaType::LongLong:
buffer = fillList<qint64>(buffer, list);
break;
- case QVariant::ULongLong:
+ case QMetaType::ULongLong:
buffer = fillList<quint64>(buffer, list);
break;
- case QVariant::String:
- for (i = 0; i < list.size(); ++i)
- buffer = qFillBufferWithString(buffer, list.at(i).toString(),
+ case QMetaType::QString:
+ for (const auto &elem : list)
+ buffer = qFillBufferWithString(buffer, elem.toString(),
arrayDesc->array_desc_length,
arrayDesc->array_desc_dtype == blr_varying,
- true, tc);
+ true);
break;
- case QVariant::Date:
- for (i = 0; i < list.size(); ++i) {
- *((ISC_DATE*)buffer) = toDate(list.at(i).toDate());
+ case QMetaType::QDate:
+ for (const auto &elem : list) {
+ *((ISC_DATE*)buffer) = toDate(elem.toDate());
buffer += sizeof(ISC_DATE);
}
break;
- case QVariant::Time:
- for (i = 0; i < list.size(); ++i) {
- *((ISC_TIME*)buffer) = toTime(list.at(i).toTime());
+ case QMetaType::QTime:
+ for (const auto &elem : list) {
+ *((ISC_TIME*)buffer) = toTime(elem.toTime());
buffer += sizeof(ISC_TIME);
}
break;
-
- case QVariant::DateTime:
- for (i = 0; i < list.size(); ++i) {
- *((ISC_TIMESTAMP*)buffer) = toTimeStamp(list.at(i).toDateTime());
- buffer += sizeof(ISC_TIMESTAMP);
+ case QMetaType::QDateTime:
+ for (const auto &elem : list) {
+ switch (arrayDesc->array_desc_dtype) {
+ case blr_timestamp:
+ *((ISC_TIMESTAMP*)buffer) = toTimeStamp(elem.toDateTime());
+ buffer += sizeof(ISC_TIMESTAMP);
+ break;
+#if (FB_API_VER >= 40)
+ case blr_timestamp_tz:
+ *((ISC_TIMESTAMP_TZ*)buffer) = toTimeStampTz(elem.toDateTime());
+ buffer += sizeof(ISC_TIMESTAMP_TZ);
+ break;
+#endif
+ default:
+ break;
+ }
}
break;
+ case QMetaType::Bool:
+ buffer = fillList<bool>(buffer, list);
+ break;
default:
break;
}
@@ -794,7 +826,7 @@ static char* createArrayBuffer(char *buffer, const QList<QVariant> &list,
return buffer;
}
-bool QIBaseResultPrivate::writeArray(int column, const QList<QVariant> &list)
+bool QIBaseResultPrivate::writeArray(qsizetype column, const QList<QVariant> &list)
{
Q_Q(QIBaseResult);
QString error;
@@ -802,7 +834,7 @@ bool QIBaseResultPrivate::writeArray(int column, const QList<QVariant> &list)
ISC_ARRAY_DESC desc;
QByteArray relname(inda->sqlvar[column].relname, inda->sqlvar[column].relname_length);
- QByteArray sqlname(inda->sqlvar[column].aliasname, inda->sqlvar[column].aliasname_length);
+ QByteArray sqlname(inda->sqlvar[column].sqlname, inda->sqlvar[column].sqlname_length);
isc_array_lookup_bounds(status, &ibase, &trans, relname.data(), sqlname.data(), &desc);
if (isError(QT_TRANSLATE_NOOP("QIBaseResult", "Could not find array"),
@@ -811,7 +843,6 @@ bool QIBaseResultPrivate::writeArray(int column, const QList<QVariant> &list)
short arraySize = 1;
ISC_LONG bufLen;
- QList<QVariant> subList = list;
short dimensions = desc.array_desc_dimensions;
for(int i = 0; i < dimensions; ++i) {
@@ -831,16 +862,16 @@ bool QIBaseResultPrivate::writeArray(int column, const QList<QVariant> &list)
ba.resize(int(bufLen));
if (list.size() > arraySize) {
- error = QLatin1String("Array size missmatch: size of %1 is %2, size of provided list is %3");
- error = error.arg(QLatin1String(sqlname)).arg(arraySize).arg(list.size());
- q->setLastError(QSqlError(error, QLatin1String(""), QSqlError::StatementError));
+ error = "Array size mismatch: size of %1 is %2, size of provided list is %3"_L1;
+ error = error.arg(QLatin1StringView(sqlname)).arg(arraySize).arg(list.size());
+ q->setLastError(QSqlError(error, ""_L1, QSqlError::StatementError));
return false;
}
if (!createArrayBuffer(ba.data(), list,
qIBaseTypeName(desc.array_desc_dtype, inda->sqlvar[column].sqlscale < 0),
- 0, &desc, error, tc)) {
- q->setLastError(QSqlError(error.arg(QLatin1String(sqlname)), QLatin1String(""),
+ 0, &desc, error)) {
+ q->setLastError(QSqlError(error.arg(QLatin1StringView(sqlname)), ""_L1,
QSqlError::StatementError));
return false;
}
@@ -913,7 +944,7 @@ QIBaseResult::QIBaseResult(const QIBaseDriver *db)
bool QIBaseResult::prepare(const QString& query)
{
Q_D(QIBaseResult);
-// qDebug("prepare: %s", qPrintable(query));
+// qDebug("prepare: %ls", qUtf16Printable(query));
if (!driver() || !driver()->isOpen() || driver()->isOpenError())
return false;
d->cleanup();
@@ -922,13 +953,13 @@ bool QIBaseResult::prepare(const QString& query)
createDA(d->sqlda);
if (d->sqlda == (XSQLDA*)0) {
- qWarning()<<"QIOBaseResult: createDA(): failed to allocate memory";
+ qCWarning(lcIbase) << "QIOBaseResult: createDA(): failed to allocate memory";
return false;
}
createDA(d->inda);
if (d->inda == (XSQLDA*)0){
- qWarning()<<"QIOBaseResult: createDA(): failed to allocate memory";
+ qCWarning(lcIbase) << "QIOBaseResult: createDA(): failed to allocate memory";
return false;
}
@@ -940,7 +971,7 @@ bool QIBaseResult::prepare(const QString& query)
QSqlError::StatementError))
return false;
isc_dsql_prepare(d->status, &d->trans, &d->stmt, 0,
- const_cast<char*>(encodeString(d->tc, query).constData()), FBVERSION, d->sqlda);
+ const_cast<char*>(query.toUtf8().constData()), FBVERSION, d->sqlda);
if (d->isError(QT_TRANSLATE_NOOP("QIBaseResult", "Could not prepare statement"),
QSqlError::StatementError))
return false;
@@ -952,7 +983,7 @@ bool QIBaseResult::prepare(const QString& query)
if (d->inda->sqld > d->inda->sqln) {
enlargeDA(d->inda, d->inda->sqld);
if (d->inda == (XSQLDA*)0) {
- qWarning()<<"QIOBaseResult: enlargeDA(): failed to allocate memory";
+ qCWarning(lcIbase) << "QIOBaseResult: enlargeDA(): failed to allocate memory";
return false;
}
@@ -966,7 +997,7 @@ bool QIBaseResult::prepare(const QString& query)
// need more field descriptors
enlargeDA(d->sqlda, d->sqlda->sqld);
if (d->sqlda == (XSQLDA*)0) {
- qWarning()<<"QIOBaseResult: enlargeDA(): failed to allocate memory";
+ qCWarning(lcIbase) << "QIOBaseResult: enlargeDA(): failed to allocate memory";
return false;
}
@@ -986,7 +1017,6 @@ bool QIBaseResult::prepare(const QString& query)
return true;
}
-
bool QIBaseResult::exec()
{
Q_D(QIBaseResult);
@@ -1001,22 +1031,20 @@ bool QIBaseResult::exec()
setAt(QSql::BeforeFirstRow);
if (d->inda) {
- QVector<QVariant>& values = boundValues();
- int i;
+ const QList<QVariant> &values = boundValues();
if (values.count() > d->inda->sqld) {
- qWarning("QIBaseResult::exec: Parameter mismatch, expected %d, got %d parameters",
- d->inda->sqld, values.count());
+ qCWarning(lcIbase) << "QIBaseResult::exec: Parameter mismatch, expected"_L1
+ << d->inda->sqld << ", got"_L1 << values.count()
+ << "parameters"_L1;
return false;
}
- int para = 0;
- for (i = 0; i < values.count(); ++i) {
- para = i;
+ for (qsizetype para = 0; para < values.count(); ++para) {
if (!d->inda->sqlvar[para].sqldata)
// skip unknown datatypes
continue;
- const QVariant val(values[i]);
+ const QVariant &val = values[para];
if (d->inda->sqlvar[para].sqltype & 1) {
- if (val.isNull()) {
+ if (QSqlResultPrivate::isVariantNull(val)) {
// set null indicator
*(d->inda->sqlvar[para].sqlind) = -1;
// and set the value to 0, otherwise it would count as empty string.
@@ -1026,6 +1054,12 @@ bool QIBaseResult::exec()
}
// a value of 0 means non-null.
*(d->inda->sqlvar[para].sqlind) = 0;
+ } else {
+ if (QSqlResultPrivate::isVariantNull(val)) {
+ qCWarning(lcIbase) << "QIBaseResult::exec: Null value replaced by default (zero)"_L1
+ << "value for type of column"_L1 << d->inda->sqlvar[para].ownname
+ << ", which is not nullable."_L1;
+ }
}
switch(d->inda->sqlvar[para].sqltype & ~1) {
case SQL_INT64:
@@ -1062,6 +1096,11 @@ bool QIBaseResult::exec()
case SQL_TIMESTAMP:
*((ISC_TIMESTAMP*)d->inda->sqlvar[para].sqldata) = toTimeStamp(val.toDateTime());
break;
+#if (FB_API_VER >= 40)
+ case SQL_TIMESTAMP_TZ:
+ *((ISC_TIMESTAMP_TZ*)d->inda->sqlvar[para].sqldata) = toTimeStampTz(val.toDateTime());
+ break;
+#endif
case SQL_TYPE_TIME:
*((ISC_TIME*)d->inda->sqlvar[para].sqldata) = toTime(val.toTime());
break;
@@ -1072,7 +1111,7 @@ bool QIBaseResult::exec()
case SQL_TEXT:
qFillBufferWithString(d->inda->sqlvar[para].sqldata, val.toString(),
d->inda->sqlvar[para].sqllen,
- (d->inda->sqlvar[para].sqltype & ~1) == SQL_VARYING, false, d->tc);
+ (d->inda->sqlvar[para].sqltype & ~1) == SQL_VARYING, false);
break;
case SQL_BLOB:
ok &= d->writeBlob(para, val.toByteArray());
@@ -1080,19 +1119,28 @@ bool QIBaseResult::exec()
case SQL_ARRAY:
ok &= d->writeArray(para, val.toList());
break;
+ case SQL_BOOLEAN:
+ *((bool*)d->inda->sqlvar[para].sqldata) = val.toBool();
+ break;
default:
- qWarning("QIBaseResult::exec: Unknown datatype %d",
- d->inda->sqlvar[para].sqltype & ~1);
+ qCWarning(lcIbase, "QIBaseResult::exec: Unknown datatype %d",
+ d->inda->sqlvar[para].sqltype & ~1);
break;
}
}
}
if (ok) {
+ isc_dsql_free_statement(d->status, &d->stmt, DSQL_close);
+ QString imsg;
+ ISC_LONG sqlcode;
+ if (getIBaseError(imsg, d->status, sqlcode) && sqlcode != -501) {
+ setLastError(QSqlError(QCoreApplication::translate("QIBaseResult", "Unable to close statement"),
+ imsg, QSqlError::UnknownError,
+ sqlcode != -1 ? QString::number(sqlcode) : QString()));
+ return false;
+ }
if (colCount() && d->queryType != isc_info_sql_stmt_exec_procedure) {
- isc_dsql_free_statement(d->status, &d->stmt, DSQL_close);
- if (d->isError(QT_TRANSLATE_NOOP("QIBaseResult", "Unable to close statement")))
- return false;
cleanup();
}
if (d->queryType == isc_info_sql_stmt_exec_procedure)
@@ -1161,17 +1209,18 @@ bool QIBaseResult::gotoNext(QSqlCachedResult::ValueCache& row, int rowIdx)
if ((d->sqlda->sqlvar[i].sqltype & 1) && *d->sqlda->sqlvar[i].sqlind) {
// null value
QVariant v;
- v.convert(qIBaseTypeName2(d->sqlda->sqlvar[i].sqltype, d->sqlda->sqlvar[i].sqlscale < 0));
- if (v.userType() == QVariant::Double) {
+ v.convert(QMetaType(qIBaseTypeName2(d->sqlda->sqlvar[i].sqltype,
+ d->sqlda->sqlvar[i].sqlscale < 0)));
+ if (v.userType() == QMetaType::Double) {
switch(numericalPrecisionPolicy()) {
case QSql::LowPrecisionInt32:
- v.convert(QVariant::Int);
+ v.convert(QMetaType(QMetaType::Int));
break;
case QSql::LowPrecisionInt64:
- v.convert(QVariant::LongLong);
+ v.convert(QMetaType(QMetaType::LongLong));
break;
case QSql::HighPrecision:
- v.convert(QVariant::String);
+ v.convert(QMetaType(QMetaType::QString));
break;
case QSql::LowPrecisionDouble:
// no conversion
@@ -1185,10 +1234,7 @@ bool QIBaseResult::gotoNext(QSqlCachedResult::ValueCache& row, int rowIdx)
switch(d->sqlda->sqlvar[i].sqltype & ~1) {
case SQL_VARYING:
// pascal strings - a short with a length information followed by the data
- if (d->tc)
- row[idx] = d->tc->toUnicode(buf + sizeof(short), *(short*)buf);
- else
- row[idx] = QString::fromUtf8(buf + sizeof(short), *(short*)buf);
+ row[idx] = QString::fromUtf8(buf + sizeof(short), *(short*)buf);
break;
case SQL_INT64:
if (d->sqlda->sqlvar[i].sqlscale < 0)
@@ -1227,10 +1273,7 @@ bool QIBaseResult::gotoNext(QSqlCachedResult::ValueCache& row, int rowIdx)
row[idx] = fromDate(buf);
break;
case SQL_TEXT:
- if (d->tc)
- row[idx] = d->tc->toUnicode(buf, size);
- else
- row[idx] = QString::fromUtf8(buf, size);
+ row[idx] = QString::fromUtf8(buf, size);
break;
case SQL_BLOB:
row[idx] = d->fetchBlob((ISC_QUAD*)buf);
@@ -1238,6 +1281,14 @@ bool QIBaseResult::gotoNext(QSqlCachedResult::ValueCache& row, int rowIdx)
case SQL_ARRAY:
row[idx] = d->fetchArray(i, (ISC_QUAD*)buf);
break;
+ case SQL_BOOLEAN:
+ row[idx] = QVariant(bool((*(bool*)buf)));
+ break;
+#if (FB_API_VER >= 40)
+ case SQL_TIMESTAMP_TZ:
+ row[idx] = fromTimeStampTz(buf);
+ break;
+#endif
default:
// unknown type - don't even try to fetch
row[idx] = QVariant();
@@ -1247,19 +1298,19 @@ bool QIBaseResult::gotoNext(QSqlCachedResult::ValueCache& row, int rowIdx)
QVariant v = row[idx];
switch(numericalPrecisionPolicy()) {
case QSql::LowPrecisionInt32:
- if(v.convert(QVariant::Int))
+ if (v.convert(QMetaType(QMetaType::Int)))
row[idx]=v;
break;
case QSql::LowPrecisionInt64:
- if(v.convert(QVariant::LongLong))
+ if (v.convert(QMetaType(QMetaType::LongLong)))
row[idx]=v;
break;
case QSql::LowPrecisionDouble:
- if(v.convert(QVariant::Double))
+ if (v.convert(QMetaType(QMetaType::Double)))
row[idx]=v;
break;
case QSql::HighPrecision:
- if(v.convert(QVariant::String))
+ if (v.convert(QMetaType(QMetaType::QString)))
row[idx]=v;
break;
}
@@ -1344,7 +1395,7 @@ int QIBaseResult::numRowsAffected()
bIsProcedure = true; // will sum all changes
break;
default:
- qWarning() << "numRowsAffected: Unknown statement type (" << d->queryType << ")";
+ qCWarning(lcIbase) << "numRowsAffected: Unknown statement type (" << d->queryType << ")";
return -1;
}
@@ -1386,21 +1437,21 @@ QSqlRecord QIBaseResult::record() const
for (int i = 0; i < d->sqlda->sqld; ++i) {
v = d->sqlda->sqlvar[i];
QSqlField f(QString::fromLatin1(v.aliasname, v.aliasname_length).simplified(),
- qIBaseTypeName2(v.sqltype, v.sqlscale < 0),
+ QMetaType(qIBaseTypeName2(v.sqltype, v.sqlscale < 0)),
QString::fromLatin1(v.relname, v.relname_length));
f.setLength(v.sqllen);
f.setPrecision(qAbs(v.sqlscale));
f.setRequiredStatus((v.sqltype & 1) == 0 ? QSqlField::Required : QSqlField::Optional);
- if(v.sqlscale < 0) {
+ if (v.sqlscale < 0) {
QSqlQuery q(driver()->createResult());
q.setForwardOnly(true);
- q.exec(QLatin1String("select b.RDB$FIELD_PRECISION, b.RDB$FIELD_SCALE, b.RDB$FIELD_LENGTH, a.RDB$NULL_FLAG "
+ q.exec("select b.RDB$FIELD_PRECISION, b.RDB$FIELD_SCALE, b.RDB$FIELD_LENGTH, a.RDB$NULL_FLAG "
"FROM RDB$RELATION_FIELDS a, RDB$FIELDS b "
"WHERE b.RDB$FIELD_NAME = a.RDB$FIELD_SOURCE "
- "AND a.RDB$RELATION_NAME = '") + QString::fromLatin1(v.relname, v.relname_length).toUpper() + QLatin1String("' "
- "AND a.RDB$FIELD_NAME = '") + QString::fromLatin1(v.sqlname, v.sqlname_length).toUpper() + QLatin1String("' "));
- if(q.first()) {
- if(v.sqlscale < 0) {
+ "AND a.RDB$RELATION_NAME = '"_L1 + QString::fromLatin1(v.relname, v.relname_length) + "' "
+ "AND a.RDB$FIELD_NAME = '"_L1 + QString::fromLatin1(v.sqlname, v.sqlname_length) + "' "_L1);
+ if (q.first()) {
+ if (v.sqlscale < 0) {
f.setLength(q.value(0).toInt());
f.setPrecision(qAbs(q.value(1).toInt()));
} else {
@@ -1410,7 +1461,6 @@ QSqlRecord QIBaseResult::record() const
f.setRequiredStatus(q.value(3).toBool() ? QSqlField::Required : QSqlField::Optional);
}
}
- f.setSqlType(v.sqltype);
rec.append(f);
}
return rec;
@@ -1419,7 +1469,7 @@ QSqlRecord QIBaseResult::record() const
QVariant QIBaseResult::handle() const
{
Q_D(const QIBaseResult);
- return QVariant(qRegisterMetaType<isc_stmt_handle>("isc_stmt_handle"), &d->stmt);
+ return QVariant(QMetaType::fromType<isc_stmt_handle>(), &d->stmt);
}
/*********************************/
@@ -1466,51 +1516,36 @@ bool QIBaseDriver::hasFeature(DriverFeature f) const
return false;
}
-bool QIBaseDriver::open(const QString & db,
- const QString & user,
- const QString & password,
- const QString & host,
- int port,
- const QString & connOpts)
+bool QIBaseDriver::open(const QString &db,
+ const QString &user,
+ const QString &password,
+ const QString &host,
+ int port,
+ const QString &connOpts)
{
Q_D(QIBaseDriver);
if (isOpen())
close();
- const QStringList opts(connOpts.split(QLatin1Char(';'), QString::SkipEmptyParts));
+ const auto opts(QStringView(connOpts).split(u';', Qt::SkipEmptyParts));
- QString encString;
QByteArray role;
- for (int i = 0; i < opts.count(); ++i) {
- QString tmp(opts.at(i).simplified());
- int idx;
- if ((idx = tmp.indexOf(QLatin1Char('='))) != -1) {
- QString val = tmp.mid(idx + 1).simplified();
- QString opt = tmp.left(idx).simplified();
- if (opt.toUpper() == QLatin1String("ISC_DPB_LC_CTYPE"))
- encString = val;
- else if (opt.toUpper() == QLatin1String("ISC_DPB_SQL_ROLE_NAME")) {
+ for (const auto &opt : opts) {
+ const auto tmp(opt.trimmed());
+ qsizetype idx;
+ if ((idx = tmp.indexOf(u'=')) != -1) {
+ const auto val = tmp.mid(idx + 1).trimmed();
+ const auto opt = tmp.left(idx).trimmed().toString();
+ if (opt.toUpper() == "ISC_DPB_SQL_ROLE_NAME"_L1) {
role = val.toLocal8Bit();
role.truncate(255);
}
}
}
- // Use UNICODE_FSS when no ISC_DPB_LC_CTYPE is provided
- if (encString.isEmpty())
- encString = QLatin1String("UNICODE_FSS");
- else {
- d->tc = QTextCodec::codecForName(encString.toLocal8Bit());
- if (!d->tc) {
- qWarning("Unsupported encoding: %s. Using UNICODE_FFS for ISC_DPB_LC_CTYPE.", encString.toLocal8Bit().constData());
- encString = QLatin1String("UNICODE_FSS"); // Fallback to UNICODE_FSS
- }
- }
-
- QByteArray enc = encString.toLocal8Bit();
+ QByteArray enc = "UTF8";
QByteArray usr = user.toLocal8Bit();
QByteArray pass = password.toLocal8Bit();
- enc.truncate(255);
usr.truncate(255);
pass.truncate(255);
@@ -1539,7 +1574,7 @@ bool QIBaseDriver::open(const QString & db,
QString ldb;
if (!host.isEmpty())
- ldb += host + portString + QLatin1Char(':');
+ ldb += host + portString + u':';
ldb += db;
isc_attach_database(d->status, 0, const_cast<char *>(ldb.toLocal8Bit().constData()),
&d->ibase, ba.size(), ba.data());
@@ -1551,6 +1586,14 @@ bool QIBaseDriver::open(const QString & db,
setOpen(true);
setOpenError(false);
+#if (FB_API_VER >= 40)
+ std::call_once(initTZMappingFlag, [d](){ d->initTZMappingCache(); });
+ if (lastError().isValid())
+ {
+ setOpen(true);
+ return false;
+ }
+#endif
return true;
}
@@ -1569,13 +1612,6 @@ void QIBaseDriver::close()
qFreeEventBuffer(eBuffer);
}
d->eventBuffers.clear();
-
-#if defined(FB_API_VER)
- // TODO check whether this workaround for Firebird crash is still needed
- QDeadlineTimer timer(500);
- while (!timer.hasExpired())
- QCoreApplication::processEvents();
-#endif
}
isc_detach_database(d->status, &d->ibase);
@@ -1640,28 +1676,28 @@ QStringList QIBaseDriver::tables(QSql::TableType type) const
QString typeFilter;
if (type == QSql::SystemTables) {
- typeFilter += QLatin1String("RDB$SYSTEM_FLAG != 0");
+ typeFilter += "RDB$SYSTEM_FLAG != 0"_L1;
} else if (type == (QSql::SystemTables | QSql::Views)) {
- typeFilter += QLatin1String("RDB$SYSTEM_FLAG != 0 OR RDB$VIEW_BLR NOT NULL");
+ typeFilter += "RDB$SYSTEM_FLAG != 0 OR RDB$VIEW_BLR NOT NULL"_L1;
} else {
if (!(type & QSql::SystemTables))
- typeFilter += QLatin1String("RDB$SYSTEM_FLAG = 0 AND ");
+ typeFilter += "RDB$SYSTEM_FLAG = 0 AND "_L1;
if (!(type & QSql::Views))
- typeFilter += QLatin1String("RDB$VIEW_BLR IS NULL AND ");
+ typeFilter += "RDB$VIEW_BLR IS NULL AND "_L1;
if (!(type & QSql::Tables))
- typeFilter += QLatin1String("RDB$VIEW_BLR IS NOT NULL AND ");
+ typeFilter += "RDB$VIEW_BLR IS NOT NULL AND "_L1;
if (!typeFilter.isEmpty())
typeFilter.chop(5);
}
if (!typeFilter.isEmpty())
- typeFilter.prepend(QLatin1String("where "));
+ typeFilter.prepend("where "_L1);
QSqlQuery q(createResult());
q.setForwardOnly(true);
- if (!q.exec(QLatin1String("select rdb$relation_name from rdb$relations ") + typeFilter))
+ if (!q.exec("select rdb$relation_name from rdb$relations "_L1 + typeFilter))
return res;
- while(q.next())
- res << q.value(0).toString().simplified();
+ while (q.next())
+ res << q.value(0).toString().simplified();
return res;
}
@@ -1672,25 +1708,21 @@ QSqlRecord QIBaseDriver::record(const QString& tablename) const
if (!isOpen())
return rec;
+ const QString table = stripDelimiters(tablename, QSqlDriver::TableName);
QSqlQuery q(createResult());
q.setForwardOnly(true);
- QString table = tablename;
- if (isIdentifierEscaped(table, QSqlDriver::TableName))
- table = stripDelimiters(table, QSqlDriver::TableName);
- else
- table = table.toUpper();
- q.exec(QLatin1String("SELECT a.RDB$FIELD_NAME, b.RDB$FIELD_TYPE, b.RDB$FIELD_LENGTH, "
+ q.exec("SELECT a.RDB$FIELD_NAME, b.RDB$FIELD_TYPE, b.RDB$FIELD_LENGTH, "
"b.RDB$FIELD_SCALE, b.RDB$FIELD_PRECISION, a.RDB$NULL_FLAG "
"FROM RDB$RELATION_FIELDS a, RDB$FIELDS b "
"WHERE b.RDB$FIELD_NAME = a.RDB$FIELD_SOURCE "
- "AND a.RDB$RELATION_NAME = '") + table + QLatin1String("' "
- "ORDER BY a.RDB$FIELD_POSITION"));
+ "AND a.RDB$RELATION_NAME = '"_L1 + table + "' "
+ "ORDER BY a.RDB$FIELD_POSITION"_L1);
while (q.next()) {
int type = q.value(1).toInt();
bool hasScale = q.value(3).toInt() < 0;
- QSqlField f(q.value(0).toString().simplified(), qIBaseTypeName(type, hasScale), tablename);
- if(hasScale) {
+ QSqlField f(q.value(0).toString().simplified(), QMetaType(qIBaseTypeName(type, hasScale)), tablename);
+ if (hasScale) {
f.setLength(q.value(4).toInt());
f.setPrecision(qAbs(q.value(3).toInt()));
} else {
@@ -1698,7 +1730,6 @@ QSqlRecord QIBaseDriver::record(const QString& tablename) const
f.setPrecision(0);
}
f.setRequired(q.value(5).toInt() > 0);
- f.setSqlType(type);
rec.append(f);
}
@@ -1711,27 +1742,22 @@ QSqlIndex QIBaseDriver::primaryIndex(const QString &table) const
if (!isOpen())
return index;
- QString tablename = table;
- if (isIdentifierEscaped(tablename, QSqlDriver::TableName))
- tablename = stripDelimiters(tablename, QSqlDriver::TableName);
- else
- tablename = tablename.toUpper();
-
+ const QString tablename = stripDelimiters(table, QSqlDriver::TableName);
QSqlQuery q(createResult());
q.setForwardOnly(true);
- q.exec(QLatin1String("SELECT a.RDB$INDEX_NAME, b.RDB$FIELD_NAME, d.RDB$FIELD_TYPE, d.RDB$FIELD_SCALE "
+ q.exec("SELECT a.RDB$INDEX_NAME, b.RDB$FIELD_NAME, d.RDB$FIELD_TYPE, d.RDB$FIELD_SCALE "
"FROM RDB$RELATION_CONSTRAINTS a, RDB$INDEX_SEGMENTS b, RDB$RELATION_FIELDS c, RDB$FIELDS d "
"WHERE a.RDB$CONSTRAINT_TYPE = 'PRIMARY KEY' "
- "AND a.RDB$RELATION_NAME = '") + tablename +
- QLatin1String(" 'AND a.RDB$INDEX_NAME = b.RDB$INDEX_NAME "
+ "AND a.RDB$RELATION_NAME = '"_L1 + tablename +
+ " 'AND a.RDB$INDEX_NAME = b.RDB$INDEX_NAME "
"AND c.RDB$RELATION_NAME = a.RDB$RELATION_NAME "
"AND c.RDB$FIELD_NAME = b.RDB$FIELD_NAME "
"AND d.RDB$FIELD_NAME = c.RDB$FIELD_SOURCE "
- "ORDER BY b.RDB$FIELD_POSITION"));
+ "ORDER BY b.RDB$FIELD_POSITION"_L1);
while (q.next()) {
QSqlField field(q.value(1).toString().simplified(),
- qIBaseTypeName(q.value(2).toInt(), q.value(3).toInt() < 0),
+ QMetaType(qIBaseTypeName(q.value(2).toInt(), q.value(3).toInt() < 0)),
tablename);
index.append(field); //TODO: asc? desc?
index.setName(q.value(0).toString());
@@ -1742,40 +1768,40 @@ QSqlIndex QIBaseDriver::primaryIndex(const QString &table) const
QString QIBaseDriver::formatValue(const QSqlField &field, bool trimStrings) const
{
- switch (field.type()) {
- case QVariant::DateTime: {
+ switch (field.metaType().id()) {
+ case QMetaType::QDateTime: {
QDateTime datetime = field.value().toDateTime();
if (datetime.isValid())
- return QLatin1Char('\'') + QString::number(datetime.date().year()) + QLatin1Char('-') +
- QString::number(datetime.date().month()) + QLatin1Char('-') +
- QString::number(datetime.date().day()) + QLatin1Char(' ') +
- QString::number(datetime.time().hour()) + QLatin1Char(':') +
- QString::number(datetime.time().minute()) + QLatin1Char(':') +
- QString::number(datetime.time().second()) + QLatin1Char('.') +
- QString::number(datetime.time().msec()).rightJustified(3, QLatin1Char('0'), true) +
- QLatin1Char('\'');
+ return u'\'' + QString::number(datetime.date().year()) + u'-' +
+ QString::number(datetime.date().month()) + u'-' +
+ QString::number(datetime.date().day()) + u' ' +
+ QString::number(datetime.time().hour()) + u':' +
+ QString::number(datetime.time().minute()) + u':' +
+ QString::number(datetime.time().second()) + u'.' +
+ QString::number(datetime.time().msec()).rightJustified(3, u'0', true) +
+ u'\'';
else
- return QLatin1String("NULL");
+ return "NULL"_L1;
}
- case QVariant::Time: {
+ case QMetaType::QTime: {
QTime time = field.value().toTime();
if (time.isValid())
- return QLatin1Char('\'') + QString::number(time.hour()) + QLatin1Char(':') +
- QString::number(time.minute()) + QLatin1Char(':') +
- QString::number(time.second()) + QLatin1Char('.') +
- QString::number(time.msec()).rightJustified(3, QLatin1Char('0'), true) +
- QLatin1Char('\'');
+ return u'\'' + QString::number(time.hour()) + u':' +
+ QString::number(time.minute()) + u':' +
+ QString::number(time.second()) + u'.' +
+ QString::number(time.msec()).rightJustified(3, u'0', true) +
+ u'\'';
else
- return QLatin1String("NULL");
+ return "NULL"_L1;
}
- case QVariant::Date: {
+ case QMetaType::QDate: {
QDate date = field.value().toDate();
if (date.isValid())
- return QLatin1Char('\'') + QString::number(date.year()) + QLatin1Char('-') +
- QString::number(date.month()) + QLatin1Char('-') +
- QString::number(date.day()) + QLatin1Char('\'');
+ return u'\'' + QString::number(date.year()) + u'-' +
+ QString::number(date.month()) + u'-' +
+ QString::number(date.day()) + u'\'';
else
- return QLatin1String("NULL");
+ return "NULL"_L1;
}
default:
return QSqlDriver::formatValue(field, trimStrings);
@@ -1785,14 +1811,10 @@ QString QIBaseDriver::formatValue(const QSqlField &field, bool trimStrings) cons
QVariant QIBaseDriver::handle() const
{
Q_D(const QIBaseDriver);
- return QVariant(qRegisterMetaType<isc_db_handle>("isc_db_handle"), &d->ibase);
+ return QVariant(QMetaType::fromType<isc_db_handle>(), &d->ibase);
}
-#if defined(FB_API_VER) && FB_API_VER >= 20
static ISC_EVENT_CALLBACK qEventCallback(char *result, ISC_USHORT length, const ISC_UCHAR *updated)
-#else
-static isc_callback qEventCallback(char *result, short length, char *updated)
-#endif
{
if (!updated)
return 0;
@@ -1815,13 +1837,13 @@ bool QIBaseDriver::subscribeToNotification(const QString &name)
{
Q_D(QIBaseDriver);
if (!isOpen()) {
- qWarning("QIBaseDriver::subscribeFromNotificationImplementation: database not open.");
+ qCWarning(lcIbase, "QIBaseDriver::subscribeFromNotificationImplementation: database not open.");
return false;
}
if (d->eventBuffers.contains(name)) {
- qWarning("QIBaseDriver::subscribeToNotificationImplementation: already subscribing to '%s'.",
- qPrintable(name));
+ qCWarning(lcIbase, "QIBaseDriver::subscribeToNotificationImplementation: already subscribing to '%ls'.",
+ qUtf16Printable(name));
return false;
}
@@ -1844,13 +1866,8 @@ bool QIBaseDriver::subscribeToNotification(const QString &name)
&eBuffer->eventId,
eBuffer->bufferLength,
eBuffer->eventBuffer,
-#if defined (FB_API_VER) && FB_API_VER >= 20
reinterpret_cast<ISC_EVENT_CALLBACK>(reinterpret_cast<void *>
(&qEventCallback)),
-#else
- reinterpret_cast<isc_callback>(reinterpret_cast<void *>
- (&qEventCallback)),
-#endif
eBuffer->resultBuffer);
if (status[0] == 1 && status[1]) {
@@ -1867,13 +1884,13 @@ bool QIBaseDriver::unsubscribeFromNotification(const QString &name)
{
Q_D(QIBaseDriver);
if (!isOpen()) {
- qWarning("QIBaseDriver::unsubscribeFromNotificationImplementation: database not open.");
+ qCWarning(lcIbase, "QIBaseDriver::unsubscribeFromNotificationImplementation: database not open.");
return false;
}
if (!d->eventBuffers.contains(name)) {
- qWarning("QIBaseDriver::QIBaseSubscriptionState not subscribed to '%s'.",
- qPrintable(name));
+ qCWarning(lcIbase, "QIBaseDriver::QIBaseSubscriptionState not subscribed to '%ls'.",
+ qUtf16Printable(name));
return false;
}
@@ -1924,17 +1941,12 @@ void QIBaseDriver::qHandleEventNotification(void *updatedResultBuffer)
&eBuffer->eventId,
eBuffer->bufferLength,
eBuffer->eventBuffer,
-#if defined (FB_API_VER) && FB_API_VER >= 20
reinterpret_cast<ISC_EVENT_CALLBACK>(reinterpret_cast<void *>
(&qEventCallback)),
-#else
- reinterpret_cast<isc_callback>(reinterpret_cast<void *>
- (&qEventCallback)),
-#endif
eBuffer->resultBuffer);
if (Q_UNLIKELY(status[0] == 1 && status[1])) {
- qCritical("QIBaseDriver::qHandleEventNotification: could not resubscribe to '%s'",
- qPrintable(i.key()));
+ qCritical("QIBaseDriver::qHandleEventNotification: could not resubscribe to '%ls'",
+ qUtf16Printable(i.key()));
}
return;
@@ -1945,12 +1957,20 @@ void QIBaseDriver::qHandleEventNotification(void *updatedResultBuffer)
QString QIBaseDriver::escapeIdentifier(const QString &identifier, IdentifierType) const
{
QString res = identifier;
- if(!identifier.isEmpty() && !identifier.startsWith(QLatin1Char('"')) && !identifier.endsWith(QLatin1Char('"')) ) {
- res.replace(QLatin1Char('"'), QLatin1String("\"\""));
- res.prepend(QLatin1Char('"')).append(QLatin1Char('"'));
- res.replace(QLatin1Char('.'), QLatin1String("\".\""));
+ if (!identifier.isEmpty() && !identifier.startsWith(u'"') && !identifier.endsWith(u'"') ) {
+ res.replace(u'"', "\"\""_L1);
+ res.replace(u'.', "\".\""_L1);
+ res = u'"' + res + u'"';
}
return res;
}
+int QIBaseDriver::maximumIdentifierLength(IdentifierType type) const
+{
+ Q_UNUSED(type);
+ return 31;
+}
+
QT_END_NAMESPACE
+
+#include "moc_qsql_ibase_p.cpp"
diff --git a/src/plugins/sqldrivers/ibase/qsql_ibase_p.h b/src/plugins/sqldrivers/ibase/qsql_ibase_p.h
index 295f6c0cec..86c7ae1241 100644
--- a/src/plugins/sqldrivers/ibase/qsql_ibase_p.h
+++ b/src/plugins/sqldrivers/ibase/qsql_ibase_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtSql module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QSQL_IBASE_H
#define QSQL_IBASE_H
@@ -60,6 +24,8 @@
#define Q_EXPORT_SQLDRIVER_IBASE Q_SQL_EXPORT
#endif
+static_assert(FB_API_VER >= 20, "Qt requires at least the Firebird 2.0 client APIs.");
+
QT_BEGIN_NAMESPACE
class QSqlResult;
@@ -71,8 +37,8 @@ class Q_EXPORT_SQLDRIVER_IBASE QIBaseDriver : public QSqlDriver
Q_DECLARE_PRIVATE(QIBaseDriver)
Q_OBJECT
public:
- explicit QIBaseDriver(QObject *parent = 0);
- explicit QIBaseDriver(isc_db_handle connection, QObject *parent = 0);
+ explicit QIBaseDriver(QObject *parent = nullptr);
+ explicit QIBaseDriver(isc_db_handle connection, QObject *parent = nullptr);
virtual ~QIBaseDriver();
bool hasFeature(DriverFeature f) const override;
bool open(const QString &db,
@@ -104,7 +70,7 @@ public:
bool subscribeToNotification(const QString &name) override;
bool unsubscribeFromNotification(const QString &name) override;
QStringList subscribedToNotifications() const override;
-
+ int maximumIdentifierLength(IdentifierType type) const override;
private Q_SLOTS:
void qHandleEventNotification(void* updatedResultBuffer);
};
diff --git a/src/plugins/sqldrivers/mimer/CMakeLists.txt b/src/plugins/sqldrivers/mimer/CMakeLists.txt
new file mode 100644
index 0000000000..303af7120c
--- /dev/null
+++ b/src/plugins/sqldrivers/mimer/CMakeLists.txt
@@ -0,0 +1,24 @@
+# Generated from mimer.pro.
+
+#####################################################################
+## MIMERSQLDriverPlugin Plugin:
+#####################################################################
+
+qt_internal_add_plugin(QMimerSQLDriverPlugin
+ OUTPUT_NAME qsqlmimer
+ PLUGIN_TYPE sqldrivers
+ SOURCES
+ main.cpp
+ qsql_mimer.cpp qsql_mimer.h
+ DEFINES
+ QT_NO_CAST_FROM_ASCII
+ QT_NO_CAST_TO_ASCII
+ QT_NO_CONTEXTLESS_CONNECT
+ LIBRARIES
+ MimerSQL::MimerSQL
+ Qt::Core
+ Qt::SqlPrivate
+)
+
+#### Keys ignored in scope 1:.:.:mimer.pro:<TRUE>:
+# OTHER_FILES = "mimer.json"
diff --git a/src/plugins/sqldrivers/mimer/README b/src/plugins/sqldrivers/mimer/README
new file mode 100644
index 0000000000..02e4c3e162
--- /dev/null
+++ b/src/plugins/sqldrivers/mimer/README
@@ -0,0 +1,6 @@
+You will need the Mimer SQL development headers and libraries installed before
+compiling this plugin. qsql_mimer.h contains an include to mimerapi.h that is
+needed for the driver to compile.
+
+See the Qt SQL documentation for more information on compiling Qt SQL driver
+plugins.
diff --git a/src/plugins/sqldrivers/mimer/main.cpp b/src/plugins/sqldrivers/mimer/main.cpp
new file mode 100644
index 0000000000..560b7da7c7
--- /dev/null
+++ b/src/plugins/sqldrivers/mimer/main.cpp
@@ -0,0 +1,33 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// Copyright (C) 2022 Mimer Information Technology
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+#include "qsql_mimer.h"
+
+#include <qsqldriverplugin.h>
+#include <qstringlist.h>
+
+QT_BEGIN_NAMESPACE
+
+using namespace Qt::StringLiterals;
+
+class QMimerSQLDriverPlugin : public QSqlDriverPlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QSqlDriverFactoryInterface" FILE "mimer.json")
+public:
+ QMimerSQLDriverPlugin();
+ QSqlDriver *create(const QString &) override;
+};
+
+QMimerSQLDriverPlugin::QMimerSQLDriverPlugin() : QSqlDriverPlugin() { }
+
+QSqlDriver *QMimerSQLDriverPlugin::create(const QString &name)
+{
+ if (name == "QMIMER"_L1)
+ return new QMimerSQLDriver;
+ return nullptr;
+}
+
+QT_END_NAMESPACE
+
+#include "main.moc"
diff --git a/src/plugins/sqldrivers/mimer/mimer.json b/src/plugins/sqldrivers/mimer/mimer.json
new file mode 100644
index 0000000000..fba96b765d
--- /dev/null
+++ b/src/plugins/sqldrivers/mimer/mimer.json
@@ -0,0 +1,5 @@
+{
+ "Keys": [
+ "QMIMER"
+ ]
+}
diff --git a/src/plugins/sqldrivers/mimer/qsql_mimer.cpp b/src/plugins/sqldrivers/mimer/qsql_mimer.cpp
new file mode 100644
index 0000000000..7f89e0a0d5
--- /dev/null
+++ b/src/plugins/sqldrivers/mimer/qsql_mimer.cpp
@@ -0,0 +1,1610 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// Copyright (C) 2022 Mimer Information Technology
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+#include <qcoreapplication.h>
+#include <qvariant.h>
+#include <qmetatype.h>
+#include <qdatetime.h>
+#include <qloggingcategory.h>
+#include <qsqlerror.h>
+#include <qsqlfield.h>
+#include <qsqlindex.h>
+#include <qsqlrecord.h>
+#include <qsqlquery.h>
+#include <qsocketnotifier.h>
+#include <qstringlist.h>
+#include <qlocale.h>
+#if defined(Q_OS_WIN32)
+# include <QtCore/qt_windows.h>
+#endif
+#include <QtSql/private/qsqlresult_p.h>
+#include <QtSql/private/qsqldriver_p.h>
+#include "qsql_mimer.h"
+
+#define MIMER_DEFAULT_DATATYPE 1000
+
+Q_DECLARE_OPAQUE_POINTER(MimerSession)
+Q_DECLARE_METATYPE(MimerSession)
+
+Q_DECLARE_OPAQUE_POINTER(MimerStatement)
+Q_DECLARE_METATYPE(MimerStatement)
+
+QT_BEGIN_NAMESPACE
+
+static Q_LOGGING_CATEGORY(lcMimer, "qt.sql.mimer")
+
+enum class MimerColumnTypes {
+ Binary,
+ Clob,
+ Blob,
+ String,
+ Int,
+ Numeric,
+ Long,
+ Float,
+ Double,
+ Boolean,
+ Uuid,
+ Date,
+ Time,
+ Timestamp,
+ Unknown
+};
+
+using namespace Qt::StringLiterals;
+
+class QMimerSQLResultPrivate;
+
+class QMimerSQLResult final : public QSqlResult
+{
+ Q_DECLARE_PRIVATE(QMimerSQLResult)
+public:
+ QMimerSQLResult(const QMimerSQLDriver *db);
+ virtual ~QMimerSQLResult() override;
+ QVariant handle() const override;
+ static constexpr int genericError = -1;
+ static constexpr int lobChunkMaxSizeSet = 1048500;
+ static constexpr int lobChunkMaxSizeFetch = 65536;
+ static constexpr int maxStackStringSize = 200;
+ static constexpr int maxTimeStringSize = 18;
+ static constexpr int maxDateStringSize = 10;
+ static constexpr int maxTimestampStringSize = 29;
+
+private:
+ void cleanup();
+ bool fetch(int i) override;
+ bool fetchFirst() override;
+ bool fetchLast() override;
+ bool fetchNext() override;
+ QVariant data(int i) override;
+ bool isNull(int index) override;
+ bool reset(const QString &query) override;
+ int size() override;
+ int numRowsAffected() override;
+ QSqlRecord record() const override;
+ bool prepare(const QString &query) override;
+ bool execBatch(bool arrayBind = false) override;
+ bool exec() override;
+ qint64 currentRow();
+ QVariant lastInsertId() const override;
+};
+
+class QMimerSQLDriverPrivate final : public QSqlDriverPrivate
+{
+ Q_DECLARE_PUBLIC(QMimerSQLDriver)
+public:
+ QMimerSQLDriverPrivate() : QSqlDriverPrivate(QSqlDriver::MimerSQL), sessionhandle(nullptr) { }
+ MimerSession sessionhandle;
+ QString dbName;
+ QString dbUser;
+ void splitTableQualifier(const QString &qualifier, QString *schema, QString *table) const;
+};
+
+class QMimerSQLResultPrivate : public QSqlResultPrivate
+{
+ Q_DECLARE_PUBLIC(QMimerSQLResult)
+public:
+ Q_DECLARE_SQLDRIVER_PRIVATE(QMimerSQLDriver)
+ QMimerSQLResultPrivate(QMimerSQLResult *q, const QMimerSQLDriver *drv)
+ : QSqlResultPrivate(q, drv),
+ statementhandle(nullptr),
+ lobhandle(nullptr),
+ rowsAffected(0),
+ preparedQuery(false),
+ openCursor(false),
+ openStatement(false),
+ executedStatement(false),
+ callWithOut(false),
+ execBatch(false),
+ currentRow(QSql::BeforeFirstRow)
+ {
+ }
+ MimerStatement statementhandle;
+ MimerLob lobhandle;
+ int rowsAffected;
+ bool preparedQuery;
+ bool openCursor;
+ bool openStatement;
+ bool executedStatement;
+ bool callWithOut;
+ bool execBatch;
+ qint64 currentSize = -1;
+ qint64 currentRow; // Only used when forwardOnly()
+ QVector<QVariant> batch_vector;
+};
+
+static QSqlError qMakeError(const QString &err, const int errCode, QSqlError::ErrorType type,
+ const QMimerSQLDriverPrivate *p)
+{
+ QString msg;
+ if (p) {
+ size_t str_len;
+ int e_code;
+ int rc;
+ str_len = (rc = MimerGetError(p->sessionhandle, &e_code, NULL, 0)) + 1;
+ if (!MIMER_SUCCEEDED(rc)) {
+ msg = QCoreApplication::translate("QMimerSQL", "No Mimer SQL error for code %1")
+ .arg(errCode);
+ } else {
+ QVarLengthArray<wchar_t> tmp_buff((qsizetype)str_len);
+ if (!MIMER_SUCCEEDED(
+ rc = MimerGetError(p->sessionhandle, &e_code, tmp_buff.data(), str_len)))
+ msg = QCoreApplication::translate("QMimerSQL", "No Mimer SQL error for code %1")
+ .arg(errCode);
+ else
+ msg = QString::fromWCharArray(tmp_buff.data());
+ }
+ } else {
+ msg = QCoreApplication::translate("QMimerSQL", "Generic Mimer SQL error");
+ }
+
+ return QSqlError("QMIMER: "_L1 + err, msg, type, QString::number(errCode));
+}
+
+static QString msgCouldNotGet(const char *type, int column)
+{
+ //: Data type, column
+ return QCoreApplication::translate("QMimerSQLResult",
+ "Could not get %1, column %2").arg(QLatin1StringView(type)).arg(column);
+}
+
+static QString msgCouldNotSet(const char *type, int column)
+{
+ //: Data type, parameter
+ return QCoreApplication::translate("QMimerSQLResult",
+ "Could not set %1, parameter %2").arg(QLatin1StringView(type)).arg(column);
+}
+
+QMimerSQLDriver::QMimerSQLDriver(QObject *parent) : QSqlDriver(*new QMimerSQLDriverPrivate, parent)
+{
+}
+
+QMimerSQLDriver::QMimerSQLDriver(MimerSession *conn, QObject *parent)
+ : QSqlDriver(*new QMimerSQLDriverPrivate, parent)
+{
+ Q_D(QMimerSQLDriver);
+ if (conn)
+ d->sessionhandle = *conn;
+}
+
+QMimerSQLDriver::~QMimerSQLDriver()
+{
+ close();
+}
+
+QMimerSQLResult::QMimerSQLResult(const QMimerSQLDriver *db)
+ : QSqlResult(*new QMimerSQLResultPrivate(this, db))
+{
+ Q_D(QMimerSQLResult);
+ d->preparedQuery = db->hasFeature(QSqlDriver::PreparedQueries);
+}
+
+QMimerSQLResult::~QMimerSQLResult()
+{
+ cleanup();
+}
+
+static MimerColumnTypes mimerMapColumnTypes(int32_t t)
+{
+ switch (t) {
+ case MIMER_BINARY:
+ case MIMER_BINARY_VARYING:
+ return MimerColumnTypes::Binary;
+ case MIMER_BLOB:
+ case MIMER_NATIVE_BLOB:
+ return MimerColumnTypes::Blob;
+ case MIMER_CLOB:
+ case MIMER_NCLOB:
+ case MIMER_NATIVE_CLOB:
+ case MIMER_NATIVE_NCLOB:
+ return MimerColumnTypes::Clob;
+ case MIMER_DATE:
+ return MimerColumnTypes::Date;
+ case MIMER_TIME:
+ return MimerColumnTypes::Time;
+ case MIMER_TIMESTAMP:
+ return MimerColumnTypes::Timestamp;
+ case MIMER_INTERVAL_DAY:
+ case MIMER_INTERVAL_DAY_TO_HOUR:
+ case MIMER_INTERVAL_DAY_TO_MINUTE:
+ case MIMER_INTERVAL_DAY_TO_SECOND:
+ case MIMER_INTERVAL_HOUR:
+ case MIMER_INTERVAL_HOUR_TO_MINUTE:
+ case MIMER_INTERVAL_HOUR_TO_SECOND:
+ case MIMER_INTERVAL_MINUTE:
+ case MIMER_INTERVAL_MINUTE_TO_SECOND:
+ case MIMER_INTERVAL_MONTH:
+ case MIMER_INTERVAL_SECOND:
+ case MIMER_INTERVAL_YEAR:
+ case MIMER_INTERVAL_YEAR_TO_MONTH:
+ case MIMER_NCHAR:
+ case MIMER_CHARACTER:
+ case MIMER_CHARACTER_VARYING:
+ case MIMER_NCHAR_VARYING:
+ case MIMER_UTF8:
+ case MIMER_DEFAULT_DATATYPE:
+ return MimerColumnTypes::String;
+ case MIMER_INTEGER:
+ case MIMER_DECIMAL:
+ case MIMER_FLOAT:
+ return MimerColumnTypes::Numeric;
+ case MIMER_BOOLEAN:
+ return MimerColumnTypes::Boolean;
+ case MIMER_T_BIGINT:
+ case MIMER_T_UNSIGNED_BIGINT:
+ case MIMER_NATIVE_BIGINT_NULLABLE:
+ case MIMER_NATIVE_BIGINT:
+ return MimerColumnTypes::Long;
+ case MIMER_NATIVE_REAL_NULLABLE:
+ case MIMER_NATIVE_REAL:
+ case MIMER_T_REAL:
+ return MimerColumnTypes::Float;
+ case MIMER_T_FLOAT:
+ case MIMER_NATIVE_DOUBLE_NULLABLE:
+ case MIMER_NATIVE_DOUBLE:
+ case MIMER_T_DOUBLE:
+ return MimerColumnTypes::Double;
+ case MIMER_NATIVE_INTEGER:
+ case MIMER_NATIVE_INTEGER_NULLABLE:
+ case MIMER_NATIVE_SMALLINT_NULLABLE:
+ case MIMER_NATIVE_SMALLINT:
+ case MIMER_T_INTEGER:
+ case MIMER_T_SMALLINT:
+ return MimerColumnTypes::Int;
+ case MIMER_UUID:
+ return MimerColumnTypes::Uuid;
+ default:
+ qCWarning(lcMimer) << "QMimerSQLDriver::mimerMapColumnTypes: Unknown data type:" << t;
+ }
+ return MimerColumnTypes::Unknown;
+}
+
+static QMetaType::Type qDecodeMSQLType(int32_t t)
+{
+ switch (t) {
+ case MIMER_BINARY:
+ case MIMER_BINARY_VARYING:
+ case MIMER_BLOB:
+ case MIMER_NATIVE_BLOB:
+ return QMetaType::QByteArray;
+ case MIMER_CLOB:
+ case MIMER_NCLOB:
+ case MIMER_NATIVE_CLOB:
+ case MIMER_NATIVE_NCLOB:
+ case MIMER_INTERVAL_DAY:
+ case MIMER_DECIMAL:
+ case MIMER_INTERVAL_DAY_TO_HOUR:
+ case MIMER_INTERVAL_DAY_TO_MINUTE:
+ case MIMER_INTERVAL_DAY_TO_SECOND:
+ case MIMER_INTERVAL_HOUR:
+ case MIMER_INTERVAL_HOUR_TO_MINUTE:
+ case MIMER_INTERVAL_HOUR_TO_SECOND:
+ case MIMER_INTERVAL_MINUTE:
+ case MIMER_INTERVAL_MINUTE_TO_SECOND:
+ case MIMER_INTERVAL_MONTH:
+ case MIMER_INTERVAL_SECOND:
+ case MIMER_INTERVAL_YEAR:
+ case MIMER_INTERVAL_YEAR_TO_MONTH:
+ case MIMER_NCHAR:
+ case MIMER_CHARACTER:
+ case MIMER_CHARACTER_VARYING:
+ case MIMER_NCHAR_VARYING:
+ case MIMER_UTF8:
+ case MIMER_DEFAULT_DATATYPE:
+ case MIMER_INTEGER:
+ case MIMER_FLOAT:
+ return QMetaType::QString;
+ case MIMER_BOOLEAN:
+ return QMetaType::Bool;
+ case MIMER_T_BIGINT:
+ case MIMER_T_UNSIGNED_BIGINT:
+ case MIMER_NATIVE_BIGINT_NULLABLE:
+ case MIMER_NATIVE_BIGINT:
+ return QMetaType::LongLong;
+ case MIMER_NATIVE_REAL_NULLABLE:
+ case MIMER_NATIVE_REAL:
+ case MIMER_T_REAL:
+ return QMetaType::Float;
+ case MIMER_T_FLOAT:
+ case MIMER_NATIVE_DOUBLE_NULLABLE:
+ case MIMER_NATIVE_DOUBLE:
+ case MIMER_T_DOUBLE:
+ return QMetaType::Double;
+ case MIMER_NATIVE_INTEGER_NULLABLE:
+ case MIMER_T_INTEGER:
+ case MIMER_NATIVE_INTEGER:
+ return QMetaType::Int;
+ case MIMER_NATIVE_SMALLINT_NULLABLE:
+ case MIMER_T_SMALLINT:
+ return QMetaType::Int;
+ case MIMER_DATE:
+ return QMetaType::QDate;
+ case MIMER_TIME:
+ return QMetaType::QTime;
+ break;
+ case MIMER_TIMESTAMP:
+ return QMetaType::QDateTime;
+ case MIMER_UUID:
+ return QMetaType::QUuid;
+ default:
+ qCWarning(lcMimer) << "QMimerSQLDriver::qDecodeMSQLType: Unknown data type:" << t;
+ return QMetaType::UnknownType;
+ }
+}
+
+static int32_t qLookupMimDataType(QStringView s)
+{
+ if (s == u"BINARY")
+ return MIMER_BINARY;
+ if (s == u"BINARY VARYING")
+ return MIMER_BINARY_VARYING;
+ if (s == u"BINARY LARGE OBJECT")
+ return MIMER_BLOB;
+ if (s == u"CHARACTER LARGE OBJECT")
+ return MIMER_CLOB;
+ if (s == u"NATIONAL CHAR LARGE OBJECT")
+ return MIMER_NCLOB;
+ if (s == u"INTERVAL DAY")
+ return MIMER_INTERVAL_DAY;
+ if (s == u"DECIMAL")
+ return MIMER_DECIMAL;
+ if (s == u"INTERVAL DAY TO HOUR")
+ return MIMER_INTERVAL_DAY_TO_HOUR;
+ if (s == u"INTERVAL DAY TO MINUTE")
+ return MIMER_INTERVAL_DAY_TO_MINUTE;
+ if (s == u"INTERVAL DAY TO SECOND")
+ return MIMER_INTERVAL_DAY_TO_SECOND;
+ if (s == u"INTERVAL HOUR")
+ return MIMER_INTERVAL_HOUR;
+ if (s == u"INTERVAL HOUR TO MINUTE")
+ return MIMER_INTERVAL_HOUR_TO_MINUTE;
+ if (s == u"INTERVAL HOUR TO SECOND")
+ return MIMER_INTERVAL_HOUR_TO_SECOND;
+ if (s == u"INTERVAL MINUTE")
+ return MIMER_INTERVAL_MINUTE;
+ if (s == u"INTERVAL MINUTE TO SECOND")
+ return MIMER_INTERVAL_MINUTE_TO_SECOND;
+ if (s == u"INTERVAL MONTH")
+ return MIMER_INTERVAL_MONTH;
+ if (s == u"INTERVAL SECOND")
+ return MIMER_INTERVAL_SECOND;
+ if (s == u"INTERVAL YEAR")
+ return MIMER_INTERVAL_YEAR;
+ if (s == u"INTERVAL YEAR TO MONTH")
+ return MIMER_INTERVAL_YEAR_TO_MONTH;
+ if (s == u"NATIONAL CHARACTER")
+ return MIMER_NCHAR;
+ if (s == u"CHARACTER")
+ return MIMER_CHARACTER;
+ if (s == u"CHARACTER VARYING")
+ return MIMER_CHARACTER_VARYING;
+ if (s == u"NATIONAL CHARACTER VARYING")
+ return MIMER_NCHAR_VARYING;
+ if (s == u"UTF-8")
+ return MIMER_UTF8;
+ if (s == u"BOOLEAN")
+ return MIMER_BOOLEAN;
+ if (s == u"BIGINT")
+ return MIMER_T_BIGINT;
+ if (s == u"REAL")
+ return MIMER_T_REAL;
+ if (s == u"FLOAT")
+ return MIMER_T_FLOAT;
+ if (s == u"DOUBLE PRECISION")
+ return MIMER_T_DOUBLE;
+ if (s == u"INTEGER")
+ return MIMER_T_INTEGER;
+ if (s == u"SMALLINT")
+ return MIMER_T_SMALLINT;
+ if (s == u"DATE")
+ return MIMER_DATE;
+ if (s == u"TIME")
+ return MIMER_TIME;
+ if (s == u"TIMESTAMP")
+ return MIMER_TIMESTAMP;
+ if (s == u"BUILTIN.UUID")
+ return MIMER_UUID;
+ if (s == u"USER-DEFINED")
+ return MIMER_DEFAULT_DATATYPE;
+ qCWarning(lcMimer) << "QMimerSQLDriver::qLookupMimDataType: Unhandled data type:" << s;
+ return MIMER_DEFAULT_DATATYPE;
+}
+
+QVariant QMimerSQLResult::handle() const
+{
+ Q_D(const QMimerSQLResult);
+ return QVariant::fromValue(d->statementhandle);
+}
+
+void QMimerSQLResult::cleanup()
+{
+ Q_D(QMimerSQLResult);
+ if (!driver() || !driver()->isOpen()) {
+ d->openCursor = false;
+ d->openStatement = false;
+ return;
+ }
+ if (d->openCursor) {
+ const int32_t err = MimerCloseCursor(d->statementhandle);
+ if (!MIMER_SUCCEEDED(err))
+ setLastError(qMakeError(
+ QCoreApplication::translate("QMimerSQLResult", "Could not close cursor"), err,
+ QSqlError::StatementError, d->drv_d_func()));
+ d->openCursor = false;
+ }
+ if (d->openStatement) {
+ const int32_t err = MimerEndStatement(&d->statementhandle);
+ if (!MIMER_SUCCEEDED(err))
+ setLastError(qMakeError(
+ QCoreApplication::translate("QMimerSQLResult", "Could not close statement"),
+ err, QSqlError::StatementError, d->drv_d_func()));
+ d->openStatement = false;
+ }
+ d->currentSize = -1;
+}
+
+qint64 QMimerSQLResult::currentRow()
+{
+ Q_D(const QMimerSQLResult);
+ return d->currentRow;
+}
+
+bool QMimerSQLResult::fetch(int i)
+{
+ Q_D(const QMimerSQLResult);
+ int32_t err = 0;
+ if (!isActive() || !isSelect())
+ return false;
+ if (i == at())
+ return true;
+ if (i < 0)
+ return false;
+
+ if (isForwardOnly() && i < at())
+ return false;
+
+ if (isForwardOnly()) {
+ bool rc;
+ do {
+ rc = fetchNext();
+ } while (rc && currentRow() < i);
+ return rc;
+ } else {
+ err = MimerFetchScroll(d->statementhandle, MIMER_ABSOLUTE, i + 1);
+ if (err == MIMER_NO_DATA)
+ return false;
+ }
+ if (!MIMER_SUCCEEDED(err)) {
+ setLastError(
+ qMakeError(QCoreApplication::translate("QMimerSQLResult", "Fetch did not succeed"),
+ err, QSqlError::StatementError, d->drv_d_func()));
+ return false;
+ }
+ setAt(MimerCurrentRow(d->statementhandle) - 1);
+ return true;
+}
+
+bool QMimerSQLResult::fetchFirst()
+{
+ Q_D(const QMimerSQLResult);
+ int32_t err = 0;
+ if (!isActive() || !isSelect())
+ return false;
+ if (isForwardOnly()) {
+ if (currentRow() < 0)
+ return fetchNext();
+ else if (currentRow() == 0)
+ setAt(0);
+ else
+ return false;
+ } else {
+ err = MimerFetchScroll(d->statementhandle, MIMER_FIRST, 0);
+ if (MIMER_SUCCEEDED(err) && err != MIMER_NO_DATA)
+ setAt(0);
+ }
+ if (!MIMER_SUCCEEDED(err)) {
+ setLastError(qMakeError(
+ QCoreApplication::translate("QMimerSQLResult", "Fetch first did not succeed"), err,
+ QSqlError::StatementError, d->drv_d_func()));
+ return false;
+ }
+ if (err == MIMER_NO_DATA)
+ return false;
+ return true;
+}
+
+bool QMimerSQLResult::fetchLast()
+{
+ Q_D(const QMimerSQLResult);
+ int32_t err = 0;
+ int row = 0;
+ if (!isActive() || !isSelect())
+ return false;
+ if (isForwardOnly()) {
+ bool rc;
+ do {
+ rc = fetchNext();
+ } while (rc);
+
+ return currentRow() >= 0;
+ } else {
+ err = MimerFetchScroll(d->statementhandle, static_cast<std::int32_t>(MIMER_LAST), 0);
+ if (err == MIMER_NO_DATA)
+ return false;
+ if (MIMER_SUCCEEDED(err)) {
+ row = MimerCurrentRow(d->statementhandle) - 1;
+ } else {
+ setLastError(qMakeError(
+ QCoreApplication::translate("QMimerSQLResult:", "Fetch last did not succeed"),
+ err, QSqlError::StatementError, d->drv_d_func()));
+ return false;
+ }
+ }
+
+ if (row < 0) {
+ setAt(QSql::BeforeFirstRow);
+ return false;
+ } else {
+ setAt(row);
+ return true;
+ }
+}
+
+bool QMimerSQLResult::fetchNext()
+{
+ Q_D(QMimerSQLResult);
+ int32_t err = 0;
+ if (!isActive() || !isSelect())
+ return false;
+ if (isForwardOnly())
+ err = MimerFetch(d->statementhandle);
+ else
+ err = MimerFetchScroll(d->statementhandle, MIMER_NEXT, 0);
+ if (!MIMER_SUCCEEDED(err)) {
+ setLastError(qMakeError(
+ QCoreApplication::translate("QMimerSQLResult", "Could not fetch next row"), err,
+ QSqlError::StatementError, d->drv_d_func()));
+ if (isForwardOnly())
+ d->currentRow = QSql::BeforeFirstRow;
+ return false;
+ }
+ if (err == MIMER_NO_DATA)
+ return false;
+ if (isForwardOnly())
+ setAt(++d->currentRow);
+ else
+ setAt(MimerCurrentRow(d->statementhandle) - 1);
+ return true;
+}
+
+QVariant QMimerSQLResult::data(int i)
+{
+ Q_D(QMimerSQLResult);
+ int32_t err;
+ int32_t mType;
+ if (d->callWithOut) {
+ if (i >= MimerParameterCount(d->statementhandle)) {
+ setLastError(qMakeError(
+ QCoreApplication::translate("QMimerSQLResult:", "Column %1 out of range")
+ .arg(i),
+ genericError, QSqlError::StatementError, nullptr));
+ return QVariant();
+ }
+ mType = MimerParameterType(d->statementhandle, static_cast<std::int16_t>(i + 1));
+ } else {
+ if (i >= MimerColumnCount(d->statementhandle)) {
+ setLastError(qMakeError(
+ QCoreApplication::translate("QMimerSQLResult:", "Column %1 out of range")
+ .arg(i),
+ genericError, QSqlError::StatementError, nullptr));
+ return QVariant();
+ }
+ mType = MimerColumnType(d->statementhandle, static_cast<std::int16_t>(i + 1));
+ }
+ const QMetaType::Type type = qDecodeMSQLType(mType);
+ const MimerColumnTypes mimDataType = mimerMapColumnTypes(mType);
+ err = MimerIsNull(d->statementhandle, static_cast<std::int16_t>(i + 1));
+ if (err > 0) {
+ return QVariant(QMetaType(type), nullptr);
+ } else {
+ switch (mimDataType) {
+ case MimerColumnTypes::Date: {
+ wchar_t dateString_w[maxDateStringSize + 1];
+ err = MimerGetString(d->statementhandle, static_cast<std::int16_t>(i + 1), dateString_w,
+ sizeof(dateString_w) / sizeof(dateString_w[0]));
+ if (!MIMER_SUCCEEDED(err)) {
+ setLastError(qMakeError(msgCouldNotGet("date", i),
+ err, QSqlError::StatementError, d->drv_d_func()));
+ return QVariant(QMetaType(type), nullptr);
+ }
+ return QDate::fromString(QString::fromWCharArray(dateString_w), "yyyy-MM-dd"_L1);
+ }
+ case MimerColumnTypes::Time: {
+ wchar_t timeString_w[maxTimeStringSize + 1];
+ err = MimerGetString(d->statementhandle, static_cast<std::int16_t>(i + 1), timeString_w,
+ sizeof(timeString_w) / sizeof(timeString_w[0]));
+ if (!MIMER_SUCCEEDED(err)) {
+ setLastError(qMakeError(msgCouldNotGet("time", i),
+ err, QSqlError::StatementError, d->drv_d_func()));
+ return QVariant(QMetaType(type), nullptr);
+ }
+ QString timeString = QString::fromWCharArray(timeString_w);
+ QString timeFormatString = "HH:mm:ss"_L1;
+ if (timeString.size() > 8) {
+ timeFormatString.append(".zzz"_L1);
+ timeString = timeString.left(12);
+ }
+ return QTime::fromString(timeString, timeFormatString);
+ }
+ case MimerColumnTypes::Timestamp: {
+ wchar_t dateTimeString_w[maxTimestampStringSize + 1];
+ err = MimerGetString(d->statementhandle, static_cast<std::int16_t>(i + 1),
+ dateTimeString_w,
+ sizeof(dateTimeString_w) / sizeof(dateTimeString_w[0]));
+ if (!MIMER_SUCCEEDED(err)) {
+ setLastError(
+ qMakeError(msgCouldNotGet("date time", i),
+ err, QSqlError::StatementError, d->drv_d_func()));
+ return QVariant(QMetaType(type), nullptr);
+ }
+ QString dateTimeString = QString::fromWCharArray(dateTimeString_w);
+ QString dateTimeFormatString = "yyyy-MM-dd HH:mm:ss"_L1;
+ if (dateTimeString.size() > 19) {
+ dateTimeFormatString.append(".zzz"_L1);
+ dateTimeString = dateTimeString.left(23);
+ }
+ return QDateTime::fromString(dateTimeString, dateTimeFormatString);
+ }
+ case MimerColumnTypes::Int: {
+ int resInt;
+ err = MimerGetInt32(d->statementhandle, static_cast<std::int16_t>(i + 1), &resInt);
+ if (!MIMER_SUCCEEDED(err)) {
+ setLastError(qMakeError(msgCouldNotGet("int32", i),
+ err, QSqlError::StatementError, d->drv_d_func()));
+ return QVariant(QMetaType(type), nullptr);
+ }
+ return resInt;
+ }
+ case MimerColumnTypes::Long: {
+ int64_t resLongLong;
+ err = MimerGetInt64(d->statementhandle, static_cast<std::int16_t>(i + 1), &resLongLong);
+ if (!MIMER_SUCCEEDED(err)) {
+ setLastError(qMakeError(msgCouldNotGet("int64", i),
+ err, QSqlError::StatementError, d->drv_d_func()));
+ return QVariant(QMetaType(type), nullptr);
+ }
+ return (qlonglong)resLongLong;
+ }
+ case MimerColumnTypes::Boolean: {
+ err = MimerGetBoolean(d->statementhandle, static_cast<std::int16_t>(i + 1));
+ if (!MIMER_SUCCEEDED(err)) {
+ setLastError(
+ qMakeError(msgCouldNotGet("boolean", i),
+ err, QSqlError::StatementError, d->drv_d_func()));
+ return QVariant(QMetaType(type), nullptr);
+ }
+ return err == 1;
+ }
+ case MimerColumnTypes::Float: {
+ float resFloat;
+ err = MimerGetFloat(d->statementhandle, static_cast<std::int16_t>(i + 1), &resFloat);
+ if (!MIMER_SUCCEEDED(err)) {
+ setLastError(qMakeError(msgCouldNotGet("float", i),
+ err, QSqlError::StatementError, d->drv_d_func()));
+ return QVariant(QMetaType(type), nullptr);
+ }
+ return resFloat;
+ }
+ case MimerColumnTypes::Double: {
+ double resDouble;
+ err = MimerGetDouble(d->statementhandle, static_cast<std::int16_t>(i + 1), &resDouble);
+ if (!MIMER_SUCCEEDED(err)) {
+ setLastError(
+ qMakeError(msgCouldNotGet("double", i),
+ err, QSqlError::StatementError, d->drv_d_func()));
+ return QVariant(QMetaType(type), nullptr);
+ }
+ switch (numericalPrecisionPolicy()) {
+ case QSql::LowPrecisionInt32:
+ return static_cast<std::int32_t>(resDouble);
+ case QSql::LowPrecisionInt64:
+ return static_cast<qint64>(resDouble);
+ case QSql::LowPrecisionDouble:
+ return static_cast<qreal>(resDouble);
+ case QSql::HighPrecision:
+ return QString::number(resDouble, 'g', 17);
+ }
+ return QVariant(QMetaType(type), nullptr);
+ }
+ case MimerColumnTypes::Binary: {
+ QByteArray byteArray;
+ // Get size
+ err = MimerGetBinary(d->statementhandle, static_cast<std::int16_t>(i + 1), NULL, 0);
+ if (MIMER_SUCCEEDED(err)) {
+ byteArray.resize(err);
+ err = MimerGetBinary(d->statementhandle, static_cast<std::int16_t>(i + 1),
+ byteArray.data(), err);
+ }
+ if (!MIMER_SUCCEEDED(err)) {
+ setLastError(
+ qMakeError(msgCouldNotGet("binary", i),
+ err, QSqlError::StatementError, d->drv_d_func()));
+ return QVariant(QMetaType(type), nullptr);
+ }
+ return byteArray;
+ }
+ case MimerColumnTypes::Blob: {
+ QByteArray byteArray;
+ size_t size;
+ err = MimerGetLob(d->statementhandle, static_cast<std::int16_t>(i + 1), &size,
+ &d->lobhandle);
+ if (MIMER_SUCCEEDED(err)) {
+ constexpr size_t maxSize = lobChunkMaxSizeFetch;
+ QVarLengthArray<char> blobchar(lobChunkMaxSizeFetch);
+ byteArray.reserve(size);
+ size_t left_to_return = size;
+ while (left_to_return > 0) {
+ const size_t bytesToReceive =
+ left_to_return <= maxSize ? left_to_return : maxSize;
+ err = MimerGetBlobData(&d->lobhandle, blobchar.data(), bytesToReceive);
+ byteArray.append(QByteArray::fromRawData(blobchar.data(), bytesToReceive));
+ left_to_return -= bytesToReceive;
+ if (!MIMER_SUCCEEDED(err)) {
+ setLastError(qMakeError(msgCouldNotGet("BLOB", i),
+ err, QSqlError::StatementError, d->drv_d_func()));
+ return QVariant(QMetaType(type), nullptr);
+ }
+ }
+ } else {
+ setLastError(qMakeError(msgCouldNotGet("BLOB", i),
+ err, QSqlError::StatementError, d->drv_d_func()));
+ return QVariant(QMetaType(type), nullptr);
+ }
+ return byteArray;
+ }
+ case MimerColumnTypes::Numeric:
+ case MimerColumnTypes::String: {
+ wchar_t resString_w[maxStackStringSize + 1];
+ // Get size
+ err = MimerGetString(d->statementhandle, static_cast<std::int16_t>(i + 1), resString_w,
+ 0);
+ if (MIMER_SUCCEEDED(err)) {
+ int size = err;
+ if (err <= maxStackStringSize) { // For smaller strings, use a small buffer for
+ // efficiency
+ err = MimerGetString(d->statementhandle, static_cast<std::int16_t>(i + 1),
+ resString_w, maxStackStringSize + 1);
+ if (MIMER_SUCCEEDED(err))
+ return QString::fromWCharArray(resString_w);
+ } else { // For larger strings, dynamically allocate memory
+ QVarLengthArray<wchar_t> largeResString_w(size + 1);
+ err = MimerGetString(d->statementhandle, static_cast<std::int16_t>(i + 1),
+ largeResString_w.data(), size + 1);
+ if (MIMER_SUCCEEDED(err))
+ return QString::fromWCharArray(largeResString_w.data());
+ }
+ }
+ setLastError(qMakeError(msgCouldNotGet(
+ mimDataType == MimerColumnTypes::Numeric ? "numeric" : "string", i),
+ err, QSqlError::StatementError, d->drv_d_func()));
+ return QVariant(QMetaType(type), nullptr);
+ }
+ case MimerColumnTypes::Clob: {
+ size_t size;
+ err = MimerGetLob(d->statementhandle, static_cast<std::int16_t>(i + 1), &size,
+ &d->lobhandle);
+ if (MIMER_SUCCEEDED(err)) {
+ constexpr size_t maxSize = lobChunkMaxSizeFetch;
+ QVarLengthArray<wchar_t> clobstring_w(lobChunkMaxSizeFetch + 1);
+
+ size_t left_to_return = size;
+ QString returnString;
+ while (left_to_return > 0) {
+ const size_t bytesToReceive =
+ left_to_return <= maxSize ? left_to_return : maxSize;
+ err = MimerGetNclobData(&d->lobhandle, clobstring_w.data(), bytesToReceive + 1);
+ returnString.append(QString::fromWCharArray(clobstring_w.data()));
+ left_to_return -= bytesToReceive;
+ if (!MIMER_SUCCEEDED(err)) {
+ setLastError(qMakeError(msgCouldNotGet("CLOB", i),
+ err, QSqlError::StatementError, d->drv_d_func()));
+ return QVariant(QMetaType(type), nullptr);
+ }
+ }
+ return returnString;
+ }
+ setLastError(qMakeError(msgCouldNotGet("CLOB", i),
+ err, QSqlError::StatementError, d->drv_d_func()));
+ return QVariant(QMetaType(type), nullptr);
+ }
+ case MimerColumnTypes::Uuid: {
+ unsigned char uuidChar[16];
+ err = MimerGetUUID(d->statementhandle, static_cast<std::int16_t>(i + 1), uuidChar);
+ if (!MIMER_SUCCEEDED(err)) {
+ setLastError(qMakeError(msgCouldNotGet("UUID", i),
+ err, QSqlError::StatementError, d->drv_d_func()));
+ return QVariant(QMetaType(type), nullptr);
+ }
+ const QByteArray uuidByteArray = QByteArray(reinterpret_cast<char *>(uuidChar), 16);
+ return QUuid::fromRfc4122(uuidByteArray);
+ }
+ case MimerColumnTypes::Unknown:
+ default:
+ setLastError(qMakeError(
+ QCoreApplication::translate("QMimerSQLResult", "Unknown data type %1").arg(i),
+ genericError, QSqlError::StatementError, nullptr));
+ }
+ return QVariant(QMetaType(type), nullptr);
+ }
+}
+
+bool QMimerSQLResult::isNull(int index)
+{
+ Q_D(const QMimerSQLResult);
+ const int32_t rc = MimerIsNull(d->statementhandle, static_cast<std::int16_t>(index + 1));
+ if (!MIMER_SUCCEEDED(rc)) {
+ setLastError(qMakeError(
+ QCoreApplication::translate("QMimerSQLResult", "Could not check null, column %1")
+ .arg(index),
+ rc, QSqlError::StatementError, d->drv_d_func()));
+ return false;
+ }
+ return rc != 0;
+}
+
+bool QMimerSQLResult::reset(const QString &query)
+{
+ if (!prepare(query))
+ return false;
+ return exec();
+}
+
+int QMimerSQLResult::size()
+{
+ Q_D(QMimerSQLResult);
+ if (!isActive() || !isSelect() || isForwardOnly())
+ return -1;
+
+ if (d->currentSize != -1)
+ return d->currentSize;
+
+ const int currentRow = MimerCurrentRow(d->statementhandle);
+ MimerFetchScroll(d->statementhandle, static_cast<std::int32_t>(MIMER_LAST), 0);
+ int size = MimerCurrentRow(d->statementhandle);
+ if (!MIMER_SUCCEEDED(size))
+ size = -1;
+ MimerFetchScroll(d->statementhandle, MIMER_ABSOLUTE, currentRow);
+ d->currentSize = size;
+ return size;
+}
+
+int QMimerSQLResult::numRowsAffected()
+{
+ Q_D(const QMimerSQLResult);
+ return d->rowsAffected;
+}
+
+QSqlRecord QMimerSQLResult::record() const
+{
+ Q_D(const QMimerSQLResult);
+ QSqlRecord rec;
+ if (!isActive() || !isSelect() || !driver())
+ return rec;
+ QSqlField field;
+ const int colSize = MimerColumnCount(d->statementhandle);
+ for (int i = 0; i < colSize; i++) {
+ wchar_t colName_w[100];
+ MimerColumnName(d->statementhandle, static_cast<std::int16_t>(i + 1), colName_w,
+ sizeof(colName_w) / sizeof(colName_w[0]));
+ field.setName(QString::fromWCharArray(colName_w));
+ const int32_t mType = MimerColumnType(d->statementhandle, static_cast<std::int16_t>(i + 1));
+ const QMetaType::Type type = qDecodeMSQLType(mType);
+ field.setMetaType(QMetaType(type));
+ field.setValue(QVariant(field.metaType()));
+ // field.setPrecision(); Should be implemented once the Mimer API can give this
+ // information.
+ // field.setLength(); Should be implemented once the Mimer API can give
+ // this information.
+ rec.insert(i, field);
+ }
+ return rec;
+}
+
+bool QMimerSQLResult::prepare(const QString &query)
+{
+ Q_D(QMimerSQLResult);
+ int32_t err;
+ if (!driver())
+ return false;
+ if (!d->preparedQuery)
+ return QSqlResult::prepare(query);
+ if (query.isEmpty())
+ return false;
+ cleanup();
+ const int option = isForwardOnly() ? MIMER_FORWARD_ONLY : MIMER_SCROLLABLE;
+ err = MimerBeginStatement8(d->drv_d_func()->sessionhandle, query.toUtf8().constData(), option,
+ &d->statementhandle);
+ if (err == MIMER_STATEMENT_CANNOT_BE_PREPARED) {
+ err = MimerExecuteStatement8(d->drv_d_func()->sessionhandle, query.toUtf8().constData());
+ if (MIMER_SUCCEEDED(err)) {
+ d->executedStatement = true;
+ d->openCursor = false;
+ d->openStatement = false;
+ return true;
+ }
+ }
+ if (!MIMER_SUCCEEDED(err)) {
+ setLastError(qMakeError(QCoreApplication::translate("QMimerSQLResult",
+ "Could not prepare/execute statement"),
+ err, QSqlError::StatementError, d->drv_d_func()));
+ return false;
+ }
+ d->openStatement = true;
+ return true;
+}
+
+bool QMimerSQLResult::exec()
+{
+ Q_D(QMimerSQLResult);
+ int32_t err;
+ if (!driver())
+ return false;
+ if (!d->preparedQuery)
+ return QSqlResult::exec();
+ if (d->executedStatement) {
+ d->executedStatement = false;
+ return true;
+ }
+ if (d->openCursor) {
+ setAt(QSql::BeforeFirstRow);
+ err = MimerCloseCursor(d->statementhandle);
+ d->openCursor = false;
+ d->currentSize = -1;
+ }
+ QVector<QVariant> &values = boundValues();
+ if (d->execBatch)
+ values = d->batch_vector;
+ int mimParamCount = MimerParameterCount(d->statementhandle);
+ if (!MIMER_SUCCEEDED(mimParamCount))
+ mimParamCount = 0;
+ if (mimParamCount != values.size()) {
+ setLastError(qMakeError(
+ QCoreApplication::translate("QMimerSQLResult", "Wrong number of parameters"),
+ genericError, QSqlError::StatementError, nullptr));
+ return false;
+ }
+ for (int i = 0; i < mimParamCount; i++) {
+ if (bindValueType(i) == QSql::Out) {
+ d->callWithOut = true;
+ continue;
+ }
+ const QVariant &val = values.at(i);
+ if (QSqlResultPrivate::isVariantNull(val) || val.isNull() || val.toString().isNull()) {
+ err = MimerSetNull(d->statementhandle, i + 1);
+ if (!MIMER_SUCCEEDED(err)) {
+ setLastError(
+ qMakeError(msgCouldNotSet("null", i),
+ err, QSqlError::StatementError, d->drv_d_func()));
+ return false;
+ }
+ continue;
+ }
+
+ const int mimParamType = MimerParameterType(d->statementhandle, i + 1);
+ const MimerColumnTypes mimDataType = mimerMapColumnTypes(mimParamType);
+ switch (mimDataType) {
+ case MimerColumnTypes::Int: {
+ bool convertOk;
+ err = MimerSetInt32(d->statementhandle, i + 1, val.toInt(&convertOk));
+ if (!convertOk || !MIMER_SUCCEEDED(err)) {
+ setLastError(
+ qMakeError(msgCouldNotSet("int32", i),
+ convertOk ? err : genericError, QSqlError::StatementError,
+ convertOk ? d->drv_d_func() : nullptr));
+ return false;
+ }
+ break;
+ }
+ case MimerColumnTypes::Long: {
+ bool convertOk;
+ err = MimerSetInt64(d->statementhandle, i + 1, val.toLongLong(&convertOk));
+ if (!convertOk || !MIMER_SUCCEEDED(err)) {
+ setLastError(
+ qMakeError(msgCouldNotSet("int64", i),
+ convertOk ? err : genericError, QSqlError::StatementError,
+ convertOk ? d->drv_d_func() : nullptr));
+ return false;
+ }
+ break;
+ }
+ case MimerColumnTypes::Float: {
+ bool convertOk;
+ err = MimerSetFloat(d->statementhandle, i + 1, val.toFloat(&convertOk));
+ if (!convertOk || !MIMER_SUCCEEDED(err)) {
+ setLastError(
+ qMakeError(msgCouldNotSet("float", i),
+ convertOk ? err : genericError, QSqlError::StatementError,
+ convertOk ? d->drv_d_func() : nullptr));
+ return false;
+ }
+ break;
+ }
+ case MimerColumnTypes::Double: {
+ bool convertOk;
+ err = MimerSetDouble(d->statementhandle, i + 1, val.toDouble(&convertOk));
+ if (!convertOk || !MIMER_SUCCEEDED(err)) {
+ setLastError(
+ qMakeError(msgCouldNotSet("double", i),
+ convertOk ? err : genericError, QSqlError::StatementError,
+ convertOk ? d->drv_d_func() : nullptr));
+ return false;
+ }
+ break;
+ }
+ case MimerColumnTypes::Binary: {
+ const QByteArray binArr = val.toByteArray();
+ size_t size = static_cast<std::size_t>(binArr.size());
+ err = MimerSetBinary(d->statementhandle, i + 1, binArr.data(), size);
+ if (!MIMER_SUCCEEDED(err)) {
+ setLastError(
+ qMakeError(msgCouldNotSet("binary", i),
+ err, QSqlError::StatementError, d->drv_d_func()));
+ return false;
+ }
+ break;
+ }
+ case MimerColumnTypes::Boolean: {
+ err = MimerSetBoolean(d->statementhandle, i + 1, val.toBool() == true ? 1 : 0);
+ if (!MIMER_SUCCEEDED(err)) {
+ setLastError(
+ qMakeError(msgCouldNotSet("boolean", i),
+ err, QSqlError::StatementError, d->drv_d_func()));
+ return false;
+ }
+ break;
+ }
+ case MimerColumnTypes::Uuid: {
+ const QByteArray uuidArray =
+ QByteArray::fromHex(val.toUuid().toString(QUuid::WithoutBraces).toLatin1());
+ const unsigned char *uuid =
+ reinterpret_cast<const unsigned char *>(uuidArray.constData());
+ err = MimerSetUUID(d->statementhandle, i + 1, uuid);
+ if (!MIMER_SUCCEEDED(err)) {
+ setLastError(
+ qMakeError(msgCouldNotSet("UUID", i),
+ err, QSqlError::StatementError, d->drv_d_func()));
+ return false;
+ }
+ break;
+ }
+ case MimerColumnTypes::Numeric:
+ case MimerColumnTypes::String: {
+ QByteArray string_b = val.toString().trimmed().toUtf8();
+ const char *string_u = string_b.constData();
+ err = MimerSetString8(d->statementhandle, i + 1, string_u);
+ if (!MIMER_SUCCEEDED(err)) {
+ setLastError(
+ qMakeError(msgCouldNotSet(
+ mimDataType == MimerColumnTypes::Numeric ? "numeric" : "string", i),
+ err, QSqlError::StatementError, d->drv_d_func()));
+ return false;
+ }
+ break;
+ }
+ case MimerColumnTypes::Date: {
+ err = MimerSetString8(d->statementhandle, i + 1, val.toString().toUtf8().constData());
+ if (!MIMER_SUCCEEDED(err)) {
+ setLastError(
+ qMakeError(msgCouldNotSet("date", i),
+ err, QSqlError::StatementError, d->drv_d_func()));
+ return false;
+ }
+ break;
+ }
+ case MimerColumnTypes::Time: {
+ QString timeFormatString = "hh:mm:ss"_L1;
+ const QTime timeVal = val.toTime();
+ if (timeVal.msec() > 0)
+ timeFormatString.append(".zzz"_L1);
+ err = MimerSetString8(d->statementhandle, i + 1,
+ timeVal.toString(timeFormatString).toUtf8().constData());
+ if (!MIMER_SUCCEEDED(err)) {
+ setLastError(
+ qMakeError(msgCouldNotSet("time", i),
+ err, QSqlError::StatementError, d->drv_d_func()));
+ return false;
+ }
+ break;
+ }
+ case MimerColumnTypes::Timestamp: {
+ QString dateTimeFormatString = "yyyy-MM-dd hh:mm:ss"_L1;
+ const QDateTime dateTimeVal = val.toDateTime();
+ if (dateTimeVal.time().msec() > 0)
+ dateTimeFormatString.append(".zzz"_L1);
+ err = MimerSetString8(
+ d->statementhandle, i + 1,
+ val.toDateTime().toString(dateTimeFormatString).toUtf8().constData());
+ if (!MIMER_SUCCEEDED(err)) {
+ setLastError(qMakeError(msgCouldNotSet("datetime", i),
+ err, QSqlError::StatementError, d->drv_d_func()));
+ return false;
+ }
+ break;
+ }
+ case MimerColumnTypes::Blob: {
+ QByteArray blobArr = val.toByteArray();
+ const char *blobData = blobArr.constData();
+ qsizetype size = blobArr.size();
+ err = MimerSetLob(d->statementhandle, i + 1, size, &d->lobhandle);
+ if (MIMER_SUCCEEDED(err)) {
+ qsizetype maxSize = lobChunkMaxSizeSet;
+ if (size > maxSize) {
+ qsizetype left_to_send = size;
+ for (qsizetype k = 0; left_to_send > 0; k++) {
+ if (left_to_send <= maxSize) {
+ err = MimerSetBlobData(&d->lobhandle, &blobData[k * maxSize],
+ left_to_send);
+ left_to_send = 0;
+ } else {
+ err = MimerSetBlobData(&d->lobhandle, &blobData[k * maxSize], maxSize);
+ left_to_send = left_to_send - maxSize;
+ }
+ }
+ if (!MIMER_SUCCEEDED(err)) {
+ setLastError(
+ qMakeError(msgCouldNotSet("BLOB byte array", i),
+ err, QSqlError::StatementError, d->drv_d_func()));
+ return false;
+ }
+ } else {
+ err = MimerSetBlobData(&d->lobhandle, blobArr, size);
+ }
+ }
+ if (!MIMER_SUCCEEDED(err)) {
+ setLastError(qMakeError(msgCouldNotSet("BLOB byte array", i),
+ err, QSqlError::StatementError, d->drv_d_func()));
+ return false;
+ }
+ break;
+ }
+ case MimerColumnTypes::Clob: {
+ QByteArray string_b = val.toString().trimmed().toUtf8();
+ const char *string_u = string_b.constData();
+ size_t size_c = 1;
+ size_t size = 0;
+ while (string_u[size++])
+ if ((string_u[size] & 0xc0) != 0x80)
+ size_c++;
+ err = MimerSetLob(d->statementhandle, i + 1, size_c, &d->lobhandle);
+ if (MIMER_SUCCEEDED(err)) {
+ constexpr size_t maxSize = lobChunkMaxSizeSet;
+ if (size > maxSize) {
+ size_t left_to_send = size;
+ size_t pos = 0;
+ uint step_back = 0;
+ while (left_to_send > 0 && step_back < maxSize) {
+ step_back = 0;
+ if (left_to_send <= maxSize) {
+ err = MimerSetNclobData8(&d->lobhandle, &string_u[pos], left_to_send);
+ left_to_send = 0;
+ } else {
+ // Check that we don't split a multi-byte utf-8 characters
+ while (pos + maxSize - step_back > 0
+ && (string_u[pos + maxSize - step_back] & 0xc0) == 0x80)
+ step_back++;
+ err = MimerSetNclobData8(&d->lobhandle, &string_u[pos],
+ maxSize - step_back);
+ left_to_send = left_to_send - maxSize + step_back;
+ pos += maxSize - step_back;
+ }
+ if (!MIMER_SUCCEEDED(err)) {
+ setLastError(qMakeError(msgCouldNotSet("CLOB", i),
+ err, QSqlError::StatementError, d->drv_d_func()));
+ return false;
+ }
+ }
+ } else {
+ err = MimerSetNclobData8(&d->lobhandle, string_u, size);
+ }
+ }
+ if (!MIMER_SUCCEEDED(err)) {
+ setLastError(
+ qMakeError(msgCouldNotSet("CLOB", i),
+ err, QSqlError::StatementError, d->drv_d_func()));
+ return false;
+ }
+ break;
+ }
+ case MimerColumnTypes::Unknown:
+ default:
+ setLastError(qMakeError(
+ QCoreApplication::translate("QMimerSQLResult", "Unknown datatype, parameter %1")
+ .arg(i),
+ genericError, QSqlError::StatementError, nullptr));
+ return false;
+ }
+ }
+ if (d->execBatch)
+ return true;
+ err = MimerExecute(d->statementhandle);
+ if (MIMER_SUCCEEDED(err)) {
+ d->rowsAffected = err;
+ int k = 0;
+ for (qsizetype i = 0; i < values.size(); i++) {
+ if (bindValueType(i) == QSql::Out || bindValueType(i) == QSql::InOut) {
+ bindValue(i, data(k), QSql::In);
+ k++;
+ }
+ }
+ d->callWithOut = false;
+ }
+ setSelect(false);
+ if (MIMER_SEQUENCE_ERROR == err) {
+ err = MimerOpenCursor(d->statementhandle);
+ d->rowsAffected = err;
+ d->openCursor = true;
+ d->currentRow = QSql::BeforeFirstRow;
+ setSelect(true);
+ }
+ if (!MIMER_SUCCEEDED(err)) {
+ setLastError(
+ qMakeError(QCoreApplication::translate("QMimerSQLResult",
+ "Could not execute statement/open cursor"),
+ err, QSqlError::StatementError, d->drv_d_func()));
+ return false;
+ }
+ setActive(true);
+ return true;
+}
+
+bool QMimerSQLResult::execBatch(bool arrayBind)
+{
+ Q_D(QMimerSQLResult);
+ Q_UNUSED(arrayBind);
+ int32_t err;
+ const QVector<QVariant> values = boundValues();
+
+ // Check that we only have input parameters. Currently
+ // we can only handle batch operations without output parameters.
+ for (qsizetype i = 0; i < values.first().toList().size(); i++)
+ if (bindValueType(i) == QSql::Out || bindValueType(i) == QSql::InOut) {
+ setLastError(qMakeError(QCoreApplication::translate(
+ "QMimerSQLResult",
+ "Only input parameters can be used in batch operations"),
+ genericError, QSqlError::StatementError, nullptr));
+ d->execBatch = false;
+ return false;
+ }
+ d->execBatch = true;
+ for (qsizetype i = 0; i < values.first().toList().size(); i++) {
+ for (qsizetype j = 0; j < values.size(); j++)
+ d->batch_vector.append(values.at(j).toList().at(i));
+ exec();
+ if (i != (values.at(0).toList().size() - 1)) {
+ err = MimerAddBatch(d->statementhandle);
+ if (!MIMER_SUCCEEDED(err)) {
+ setLastError(qMakeError(
+ //: %1 is the batch number
+ QCoreApplication::translate("QMimerSQLResult", "Could not add batch %1")
+ .arg(i),
+ err, QSqlError::StatementError, d->drv_d_func()));
+ d->execBatch = false;
+ return false;
+ }
+ }
+ d->batch_vector.clear();
+ }
+ d->execBatch = false;
+ err = MimerExecute(d->statementhandle);
+ if (!MIMER_SUCCEEDED(err)) {
+ setLastError(qMakeError(
+ QCoreApplication::translate("QMimerSQLResult", "Could not execute batch"), err,
+ QSqlError::StatementError, d->drv_d_func()));
+ return false;
+ }
+ return true;
+}
+
+QVariant QMimerSQLResult::lastInsertId() const
+{
+ Q_D(const QMimerSQLResult);
+ int64_t lastSequence;
+ const int32_t err = MimerGetSequenceInt64(d->statementhandle, &lastSequence);
+ if (!MIMER_SUCCEEDED(err))
+ return QVariant(QMetaType(QMetaType::LongLong), nullptr);
+ return QVariant(qint64(lastSequence));
+}
+
+bool QMimerSQLDriver::hasFeature(DriverFeature f) const
+{
+ switch (f) {
+ case NamedPlaceholders: // Is true in reality but Qt parses Sql statement...
+ case EventNotifications:
+ case LowPrecisionNumbers:
+ case MultipleResultSets:
+ case SimpleLocking:
+ case CancelQuery:
+ return false;
+ case FinishQuery:
+ case LastInsertId:
+ case Transactions:
+ case QuerySize:
+ case BLOB:
+ case Unicode:
+ case PreparedQueries:
+ case PositionalPlaceholders:
+ case BatchOperations:
+ return true;
+ }
+ return true;
+}
+
+bool QMimerSQLDriver::open(const QString &db, const QString &user, const QString &password,
+ const QString &host, int port, const QString &connOpts)
+{
+ Q_D(QMimerSQLDriver);
+ Q_UNUSED(host);
+ Q_UNUSED(port);
+ Q_UNUSED(connOpts);
+ if (isOpen())
+ close();
+ const int32_t err = MimerBeginSession8(db.toUtf8().constData(), user.toUtf8().constData(),
+ password.toUtf8().constData(), &d->sessionhandle);
+ if (!MIMER_SUCCEEDED(err)) {
+ setLastError(qMakeError(
+ QCoreApplication::translate("QMimerSQLDriver", "Could not connect to database")
+ + " "_L1 + db,
+ err, QSqlError::ConnectionError, nullptr));
+ setOpenError(true);
+ return false;
+ }
+ d->dbUser = user;
+ d->dbName = db;
+ setOpen(true);
+ setOpenError(false);
+ return true;
+}
+
+void QMimerSQLDriver::close()
+{
+ Q_D(QMimerSQLDriver);
+ if (isOpen()) {
+ const int end_err = MimerEndSession(&d->sessionhandle);
+ if (MIMER_SUCCEEDED(end_err)) {
+ setOpen(false);
+ setOpenError(false);
+ }
+ }
+}
+
+QSqlResult *QMimerSQLDriver::createResult() const
+{
+ return new QMimerSQLResult(this);
+}
+
+QStringList QMimerSQLDriver::tables(QSql::TableType type) const
+{
+ QStringList tl;
+ if (!isOpen())
+ return tl;
+ QSqlQuery t(createResult());
+ QString sql;
+ switch (type) {
+ case QSql::Tables: {
+ sql = "select table_name from information_schema.tables where "
+ "table_type=\'BASE TABLE\' AND table_schema = CURRENT_USER"_L1;
+ break;
+ }
+ case QSql::SystemTables: {
+ sql = "select table_name from information_schema.tables where "
+ "table_type=\'BASE TABLE\' AND table_schema = \'SYSTEM\'"_L1;
+ break;
+ }
+ case QSql::Views: {
+ sql = "select table_name from information_schema.tables where "
+ "table_type=\'VIEW\' AND table_schema = CURRENT_USER"_L1;
+ break;
+ }
+ case QSql::AllTables: {
+ sql = "select table_name from information_schema.tables where "
+ "(table_type=\'VIEW\' or table_type=\'BASE TABLE\')"
+ " AND (table_schema = CURRENT_USER OR table_schema =\'SYSTEM\')"_L1;
+ break;
+ }
+ default:
+ break;
+ }
+ if (sql.length() > 0) {
+ t.exec(sql);
+ while (t.next())
+ tl.append(t.value(0).toString());
+ }
+ return tl;
+}
+
+QSqlIndex QMimerSQLDriver::primaryIndex(const QString &tablename) const
+{
+ Q_D(const QMimerSQLDriver);
+ if (!isOpen())
+ return QSqlIndex();
+ QString table = tablename;
+ if (isIdentifierEscaped(table, QSqlDriver::TableName))
+ table = stripDelimiters(table, QSqlDriver::TableName);
+ QSqlIndex index(tablename);
+ QSqlQuery t(createResult());
+ QString schema;
+ QString qualifiedName = table;
+ d->splitTableQualifier(qualifiedName, &schema, &table);
+ QString sql =
+ "select information_schema.ext_access_paths.column_name,"
+ "case when data_type = 'INTERVAL' then 'INTERVAL '|| interval_type "
+ "when data_type = 'INTEGER' and numeric_precision > 10 then 'BIGINT' "
+ "when data_type = 'INTEGER' and numeric_precision <= 10 AND NUMERIC_PRECISION > 5 "
+ "then 'INTEGER' when data_type = 'INTEGER' and numeric_precision <= 5 then 'SMALLINT' "
+ "else upper(data_type) end as data_type "
+ "from information_schema.ext_access_paths full outer join "
+ "information_schema.columns on information_schema.ext_access_paths.column_name = "
+ "information_schema.columns.column_name and "
+ "information_schema.ext_access_paths.table_name = "
+ "information_schema.columns.table_name where "
+ "information_schema.ext_access_paths.table_name = \'"_L1;
+ sql.append(table)
+ .append("\' and index_type = \'PRIMARY KEY\'"_L1);
+ if (schema.length() == 0)
+ sql.append(" and table_schema = CURRENT_USER"_L1);
+ else
+ sql.append(" and table_schema = \'"_L1).append(schema).append("\'"_L1);
+
+ if (!t.exec(sql))
+ return QSqlIndex();
+ int i = 0;
+ while (t.next()) {
+ QSqlField field(t.value(0).toString(),
+ QMetaType(qDecodeMSQLType(qLookupMimDataType(t.value(1).toString()))),
+ tablename);
+ index.insert(i, field);
+ index.setName(t.value(0).toString());
+ i++;
+ }
+ return index;
+}
+
+QSqlRecord QMimerSQLDriver::record(const QString &tablename) const
+{
+ Q_D(const QMimerSQLDriver);
+ if (!isOpen())
+ return QSqlRecord();
+ QSqlRecord rec;
+ QSqlQuery t(createResult());
+ QString qualifiedName = tablename;
+ if (isIdentifierEscaped(qualifiedName, QSqlDriver::TableName))
+ qualifiedName = stripDelimiters(qualifiedName, QSqlDriver::TableName);
+ QString schema, table;
+ d->splitTableQualifier(qualifiedName, &schema, &table);
+
+ QString sql =
+ "select column_name, case when data_type = 'INTERVAL' then 'INTERVAL '|| interval_type "
+ "when data_type = 'INTEGER' and numeric_precision > 10 then 'BIGINT' "
+ "when data_type = 'INTEGER' and numeric_precision <= 10 AND numeric_precision > 5 "
+ "then 'INTEGER' when data_type = 'INTEGER' and numeric_precision <= 5 then 'SMALLINT' "
+ "else UPPER(data_type) end as data_type, case when is_nullable = 'YES' then false else "
+ "true end as required, "
+ "coalesce(numeric_precision, coalesce(datetime_precision,coalesce(interval_precision, "
+ "-1))) as prec from information_schema.columns where table_name = \'"_L1;
+ if (schema.length() == 0)
+ sql.append(table).append("\' and table_schema = CURRENT_USER"_L1);
+ else
+ sql.append(table).append("\' and table_schema = \'"_L1).append(schema).append("\'"_L1);
+ sql.append(" order by ordinal_position"_L1);
+ if (!t.exec(sql))
+ return QSqlRecord();
+
+ while (t.next()) {
+ QSqlField field(t.value(0).toString(),
+ QMetaType(qDecodeMSQLType(qLookupMimDataType(t.value(1).toString()))),
+ tablename);
+ field.setRequired(t.value(3).toBool());
+ if (t.value(3).toInt() != -1)
+ field.setPrecision(t.value(3).toInt());
+ rec.append(field);
+ }
+
+ return rec;
+}
+
+QVariant QMimerSQLDriver::handle() const
+{
+ Q_D(const QMimerSQLDriver);
+ return QVariant::fromValue(d->sessionhandle);
+}
+
+QString QMimerSQLDriver::escapeIdentifier(const QString &identifier, IdentifierType type) const
+{
+ Q_UNUSED(type);
+ QString res = identifier;
+ if (!identifier.isEmpty() && !identifier.startsWith(u'"') && !identifier.endsWith(u'"')) {
+ res.replace(u'"', "\"\""_L1);
+ res = u'"' + res + u'"';
+ res.replace(u'.', "\".\""_L1);
+ }
+ return res;
+}
+
+bool QMimerSQLDriver::beginTransaction()
+{
+ Q_D(const QMimerSQLDriver);
+ const int32_t err = MimerBeginTransaction(d->sessionhandle, MIMER_TRANS_READWRITE);
+ if (!MIMER_SUCCEEDED(err)) {
+ setLastError(qMakeError(
+ QCoreApplication::translate("QMimerSQLDriver", "Could not start transaction"), err,
+ QSqlError::TransactionError, d));
+ return false;
+ }
+ return true;
+}
+
+bool QMimerSQLDriver::commitTransaction()
+{
+ Q_D(const QMimerSQLDriver);
+ const int32_t err = MimerEndTransaction(d->sessionhandle, MIMER_COMMIT);
+ if (!MIMER_SUCCEEDED(err)) {
+ setLastError(qMakeError(
+ QCoreApplication::translate("QMimerSQLDriver", "Could not commit transaction"), err,
+ QSqlError::TransactionError, d));
+ return false;
+ }
+ return true;
+}
+
+bool QMimerSQLDriver::rollbackTransaction()
+{
+ Q_D(const QMimerSQLDriver);
+ const int32_t err = MimerEndTransaction(d->sessionhandle, MIMER_ROLLBACK);
+ if (!MIMER_SUCCEEDED(err)) {
+ setLastError(qMakeError(
+ QCoreApplication::translate("QMimerSQLDriver", "Could not roll back transaction"),
+ err, QSqlError::TransactionError, d));
+ return false;
+ }
+ return true;
+}
+
+void QMimerSQLDriverPrivate::splitTableQualifier(const QString &qualifiedName, QString *schema,
+ QString *table) const
+{
+ const QList<QStringView> l = QStringView(qualifiedName).split(u'.');
+ int n = l.count();
+ if (n > 2) {
+ return; // can't possibly be a valid table qualifier
+ } else if (n == 1) {
+ *schema = QString();
+ *table = l.at(0).toString();
+ } else {
+ *schema = l.at(0).toString();
+ *table = l.at(1).toString();
+ }
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qsql_mimer.cpp"
diff --git a/src/plugins/sqldrivers/mimer/qsql_mimer.h b/src/plugins/sqldrivers/mimer/qsql_mimer.h
new file mode 100644
index 0000000000..03ad8f21f2
--- /dev/null
+++ b/src/plugins/sqldrivers/mimer/qsql_mimer.h
@@ -0,0 +1,50 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// Copyright (C) 2022 Mimer Information Technology
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+#ifndef QSQL_MIMER_H
+#define QSQL_MIMER_H
+
+#include <QtSql/qsqldriver.h>
+#include <QUuid>
+#include <mimerapi.h>
+
+#ifdef QT_PLUGIN
+# define Q_EXPORT_SQLDRIVER_MIMER
+#else
+# define Q_EXPORT_SQLDRIVER_MIMER Q_SQL_EXPORT
+#endif
+
+QT_BEGIN_NAMESPACE
+
+class QMimerSQLDriverPrivate;
+
+class Q_EXPORT_SQLDRIVER_MIMER QMimerSQLDriver : public QSqlDriver
+{
+ friend class QMimerSQLResultPrivate;
+ Q_DECLARE_PRIVATE(QMimerSQLDriver)
+ Q_OBJECT
+public:
+ explicit QMimerSQLDriver(QObject *parent = nullptr);
+ explicit QMimerSQLDriver(MimerSession *conn, QObject *parent = nullptr);
+ ~QMimerSQLDriver() override;
+ bool hasFeature(DriverFeature f) const override;
+ bool open(const QString &db, const QString &user, const QString &password, const QString &host,
+ int port, const QString &connOpts) override;
+ void close() override;
+ QSqlResult *createResult() const override;
+ QStringList tables(QSql::TableType type) const override;
+ QSqlIndex primaryIndex(const QString &tablename) const override;
+ QSqlRecord record(const QString &tablename) const override;
+ QVariant handle() const override;
+ QString escapeIdentifier(const QString &identifier, IdentifierType type) const override;
+protected:
+ bool beginTransaction() override;
+ bool commitTransaction() override;
+ bool rollbackTransaction() override;
+
+private:
+};
+
+QT_END_NAMESPACE
+
+#endif // QSQL_MIMER
diff --git a/src/plugins/sqldrivers/mysql/CMakeLists.txt b/src/plugins/sqldrivers/mysql/CMakeLists.txt
index c99f322dfb..2e3d028584 100644
--- a/src/plugins/sqldrivers/mysql/CMakeLists.txt
+++ b/src/plugins/sqldrivers/mysql/CMakeLists.txt
@@ -1,24 +1,25 @@
-# Generated from mysql.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## QMYSQLDriverPlugin Plugin:
#####################################################################
-qt_add_plugin(QMYSQLDriverPlugin
+qt_internal_add_plugin(QMYSQLDriverPlugin
OUTPUT_NAME qsqlmysql
- TYPE sqldrivers
+ PLUGIN_TYPE sqldrivers
SOURCES
main.cpp
qsql_mysql.cpp qsql_mysql_p.h
DEFINES
QT_NO_CAST_FROM_ASCII
QT_NO_CAST_TO_ASCII
- PUBLIC_LIBRARIES
+ QT_NO_CONTEXTLESS_CONNECT
+ LIBRARIES
MySQL::MySQL
Qt::Core
Qt::CorePrivate
Qt::SqlPrivate
)
-#### Keys ignored in scope 1:.:.:mysql.pro:<TRUE>:
-# OTHER_FILES = "mysql.json"
+qt_internal_force_macos_intel_arch(QMYSQLDriverPlugin)
diff --git a/src/plugins/sqldrivers/mysql/main.cpp b/src/plugins/sqldrivers/mysql/main.cpp
index f7d56dd1c9..2c10c4d348 100644
--- a/src/plugins/sqldrivers/mysql/main.cpp
+++ b/src/plugins/sqldrivers/mysql/main.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <qsqldriverplugin.h>
#include <qstringlist.h>
@@ -43,6 +7,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
class QMYSQLDriverPlugin : public QSqlDriverPlugin
{
Q_OBJECT
@@ -61,8 +27,7 @@ QMYSQLDriverPlugin::QMYSQLDriverPlugin()
QSqlDriver* QMYSQLDriverPlugin::create(const QString &name)
{
- if (name == QLatin1String("QMYSQL") ||
- name == QLatin1String("QMARIADB")) {
+ if (name == "QMYSQL"_L1 || name == "QMARIADB"_L1) {
QMYSQLDriver* driver = new QMYSQLDriver();
return driver;
}
diff --git a/src/plugins/sqldrivers/mysql/mysql.pro b/src/plugins/sqldrivers/mysql/mysql.pro
deleted file mode 100644
index 56dd5f598c..0000000000
--- a/src/plugins/sqldrivers/mysql/mysql.pro
+++ /dev/null
@@ -1,11 +0,0 @@
-TARGET = qsqlmysql
-
-HEADERS += $$PWD/qsql_mysql_p.h
-SOURCES += $$PWD/qsql_mysql.cpp $$PWD/main.cpp
-
-QMAKE_USE += mysql
-
-OTHER_FILES += mysql.json
-
-PLUGIN_CLASS_NAME = QMYSQLDriverPlugin
-include(../qsqldriverbase.pri)
diff --git a/src/plugins/sqldrivers/mysql/qsql_mysql.cpp b/src/plugins/sqldrivers/mysql/qsql_mysql.cpp
index 2930df7261..cfd4931b46 100644
--- a/src/plugins/sqldrivers/mysql/qsql_mysql.cpp
+++ b/src/plugins/sqldrivers/mysql/qsql_mysql.cpp
@@ -1,59 +1,23 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtSql module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and 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$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qsql_mysql_p.h"
#include <qcoreapplication.h>
#include <qvariant.h>
+#include <qvarlengtharray.h>
#include <qdatetime.h>
+#include <qdebug.h>
+#include <qfile.h>
+#include <qlist.h>
+#include <qloggingcategory.h>
#include <qsqlerror.h>
#include <qsqlfield.h>
#include <qsqlindex.h>
#include <qsqlquery.h>
#include <qsqlrecord.h>
#include <qstringlist.h>
-#if QT_CONFIG(textcodec)
-#include <qtextcodec.h>
-#endif
-#include <qvector.h>
-#include <qfile.h>
-#include <qdebug.h>
+#include <qtimezone.h>
#include <QtSql/private/qsqldriver_p.h>
#include <QtSql/private/qsqlresult_p.h>
@@ -67,60 +31,44 @@ Q_DECLARE_METATYPE(MYSQL_RES*)
Q_DECLARE_METATYPE(MYSQL*)
Q_DECLARE_METATYPE(MYSQL_STMT*)
+// MYSQL_TYPE_JSON was introduced with MySQL 5.7.9
+#if defined(MYSQL_VERSION_ID) && MYSQL_VERSION_ID < 50709
+#define MYSQL_TYPE_JSON 245
+#endif
+
// MySQL above version 8 removed my_bool typedef while MariaDB kept it,
// by redefining it we can regain source compatibility.
using my_bool = decltype(mysql_stmt_bind_result(nullptr, nullptr));
+// this is a copy of the old MYSQL_TIME before an additional integer was added in
+// 8.0.27.0. This kills the sanity check during retrieving this struct from mysql
+// when another libmysql version is used during runtime than during compile time
+struct QT_MYSQL_TIME
+{
+ unsigned int year, month, day, hour, minute, second;
+ unsigned long second_part; /**< microseconds */
+ my_bool neg;
+ enum enum_mysql_timestamp_type time_type;
+};
+
QT_BEGIN_NAMESPACE
+static Q_LOGGING_CATEGORY(lcMysql, "qt.sql.mysql")
+
+using namespace Qt::StringLiterals;
+
class QMYSQLDriverPrivate : public QSqlDriverPrivate
{
Q_DECLARE_PUBLIC(QMYSQLDriver)
public:
- QMYSQLDriverPrivate() : QSqlDriverPrivate(), mysql(0),
-#if QT_CONFIG(textcodec)
- tc(QTextCodec::codecForLocale()),
-#else
- tc(0),
-#endif
- preparedQuerysEnabled(false) { dbmsType = QSqlDriver::MySqlServer; }
- MYSQL *mysql;
- QTextCodec *tc;
-
- bool preparedQuerysEnabled;
+ QMYSQLDriverPrivate() : QSqlDriverPrivate(QSqlDriver::MySqlServer)
+ {}
+ MYSQL *mysql = nullptr;
+ QString dbName;
+ bool preparedQuerysEnabled = false;
};
-static inline QString toUnicode(QTextCodec *tc, const char *str)
-{
-#if !QT_CONFIG(textcodec)
- Q_UNUSED(tc);
- return QString::fromLatin1(str);
-#else
- return tc->toUnicode(str);
-#endif
-}
-
-static inline QString toUnicode(QTextCodec *tc, const char *str, int length)
-{
-#if !QT_CONFIG(textcodec)
- Q_UNUSED(tc);
- return QString::fromLatin1(str, length);
-#else
- return tc->toUnicode(str, length);
-#endif
-}
-
-static inline QByteArray fromUnicode(QTextCodec *tc, const QString &str)
-{
-#if !QT_CONFIG(textcodec)
- Q_UNUSED(tc);
- return str.toLatin1();
-#else
- return tc->fromUnicode(str);
-#endif
-}
-
static inline QVariant qDateFromString(const QString &val)
{
#if !QT_CONFIG(datestring)
@@ -153,14 +101,45 @@ static inline QVariant qDateTimeFromString(QString &val)
#else
if (val.isEmpty())
return QVariant(QDateTime());
- if (val.length() == 14)
- // TIMESTAMPS have the format yyyyMMddhhmmss
- val.insert(4, QLatin1Char('-')).insert(7, QLatin1Char('-')).insert(10,
- QLatin1Char('T')).insert(13, QLatin1Char(':')).insert(16, QLatin1Char(':'));
+
+ // TIMESTAMPS have either the format "yyyyMMddhhmmss" or "yyyy-MM-dd
+ // hh:mm:ss". QDateTime::fromString() can convert the latter, but not the
+ // former, so adapt it if necessary.
+ if (val.size() == 14)
+ val.insert(4, u'-').insert(7, u'-').insert(10, u'T').insert(13, u':').insert(16, u':');
+
+ if (!val.endsWith(u'Z'))
+ val.append(u'Z'); // make UTC
return QVariant(QDateTime::fromString(val, Qt::ISODate));
#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;
+}
+
+// used with prepared queries and bound arguments
+static inline void setUtcTimeZone(MYSQL *mysql)
+{
+ std::unique_ptr<MYSQL_STMT, decltype(&mysql_stmt_close)> stmt(mysql_stmt_init(mysql), &mysql_stmt_close);
+ if (!stmt)
+ return;
+
+ static const char query[] = "SET time_zone = '+00:00'";
+ if (mysql_stmt_prepare(stmt.get(), query, sizeof(query) - 1))
+ mysql_stmt_execute(stmt.get());
+}
+
class QMYSQLResultPrivate;
class QMYSQLResult : public QSqlResult
@@ -201,153 +180,141 @@ class QMYSQLResultPrivate: public QSqlResultPrivate
public:
Q_DECLARE_SQLDRIVER_PRIVATE(QMYSQLDriver)
- QMYSQLResultPrivate(QMYSQLResult *q, const QMYSQLDriver *drv)
- : QSqlResultPrivate(q, drv),
- result(0),
- rowsAffected(0),
- hasBlobs(false)
- , stmt(0), meta(0), inBinds(0), outBinds(0)
- , preparedQuery(false)
- { }
-
- MYSQL_RES *result;
- MYSQL_ROW row;
-
- int rowsAffected;
+ using QSqlResultPrivate::QSqlResultPrivate;
bool bindInValues();
void bindBlobs();
- bool hasBlobs;
+ MYSQL_RES *result = nullptr;
+ MYSQL_ROW row;
+
struct QMyField
{
- QMyField()
- : outField(0), nullIndicator(false), bufLength(0ul),
- myField(0), type(QMetaType::UnknownType)
- {}
- char *outField;
- my_bool nullIndicator;
- ulong bufLength;
- MYSQL_FIELD *myField;
- QMetaType::Type type;
+ char *outField = nullptr;
+ const MYSQL_FIELD *myField = nullptr;
+ QMetaType type = QMetaType();
+ my_bool nullIndicator = false;
+ ulong bufLength = 0ul;
};
- QVector<QMyField> fields;
+ QList<QMyField> fields;
- MYSQL_STMT* stmt;
- MYSQL_RES* meta;
+ MYSQL_STMT *stmt = nullptr;
+ MYSQL_RES *meta = nullptr;
- MYSQL_BIND *inBinds;
- MYSQL_BIND *outBinds;
+ MYSQL_BIND *inBinds = nullptr;
+ MYSQL_BIND *outBinds = nullptr;
- bool preparedQuery;
+ int rowsAffected = 0;
+ bool hasBlobs = false;
+ bool preparedQuery = false;
};
-#if QT_CONFIG(textcodec)
-static QTextCodec* codec(MYSQL* mysql)
-{
- QTextCodec* heuristicCodec = QTextCodec::codecForName(mysql_character_set_name(mysql));
- if (heuristicCodec)
- return heuristicCodec;
- return QTextCodec::codecForLocale();
-}
-#endif // textcodec
-
-static QSqlError qMakeError(const QString& err, QSqlError::ErrorType type,
- const QMYSQLDriverPrivate* p)
+static QSqlError qMakeError(const QString &err, QSqlError::ErrorType type,
+ const QMYSQLDriverPrivate *p)
{
- const char *cerr = p->mysql ? mysql_error(p->mysql) : 0;
- return QSqlError(QLatin1String("QMYSQL: ") + err,
- p->tc ? toUnicode(p->tc, cerr) : QString::fromLatin1(cerr),
+ const char *cerr = p->mysql ? mysql_error(p->mysql) : nullptr;
+ return QSqlError("QMYSQL: "_L1 + err,
+ QString::fromUtf8(cerr),
type, QString::number(mysql_errno(p->mysql)));
}
-static QMetaType::Type qDecodeMYSQLType(int mysqltype, uint flags)
+static QMetaType qDecodeMYSQLType(enum_field_types mysqltype, uint flags)
{
QMetaType::Type type;
switch (mysqltype) {
- case FIELD_TYPE_TINY :
+ case MYSQL_TYPE_TINY:
type = (flags & UNSIGNED_FLAG) ? QMetaType::UChar : QMetaType::Char;
break;
- case FIELD_TYPE_SHORT :
+ case MYSQL_TYPE_SHORT:
type = (flags & UNSIGNED_FLAG) ? QMetaType::UShort : QMetaType::Short;
break;
- case FIELD_TYPE_LONG :
- case FIELD_TYPE_INT24 :
+ case MYSQL_TYPE_LONG:
+ case MYSQL_TYPE_INT24:
type = (flags & UNSIGNED_FLAG) ? QMetaType::UInt : QMetaType::Int;
break;
- case FIELD_TYPE_YEAR :
+ case MYSQL_TYPE_YEAR:
type = QMetaType::Int;
break;
- case FIELD_TYPE_LONGLONG :
+ case MYSQL_TYPE_BIT:
+ case MYSQL_TYPE_LONGLONG:
type = (flags & UNSIGNED_FLAG) ? QMetaType::ULongLong : QMetaType::LongLong;
break;
- case FIELD_TYPE_FLOAT :
- case FIELD_TYPE_DOUBLE :
- case FIELD_TYPE_DECIMAL :
-#if defined(FIELD_TYPE_NEWDECIMAL)
- case FIELD_TYPE_NEWDECIMAL:
-#endif
+ case MYSQL_TYPE_FLOAT:
+ case MYSQL_TYPE_DOUBLE:
+ case MYSQL_TYPE_DECIMAL:
+ case MYSQL_TYPE_NEWDECIMAL:
type = QMetaType::Double;
break;
- case FIELD_TYPE_DATE :
+ case MYSQL_TYPE_DATE:
type = QMetaType::QDate;
break;
- case FIELD_TYPE_TIME :
+ case MYSQL_TYPE_TIME:
// A time field can be within the range '-838:59:59' to '838:59:59' so
// use QString instead of QTime since QTime is limited to 24 hour clock
type = QMetaType::QString;
break;
- case FIELD_TYPE_DATETIME :
- case FIELD_TYPE_TIMESTAMP :
+ case MYSQL_TYPE_DATETIME:
+ case MYSQL_TYPE_TIMESTAMP:
type = QMetaType::QDateTime;
break;
- case FIELD_TYPE_STRING :
- case FIELD_TYPE_VAR_STRING :
- case FIELD_TYPE_BLOB :
- case FIELD_TYPE_TINY_BLOB :
- case FIELD_TYPE_MEDIUM_BLOB :
- case FIELD_TYPE_LONG_BLOB :
+ case MYSQL_TYPE_STRING:
+ case MYSQL_TYPE_VAR_STRING:
+ case MYSQL_TYPE_BLOB:
+ case MYSQL_TYPE_TINY_BLOB:
+ case MYSQL_TYPE_MEDIUM_BLOB:
+ case MYSQL_TYPE_LONG_BLOB:
+ case MYSQL_TYPE_GEOMETRY:
+ case MYSQL_TYPE_JSON:
type = (flags & BINARY_FLAG) ? QMetaType::QByteArray : QMetaType::QString;
break;
- default:
- case FIELD_TYPE_ENUM :
- case FIELD_TYPE_SET :
+ case MYSQL_TYPE_ENUM:
+ case MYSQL_TYPE_SET:
+ type = QMetaType::QString;
+ break;
+ default: // needed because there are more enum values which are not available in all headers
type = QMetaType::QString;
break;
}
- return type;
+ return QMetaType(type);
}
-static QSqlField qToField(MYSQL_FIELD *field, QTextCodec *tc)
+static QSqlField qToField(MYSQL_FIELD *field)
{
- QSqlField f(toUnicode(tc, field->name),
- QVariant::Type(qDecodeMYSQLType(int(field->type), field->flags)),
- toUnicode(tc, field->table));
+ QSqlField f(QString::fromUtf8(field->name),
+ qDecodeMYSQLType(field->type, field->flags),
+ QString::fromUtf8(field->table));
f.setRequired(IS_NOT_NULL(field->flags));
f.setLength(field->length);
f.setPrecision(field->decimals);
- f.setSqlType(field->type);
f.setAutoValue(field->flags & AUTO_INCREMENT_FLAG);
return f;
}
-static QSqlError qMakeStmtError(const QString& err, QSqlError::ErrorType type,
- MYSQL_STMT* stmt)
+static QSqlError qMakeStmtError(const QString &err, QSqlError::ErrorType type,
+ MYSQL_STMT *stmt)
{
const char *cerr = mysql_stmt_error(stmt);
- return QSqlError(QLatin1String("QMYSQL: ") + err,
+ return QSqlError("QMYSQL: "_L1 + err,
QString::fromLatin1(cerr),
type, QString::number(mysql_stmt_errno(stmt)));
}
-static bool qIsBlob(int t)
+static bool qIsBlob(enum_field_types t)
{
return t == MYSQL_TYPE_TINY_BLOB
|| t == MYSQL_TYPE_BLOB
|| t == MYSQL_TYPE_MEDIUM_BLOB
- || t == MYSQL_TYPE_LONG_BLOB;
+ || t == MYSQL_TYPE_LONG_BLOB
+ || t == MYSQL_TYPE_JSON;
+}
+
+static bool qIsTimeOrDate(enum_field_types 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)
@@ -358,16 +325,17 @@ static bool qIsInteger(int t)
|| t == QMetaType::LongLong || t == QMetaType::ULongLong;
}
-void QMYSQLResultPrivate::bindBlobs()
+static inline bool qIsBitfield(enum_field_types type)
{
- int i;
- MYSQL_FIELD *fieldInfo;
- MYSQL_BIND *bind;
+ return type == MYSQL_TYPE_BIT;
+}
- for(i = 0; i < fields.count(); ++i) {
- fieldInfo = fields.at(i).myField;
+void QMYSQLResultPrivate::bindBlobs()
+{
+ for (int i = 0; i < fields.size(); ++i) {
+ const MYSQL_FIELD *fieldInfo = fields.at(i).myField;
if (qIsBlob(inBinds[i].buffer_type) && meta && fieldInfo) {
- bind = &inBinds[i];
+ MYSQL_BIND *bind = &inBinds[i];
bind->buffer_length = fieldInfo->max_length;
delete[] static_cast<char*>(bind->buffer);
bind->buffer = new char[fieldInfo->max_length];
@@ -378,10 +346,6 @@ void QMYSQLResultPrivate::bindBlobs()
bool QMYSQLResultPrivate::bindInValues()
{
- MYSQL_BIND *bind;
- char *field;
- int i = 0;
-
if (!meta)
meta = mysql_stmt_result_metadata(stmt);
if (!meta)
@@ -392,35 +356,37 @@ 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 (qIsInteger(f.type)) {
- fieldInfo->length = 8;
+ } else if (qIsTimeOrDate(fieldInfo->type)) {
+ bind->buffer_length = f.bufLength = sizeof(QT_MYSQL_TIME);
+ } else if (qIsInteger(f.type.id())) {
+ bind->buffer_length = f.bufLength = 8;
} else {
- fieldInfo->type = MYSQL_TYPE_STRING;
+ bind->buffer_type = MYSQL_TYPE_STRING;
}
- bind = &inBinds[i];
- 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;
++i;
}
@@ -440,7 +406,7 @@ QMYSQLResult::~QMYSQLResult()
QVariant QMYSQLResult::handle() const
{
Q_D(const QMYSQLResult);
- if(d->preparedQuery)
+ if (d->preparedQuery)
return d->meta ? QVariant::fromValue(d->meta) : QVariant::fromValue(d->stmt);
else
return QVariant::fromValue(d->result);
@@ -452,7 +418,7 @@ void QMYSQLResult::cleanup()
if (d->result)
mysql_free_result(d->result);
-// must iterate trough leftover result sets from multi-selects or stored procedures
+// must iterate through leftover result sets from multi-selects or stored procedures
// if this isn't done subsequent queries will fail with "Commands out of sync"
while (driver() && d->drv_d_func()->mysql && mysql_next_result(d->drv_d_func()->mysql) == 0) {
MYSQL_RES *res = mysql_store_result(d->drv_d_func()->mysql);
@@ -462,7 +428,7 @@ void QMYSQLResult::cleanup()
if (d->stmt) {
if (mysql_stmt_close(d->stmt))
- qWarning("QMYSQLResult::cleanup: unable to free statement handle");
+ qCWarning(lcMysql, "QMYSQLResult::cleanup: unable to free statement handle");
d->stmt = 0;
}
@@ -471,9 +437,8 @@ void QMYSQLResult::cleanup()
d->meta = 0;
}
- int i;
- for (i = 0; i < d->fields.count(); ++i)
- delete[] d->fields[i].outField;
+ for (const QMYSQLResultPrivate::QMyField &f : std::as_const(d->fields))
+ delete[] f.outField;
if (d->outBinds) {
delete[] d->outBinds;
@@ -487,8 +452,8 @@ void QMYSQLResult::cleanup()
d->hasBlobs = false;
d->fields.clear();
- d->result = NULL;
- d->row = NULL;
+ d->result = nullptr;
+ d->row = nullptr;
setAt(-1);
setActive(false);
}
@@ -514,11 +479,7 @@ bool QMYSQLResult::fetch(int i)
int nRC = mysql_stmt_fetch(d->stmt);
if (nRC) {
-#ifdef MYSQL_DATA_TRUNCATED
if (nRC == 1 || nRC == MYSQL_DATA_TRUNCATED)
-#else
- if (nRC == 1)
-#endif
setLastError(qMakeStmtError(QCoreApplication::translate("QMYSQLResult",
"Unable to fetch data"), QSqlError::StatementError, d->stmt));
return false;
@@ -542,11 +503,7 @@ bool QMYSQLResult::fetchNext()
if (d->preparedQuery) {
int nRC = mysql_stmt_fetch(d->stmt);
if (nRC) {
-#ifdef MYSQL_DATA_TRUNCATED
if (nRC == 1 || nRC == MYSQL_DATA_TRUNCATED)
-#else
- if (nRC == 1)
-#endif // MYSQL_DATA_TRUNCATED
setLastError(qMakeStmtError(QCoreApplication::translate("QMYSQLResult",
"Unable to fetch data"), QSqlError::StatementError, d->stmt));
return false;
@@ -571,12 +528,7 @@ bool QMYSQLResult::fetchLast()
return success;
}
- my_ulonglong numRows;
- if (d->preparedQuery) {
- numRows = mysql_stmt_num_rows(d->stmt);
- } else {
- numRows = mysql_num_rows(d->result);
- }
+ my_ulonglong numRows = d->preparedQuery ? mysql_stmt_num_rows(d->stmt) : mysql_num_rows(d->result);
if (at() == int(numRows))
return true;
if (!numRows)
@@ -594,49 +546,81 @@ bool QMYSQLResult::fetchFirst()
return fetch(0);
}
+static inline uint64_t
+qDecodeBitfield(const QMYSQLResultPrivate::QMyField &f, const char *outField)
+{
+ // byte-aligned length
+ const auto numBytes = (f.myField->length + 7) / 8;
+ uint64_t val = 0;
+ for (unsigned long i = 0; i < numBytes && outField; ++i) {
+ uint64_t tmp = static_cast<uint8_t>(outField[i]);
+ val <<= 8;
+ val |= tmp;
+ }
+ return val;
+}
+
QVariant QMYSQLResult::data(int field)
{
Q_D(QMYSQLResult);
- if (!isSelect() || field >= d->fields.count()) {
- qWarning("QMYSQLResult::data: column %d out of range", field);
+ if (!isSelect() || field >= d->fields.size()) {
+ qCWarning(lcMysql, "QMYSQLResult::data: column %d out of range", field);
return QVariant();
}
if (!driver())
return QVariant();
- int fieldLength = 0;
+ my_ulonglong fieldLength = 0;
const QMYSQLResultPrivate::QMyField &f = d->fields.at(field);
QString val;
if (d->preparedQuery) {
if (f.nullIndicator)
- return QVariant(QVariant::Type(f.type));
-
- if (qIsInteger(f.type)) {
+ return QVariant(f.type);
+ if (qIsBitfield(f.myField->type)) {
+ return QVariant::fromValue(qDecodeBitfield(f, f.outField));
+ } else if (qIsInteger(f.type.id())) {
QVariant variant(f.type, f.outField);
// we never want to return char variants here, see QTBUG-53397
- if (static_cast<int>(f.type) == QMetaType::UChar)
+ if (f.type.id() == QMetaType::UChar)
return variant.toUInt();
- else if (static_cast<int>(f.type) == QMetaType::Char)
+ else if (f.type.id() == QMetaType::Char)
return variant.toInt();
return variant;
+ } else if (qIsTimeOrDate(f.myField->type) && f.bufLength >= sizeof(QT_MYSQL_TIME)) {
+ auto t = reinterpret_cast<const QT_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, QTimeZone::UTC);
+ else if (f.type.id() == QMetaType::QDate)
+ return date;
+ else
+ return time;
}
- if (f.type != QMetaType::QByteArray)
- val = toUnicode(d->drv_d_func()->tc, f.outField, f.bufLength);
+ if (f.type.id() != QMetaType::QByteArray)
+ val = QString::fromUtf8(f.outField, f.bufLength);
} else {
- if (d->row[field] == NULL) {
+ if (d->row[field] == nullptr) {
// NULL value
- return QVariant(QVariant::Type(f.type));
+ return QVariant(f.type);
}
+ if (qIsBitfield(f.myField->type))
+ return QVariant::fromValue(qDecodeBitfield(f, d->row[field]));
+
fieldLength = mysql_fetch_lengths(d->result)[field];
- if (f.type != QMetaType::QByteArray)
- val = toUnicode(d->drv_d_func()->tc, d->row[field], fieldLength);
+ if (f.type.id() != QMetaType::QByteArray)
+ val = QString::fromUtf8(d->row[field], fieldLength);
}
- switch (static_cast<int>(f.type)) {
+ switch (f.type.id()) {
case QMetaType::LongLong:
return QVariant(val.toLongLong());
case QMetaType::ULongLong:
@@ -669,7 +653,7 @@ QVariant QMYSQLResult::data(int field)
ok = true;
break;
}
- if(ok)
+ if (ok)
return v;
return QVariant();
}
@@ -699,12 +683,12 @@ QVariant QMYSQLResult::data(int field)
bool QMYSQLResult::isNull(int field)
{
Q_D(const QMYSQLResult);
- if (field < 0 || field >= d->fields.count())
+ if (field < 0 || field >= d->fields.size())
return true;
if (d->preparedQuery)
return d->fields.at(field).nullIndicator;
else
- return d->row[field] == NULL;
+ return d->row[field] == nullptr;
}
bool QMYSQLResult::reset (const QString& query)
@@ -717,8 +701,8 @@ bool QMYSQLResult::reset (const QString& query)
cleanup();
- const QByteArray encQuery(fromUnicode(d->drv_d_func()->tc, query));
- if (mysql_real_query(d->drv_d_func()->mysql, encQuery.data(), encQuery.length())) {
+ const QByteArray encQuery = query.toUtf8();
+ if (mysql_real_query(d->drv_d_func()->mysql, encQuery.data(), encQuery.size())) {
setLastError(qMakeError(QCoreApplication::translate("QMYSQLResult", "Unable to execute query"),
QSqlError::StatementError, d->drv_d_func()));
return false;
@@ -738,6 +722,7 @@ bool QMYSQLResult::reset (const QString& query)
for(int i = 0; i < numFields; i++) {
MYSQL_FIELD* field = mysql_fetch_field_direct(d->result, i);
d->fields[i].type = qDecodeMYSQLType(field->type, field->flags);
+ d->fields[i].myField = field;
}
setAt(QSql::BeforeFirstRow);
}
@@ -803,8 +788,8 @@ QSqlRecord QMYSQLResult::record() const
if (!mysql_errno(d->drv_d_func()->mysql)) {
mysql_field_seek(res, 0);
MYSQL_FIELD* field = mysql_fetch_field(res);
- while(field) {
- info.append(qToField(field, d->drv_d_func()->tc));
+ while (field) {
+ info.append(qToField(field));
field = mysql_fetch_field(res);
}
}
@@ -826,8 +811,8 @@ bool QMYSQLResult::nextResult()
d->result = 0;
setSelect(false);
- for (int i = 0; i < d->fields.count(); ++i)
- delete[] d->fields[i].outField;
+ for (const QMYSQLResultPrivate::QMyField &f : std::as_const(d->fields))
+ delete[] f.outField;
d->fields.clear();
int status = mysql_next_result(d->drv_d_func()->mysql);
@@ -840,7 +825,7 @@ bool QMYSQLResult::nextResult()
}
d->result = mysql_store_result(d->drv_d_func()->mysql);
- int numFields = mysql_field_count(d->drv_d_func()->mysql);
+ unsigned int numFields = mysql_field_count(d->drv_d_func()->mysql);
if (!d->result && numFields > 0) {
setLastError(qMakeError(QCoreApplication::translate("QMYSQLResult", "Unable to store next result"),
QSqlError::StatementError, d->drv_d_func()));
@@ -852,9 +837,10 @@ bool QMYSQLResult::nextResult()
d->rowsAffected = mysql_affected_rows(d->drv_d_func()->mysql);
if (isSelect()) {
- for (int i = 0; i < numFields; i++) {
- MYSQL_FIELD* field = mysql_fetch_field_direct(d->result, i);
+ for (unsigned int i = 0; i < numFields; i++) {
+ MYSQL_FIELD *field = mysql_fetch_field_direct(d->result, i);
d->fields[i].type = qDecodeMYSQLType(field->type, field->flags);
+ d->fields[i].myField = field;
}
}
@@ -867,29 +853,6 @@ void QMYSQLResult::virtual_hook(int id, void *data)
QSqlResult::virtual_hook(id, data);
}
-static MYSQL_TIME *toMySqlDate(QDate date, QTime time, int type)
-{
- Q_ASSERT(type == QMetaType::QTime || type == QMetaType::QDate
- || type == QMetaType::QDateTime);
-
- MYSQL_TIME *myTime = new MYSQL_TIME;
- memset(myTime, 0, sizeof(MYSQL_TIME));
-
- if (type == QMetaType::QTime || type == QMetaType::QDateTime) {
- myTime->hour = time.hour();
- myTime->minute = time.minute();
- myTime->second = time.second();
- myTime->second_part = time.msec() * 1000;
- }
- if (type == QMetaType::QDate || type == QMetaType::QDateTime) {
- myTime->year = date.year();
- myTime->month = date.month();
- myTime->day = date.day();
- }
-
- return myTime;
-}
-
bool QMYSQLResult::prepare(const QString& query)
{
Q_D(QMYSQLResult);
@@ -913,8 +876,8 @@ bool QMYSQLResult::prepare(const QString& query)
return false;
}
- const QByteArray encQuery(fromUnicode(d->drv_d_func()->tc, query));
- r = mysql_stmt_prepare(d->stmt, encQuery.constData(), encQuery.length());
+ const QByteArray encQuery = query.toUtf8();
+ r = mysql_stmt_prepare(d->stmt, encQuery.constData(), encQuery.size());
if (r != 0) {
setLastError(qMakeStmtError(QCoreApplication::translate("QMYSQLResult",
"Unable to prepare statement"), QSqlError::StatementError, d->stmt));
@@ -922,9 +885,9 @@ bool QMYSQLResult::prepare(const QString& query)
return false;
}
- if (mysql_stmt_param_count(d->stmt) > 0) {// allocate memory for outvalues
- d->outBinds = new MYSQL_BIND[mysql_stmt_param_count(d->stmt)];
- }
+ const auto paramCount = mysql_stmt_param_count(d->stmt);
+ if (paramCount > 0) // allocate memory for outvalues
+ d->outBinds = new MYSQL_BIND[paramCount]();
setSelect(d->bindInValues());
d->preparedQuery = true;
@@ -942,12 +905,11 @@ bool QMYSQLResult::exec()
return false;
int r = 0;
- MYSQL_BIND* currBind;
- QVector<MYSQL_TIME *> timeVector;
- QVector<QByteArray> stringVector;
- QVector<my_bool> nullVector;
+ QList<QT_MYSQL_TIME *> timeVector;
+ QList<QByteArray> stringVector;
+ QList<my_bool> nullVector;
- const QVector<QVariant> values = boundValues();
+ const QList<QVariant> values = boundValues();
r = mysql_stmt_reset(d->stmt);
if (r != 0) {
@@ -956,17 +918,16 @@ bool QMYSQLResult::exec()
return false;
}
- if (mysql_stmt_param_count(d->stmt) > 0 &&
- mysql_stmt_param_count(d->stmt) == (uint)values.count()) {
-
- nullVector.resize(values.count());
- for (int i = 0; i < values.count(); ++i) {
+ const unsigned long paramCount = mysql_stmt_param_count(d->stmt);
+ if (paramCount > 0 && paramCount == static_cast<size_t>(values.size())) {
+ nullVector.resize(values.size());
+ for (qsizetype i = 0; i < values.size(); ++i) {
const QVariant &val = boundValues().at(i);
void *data = const_cast<void *>(val.constData());
- currBind = &d->outBinds[i];
+ MYSQL_BIND* currBind = &d->outBinds[i];
- nullVector[i] = static_cast<my_bool>(val.isNull());
+ nullVector[i] = static_cast<my_bool>(QSqlResultPrivate::isVariantNull(val));
currBind->is_null = &nullVector[i];
currBind->length = 0;
currBind->is_unsigned = 0;
@@ -981,27 +942,41 @@ bool QMYSQLResult::exec()
case QMetaType::QTime:
case QMetaType::QDate:
case QMetaType::QDateTime: {
- MYSQL_TIME *myTime = toMySqlDate(val.toDate(), val.toTime(), val.userType());
+ auto myTime = new QT_MYSQL_TIME{};
timeVector.append(myTime);
-
currBind->buffer = myTime;
- switch (val.userType()) {
- case QMetaType::QTime:
+
+ QDate date;
+ QTime time;
+ int type = val.userType();
+ if (type == QMetaType::QTime) {
+ time = val.toTime();
currBind->buffer_type = MYSQL_TYPE_TIME;
myTime->time_type = MYSQL_TIMESTAMP_TIME;
- break;
- case QMetaType::QDate:
+ } else if (type == QMetaType::QDate) {
+ date = val.toDate();
currBind->buffer_type = MYSQL_TYPE_DATE;
myTime->time_type = MYSQL_TIMESTAMP_DATE;
- break;
- case QMetaType::QDateTime:
+ } else {
+ QDateTime dt = val.toDateTime().toUTC();
+ date = dt.date();
+ time = dt.time();
currBind->buffer_type = MYSQL_TYPE_DATETIME;
myTime->time_type = MYSQL_TIMESTAMP_DATETIME;
- break;
- default:
- break;
}
- currBind->buffer_length = sizeof(MYSQL_TIME);
+
+ if (type == QMetaType::QTime || type == QMetaType::QDateTime) {
+ myTime->hour = time.hour();
+ myTime->minute = time.minute();
+ myTime->second = time.second();
+ myTime->second_part = time.msec() * 1000;
+ }
+ if (type == QMetaType::QDate || type == QMetaType::QDateTime) {
+ myTime->year = date.year();
+ myTime->month = date.month();
+ myTime->day = date.day();
+ }
+ currBind->buffer_length = sizeof(QT_MYSQL_TIME);
currBind->length = 0;
break; }
case QMetaType::UInt:
@@ -1031,16 +1006,20 @@ bool QMYSQLResult::exec()
break;
case QMetaType::QString:
default: {
- QByteArray ba = fromUnicode(d->drv_d_func()->tc, val.toString());
+ QByteArray ba = val.toString().toUtf8();
stringVector.append(ba);
currBind->buffer_type = MYSQL_TYPE_STRING;
currBind->buffer = const_cast<char *>(ba.constData());
- currBind->buffer_length = ba.length();
+ currBind->buffer_length = ba.size();
break; }
}
}
+#if defined(MARIADB_VERSION_ID) || MYSQL_VERSION_ID < 80300
r = mysql_stmt_bind_param(d->stmt, d->outBinds);
+#else
+ r = mysql_stmt_bind_named_param(d->stmt, d->outBinds, paramCount, nullptr);
+#endif
if (r != 0) {
setLastError(qMakeStmtError(QCoreApplication::translate("QMYSQLResult",
"Unable to bind value"), QSqlError::StatementError, d->stmt));
@@ -1110,12 +1089,8 @@ static void qLibraryInit()
if (qMySqlInitHandledByUser || qMySqlConnectionCount > 1)
return;
-# if MYSQL_VERSION_ID >= 50003
if (mysql_library_init(0, 0, 0)) {
-# else
- if (mysql_server_init(0, 0, 0)) {
-# endif
- qWarning("QMYSQLDriver::qServerInit: unable to start server.");
+ qCWarning(lcMysql, "QMYSQLDriver::qServerInit: unable to start server.");
}
#endif // Q_NO_MYSQL_EMBEDDED
@@ -1128,11 +1103,7 @@ static void qLibraryEnd()
{
#if !defined(MARIADB_BASE_VERSION) && !defined(MARIADB_VERSION_ID)
# if !defined(Q_NO_MYSQL_EMBEDDED)
-# if MYSQL_VERSION_ID >= 50003
mysql_library_end();
-# else
- mysql_server_end();
-# endif
# endif
#endif
}
@@ -1155,10 +1126,7 @@ QMYSQLDriver::QMYSQLDriver(MYSQL * con, QObject * parent)
Q_D(QMYSQLDriver);
init();
if (con) {
- d->mysql = (MYSQL *) con;
-#if QT_CONFIG(textcodec)
- d->tc = codec(con);
-#endif
+ d->mysql = con;
setOpen(true);
setOpenError(false);
if (qMySqlConnectionCount == 1)
@@ -1187,13 +1155,10 @@ bool QMYSQLDriver::hasFeature(DriverFeature f) const
Q_D(const QMYSQLDriver);
switch (f) {
case Transactions:
-// CLIENT_TRANSACTION should be defined in all recent mysql client libs > 3.23.34
-#ifdef CLIENT_TRANSACTIONS
if (d->mysql) {
if ((d->mysql->server_capabilities & CLIENT_TRANSACTIONS) == CLIENT_TRANSACTIONS)
return true;
}
-#endif
return false;
case NamedPlaceholders:
case BatchOperations:
@@ -1217,176 +1182,246 @@ bool QMYSQLDriver::hasFeature(DriverFeature f) const
return false;
}
-static void setOptionFlag(uint &optionFlags, const QString &opt)
+static void setOptionFlag(uint &optionFlags, QStringView opt)
{
- if (opt == QLatin1String("CLIENT_COMPRESS"))
+ if (opt == "CLIENT_COMPRESS"_L1)
optionFlags |= CLIENT_COMPRESS;
- else if (opt == QLatin1String("CLIENT_FOUND_ROWS"))
+ else if (opt == "CLIENT_FOUND_ROWS"_L1)
optionFlags |= CLIENT_FOUND_ROWS;
- else if (opt == QLatin1String("CLIENT_IGNORE_SPACE"))
+ else if (opt == "CLIENT_IGNORE_SPACE"_L1)
optionFlags |= CLIENT_IGNORE_SPACE;
- else if (opt == QLatin1String("CLIENT_INTERACTIVE"))
+ else if (opt == "CLIENT_INTERACTIVE"_L1)
optionFlags |= CLIENT_INTERACTIVE;
- else if (opt == QLatin1String("CLIENT_NO_SCHEMA"))
+ else if (opt == "CLIENT_NO_SCHEMA"_L1)
optionFlags |= CLIENT_NO_SCHEMA;
- else if (opt == QLatin1String("CLIENT_ODBC"))
+ else if (opt == "CLIENT_ODBC"_L1)
optionFlags |= CLIENT_ODBC;
- else if (opt == QLatin1String("CLIENT_SSL"))
- qWarning("QMYSQLDriver: SSL_KEY, SSL_CERT and SSL_CA should be used instead of CLIENT_SSL.");
+ else if (opt == "CLIENT_SSL"_L1)
+ qCWarning(lcMysql, "QMYSQLDriver: MYSQL_OPT_SSL_KEY, MYSQL_OPT_SSL_CERT "
+ "and MYSQL_OPT_SSL_CA should be used instead of CLIENT_SSL.");
else
- qWarning("QMYSQLDriver::open: Unknown connect option '%s'", opt.toLocal8Bit().constData());
+ qCWarning(lcMysql, "QMYSQLDriver::open: Unknown connect option '%ls'",
+ qUtf16Printable(QString(opt)));
+}
+
+static bool setOptionString(MYSQL *mysql, mysql_option option, QStringView v)
+{
+ return mysql_options(mysql, option, v.toUtf8().constData()) == 0;
+}
+
+static bool setOptionInt(MYSQL *mysql, mysql_option option, QStringView v)
+{
+ bool bOk;
+ const auto val = v.toInt(&bOk);
+ return bOk ? mysql_options(mysql, option, &val) == 0 : false;
+}
+
+static bool setOptionBool(MYSQL *mysql, mysql_option option, QStringView v)
+{
+ bool val = (v.isEmpty() || v == "TRUE"_L1 || v == "1"_L1);
+ return mysql_options(mysql, option, &val) == 0;
}
-bool QMYSQLDriver::open(const QString& db,
- const QString& user,
- const QString& password,
- const QString& host,
- int port,
- const QString& connOpts)
+// MYSQL_OPT_SSL_MODE was introduced with MySQL 5.7.11
+#if defined(MYSQL_VERSION_ID) && MYSQL_VERSION_ID >= 50711 && !defined(MARIADB_VERSION_ID)
+static bool setOptionSslMode(MYSQL *mysql, mysql_option option, QStringView v)
+{
+ mysql_ssl_mode sslMode = SSL_MODE_DISABLED;
+ if (v == "DISABLED"_L1 || v == "SSL_MODE_DISABLED"_L1)
+ sslMode = SSL_MODE_DISABLED;
+ else if (v == "PREFERRED"_L1 || v == "SSL_MODE_PREFERRED"_L1)
+ sslMode = SSL_MODE_PREFERRED;
+ else if (v == "REQUIRED"_L1 || v == "SSL_MODE_REQUIRED"_L1)
+ sslMode = SSL_MODE_REQUIRED;
+ else if (v == "VERIFY_CA"_L1 || v == "SSL_MODE_VERIFY_CA"_L1)
+ sslMode = SSL_MODE_VERIFY_CA;
+ else if (v == "VERIFY_IDENTITY"_L1 || v == "SSL_MODE_VERIFY_IDENTITY"_L1)
+ sslMode = SSL_MODE_VERIFY_IDENTITY;
+ else
+ qCWarning(lcMysql, "Unknown ssl mode '%ls' - using SSL_MODE_DISABLED",
+ qUtf16Printable(QString(v)));
+ return mysql_options(mysql, option, &sslMode) == 0;
+}
+#endif
+
+static bool setOptionProtocol(MYSQL *mysql, mysql_option option, QStringView v)
+{
+ mysql_protocol_type proto = MYSQL_PROTOCOL_DEFAULT;
+ if (v == "TCP"_L1 || v == "MYSQL_PROTOCOL_TCP"_L1)
+ proto = MYSQL_PROTOCOL_TCP;
+ else if (v == "SOCKET"_L1 || v == "MYSQL_PROTOCOL_SOCKET"_L1)
+ proto = MYSQL_PROTOCOL_SOCKET;
+ else if (v == "PIPE"_L1 || v == "MYSQL_PROTOCOL_PIPE"_L1)
+ proto = MYSQL_PROTOCOL_PIPE;
+ else if (v == "MEMORY"_L1 || v == "MYSQL_PROTOCOL_MEMORY"_L1)
+ proto = MYSQL_PROTOCOL_MEMORY;
+ else if (v == "DEFAULT"_L1 || v == "MYSQL_PROTOCOL_DEFAULT"_L1)
+ proto = MYSQL_PROTOCOL_DEFAULT;
+ else
+ qCWarning(lcMysql, "Unknown protocol '%ls' - using MYSQL_PROTOCOL_DEFAULT",
+ qUtf16Printable(QString(v)));
+ return mysql_options(mysql, option, &proto) == 0;
+}
+
+bool QMYSQLDriver::open(const QString &db,
+ const QString &user,
+ const QString &password,
+ const QString &host,
+ int port,
+ const QString &connOpts)
{
Q_D(QMYSQLDriver);
if (isOpen())
close();
+ if (!(d->mysql = mysql_init(nullptr))) {
+ setLastError(qMakeError(tr("Unable to allocate a MYSQL object"),
+ QSqlError::ConnectionError, d));
+ setOpenError(true);
+ return false;
+ }
+
+ typedef bool (*SetOptionFunc)(MYSQL*, mysql_option, QStringView);
+ struct mysqloptions {
+ QLatin1StringView key;
+ mysql_option option;
+ SetOptionFunc func;
+ };
+ const mysqloptions options[] = {
+ {"SSL_KEY"_L1, MYSQL_OPT_SSL_KEY, setOptionString},
+ {"SSL_CERT"_L1, MYSQL_OPT_SSL_CERT, setOptionString},
+ {"SSL_CA"_L1, MYSQL_OPT_SSL_CA, setOptionString},
+ {"SSL_CAPATH"_L1, MYSQL_OPT_SSL_CAPATH, setOptionString},
+ {"SSL_CIPHER"_L1, MYSQL_OPT_SSL_CIPHER, setOptionString},
+ {"MYSQL_OPT_SSL_KEY"_L1, MYSQL_OPT_SSL_KEY, setOptionString},
+ {"MYSQL_OPT_SSL_CERT"_L1, MYSQL_OPT_SSL_CERT, setOptionString},
+ {"MYSQL_OPT_SSL_CA"_L1, MYSQL_OPT_SSL_CA, setOptionString},
+ {"MYSQL_OPT_SSL_CAPATH"_L1, MYSQL_OPT_SSL_CAPATH, setOptionString},
+ {"MYSQL_OPT_SSL_CIPHER"_L1, MYSQL_OPT_SSL_CIPHER, setOptionString},
+ {"MYSQL_OPT_SSL_CRL"_L1, MYSQL_OPT_SSL_CRL, setOptionString},
+ {"MYSQL_OPT_SSL_CRLPATH"_L1, MYSQL_OPT_SSL_CRLPATH, setOptionString},
+#if defined(MYSQL_VERSION_ID) && MYSQL_VERSION_ID >= 50710
+ {"MYSQL_OPT_TLS_VERSION"_L1, MYSQL_OPT_TLS_VERSION, setOptionString},
+#endif
+#if defined(MYSQL_VERSION_ID) && MYSQL_VERSION_ID >= 50711 && !defined(MARIADB_VERSION_ID)
+ {"MYSQL_OPT_SSL_MODE"_L1, MYSQL_OPT_SSL_MODE, setOptionSslMode},
+#endif
+ {"MYSQL_OPT_CONNECT_TIMEOUT"_L1, MYSQL_OPT_CONNECT_TIMEOUT, setOptionInt},
+ {"MYSQL_OPT_READ_TIMEOUT"_L1, MYSQL_OPT_READ_TIMEOUT, setOptionInt},
+ {"MYSQL_OPT_WRITE_TIMEOUT"_L1, MYSQL_OPT_WRITE_TIMEOUT, setOptionInt},
+ {"MYSQL_OPT_RECONNECT"_L1, MYSQL_OPT_RECONNECT, setOptionBool},
+ {"MYSQL_OPT_LOCAL_INFILE"_L1, MYSQL_OPT_LOCAL_INFILE, setOptionInt},
+ {"MYSQL_OPT_PROTOCOL"_L1, MYSQL_OPT_PROTOCOL, setOptionProtocol},
+ {"MYSQL_SHARED_MEMORY_BASE_NAME"_L1, MYSQL_SHARED_MEMORY_BASE_NAME, setOptionString},
+ };
+ auto trySetOption = [&](const QStringView &key, const QStringView &value) -> bool {
+ for (const mysqloptions &opt : options) {
+ if (key == opt.key) {
+ if (!opt.func(d->mysql, opt.option, value)) {
+ qCWarning(lcMysql, "QMYSQLDriver::open: Could not set connect option value "
+ "'%ls' to '%ls'",
+ qUtf16Printable(QString(key)), qUtf16Printable(QString(value)));
+ }
+ return true;
+ }
+ }
+ return false;
+ };
+
/* This is a hack to get MySQL's stored procedure support working.
Since a stored procedure _may_ return multiple result sets,
we have to enable CLIEN_MULTI_STATEMENTS here, otherwise _any_
stored procedure call will fail.
*/
unsigned int optionFlags = CLIENT_MULTI_STATEMENTS;
- const QStringList opts(connOpts.split(QLatin1Char(';'), QString::SkipEmptyParts));
+ const QList<QStringView> opts(QStringView(connOpts).split(u';', Qt::SkipEmptyParts));
QString unixSocket;
- QString sslCert;
- QString sslCA;
- QString sslKey;
- QString sslCAPath;
- QString sslCipher;
- my_bool reconnect=false;
- uint connectTimeout = 0;
- uint readTimeout = 0;
- uint writeTimeout = 0;
// extract the real options from the string
- for (int i = 0; i < opts.count(); ++i) {
- QString tmp(opts.at(i).simplified());
- int idx;
- if ((idx = tmp.indexOf(QLatin1Char('='))) != -1) {
- QString val = tmp.mid(idx + 1).simplified();
- QString opt = tmp.left(idx).simplified();
- if (opt == QLatin1String("UNIX_SOCKET"))
- unixSocket = val;
- else if (opt == QLatin1String("MYSQL_OPT_RECONNECT")) {
- if (val == QLatin1String("TRUE") || val == QLatin1String("1") || val.isEmpty())
- reconnect = true;
- } else if (opt == QLatin1String("MYSQL_OPT_CONNECT_TIMEOUT"))
- connectTimeout = val.toInt();
- else if (opt == QLatin1String("MYSQL_OPT_READ_TIMEOUT"))
- readTimeout = val.toInt();
- else if (opt == QLatin1String("MYSQL_OPT_WRITE_TIMEOUT"))
- writeTimeout = val.toInt();
- else if (opt == QLatin1String("SSL_KEY"))
- sslKey = val;
- else if (opt == QLatin1String("SSL_CERT"))
- sslCert = val;
- else if (opt == QLatin1String("SSL_CA"))
- sslCA = val;
- else if (opt == QLatin1String("SSL_CAPATH"))
- sslCAPath = val;
- else if (opt == QLatin1String("SSL_CIPHER"))
- sslCipher = val;
- else if (val == QLatin1String("TRUE") || val == QLatin1String("1"))
- setOptionFlag(optionFlags, tmp.left(idx).simplified());
+ for (const auto &option : opts) {
+ const QStringView sv = QStringView(option).trimmed();
+ qsizetype idx;
+ if ((idx = sv.indexOf(u'=')) != -1) {
+ const QStringView key = sv.left(idx).trimmed();
+ const QStringView val = sv.mid(idx + 1).trimmed();
+ if (trySetOption(key, val))
+ continue;
+ else if (key == "UNIX_SOCKET"_L1)
+ unixSocket = val.toString();
+ else if (val == "TRUE"_L1 || val == "1"_L1)
+ setOptionFlag(optionFlags, key);
else
- qWarning("QMYSQLDriver::open: Illegal connect option value '%s'",
- tmp.toLocal8Bit().constData());
+ qCWarning(lcMysql, "QMYSQLDriver::open: Illegal connect option value '%ls'",
+ qUtf16Printable(QString(sv)));
} else {
- setOptionFlag(optionFlags, tmp);
+ setOptionFlag(optionFlags, sv);
}
}
- if (!(d->mysql = mysql_init((MYSQL*) 0))) {
- setLastError(qMakeError(tr("Unable to allocate a MYSQL object"),
- QSqlError::ConnectionError, d));
- setOpenError(true);
- return false;
- }
-
- if (!sslKey.isNull() || !sslCert.isNull() || !sslCA.isNull() ||
- !sslCAPath.isNull() || !sslCipher.isNull()) {
- mysql_ssl_set(d->mysql,
- sslKey.isNull() ? static_cast<const char *>(0)
- : QFile::encodeName(sslKey).constData(),
- sslCert.isNull() ? static_cast<const char *>(0)
- : QFile::encodeName(sslCert).constData(),
- sslCA.isNull() ? static_cast<const char *>(0)
- : QFile::encodeName(sslCA).constData(),
- sslCAPath.isNull() ? static_cast<const char *>(0)
- : QFile::encodeName(sslCAPath).constData(),
- sslCipher.isNull() ? static_cast<const char *>(0)
- : sslCipher.toLocal8Bit().constData());
+ // try utf8 with non BMP first, utf8 (BMP only) if that fails
+ 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;
+ }
}
-
-#if MYSQL_VERSION_ID >= 50100
- if (connectTimeout != 0)
- mysql_options(d->mysql, MYSQL_OPT_CONNECT_TIMEOUT, &connectTimeout);
- if (readTimeout != 0)
- mysql_options(d->mysql, MYSQL_OPT_READ_TIMEOUT, &readTimeout);
- if (writeTimeout != 0)
- mysql_options(d->mysql, MYSQL_OPT_WRITE_TIMEOUT, &writeTimeout);
+#else
+ // dummy
+ struct {
+ const char *csname;
+ } *cs = nullptr;
#endif
+
MYSQL *mysql = mysql_real_connect(d->mysql,
- host.isNull() ? static_cast<const char *>(0)
- : host.toLocal8Bit().constData(),
- user.isNull() ? static_cast<const char *>(0)
- : user.toLocal8Bit().constData(),
- password.isNull() ? static_cast<const char *>(0)
- : password.toLocal8Bit().constData(),
- db.isNull() ? static_cast<const char *>(0)
- : db.toLocal8Bit().constData(),
+ host.isNull() ? nullptr : host.toUtf8().constData(),
+ user.isNull() ? nullptr : user.toUtf8().constData(),
+ password.isNull() ? nullptr : password.toUtf8().constData(),
+ db.isNull() ? nullptr : db.toUtf8().constData(),
(port > -1) ? port : 0,
- unixSocket.isNull() ? static_cast<const char *>(0)
- : unixSocket.toLocal8Bit().constData(),
+ unixSocket.isNull() ? nullptr : unixSocket.toUtf8().constData(),
optionFlags);
- if (mysql == d->mysql) {
- if (!db.isEmpty() && mysql_select_db(d->mysql, db.toLocal8Bit().constData())) {
- setLastError(qMakeError(tr("Unable to open database '%1'").arg(db), QSqlError::ConnectionError, d));
- mysql_close(d->mysql);
- setOpenError(true);
- return false;
- }
-#if MYSQL_VERSION_ID >= 50100
- if (reconnect)
- mysql_options(d->mysql, MYSQL_OPT_RECONNECT, &reconnect);
-#endif
- } else {
+ if (mysql != d->mysql) {
setLastError(qMakeError(tr("Unable to connect"),
QSqlError::ConnectionError, d));
mysql_close(d->mysql);
- d->mysql = NULL;
+ d->mysql = nullptr;
setOpenError(true);
return false;
}
-#if MYSQL_VERSION_ID >= 50007
- if (mysql_get_client_version() >= 50503 && mysql_get_server_version(d->mysql) >= 50503) {
- // force the communication to be utf8mb4 (only utf8mb4 supports 4-byte characters)
- mysql_set_character_set(d->mysql, "utf8mb4");
-#if QT_CONFIG(textcodec)
- d->tc = QTextCodec::codecForName("UTF-8");
-#endif
- } else
- {
- // force the communication to be utf8
- mysql_set_character_set(d->mysql, "utf8");
-#if QT_CONFIG(textcodec)
- d->tc = codec(d->mysql);
-#endif
+ // now ask the server to match the charset we selected
+ if (!cs || mysql_set_character_set(d->mysql, cs->csname) != 0) {
+ bool ok = false;
+ for (const char *p : wanted_charsets) {
+ if (mysql_set_character_set(d->mysql, p) == 0) {
+ ok = true;
+ break;
+ }
+ }
+ if (!ok)
+ qCWarning(lcMysql, "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 (!db.isEmpty() && mysql_select_db(d->mysql, db.toUtf8().constData())) {
+ setLastError(qMakeError(tr("Unable to open database '%1'").arg(db), QSqlError::ConnectionError, d));
+ mysql_close(d->mysql);
+ setOpenError(true);
+ return false;
}
-#endif // MYSQL_VERSION_ID >= 50007
- d->preparedQuerysEnabled = mysql_get_client_version() >= 40108
- && mysql_get_server_version(d->mysql) >= 40100;
+ d->preparedQuerysEnabled = checkPreparedQueries(d->mysql);
+ d->dbName = db;
+
+ if (d->preparedQuerysEnabled)
+ setUtcTimeZone(d->mysql);
#if QT_CONFIG(thread)
mysql_thread_init();
@@ -1405,7 +1440,8 @@ void QMYSQLDriver::close()
mysql_thread_end();
#endif
mysql_close(d->mysql);
- d->mysql = NULL;
+ d->mysql = nullptr;
+ d->dbName.clear();
setOpen(false);
setOpenError(false);
}
@@ -1422,14 +1458,14 @@ QStringList QMYSQLDriver::tables(QSql::TableType type) const
QStringList tl;
QSqlQuery q(createResult());
if (type & QSql::Tables) {
- QString sql = QLatin1String("select table_name from information_schema.tables where table_schema = '") + QLatin1String(d->mysql->db) + QLatin1String("' and table_type = 'BASE TABLE'");
+ QString sql = "select table_name from information_schema.tables where table_schema = '"_L1 + d->dbName + "' and table_type = 'BASE TABLE'"_L1;
q.exec(sql);
while (q.next())
tl.append(q.value(0).toString());
}
if (type & QSql::Views) {
- QString sql = QLatin1String("select table_name from information_schema.tables where table_schema = '") + QLatin1String(d->mysql->db) + QLatin1String("' and table_type = 'VIEW'");
+ QString sql = "select table_name from information_schema.tables where table_schema = '"_L1 + d->dbName + "' and table_type = 'VIEW'"_L1;
q.exec(sql);
while (q.next())
@@ -1438,18 +1474,18 @@ QStringList QMYSQLDriver::tables(QSql::TableType type) const
return tl;
}
-QSqlIndex QMYSQLDriver::primaryIndex(const QString& tablename) const
+QSqlIndex QMYSQLDriver::primaryIndex(const QString &tablename) const
{
QSqlIndex idx;
if (!isOpen())
return idx;
QSqlQuery i(createResult());
- QString stmt(QLatin1String("show index from %1;"));
+ QString stmt("show index from %1;"_L1);
QSqlRecord fil = record(tablename);
i.exec(stmt.arg(escapeIdentifier(tablename, QSqlDriver::TableName)));
while (i.isActive() && i.next()) {
- if (i.value(2).toString() == QLatin1String("PRIMARY")) {
+ if (i.value(2).toString() == "PRIMARY"_L1) {
idx.append(fil.field(i.value(4).toString()));
idx.setCursorName(i.value(0).toString());
idx.setName(i.value(2).toString());
@@ -1459,26 +1495,41 @@ QSqlIndex QMYSQLDriver::primaryIndex(const QString& tablename) const
return idx;
}
-QSqlRecord QMYSQLDriver::record(const QString& tablename) const
+QSqlRecord QMYSQLDriver::record(const QString &tablename) const
{
Q_D(const QMYSQLDriver);
- QString table=tablename;
- if(isIdentifierEscaped(table, QSqlDriver::TableName))
- table = stripDelimiters(table, QSqlDriver::TableName);
-
- QSqlRecord info;
if (!isOpen())
- return info;
- MYSQL_RES* r = mysql_list_fields(d->mysql, table.toLocal8Bit().constData(), 0);
- if (!r) {
- return info;
+ return {};
+ QSqlQuery i(createResult());
+ QString stmt("SELECT * FROM %1 LIMIT 0"_L1);
+ i.exec(stmt.arg(escapeIdentifier(tablename, QSqlDriver::TableName)));
+ auto r = i.record();
+ if (r.isEmpty())
+ return r;
+ // no binding of WHERE possible with MySQL
+ // escaping on WHERE clause does not work, so use mysql_real_escape_string()
+ stmt = "SELECT column_name, column_default FROM information_schema.columns WHERE table_name = '%1'"_L1;
+ const auto baTableName = tablename.toUtf8();
+ QVarLengthArray<char> tableNameQuoted(baTableName.size() * 2 + 1);
+#if defined(MARIADB_VERSION_ID)
+ const auto len = mysql_real_escape_string(d->mysql, tableNameQuoted.data(),
+ baTableName.data(), baTableName.size());
+#else
+ const auto len = mysql_real_escape_string_quote(d->mysql, tableNameQuoted.data(),
+ baTableName.data(), baTableName.size(), '\'');
+#endif
+ if (i.exec(stmt.arg(QString::fromUtf8(tableNameQuoted.data(), len)))) {
+ while (i.next()) {
+ const auto colName = i.value(0).toString();
+ const auto recordIdx = r.indexOf(colName);
+ if (recordIdx >= 0) {
+ auto field = r.field(recordIdx);
+ field.setDefaultValue(i.value(1));
+ r.replace(recordIdx, field);
+ }
+ }
}
- MYSQL_FIELD* field;
-
- while ((field = mysql_fetch_field(r)))
- info.append(qToField(field, d->tc));
- mysql_free_result(r);
- return info;
+ return r;
}
QVariant QMYSQLDriver::handle() const
@@ -1490,11 +1541,8 @@ QVariant QMYSQLDriver::handle() const
bool QMYSQLDriver::beginTransaction()
{
Q_D(QMYSQLDriver);
-#ifndef CLIENT_TRANSACTIONS
- return false;
-#endif
if (!isOpen()) {
- qWarning("QMYSQLDriver::beginTransaction: Database not open");
+ qCWarning(lcMysql, "QMYSQLDriver::beginTransaction: Database not open");
return false;
}
if (mysql_query(d->mysql, "BEGIN WORK")) {
@@ -1508,11 +1556,8 @@ bool QMYSQLDriver::beginTransaction()
bool QMYSQLDriver::commitTransaction()
{
Q_D(QMYSQLDriver);
-#ifndef CLIENT_TRANSACTIONS
- return false;
-#endif
if (!isOpen()) {
- qWarning("QMYSQLDriver::commitTransaction: Database not open");
+ qCWarning(lcMysql, "QMYSQLDriver::commitTransaction: Database not open");
return false;
}
if (mysql_query(d->mysql, "COMMIT")) {
@@ -1526,11 +1571,8 @@ bool QMYSQLDriver::commitTransaction()
bool QMYSQLDriver::rollbackTransaction()
{
Q_D(QMYSQLDriver);
-#ifndef CLIENT_TRANSACTIONS
- return false;
-#endif
if (!isOpen()) {
- qWarning("QMYSQLDriver::rollbackTransaction: Database not open");
+ qCWarning(lcMysql, "QMYSQLDriver::rollbackTransaction: Database not open");
return false;
}
if (mysql_query(d->mysql, "ROLLBACK")) {
@@ -1548,30 +1590,41 @@ QString QMYSQLDriver::formatValue(const QSqlField &field, bool trimStrings) cons
if (field.isNull()) {
r = QStringLiteral("NULL");
} else {
- switch (+field.type()) {
+ switch (field.metaType().id()) {
case QMetaType::Double:
r = QString::number(field.value().toDouble(), 'g', field.precision());
break;
case QMetaType::QString:
// Escape '\' characters
r = QSqlDriver::formatValue(field, trimStrings);
- r.replace(QLatin1String("\\"), QLatin1String("\\\\"));
+ r.replace("\\"_L1, "\\\\"_L1);
break;
case QMetaType::QByteArray:
if (isOpen()) {
const QByteArray ba = field.value().toByteArray();
// buffer has to be at least length*2+1 bytes
- char* buffer = new char[ba.size() * 2 + 1];
- int escapedSize = int(mysql_real_escape_string(d->mysql, buffer,
- ba.data(), ba.size()));
+ QVarLengthArray<char, 512> buffer(ba.size() * 2 + 1);
+ auto escapedSize = mysql_real_escape_string(d->mysql, buffer.data(), ba.data(), ba.size());
r.reserve(escapedSize + 3);
- r.append(QLatin1Char('\'')).append(toUnicode(d->tc, buffer)).append(QLatin1Char('\''));
- delete[] buffer;
+ r = u'\'' + QString::fromUtf8(buffer.data(), escapedSize) + u'\'';
break;
} else {
- qWarning("QMYSQLDriver::formatValue: Database not open");
+ qCWarning(lcMysql, "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.
+ r = u'\'' +
+ dt.date().toString(Qt::ISODate) +
+ u'T' +
+ dt.time().toString(Qt::ISODate) +
+ u'\'';
}
- // fall through
+ break;
default:
r = QSqlDriver::formatValue(field, trimStrings);
}
@@ -1582,9 +1635,9 @@ QString QMYSQLDriver::formatValue(const QSqlField &field, bool trimStrings) cons
QString QMYSQLDriver::escapeIdentifier(const QString &identifier, IdentifierType) const
{
QString res = identifier;
- if(!identifier.isEmpty() && !identifier.startsWith(QLatin1Char('`')) && !identifier.endsWith(QLatin1Char('`')) ) {
- res.prepend(QLatin1Char('`')).append(QLatin1Char('`'));
- res.replace(QLatin1Char('.'), QLatin1String("`.`"));
+ if (!identifier.isEmpty() && !identifier.startsWith(u'`') && !identifier.endsWith(u'`')) {
+ res.replace(u'.', "`.`"_L1);
+ res = u'`' + res + u'`';
}
return res;
}
@@ -1593,8 +1646,10 @@ bool QMYSQLDriver::isIdentifierEscaped(const QString &identifier, IdentifierType
{
Q_UNUSED(type);
return identifier.size() > 2
- && identifier.startsWith(QLatin1Char('`')) //left delimited
- && identifier.endsWith(QLatin1Char('`')); //right delimited
+ && identifier.startsWith(u'`') //left delimited
+ && identifier.endsWith(u'`'); //right delimited
}
QT_END_NAMESPACE
+
+#include "moc_qsql_mysql_p.cpp"
diff --git a/src/plugins/sqldrivers/mysql/qsql_mysql_p.h b/src/plugins/sqldrivers/mysql/qsql_mysql_p.h
index 9ccc8f4e4f..ae3334d35e 100644
--- a/src/plugins/sqldrivers/mysql/qsql_mysql_p.h
+++ b/src/plugins/sqldrivers/mysql/qsql_mysql_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtSql module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QSQL_MYSQL_H
#define QSQL_MYSQL_H
diff --git a/src/plugins/sqldrivers/oci/CMakeLists.txt b/src/plugins/sqldrivers/oci/CMakeLists.txt
index 713c9fc871..66c4219905 100644
--- a/src/plugins/sqldrivers/oci/CMakeLists.txt
+++ b/src/plugins/sqldrivers/oci/CMakeLists.txt
@@ -1,32 +1,32 @@
-# Generated from oci.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## QOCIDriverPlugin Plugin:
#####################################################################
-qt_add_plugin(QOCIDriverPlugin
+qt_internal_add_plugin(QOCIDriverPlugin
OUTPUT_NAME qsqloci
- TYPE sqldrivers
+ PLUGIN_TYPE sqldrivers
SOURCES
main.cpp
qsql_oci.cpp qsql_oci_p.h
DEFINES
QT_NO_CAST_FROM_ASCII
QT_NO_CAST_TO_ASCII
- PUBLIC_LIBRARIES
+ LIBRARIES
Oracle::OCI
Qt::Core
Qt::CorePrivate
Qt::SqlPrivate
)
-#### Keys ignored in scope 1:.:.:oci.pro:<TRUE>:
-# OTHER_FILES = "oci.json"
-
## Scopes:
#####################################################################
-qt_extend_target(QOCIDriverPlugin CONDITION APPLE
+qt_internal_extend_target(QOCIDriverPlugin CONDITION APPLE
LINK_OPTIONS
"-Wl,-flat_namespace,-U,_environ"
)
+
+qt_internal_force_macos_intel_arch(QOCIDriverPlugin)
diff --git a/src/plugins/sqldrivers/oci/main.cpp b/src/plugins/sqldrivers/oci/main.cpp
index db273bfb04..6cc0062671 100644
--- a/src/plugins/sqldrivers/oci/main.cpp
+++ b/src/plugins/sqldrivers/oci/main.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <qsqldriverplugin.h>
#include <qstringlist.h>
@@ -43,6 +7,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
class QOCIDriverPlugin : public QSqlDriverPlugin
{
Q_OBJECT
@@ -51,7 +17,7 @@ class QOCIDriverPlugin : public QSqlDriverPlugin
public:
QOCIDriverPlugin();
- QSqlDriver* create(const QString &);
+ QSqlDriver* create(const QString &) override;
};
QOCIDriverPlugin::QOCIDriverPlugin()
@@ -61,7 +27,7 @@ QOCIDriverPlugin::QOCIDriverPlugin()
QSqlDriver* QOCIDriverPlugin::create(const QString &name)
{
- if (name == QLatin1String("QOCI")) {
+ if (name == "QOCI"_L1) {
QOCIDriver* driver = new QOCIDriver();
return driver;
}
diff --git a/src/plugins/sqldrivers/oci/oci.pro b/src/plugins/sqldrivers/oci/oci.pro
deleted file mode 100644
index e6ef71f20f..0000000000
--- a/src/plugins/sqldrivers/oci/oci.pro
+++ /dev/null
@@ -1,13 +0,0 @@
-TARGET = qsqloci
-
-HEADERS += $$PWD/qsql_oci_p.h
-SOURCES += $$PWD/qsql_oci.cpp $$PWD/main.cpp
-
-QMAKE_USE += oci
-
-darwin:QMAKE_LFLAGS += -Wl,-flat_namespace,-U,_environ
-
-OTHER_FILES += oci.json
-
-PLUGIN_CLASS_NAME = QOCIDriverPlugin
-include(../qsqldriverbase.pri)
diff --git a/src/plugins/sqldrivers/oci/qsql_oci.cpp b/src/plugins/sqldrivers/oci/qsql_oci.cpp
index aee8e92b36..68e303490d 100644
--- a/src/plugins/sqldrivers/oci/qsql_oci.cpp
+++ b/src/plugins/sqldrivers/oci/qsql_oci.cpp
@@ -1,49 +1,17 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtSql module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and 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$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qsql_oci_p.h"
#include <qcoreapplication.h>
-#include <qvariant.h>
#include <qdatetime.h>
+#include <qdebug.h>
+#include <qlist.h>
+#include <qloggingcategory.h>
#include <qmetatype.h>
-#include <qregexp.h>
+#if QT_CONFIG(regularexpression)
+#include <qregularexpression.h>
+#endif
#include <qshareddata.h>
#include <qsqlerror.h>
#include <qsqlfield.h>
@@ -52,24 +20,18 @@
#include <QtSql/private/qsqlcachedresult_p.h>
#include <QtSql/private/qsqldriver_p.h>
#include <qstringlist.h>
-#include <qvarlengtharray.h>
-#include <qvector.h>
-#include <qdebug.h>
+#if QT_CONFIG(timezone)
#include <qtimezone.h>
+#endif
+#include <qvariant.h>
+#include <qvarlengtharray.h>
// This is needed for oracle oci when compiling with mingw-w64 headers
#if defined(__MINGW64_VERSION_MAJOR) && defined(_WIN64)
#define _int64 __int64
#endif
-
#include <oci.h>
-#ifdef max
-#undef max
-#endif
-#ifdef min
-#undef min
-#endif
#include <stdlib.h>
@@ -90,6 +52,10 @@ Q_DECLARE_METATYPE(OCIStmt*)
QT_BEGIN_NAMESPACE
+static Q_LOGGING_CATEGORY(lcOci, "qt.sql.oci")
+
+using namespace Qt::StringLiterals;
+
#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
enum { QOCIEncoding = 2002 }; // AL16UTF16LE
#else
@@ -170,8 +136,8 @@ QOCIDateTime::QOCIDateTime(OCIEnv *env, OCIError *err, const QDateTime &dt)
if (dt.isValid()) {
const QDate date = dt.date();
const QTime time = dt.time();
- // Zone in +hh:mm format (stripping UTC prefix from OffsetName)
- QString timeZone = dt.timeZone().displayName(dt, QTimeZone::OffsetName).mid(3);
+ // Zone in +hh:mm format
+ const QString timeZone = dt.toString("ttt"_L1);
const OraText *tz = reinterpret_cast<const OraText *>(timeZone.utf16());
OCIDateTimeConstruct(env, err, dateTime, date.year(), date.month(), date.day(), time.hour(),
time.minute(), time.second(), time.msec() * 1000000,
@@ -200,7 +166,7 @@ QDateTime QOCIDateTime::fromOCIDateTime(OCIEnv *env, OCIError *err, OCIDateTime
secondsOffset = -secondsOffset;
// OCIDateTimeGetTime gives "fractions of second" as nanoseconds
return QDateTime(QDate(year, month, day), QTime(hour, minute, second, nsec / 1000000),
- Qt::OffsetFromUTC, secondsOffset);
+ QTimeZone::fromSecondsAheadOfUtc(secondsOffset));
}
struct TempStorage {
@@ -220,15 +186,17 @@ 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;
+ ub4 authMode = OCI_DEFAULT;
+ bool transaction = false;
+ int serverVersion = -1;
+ int prefetchRows = -1;
+ int prefetchMem = QOCI_PREFETCH_MEM;
QString user;
void allocErrorHandle();
@@ -269,11 +237,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;
@@ -281,9 +249,9 @@ public:
void setStatementAttributes();
int bindValue(OCIStmt *sql, OCIBind **hbnd, OCIError *err, int pos,
const QVariant &val, dvoid *indPtr, ub2 *tmpSize, TempStorage &tmpStorage);
- int bindValues(QVector<QVariant> &values, IndicatorArray &indicators, SizeArray &tmpSizes,
+ int bindValues(QVariantList &values, IndicatorArray &indicators, SizeArray &tmpSizes,
TempStorage &tmpStorage);
- void outValues(QVector<QVariant> &values, IndicatorArray &indicators,
+ void outValues(QVariantList &values, IndicatorArray &indicators,
TempStorage &tmpStorage);
inline bool isOutValue(int i) const
{ Q_Q(const QOCIResult); return q->bindValueType(i) & QSql::Out; }
@@ -308,7 +276,7 @@ public:
0);
#ifdef QOCI_DEBUG
if (r != 0)
- qWarning("QOCIResultPrivate::setCharset: Couldn't set OCI_ATTR_CHARSET_FORM.");
+ qCWarning(lcOci, "QOCIResultPrivate::setCharset: Couldn't set OCI_ATTR_CHARSET_FORM.");
#endif
#endif
@@ -362,8 +330,8 @@ int QOCIResultPrivate::bindValue(OCIStmt *sql, OCIBind **hbnd, OCIError *err, in
int r = OCI_SUCCESS;
void *data = const_cast<void *>(val.constData());
- switch (val.type()) {
- case QVariant::ByteArray:
+ switch (val.typeId()) {
+ case QMetaType::QByteArray:
r = OCIBindByPos(sql, hbnd, err,
pos + 1,
isOutValue(pos)
@@ -372,9 +340,9 @@ int QOCIResultPrivate::bindValue(OCIStmt *sql, OCIBind **hbnd, OCIError *err, in
reinterpret_cast<QByteArray *>(data)->size(),
SQLT_BIN, indPtr, 0, 0, 0, 0, OCI_DEFAULT);
break;
- case QVariant::Time:
- case QVariant::Date:
- case QVariant::DateTime: {
+ case QMetaType::QTime:
+ case QMetaType::QDate:
+ case QMetaType::QDateTime: {
QOCIDateTime *ptr = new QOCIDateTime(env, err, val.toDateTime());
r = OCIBindByPos(sql, hbnd, err,
pos + 1,
@@ -384,7 +352,7 @@ int QOCIResultPrivate::bindValue(OCIStmt *sql, OCIBind **hbnd, OCIError *err, in
tmpStorage.dateTimes.append(ptr);
break;
}
- case QVariant::Int:
+ case QMetaType::Int:
r = OCIBindByPos(sql, hbnd, err,
pos + 1,
// if it's an out value, the data is already detached
@@ -393,7 +361,7 @@ int QOCIResultPrivate::bindValue(OCIStmt *sql, OCIBind **hbnd, OCIError *err, in
sizeof(int),
SQLT_INT, indPtr, 0, 0, 0, 0, OCI_DEFAULT);
break;
- case QVariant::UInt:
+ case QMetaType::UInt:
r = OCIBindByPos(sql, hbnd, err,
pos + 1,
// if it's an out value, the data is already detached
@@ -402,7 +370,7 @@ int QOCIResultPrivate::bindValue(OCIStmt *sql, OCIBind **hbnd, OCIError *err, in
sizeof(uint),
SQLT_UIN, indPtr, 0, 0, 0, 0, OCI_DEFAULT);
break;
- case QVariant::LongLong:
+ case QMetaType::LongLong:
{
QByteArray ba = qMakeOCINumber(val.toLongLong(), err);
r = OCIBindByPos(sql, hbnd, err,
@@ -413,7 +381,7 @@ int QOCIResultPrivate::bindValue(OCIStmt *sql, OCIBind **hbnd, OCIError *err, in
tmpStorage.rawData.append(ba);
break;
}
- case QVariant::ULongLong:
+ case QMetaType::ULongLong:
{
QByteArray ba = qMakeOCINumber(val.toULongLong(), err);
r = OCIBindByPos(sql, hbnd, err,
@@ -424,7 +392,7 @@ int QOCIResultPrivate::bindValue(OCIStmt *sql, OCIBind **hbnd, OCIError *err, in
tmpStorage.rawData.append(ba);
break;
}
- case QVariant::Double:
+ case QMetaType::Double:
r = OCIBindByPos(sql, hbnd, err,
pos + 1,
// if it's an out value, the data is already detached
@@ -433,22 +401,7 @@ int QOCIResultPrivate::bindValue(OCIStmt *sql, OCIBind **hbnd, OCIError *err, in
sizeof(double),
SQLT_FLT, indPtr, 0, 0, 0, 0, OCI_DEFAULT);
break;
- case QVariant::UserType:
- if (val.canConvert<QOCIRowIdPointer>() && !isOutValue(pos)) {
- // use a const pointer to prevent a detach
- const QOCIRowIdPointer rptr = qvariant_cast<QOCIRowIdPointer>(val);
- r = OCIBindByPos(sql, hbnd, err,
- pos + 1,
- // it's an IN value, so const_cast is ok
- const_cast<OCIRowid **>(&rptr->id),
- -1,
- SQLT_RDD, indPtr, 0, 0, 0, 0, OCI_DEFAULT);
- } else {
- qWarning("Unknown bind variable");
- r = OCI_ERROR;
- }
- break;
- case QVariant::String: {
+ case QMetaType::QString: {
const QString s = val.toString();
if (isBinaryValue(pos)) {
r = OCIBindByPos(sql, hbnd, err,
@@ -470,28 +423,45 @@ int QOCIResultPrivate::bindValue(OCIStmt *sql, OCIBind **hbnd, OCIError *err, in
break;
}
} // fall through for OUT values
+ Q_FALLTHROUGH();
default: {
- const QString s = val.toString();
- // create a deep-copy
- QByteArray ba(reinterpret_cast<const char *>(s.utf16()), (s.length() + 1) * sizeof(QChar));
- if (isOutValue(pos)) {
- ba.reserve((s.capacity() + 1) * sizeof(QChar));
- *tmpSize = ba.size();
- r = OCIBindByPos(sql, hbnd, err,
- pos + 1,
- ba.data(),
- ba.capacity(),
- SQLT_STR, indPtr, tmpSize, 0, 0, 0, OCI_DEFAULT);
+ if (val.typeId() >= QMetaType::User) {
+ if (val.canConvert<QOCIRowIdPointer>() && !isOutValue(pos)) {
+ // use a const pointer to prevent a detach
+ const QOCIRowIdPointer rptr = qvariant_cast<QOCIRowIdPointer>(val);
+ r = OCIBindByPos(sql, hbnd, err,
+ pos + 1,
+ // it's an IN value, so const_cast is ok
+ const_cast<OCIRowid **>(&rptr->id),
+ -1,
+ SQLT_RDD, indPtr, 0, 0, 0, 0, OCI_DEFAULT);
+ } else {
+ qCWarning(lcOci, "Unknown bind variable");
+ r = OCI_ERROR;
+ }
} else {
- r = OCIBindByPos(sql, hbnd, err,
- pos + 1,
- ba.data(),
- ba.size(),
- SQLT_STR, indPtr, 0, 0, 0, 0, OCI_DEFAULT);
+ const QString s = val.toString();
+ // create a deep-copy
+ QByteArray ba(reinterpret_cast<const char *>(s.utf16()), (s.length() + 1) * sizeof(QChar));
+ if (isOutValue(pos)) {
+ ba.reserve((s.capacity() + 1) * sizeof(QChar));
+ *tmpSize = ba.size();
+ r = OCIBindByPos(sql, hbnd, err,
+ pos + 1,
+ ba.data(),
+ ba.capacity(),
+ SQLT_STR, indPtr, tmpSize, 0, 0, 0, OCI_DEFAULT);
+ } else {
+ r = OCIBindByPos(sql, hbnd, err,
+ pos + 1,
+ ba.data(),
+ ba.size(),
+ SQLT_STR, indPtr, 0, 0, 0, 0, OCI_DEFAULT);
+ }
+ if (r == OCI_SUCCESS)
+ setCharset(*hbnd, OCI_HTYPE_BIND);
+ tmpStorage.rawData.append(ba);
}
- if (r == OCI_SUCCESS)
- setCharset(*hbnd, OCI_HTYPE_BIND);
- tmpStorage.rawData.append(ba);
break;
} // default case
} // switch
@@ -500,7 +470,7 @@ int QOCIResultPrivate::bindValue(OCIStmt *sql, OCIBind **hbnd, OCIError *err, in
return r;
}
-int QOCIResultPrivate::bindValues(QVector<QVariant> &values, IndicatorArray &indicators,
+int QOCIResultPrivate::bindValues(QVariantList &values, IndicatorArray &indicators,
SizeArray &tmpSizes, TempStorage &tmpStorage)
{
int r = OCI_SUCCESS;
@@ -509,9 +479,9 @@ int QOCIResultPrivate::bindValues(QVector<QVariant> &values, IndicatorArray &ind
values[i].detach();
const QVariant &val = values.at(i);
- OCIBind * hbnd = 0; // Oracle handles these automatically
+ OCIBind * hbnd = nullptr; // Oracle handles these automatically
sb2 *indPtr = &indicators[i];
- *indPtr = val.isNull() ? -1 : 0;
+ *indPtr = QSqlResultPrivate::isVariantNull(val) ? -1 : 0;
bindValue(sql, &hbnd, err, i, val, indPtr, &tmpSizes[i], tmpStorage);
}
@@ -521,26 +491,26 @@ int QOCIResultPrivate::bindValues(QVector<QVariant> &values, IndicatorArray &ind
// will assign out value and remove its temp storage.
static void qOraOutValue(QVariant &value, TempStorage &tmpStorage, OCIEnv *env, OCIError* err)
{
- switch (value.type()) {
- case QVariant::Time:
+ switch (value.typeId()) {
+ case QMetaType::QTime:
value = QOCIDateTime::fromOCIDateTime(env, err,
tmpStorage.dateTimes.takeFirst()->dateTime).time();
break;
- case QVariant::Date:
+ case QMetaType::QDate:
value = QOCIDateTime::fromOCIDateTime(env, err,
tmpStorage.dateTimes.takeFirst()->dateTime).date();
break;
- case QVariant::DateTime:
+ case QMetaType::QDateTime:
value = QOCIDateTime::fromOCIDateTime(env, err,
tmpStorage.dateTimes.takeFirst()->dateTime);
break;
- case QVariant::LongLong:
+ case QMetaType::LongLong:
value = qMakeLongLong(tmpStorage.rawData.takeFirst(), err);
break;
- case QVariant::ULongLong:
+ case QMetaType::ULongLong:
value = qMakeULongLong(tmpStorage.rawData.takeFirst(), err);
break;
- case QVariant::String:
+ case QMetaType::QString:
value = QString(
reinterpret_cast<const QChar *>(tmpStorage.rawData.takeFirst().constData()));
break;
@@ -549,7 +519,7 @@ static void qOraOutValue(QVariant &value, TempStorage &tmpStorage, OCIEnv *env,
}
}
-void QOCIResultPrivate::outValues(QVector<QVariant> &values, IndicatorArray &indicators,
+void QOCIResultPrivate::outValues(QVariantList &values, IndicatorArray &indicators,
TempStorage &tmpStorage)
{
for (int i = 0; i < values.count(); ++i) {
@@ -559,7 +529,7 @@ void QOCIResultPrivate::outValues(QVector<QVariant> &values, IndicatorArray &ind
qOraOutValue(values[i], tmpStorage, env, err);
- QVariant::Type typ = values.at(i).type();
+ auto typ = values.at(i).metaType();
if (indicators[i] == -1) // NULL
values[i] = QVariant(typ);
else
@@ -569,27 +539,26 @@ void QOCIResultPrivate::outValues(QVector<QVariant> &values, IndicatorArray &ind
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)
- qWarning("QOCIDriver: unable to allocate error handle");
+ 0, nullptr);
+ if (r != OCI_SUCCESS)
+ qCWarning(lcOci, "QOCIDriver: unable to allocate error handle");
}
struct OraFieldInfo
{
QString name;
- QVariant::Type type;
+ QMetaType type;
ub1 oraIsNull;
ub4 oraType;
sb1 oraScale;
@@ -619,12 +588,7 @@ QString qOraWarn(OCIError *err, int *errorCode)
void qOraWarning(const char* msg, OCIError *err)
{
-#ifdef QOCI_DEBUG
- qWarning("%s %s", msg, qPrintable(qOraWarn(err)));
-#else
- Q_UNUSED(msg);
- Q_UNUSED(err);
-#endif
+ qCWarning(lcOci, "%s %ls", msg, qUtf16Printable(qOraWarn(err)));
}
static int qOraErrorNumber(OCIError *err)
@@ -648,53 +612,52 @@ QSqlError qMakeError(const QString& errString, QSqlError::ErrorType type, OCIErr
errorCode != -1 ? QString::number(errorCode) : QString());
}
-QVariant::Type qDecodeOCIType(const QString& ocitype, QSql::NumericalPrecisionPolicy precisionPolicy)
+QMetaType qDecodeOCIType(const QString& ocitype, QSql::NumericalPrecisionPolicy precisionPolicy)
{
- QVariant::Type type = QVariant::Invalid;
- if (ocitype == QLatin1String("VARCHAR2") || ocitype == QLatin1String("VARCHAR")
- || ocitype.startsWith(QLatin1String("INTERVAL"))
- || ocitype == QLatin1String("CHAR") || ocitype == QLatin1String("NVARCHAR2")
- || ocitype == QLatin1String("NCHAR"))
- type = QVariant::String;
- else if (ocitype == QLatin1String("NUMBER")
- || ocitype == QLatin1String("FLOAT")
- || ocitype == QLatin1String("BINARY_FLOAT")
- || ocitype == QLatin1String("BINARY_DOUBLE")) {
+ int type = QMetaType::UnknownType;
+ if (ocitype == "VARCHAR2"_L1 || ocitype == "VARCHAR"_L1
+ || ocitype.startsWith("INTERVAL"_L1)
+ || ocitype == "CHAR"_L1 || ocitype == "NVARCHAR2"_L1
+ || ocitype == "NCHAR"_L1)
+ type = QMetaType::QString;
+ else if (ocitype == "NUMBER"_L1
+ || ocitype == "FLOAT"_L1
+ || ocitype == "BINARY_FLOAT"_L1
+ || ocitype == "BINARY_DOUBLE"_L1) {
switch(precisionPolicy) {
case QSql::LowPrecisionInt32:
- type = QVariant::Int;
+ type = QMetaType::Int;
break;
case QSql::LowPrecisionInt64:
- type = QVariant::LongLong;
+ type = QMetaType::LongLong;
break;
case QSql::LowPrecisionDouble:
- type = QVariant::Double;
+ type = QMetaType::Double;
break;
case QSql::HighPrecision:
default:
- type = QVariant::String;
+ type = QMetaType::QString;
break;
}
}
- else if (ocitype == QLatin1String("LONG") || ocitype == QLatin1String("NCLOB")
- || ocitype == QLatin1String("CLOB"))
- type = QVariant::ByteArray;
- else if (ocitype == QLatin1String("RAW") || ocitype == QLatin1String("LONG RAW")
- || ocitype == QLatin1String("ROWID") || ocitype == QLatin1String("BLOB")
- || ocitype == QLatin1String("CFILE") || ocitype == QLatin1String("BFILE"))
- type = QVariant::ByteArray;
- else if (ocitype == QLatin1String("DATE") || ocitype.startsWith(QLatin1String("TIME")))
- type = QVariant::DateTime;
- else if (ocitype == QLatin1String("UNDEFINED"))
- type = QVariant::Invalid;
- if (type == QVariant::Invalid)
- qWarning("qDecodeOCIType: unknown type: %s", ocitype.toLocal8Bit().constData());
- return type;
-}
-
-QVariant::Type qDecodeOCIType(int ocitype, QSql::NumericalPrecisionPolicy precisionPolicy)
-{
- QVariant::Type type = QVariant::Invalid;
+ else if (ocitype == "LONG"_L1 || ocitype == "NCLOB"_L1 || ocitype == "CLOB"_L1)
+ type = QMetaType::QByteArray;
+ else if (ocitype == "RAW"_L1 || ocitype == "LONG RAW"_L1
+ || ocitype == "ROWID"_L1 || ocitype == "BLOB"_L1
+ || ocitype == "CFILE"_L1 || ocitype == "BFILE"_L1)
+ type = QMetaType::QByteArray;
+ else if (ocitype == "DATE"_L1 || ocitype.startsWith("TIME"_L1))
+ type = QMetaType::QDateTime;
+ else if (ocitype == "UNDEFINED"_L1)
+ type = QMetaType::UnknownType;
+ if (type == QMetaType::UnknownType)
+ qCWarning(lcOci, "qDecodeOCIType: unknown type: %ls", qUtf16Printable(ocitype));
+ return QMetaType(type);
+}
+
+QMetaType qDecodeOCIType(int ocitype, QSql::NumericalPrecisionPolicy precisionPolicy)
+{
+ int type = QMetaType::UnknownType;
switch (ocitype) {
case SQLT_STR:
case SQLT_VST:
@@ -710,10 +673,10 @@ QVariant::Type qDecodeOCIType(int ocitype, QSql::NumericalPrecisionPolicy precis
#ifdef SQLT_INTERVAL_DS
case SQLT_INTERVAL_DS:
#endif
- type = QVariant::String;
+ type = QMetaType::QString;
break;
case SQLT_INT:
- type = QVariant::Int;
+ type = QMetaType::Int;
break;
case SQLT_FLT:
case SQLT_NUM:
@@ -721,17 +684,17 @@ QVariant::Type qDecodeOCIType(int ocitype, QSql::NumericalPrecisionPolicy precis
case SQLT_UIN:
switch(precisionPolicy) {
case QSql::LowPrecisionInt32:
- type = QVariant::Int;
+ type = QMetaType::Int;
break;
case QSql::LowPrecisionInt64:
- type = QVariant::LongLong;
+ type = QMetaType::LongLong;
break;
case QSql::LowPrecisionDouble:
- type = QVariant::Double;
+ type = QMetaType::Double;
break;
case QSql::HighPrecision:
default:
- type = QVariant::String;
+ type = QMetaType::QString;
break;
}
break;
@@ -746,21 +709,20 @@ QVariant::Type qDecodeOCIType(int ocitype, QSql::NumericalPrecisionPolicy precis
case SQLT_NTY:
case SQLT_REF:
case SQLT_RID:
- type = QVariant::ByteArray;
+ type = QMetaType::QByteArray;
break;
case SQLT_DAT:
case SQLT_ODT:
case SQLT_TIMESTAMP:
case SQLT_TIMESTAMP_TZ:
case SQLT_TIMESTAMP_LTZ:
- type = QVariant::DateTime;
+ type = QMetaType::QDateTime;
break;
default:
- type = QVariant::Invalid;
- qWarning("qDecodeOCIType: unknown OCI datatype: %d", ocitype);
+ qCWarning(lcOci, "qDecodeOCIType: unknown OCI datatype: %d", ocitype);
break;
}
- return type;
+ return QMetaType(type);
}
static QSqlField qFromOraInf(const OraFieldInfo &ofi)
@@ -768,13 +730,12 @@ static QSqlField qFromOraInf(const OraFieldInfo &ofi)
QSqlField f(ofi.name, ofi.type);
f.setRequired(ofi.oraIsNull == 0);
- if (ofi.type == QVariant::String && ofi.oraType != SQLT_NUM && ofi.oraType != SQLT_VNU)
+ if (ofi.type.id() == QMetaType::QString && ofi.oraType != SQLT_NUM && ofi.oraType != SQLT_VNU)
f.setLength(ofi.oraFieldLength);
else
f.setLength(ofi.oraPrecision == 0 ? 38 : int(ofi.oraPrecision));
f.setPrecision(ofi.oraScale);
- f.setSqlType(int(ofi.oraType));
return f;
}
@@ -833,12 +794,12 @@ class QOCICols
public:
QOCICols(int size, QOCIResultPrivate* dp);
~QOCICols();
- int readPiecewise(QVector<QVariant> &values, int index = 0);
- int readLOBs(QVector<QVariant> &values, int index = 0);
+ int readPiecewise(QVariantList &values, int index = 0);
+ int readLOBs(QVariantList &values, int index = 0);
int fieldFromDefine(OCIDefine* d);
- void getValues(QVector<QVariant> &v, int index);
+ void getValues(QVariantList &v, int index);
inline int size() { return fieldInf.size(); }
- static bool execBatch(QOCIResultPrivate *d, QVector<QVariant> &boundValues, bool arrayBind);
+ static bool execBatch(QOCIResultPrivate *d, QVariantList &boundValues, bool arrayBind);
QSqlRecord rec;
@@ -850,20 +811,20 @@ private:
class OraFieldInf
{
public:
- OraFieldInf() : data(0), len(0), ind(0), typ(QVariant::Invalid), oraType(0), def(0), lob(0), dataPtr(nullptr)
+ OraFieldInf() : data(0), len(0), ind(0), oraType(0), def(0), lob(0), dataPtr(nullptr)
{}
~OraFieldInf();
char *data;
int len;
sb2 ind;
- QVariant::Type typ;
+ QMetaType typ;
ub4 oraType;
OCIDefine *def;
OCILobLocator *lob;
void *dataPtr;
};
- QVector<OraFieldInf> fieldInf;
+ QList<OraFieldInf> fieldInf;
const QOCIResultPrivate *const d;
};
@@ -873,16 +834,16 @@ QOCICols::OraFieldInf::~OraFieldInf()
if (lob) {
int r = OCIDescriptorFree(lob, OCI_DTYPE_LOB);
if (r != 0)
- qWarning("QOCICols: Cannot free LOB descriptor");
+ qCWarning(lcOci, "QOCICols: Cannot free LOB descriptor");
}
if (dataPtr) {
- switch (typ) {
- case QVariant::Date:
- case QVariant::Time:
- case QVariant::DateTime: {
+ switch (typ.id()) {
+ case QMetaType::QDate:
+ case QMetaType::QTime:
+ case QMetaType::QDateTime: {
int r = OCIDescriptorFree(dataPtr, OCI_DTYPE_TIMESTAMP_TZ);
if (r != OCI_SUCCESS)
- qWarning("QOCICols: Cannot free OCIDateTime descriptor");
+ qCWarning(lcOci, "QOCICols: Cannot free OCIDateTime descriptor");
break;
}
default:
@@ -895,10 +856,10 @@ QOCICols::QOCICols(int size, QOCIResultPrivate* dp)
: fieldInf(size), d(dp)
{
ub4 dataSize = 0;
- OCIDefine* dfn = 0;
+ OCIDefine *dfn = nullptr;
int r;
- OCIParam* param = 0;
+ OCIParam *param = nullptr;
sb4 parmStatus = 0;
ub4 count = 1;
int idx = 0;
@@ -933,11 +894,11 @@ QOCICols::QOCICols(int size, QOCIResultPrivate* dp)
fieldInf[idx].oraType = ofi.oraType;
rec.append(qFromOraInf(ofi));
- switch (ofi.type) {
- case QVariant::DateTime:
+ switch (ofi.type.id()) {
+ case QMetaType::QDateTime:
r = OCIDescriptorAlloc(d->env, (void **)&fieldInf[idx].dataPtr, OCI_DTYPE_TIMESTAMP_TZ, 0, 0);
if (r != OCI_SUCCESS) {
- qWarning("QOCICols: Unable to allocate the OCIDateTime descriptor");
+ qCWarning(lcOci, "QOCICols: Unable to allocate the OCIDateTime descriptor");
break;
}
r = OCIDefineByPos(d->sql,
@@ -950,7 +911,7 @@ QOCICols::QOCICols(int size, QOCIResultPrivate* dp)
&(fieldInf[idx].ind),
0, 0, OCI_DEFAULT);
break;
- case QVariant::Double:
+ case QMetaType::Double:
r = OCIDefineByPos(d->sql,
&dfn,
d->err,
@@ -961,7 +922,7 @@ QOCICols::QOCICols(int size, QOCIResultPrivate* dp)
&(fieldInf[idx].ind),
0, 0, OCI_DEFAULT);
break;
- case QVariant::Int:
+ case QMetaType::Int:
r = OCIDefineByPos(d->sql,
&dfn,
d->err,
@@ -972,7 +933,7 @@ QOCICols::QOCICols(int size, QOCIResultPrivate* dp)
&(fieldInf[idx].ind),
0, 0, OCI_DEFAULT);
break;
- case QVariant::LongLong:
+ case QMetaType::LongLong:
r = OCIDefineByPos(d->sql,
&dfn,
d->err,
@@ -983,7 +944,7 @@ QOCICols::QOCICols(int size, QOCIResultPrivate* dp)
&(fieldInf[idx].ind),
0, 0, OCI_DEFAULT);
break;
- case QVariant::ByteArray:
+ case QMetaType::QByteArray:
// RAW and LONG RAW fields can't be bound to LOB locators
if (ofi.oraType == SQLT_BIN) {
// qDebug("binding SQLT_BIN");
@@ -1030,7 +991,7 @@ QOCICols::QOCICols(int size, QOCIResultPrivate* dp)
0, 0, OCI_DEFAULT);
}
break;
- case QVariant::String:
+ case QMetaType::QString:
if (ofi.oraType == SQLT_LNG) {
r = OCIDefineByPos(d->sql,
&dfn,
@@ -1108,13 +1069,13 @@ OCILobLocator **QOCICols::createLobLocator(int position, OCIEnv* env)
0,
0);
if (r != 0) {
- qWarning("QOCICols: Cannot create LOB locator");
+ qCWarning(lcOci, "QOCICols: Cannot create LOB locator");
lob = 0;
}
return &lob;
}
-int QOCICols::readPiecewise(QVector<QVariant> &values, int index)
+int QOCICols::readPiecewise(QVariantList &values, int index)
{
OCIDefine* dfn;
ub4 typep;
@@ -1182,7 +1143,7 @@ OraFieldInfo QOCICols::qMakeOraField(const QOCIResultPrivate* p, OCIParam* param
{
OraFieldInfo ofi;
ub2 colType(0);
- text *colName = 0;
+ text *colName = nullptr;
ub4 colNameLen(0);
sb1 colScale(0);
ub2 colLength(0);
@@ -1190,7 +1151,6 @@ OraFieldInfo QOCICols::qMakeOraField(const QOCIResultPrivate* p, OCIParam* param
sb2 colPrecision(0);
ub1 colIsNull(0);
int r(0);
- QVariant::Type type(QVariant::Invalid);
r = OCIAttrGet(param,
OCI_DTYPE_PARAM,
@@ -1267,28 +1227,26 @@ OraFieldInfo QOCICols::qMakeOraField(const QOCIResultPrivate* p, OCIParam* param
if (r != 0)
qOraWarning("qMakeOraField:", p->err);
- type = qDecodeOCIType(colType, p->q_func()->numericalPrecisionPolicy());
+ QMetaType type = qDecodeOCIType(colType, p->q_func()->numericalPrecisionPolicy());
- if (type == QVariant::Int) {
- if (colLength == 22 && colPrecision == 0 && colScale == 0)
- type = QVariant::String;
- if (colScale > 0)
- type = QVariant::String;
+ if (type.id() == QMetaType::Int) {
+ if ((colLength == 22 && colPrecision == 0 && colScale == 0) || colScale > 0)
+ type = QMetaType(QMetaType::QString);
}
// bind as double if the precision policy asks for it
if (((colType == SQLT_FLT) || (colType == SQLT_NUM))
&& (p->q_func()->numericalPrecisionPolicy() == QSql::LowPrecisionDouble)) {
- type = QVariant::Double;
+ type = QMetaType(QMetaType::Double);
}
// bind as int32 or int64 if the precision policy asks for it
if ((colType == SQLT_NUM) || (colType == SQLT_VNU) || (colType == SQLT_UIN)
|| (colType == SQLT_INT)) {
if (p->q_func()->numericalPrecisionPolicy() == QSql::LowPrecisionInt64)
- type = QVariant::LongLong;
+ type = QMetaType(QMetaType::LongLong);
else if (p->q_func()->numericalPrecisionPolicy() == QSql::LowPrecisionInt32)
- type = QVariant::Int;
+ type = QMetaType(QMetaType::Int);
}
if (colType == SQLT_BLOB)
@@ -1326,7 +1284,7 @@ struct QOCIBatchColumn
struct QOCIBatchCleanupHandler
{
- inline QOCIBatchCleanupHandler(QVector<QOCIBatchColumn> &columns)
+ inline QOCIBatchCleanupHandler(QList<QOCIBatchColumn> &columns)
: col(columns) {}
~QOCIBatchCleanupHandler()
@@ -1339,42 +1297,41 @@ struct QOCIBatchCleanupHandler
}
}
- QVector<QOCIBatchColumn> &col;
+ QList<QOCIBatchColumn> &col;
};
-bool QOCICols::execBatch(QOCIResultPrivate *d, QVector<QVariant> &boundValues, bool arrayBind)
+bool QOCICols::execBatch(QOCIResultPrivate *d, QVariantList &boundValues, bool arrayBind)
{
int columnCount = boundValues.count();
if (boundValues.isEmpty() || columnCount == 0)
return false;
#ifdef QOCI_DEBUG
- qDebug() << "columnCount:" << columnCount << boundValues;
+ qCDebug(lcOci) << "columnCount:" << columnCount << boundValues;
#endif
int i;
sword r;
- QVarLengthArray<QVariant::Type> fieldTypes;
+ QVarLengthArray<QMetaType> fieldTypes;
for (i = 0; i < columnCount; ++i) {
- QVariant::Type tp = boundValues.at(i).type();
- fieldTypes.append(tp == QVariant::List ? boundValues.at(i).toList().value(0).type()
- : tp);
+ QMetaType tp = boundValues.at(i).metaType();
+ fieldTypes.append(tp.id() == QMetaType::QVariantList ? boundValues.at(i).toList().value(0).metaType() : tp);
}
SizeArray tmpSizes(columnCount);
- QVector<QOCIBatchColumn> columns(columnCount);
+ QList<QOCIBatchColumn> columns(columnCount);
QOCIBatchCleanupHandler cleaner(columns);
TempStorage tmpStorage;
// figuring out buffer sizes
for (i = 0; i < columnCount; ++i) {
- if (boundValues.at(i).type() != QVariant::List) {
+ if (boundValues.at(i).typeId() != QMetaType::QVariantList) {
// not a list - create a deep-copy of the single value
QOCIBatchColumn &singleCol = columns[i];
singleCol.indicators = new sb2[1];
- *singleCol.indicators = boundValues.at(i).isNull() ? -1 : 0;
+ *singleCol.indicators = QSqlResultPrivate::isVariantNull(boundValues.at(i)) ? -1 : 0;
r = d->bindValue(d->sql, &singleCol.bindh, d->err, i,
boundValues.at(i), singleCol.indicators, &tmpSizes[i], tmpStorage);
@@ -1397,49 +1354,44 @@ bool QOCICols::execBatch(QOCIResultPrivate *d, QVector<QVariant> &boundValues, b
col.maxarr_len = col.recordCount;
col.curelep = col.recordCount;
- switch (fieldTypes[i]) {
- case QVariant::Time:
- case QVariant::Date:
- case QVariant::DateTime:
+ switch (fieldTypes[i].id()) {
+ case QMetaType::QTime:
+ case QMetaType::QDate:
+ case QMetaType::QDateTime:
col.bindAs = SQLT_TIMESTAMP_TZ;
col.maxLen = sizeof(OCIDateTime *);
break;
- case QVariant::Int:
+ case QMetaType::Int:
col.bindAs = SQLT_INT;
col.maxLen = sizeof(int);
break;
- case QVariant::UInt:
+ case QMetaType::UInt:
col.bindAs = SQLT_UIN;
col.maxLen = sizeof(uint);
break;
- case QVariant::LongLong:
+ case QMetaType::LongLong:
col.bindAs = SQLT_VNU;
col.maxLen = sizeof(OCINumber);
break;
- case QVariant::ULongLong:
+ case QMetaType::ULongLong:
col.bindAs = SQLT_VNU;
col.maxLen = sizeof(OCINumber);
break;
- case QVariant::Double:
+ case QMetaType::Double:
col.bindAs = SQLT_FLT;
col.maxLen = sizeof(double);
break;
- case QVariant::UserType:
- col.bindAs = SQLT_RDD;
- col.maxLen = sizeof(OCIRowid*);
- break;
-
- case QVariant::String: {
+ case QMetaType::QString: {
col.bindAs = SQLT_STR;
for (uint j = 0; j < col.recordCount; ++j) {
uint len;
- if(d->isOutValue(i))
+ if (d->isOutValue(i))
len = boundValues.at(i).toList().at(j).toString().capacity() + 1;
else
len = boundValues.at(i).toList().at(j).toString().length() + 1;
@@ -1449,18 +1401,24 @@ bool QOCICols::execBatch(QOCIResultPrivate *d, QVector<QVariant> &boundValues, b
col.maxLen *= sizeof(QChar);
break; }
- case QVariant::ByteArray:
+ case QMetaType::QByteArray:
default: {
- col.bindAs = SQLT_LBI;
- for (uint j = 0; j < col.recordCount; ++j) {
- if(d->isOutValue(i))
- col.lengths[j] = boundValues.at(i).toList().at(j).toByteArray().capacity();
- else
- col.lengths[j] = boundValues.at(i).toList().at(j).toByteArray().size();
- if (col.lengths[j] > col.maxLen)
- col.maxLen = col.lengths[j];
+ if (fieldTypes[i].id() >= QMetaType::User) {
+ col.bindAs = SQLT_RDD;
+ col.maxLen = sizeof(OCIRowid*);
+ } else {
+ col.bindAs = SQLT_LBI;
+ for (uint j = 0; j < col.recordCount; ++j) {
+ if (d->isOutValue(i))
+ col.lengths[j] = boundValues.at(i).toList().at(j).toByteArray().capacity();
+ else
+ col.lengths[j] = boundValues.at(i).toList().at(j).toByteArray().size();
+ if (col.lengths[j] > col.maxLen)
+ col.maxLen = col.lengths[j];
+ }
}
- break; }
+ break;
+ }
}
col.data = new char[col.maxLen * col.recordCount];
@@ -1468,34 +1426,35 @@ bool QOCICols::execBatch(QOCIResultPrivate *d, QVector<QVariant> &boundValues, b
// we may now populate column with data
for (uint row = 0; row < col.recordCount; ++row) {
- const QVariant &val = boundValues.at(i).toList().at(row);
+ const QVariant val = boundValues.at(i).toList().at(row);
- if (val.isNull() && !d->isOutValue(i)) {
+ if (QSqlResultPrivate::isVariantNull(val) && !d->isOutValue(i)) {
columns[i].indicators[row] = -1;
columns[i].lengths[row] = 0;
} else {
columns[i].indicators[row] = 0;
char *dataPtr = columns[i].data + (columns[i].maxLen * row);
- switch (fieldTypes[i]) {
- case QVariant::Time:
- case QVariant::Date:
- case QVariant::DateTime:{
+ switch (fieldTypes[i].id()) {
+ case QMetaType::QTime:
+ case QMetaType::QDate:
+ case QMetaType::QDateTime:{
columns[i].lengths[row] = columns[i].maxLen;
QOCIDateTime *date = new QOCIDateTime(d->env, d->err, val.toDateTime());
*reinterpret_cast<OCIDateTime**>(dataPtr) = date->dateTime;
+ tmpStorage.dateTimes.append(date);
break;
}
- case QVariant::Int:
+ case QMetaType::Int:
columns[i].lengths[row] = columns[i].maxLen;
*reinterpret_cast<int*>(dataPtr) = val.toInt();
break;
- case QVariant::UInt:
+ case QMetaType::UInt:
columns[i].lengths[row] = columns[i].maxLen;
*reinterpret_cast<uint*>(dataPtr) = val.toUInt();
break;
- case QVariant::LongLong:
+ case QMetaType::LongLong:
{
columns[i].lengths[row] = columns[i].maxLen;
const QByteArray ba = qMakeOCINumber(val.toLongLong(), d->err);
@@ -1503,7 +1462,7 @@ bool QOCICols::execBatch(QOCIResultPrivate *d, QVector<QVariant> &boundValues, b
memcpy(dataPtr, ba.constData(), columns[i].maxLen);
break;
}
- case QVariant::ULongLong:
+ case QMetaType::ULongLong:
{
columns[i].lengths[row] = columns[i].maxLen;
const QByteArray ba = qMakeOCINumber(val.toULongLong(), d->err);
@@ -1511,29 +1470,31 @@ bool QOCICols::execBatch(QOCIResultPrivate *d, QVector<QVariant> &boundValues, b
memcpy(dataPtr, ba.constData(), columns[i].maxLen);
break;
}
- case QVariant::Double:
+ case QMetaType::Double:
columns[i].lengths[row] = columns[i].maxLen;
*reinterpret_cast<double*>(dataPtr) = val.toDouble();
break;
- case QVariant::String: {
+ case QMetaType::QString: {
const QString s = val.toString();
columns[i].lengths[row] = (s.length() + 1) * sizeof(QChar);
memcpy(dataPtr, s.utf16(), columns[i].lengths[row]);
break;
}
- case QVariant::UserType:
- if (val.canConvert<QOCIRowIdPointer>()) {
- const QOCIRowIdPointer rptr = qvariant_cast<QOCIRowIdPointer>(val);
- *reinterpret_cast<OCIRowid**>(dataPtr) = rptr->id;
- columns[i].lengths[row] = 0;
- break;
- }
- case QVariant::ByteArray:
+ case QMetaType::QByteArray:
default: {
- const QByteArray ba = val.toByteArray();
- columns[i].lengths[row] = ba.size();
- memcpy(dataPtr, ba.constData(), ba.size());
+ if (fieldTypes[i].id() >= QMetaType::User) {
+ if (val.canConvert<QOCIRowIdPointer>()) {
+ const QOCIRowIdPointer rptr = qvariant_cast<QOCIRowIdPointer>(val);
+ *reinterpret_cast<OCIRowid**>(dataPtr) = rptr->id;
+ columns[i].lengths[row] = 0;
+ break;
+ }
+ } else {
+ const QByteArray ba = val.toByteArray();
+ columns[i].lengths[row] = ba.size();
+ memcpy(dataPtr, ba.constData(), ba.size());
+ }
break;
}
}
@@ -1543,13 +1504,13 @@ bool QOCICols::execBatch(QOCIResultPrivate *d, QVector<QVariant> &boundValues, b
QOCIBatchColumn &bindColumn = columns[i];
#ifdef QOCI_DEBUG
- qDebug("OCIBindByPos(%p, %p, %p, %d, %p, %d, %d, %p, %p, 0, %d, %p, OCI_DEFAULT)",
+ qCDebug(lcOci, "OCIBindByPos(%p, %p, %p, %d, %p, %d, %d, %p, %p, 0, %d, %p, OCI_DEFAULT)",
d->sql, &bindColumn.bindh, d->err, i + 1, bindColumn.data,
bindColumn.maxLen, bindColumn.bindAs, bindColumn.indicators, bindColumn.lengths,
arrayBind ? bindColumn.maxarr_len : 0, arrayBind ? &bindColumn.curelep : 0);
for (int ii = 0; ii < (int)bindColumn.recordCount; ++ii) {
- qDebug(" record %d: indicator %d, length %d", ii, bindColumn.indicators[ii],
+ qCDebug(lcOci, " record %d: indicator %d, length %d", ii, bindColumn.indicators[ii],
bindColumn.lengths[ii]);
}
#endif
@@ -1569,7 +1530,7 @@ bool QOCICols::execBatch(QOCIResultPrivate *d, QVector<QVariant> &boundValues, b
OCI_DEFAULT);
#ifdef QOCI_DEBUG
- qDebug("After OCIBindByPos: r = %d, bindh = %p", r, bindColumn.bindh);
+ qCDebug(lcOci, "After OCIBindByPos: r = %d, bindh = %p", r, bindColumn.bindh);
#endif
if (r != OCI_SUCCESS && r != OCI_SUCCESS_WITH_INFO) {
@@ -1596,7 +1557,7 @@ bool QOCICols::execBatch(QOCIResultPrivate *d, QVector<QVariant> &boundValues, b
}
}
- //finaly we can execute
+ //finally we can execute
r = OCIStmtExecute(d->svc, d->sql, d->err,
arrayBind ? 1 : columns[0].recordCount,
0, NULL, NULL,
@@ -1610,14 +1571,13 @@ bool QOCICols::execBatch(QOCIResultPrivate *d, QVector<QVariant> &boundValues, b
return false;
}
- // for out parameters we copy data back to value vector
+ // for out parameters we copy data back to value list
for (i = 0; i < columnCount; ++i) {
if (!d->isOutValue(i))
continue;
- QVariant::Type tp = boundValues.at(i).type();
- if (tp != QVariant::List) {
+ if (auto tp = boundValues.at(i).metaType(); tp.id() != QMetaType::QVariantList) {
qOraOutValue(boundValues[i], tmpStorage, d->env, d->err);
if (*columns[i].indicators == -1)
boundValues[i] = QVariant(tp);
@@ -1650,11 +1610,11 @@ bool QOCICols::execBatch(QOCIResultPrivate *d, QVector<QVariant> &boundValues, b
case SQLT_VNU:
{
- switch (boundValues.at(i).type()) {
- case QVariant::LongLong:
+ switch (boundValues.at(i).typeId()) {
+ case QMetaType::LongLong:
(*list)[r] = qMakeLongLong(data + r * columns[i].maxLen, d->err);
break;
- case QVariant::ULongLong:
+ case QMetaType::ULongLong:
(*list)[r] = qMakeULongLong(data + r * columns[i].maxLen, d->err);
break;
default:
@@ -1737,7 +1697,7 @@ int qReadLob(T &buf, const QOCIResultPrivate *d, OCILobLocator *lob)
return r;
}
-int QOCICols::readLOBs(QVector<QVariant> &values, int index)
+int QOCICols::readLOBs(QVariantList &values, int index)
{
OCILobLocator *lob;
int r = OCI_SUCCESS;
@@ -1776,7 +1736,7 @@ int QOCICols::fieldFromDefine(OCIDefine* d)
return -1;
}
-void QOCICols::getValues(QVector<QVariant> &v, int index)
+void QOCICols::getValues(QVariantList &v, int index)
{
for (int i = 0; i < fieldInf.size(); ++i) {
const OraFieldInf &fld = fieldInf.at(i);
@@ -1790,47 +1750,47 @@ void QOCICols::getValues(QVector<QVariant> &v, int index)
if (fld.oraType == SQLT_BIN || fld.oraType == SQLT_LBI || fld.oraType == SQLT_LNG)
continue; // already fetched piecewise
- switch (fld.typ) {
- case QVariant::DateTime:
+ switch (fld.typ.id()) {
+ case QMetaType::QDateTime:
v[index + i] = QVariant(QOCIDateTime::fromOCIDateTime(d->env, d->err,
reinterpret_cast<OCIDateTime *>(fld.dataPtr)));
break;
- case QVariant::Double:
- case QVariant::Int:
- case QVariant::LongLong:
+ case QMetaType::Double:
+ case QMetaType::Int:
+ case QMetaType::LongLong:
if (d->q_func()->numericalPrecisionPolicy() != QSql::HighPrecision) {
if ((d->q_func()->numericalPrecisionPolicy() == QSql::LowPrecisionDouble)
- && (fld.typ == QVariant::Double)) {
+ && (fld.typ.id() == QMetaType::Double)) {
v[index + i] = *reinterpret_cast<double *>(fld.data);
break;
} else if ((d->q_func()->numericalPrecisionPolicy() == QSql::LowPrecisionInt64)
- && (fld.typ == QVariant::LongLong)) {
+ && (fld.typ.id() == QMetaType::LongLong)) {
qint64 qll = 0;
int r = OCINumberToInt(d->err, reinterpret_cast<OCINumber *>(fld.data), sizeof(qint64),
OCI_NUMBER_SIGNED, &qll);
- if(r == OCI_SUCCESS)
+ if (r == OCI_SUCCESS)
v[index + i] = qll;
else
v[index + i] = QVariant();
break;
} else if ((d->q_func()->numericalPrecisionPolicy() == QSql::LowPrecisionInt32)
- && (fld.typ == QVariant::Int)) {
+ && (fld.typ.id() == QMetaType::Int)) {
v[index + i] = *reinterpret_cast<int *>(fld.data);
break;
}
}
// else fall through
- case QVariant::String:
+ case QMetaType::QString:
v[index + i] = QString(reinterpret_cast<const QChar *>(fld.data));
break;
- case QVariant::ByteArray:
+ case QMetaType::QByteArray:
if (fld.len > 0)
v[index + i] = QByteArray(fld.data, fld.len);
else
- v[index + i] = QVariant(QVariant::ByteArray);
+ v[index + i] = QVariant(QMetaType(QMetaType::QByteArray));
break;
default:
- qWarning("QOCICols::value: unknown data type");
+ qCWarning(lcOci, "QOCICols::value: unknown data type");
break;
}
}
@@ -1838,32 +1798,31 @@ void QOCICols::getValues(QVector<QVariant> &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)
- qWarning("QOCIResult: unable to alloc error handle");
+ 0, nullptr);
+ if (r != OCI_SUCCESS)
+ qCWarning(lcOci, "QOCIResult: unable to alloc error handle");
}
QOCIResultPrivate::~QOCIResultPrivate()
{
delete cols;
- int r = OCIHandleFree(err, OCI_HTYPE_ERROR);
- if (r != 0)
- qWarning("~QOCIResult: unable to free statement handle");
+ if (sql && OCIHandleFree(sql, OCI_HTYPE_STMT) != OCI_SUCCESS)
+ qCWarning(lcOci, "~QOCIResult: unable to free statement handle");
+
+ if (OCIHandleFree(err, OCI_HTYPE_ERROR) != OCI_SUCCESS)
+ qCWarning(lcOci, "~QOCIResult: unable to free error report handle");
}
@@ -1876,12 +1835,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
@@ -1926,7 +1879,7 @@ bool QOCIResult::gotoNext(QSqlCachedResult::ValueCache &values, int index)
break;
case OCI_ERROR:
if (qOraErrorNumber(d->err) == 1406) {
- qWarning("QOCI Warning: data truncated for %s", lastQuery().toLocal8Bit().constData());
+ qCWarning(lcOci, "QOCI Warning: data truncated for %ls", qUtf16Printable(lastQuery()));
r = OCI_SUCCESS; /* ignore it */
break;
}
@@ -1977,12 +1930,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 +1945,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",
@@ -2039,7 +1993,7 @@ bool QOCIResult::exec()
setLastError(qMakeError(QCoreApplication::translate("QOCIResult",
"Unable to get statement type"), QSqlError::StatementError, d->err));
#ifdef QOCI_DEBUG
- qDebug() << "lastQuery()" << lastQuery();
+ qCDebug(lcOci) << "lastQuery()" << lastQuery();
#endif
return false;
}
@@ -2054,7 +2008,7 @@ bool QOCIResult::exec()
setLastError(qMakeError(QCoreApplication::translate("QOCIResult", "Unable to bind value"),
QSqlError::StatementError, d->err));
#ifdef QOCI_DEBUG
- qDebug() << "lastQuery()" << lastQuery();
+ qCDebug(lcOci) << "lastQuery()" << lastQuery();
#endif
return false;
}
@@ -2073,7 +2027,7 @@ bool QOCIResult::exec()
setLastError(qMakeError(QCoreApplication::translate("QOCIResult",
"Unable to execute statement"), QSqlError::StatementError, d->err));
#ifdef QOCI_DEBUG
- qDebug() << "lastQuery()" << lastQuery();
+ qCDebug(lcOci) << "lastQuery()" << lastQuery();
#endif
return false;
}
@@ -2165,7 +2119,7 @@ QOCIDriver::QOCIDriver(QObject* parent)
0,
NULL);
if (r != 0) {
- qWarning("QOCIDriver: unable to create environment");
+ qCWarning(lcOci, "QOCIDriver: unable to create environment");
setLastError(qMakeError(tr("Unable to initialize", "QOCIDriver"),
QSqlError::ConnectionError, d->err));
return;
@@ -2196,10 +2150,10 @@ QOCIDriver::~QOCIDriver()
close();
int r = OCIHandleFree(d->err, OCI_HTYPE_ERROR);
if (r != OCI_SUCCESS)
- qWarning("Unable to free Error handle: %d", r);
+ qCWarning(lcOci, "Unable to free Error handle: %d", r);
r = OCIHandleFree(d->env, OCI_HTYPE_ENV);
if (r != OCI_SUCCESS)
- qWarning("Unable to free Environment handle: %d", r);
+ qCWarning(lcOci, "Unable to free Environment handle: %d", r);
}
bool QOCIDriver::hasFeature(DriverFeature f) const
@@ -2230,29 +2184,37 @@ bool QOCIDriver::hasFeature(DriverFeature f) const
static void qParseOpts(const QString &options, QOCIDriverPrivate *d)
{
- const QStringList opts(options.split(QLatin1Char(';'), QString::SkipEmptyParts));
- for (int i = 0; i < opts.count(); ++i) {
- const QString tmp(opts.at(i));
- int idx;
- if ((idx = tmp.indexOf(QLatin1Char('='))) == -1) {
- qWarning("QOCIDriver::parseArgs: Invalid parameter: '%s'",
- tmp.toLocal8Bit().constData());
+ const QVector<QStringView> opts(QStringView(options).split(u';', Qt::SkipEmptyParts));
+ for (const auto tmp : opts) {
+ qsizetype idx;
+ if ((idx = tmp.indexOf(u'=')) == -1) {
+ qCWarning(lcOci, "QOCIDriver::parseArgs: Invalid parameter: '%ls'",
+ qUtf16Printable(tmp.toString()));
continue;
}
- const QString opt = tmp.left(idx);
- const QString val = tmp.mid(idx + 1).simplified();
+ const QStringView opt = tmp.left(idx);
+ const QStringView val = tmp.mid(idx + 1).trimmed();
bool ok;
- if (opt == QLatin1String("OCI_ATTR_PREFETCH_ROWS")) {
+ if (opt == "OCI_ATTR_PREFETCH_ROWS"_L1) {
d->prefetchRows = val.toInt(&ok);
if (!ok)
d->prefetchRows = -1;
- } else if (opt == QLatin1String("OCI_ATTR_PREFETCH_MEMORY")) {
+ } else if (opt == "OCI_ATTR_PREFETCH_MEMORY"_L1) {
d->prefetchMem = val.toInt(&ok);
if (!ok)
d->prefetchMem = -1;
+ } else if (opt == "OCI_AUTH_MODE"_L1) {
+ if (val == "OCI_SYSDBA"_L1) {
+ d->authMode = OCI_SYSDBA;
+ } else if (val == "OCI_SYSOPER"_L1) {
+ d->authMode = OCI_SYSOPER;
+ } else if (val != "OCI_DEFAULT"_L1) {
+ qCWarning(lcOci, "QOCIDriver::parseArgs: Unsupported value for OCI_AUTH_MODE: '%ls'",
+ qUtf16Printable(val.toString()));
+ }
} else {
- qWarning ("QOCIDriver::parseArgs: Invalid parameter: '%s'",
- opt.toLocal8Bit().constData());
+ qCWarning(lcOci, "QOCIDriver::parseArgs: Invalid parameter: '%ls'",
+ qUtf16Printable(opt.toString()));
}
}
}
@@ -2279,34 +2241,46 @@ 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())
- r = OCISessionBegin(d->svc, d->err, d->authp, OCI_CRED_EXT, OCI_DEFAULT);
+ r = OCISessionBegin(d->svc, d->err, d->authp, OCI_CRED_EXT, d->authMode);
else
- r = OCISessionBegin(d->svc, d->err, d->authp, OCI_CRED_RDBMS, OCI_DEFAULT);
+ r = OCISessionBegin(d->svc, d->err, d->authp, OCI_CRED_RDBMS, d->authMode);
}
if (r == OCI_SUCCESS || r == OCI_SUCCESS_WITH_INFO)
r = OCIAttrSet(d->svc, OCI_HTYPE_SVCCTX, d->authp, 0, OCI_ATTR_SESSION, d->err);
@@ -2314,12 +2288,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;
}
@@ -2331,13 +2311,15 @@ bool QOCIDriver::open(const QString & db,
sizeof(vertxt),
OCI_HTYPE_SVCCTX);
if (r != 0) {
- qWarning("QOCIDriver::open: could not get Oracle server version.");
+ qCWarning(lcOci, "QOCIDriver::open: could not get Oracle server version.");
} else {
QString versionStr;
versionStr = QString(reinterpret_cast<const QChar *>(vertxt));
- QRegExp vers(QLatin1String("([0-9]+)\\.[0-9\\.]+[0-9]"));
- if (vers.indexIn(versionStr) >= 0)
- d->serverVersion = vers.cap(1).toInt();
+#if QT_CONFIG(regularexpression)
+ auto match = QRegularExpression("([0-9]+)\\.[0-9\\.]+[0-9]"_L1).match(versionStr);
+ if (match.hasMatch())
+ d->serverVersion = match.captured(1).toInt();
+#endif
if (d->serverVersion == 0)
d->serverVersion = -1;
}
@@ -2357,12 +2339,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);
}
@@ -2376,7 +2360,7 @@ bool QOCIDriver::beginTransaction()
{
Q_D(QOCIDriver);
if (!isOpen()) {
- qWarning("QOCIDriver::beginTransaction: Database not open");
+ qCWarning(lcOci, "QOCIDriver::beginTransaction: Database not open");
return false;
}
int r = OCITransStart(d->svc,
@@ -2397,7 +2381,7 @@ bool QOCIDriver::commitTransaction()
{
Q_D(QOCIDriver);
if (!isOpen()) {
- qWarning("QOCIDriver::commitTransaction: Database not open");
+ qCWarning(lcOci, "QOCIDriver::commitTransaction: Database not open");
return false;
}
int r = OCITransCommit(d->svc,
@@ -2417,7 +2401,7 @@ bool QOCIDriver::rollbackTransaction()
{
Q_D(QOCIDriver);
if (!isOpen()) {
- qWarning("QOCIDriver::rollbackTransaction: Database not open");
+ qCWarning(lcOci, "QOCIDriver::rollbackTransaction: Database not open");
return false;
}
int r = OCITransRollback(d->svc,
@@ -2450,18 +2434,18 @@ static QString make_where_clause(const QString &user, Expression e)
"WMSYS",
};
static const char joinC[][4] = { "or" , "and" };
- static Q_CONSTEXPR QLatin1Char bang[] = { QLatin1Char(' '), QLatin1Char('!') };
+ static constexpr char16_t bang[] = { u' ', u'!' };
- const QLatin1String join(joinC[e]);
+ const QLatin1StringView join(joinC[e]);
QString result;
result.reserve(sizeof sysUsers / sizeof *sysUsers *
// max-sizeof(owner != <sysuser> and )
(9 + sizeof *sysUsers + 5));
for (const auto &sysUser : sysUsers) {
- const QLatin1String l1(sysUser);
+ const QLatin1StringView l1(sysUser);
if (l1 != user)
- result += QLatin1String("owner ") + bang[e] + QLatin1String("= '") + l1 + QLatin1String("' ") + join + QLatin1Char(' ');
+ result += "owner "_L1 + bang[e] + "= '"_L1 + l1 + "' "_L1 + join + u' ';
}
result.chop(join.size() + 2); // remove final " <join> "
@@ -2486,58 +2470,58 @@ QStringList QOCIDriver::tables(QSql::TableType type) const
QSqlQuery t(createResult());
t.setForwardOnly(true);
if (type & QSql::Tables) {
- const QLatin1String tableQuery("select owner, table_name from all_tables where ");
+ const auto tableQuery = "select owner, table_name from all_tables where "_L1;
const QString where = make_where_clause(user, AndExpression);
t.exec(tableQuery + where);
while (t.next()) {
if (t.value(0).toString().toUpper() != user.toUpper())
- tl.append(t.value(0).toString() + QLatin1Char('.') + t.value(1).toString());
+ tl.append(t.value(0).toString() + u'.' + t.value(1).toString());
else
tl.append(t.value(1).toString());
}
// list all table synonyms as well
- const QLatin1String synonymQuery("select owner, synonym_name from all_synonyms where ");
+ const auto synonymQuery = "select owner, synonym_name from all_synonyms where "_L1;
t.exec(synonymQuery + where);
while (t.next()) {
if (t.value(0).toString() != d->user)
- tl.append(t.value(0).toString() + QLatin1Char('.') + t.value(1).toString());
+ tl.append(t.value(0).toString() + u'.' + t.value(1).toString());
else
tl.append(t.value(1).toString());
}
}
if (type & QSql::Views) {
- const QLatin1String query("select owner, view_name from all_views where ");
+ const auto query = "select owner, view_name from all_views where "_L1;
const QString where = make_where_clause(user, AndExpression);
t.exec(query + where);
while (t.next()) {
if (t.value(0).toString().toUpper() != d->user.toUpper())
- tl.append(t.value(0).toString() + QLatin1Char('.') + t.value(1).toString());
+ tl.append(t.value(0).toString() + u'.' + t.value(1).toString());
else
tl.append(t.value(1).toString());
}
}
if (type & QSql::SystemTables) {
- t.exec(QLatin1String("select table_name from dictionary"));
+ t.exec("select table_name from dictionary"_L1);
while (t.next()) {
tl.append(t.value(0).toString());
}
- const QLatin1String tableQuery("select owner, table_name from all_tables where ");
+ const auto tableQuery = "select owner, table_name from all_tables where "_L1;
const QString where = make_where_clause(user, OrExpression);
t.exec(tableQuery + where);
while (t.next()) {
if (t.value(0).toString().toUpper() != user.toUpper())
- tl.append(t.value(0).toString() + QLatin1Char('.') + t.value(1).toString());
+ tl.append(t.value(0).toString() + u'.' + t.value(1).toString());
else
tl.append(t.value(1).toString());
}
// list all table synonyms as well
- const QLatin1String synonymQuery("select owner, synonym_name from all_synonyms where ");
+ const auto synonymQuery = "select owner, synonym_name from all_synonyms where "_L1;
t.exec(synonymQuery + where);
while (t.next()) {
if (t.value(0).toString() != d->user)
- tl.append(t.value(0).toString() + QLatin1Char('.') + t.value(1).toString());
+ tl.append(t.value(0).toString() + u'.' + t.value(1).toString());
else
tl.append(t.value(1).toString());
}
@@ -2548,7 +2532,7 @@ QStringList QOCIDriver::tables(QSql::TableType type) const
void qSplitTableAndOwner(const QString & tname, QString * tbl,
QString * owner)
{
- int i = tname.indexOf(QLatin1Char('.')); // prefixed with owner?
+ qsizetype i = tname.indexOf(u'.'); // prefixed with owner?
if (i != -1) {
*tbl = tname.right(tname.length() - i - 1);
*owner = tname.left(i);
@@ -2567,14 +2551,13 @@ QSqlRecord QOCIDriver::record(const QString& tablename) const
QSqlQuery t(createResult());
// using two separate queries for this is A LOT faster than using
// eg. a sub-query on the sys.synonyms table
- QString stmt(QLatin1String("select column_name, data_type, data_length, "
+ QString stmt("select column_name, data_type, data_length, "
"data_precision, data_scale, nullable, data_default%1"
- "from all_tab_columns a "
- "where a.table_name=%2"));
+ "from all_tab_columns a "_L1);
if (d->serverVersion >= 9)
- stmt = stmt.arg(QLatin1String(", char_length "));
+ stmt = stmt.arg(", char_length "_L1);
else
- stmt = stmt.arg(QLatin1String(" "));
+ stmt = stmt.arg(" "_L1);
bool buildRecordInfo = false;
QString table, owner, tmpStmt;
qSplitTableAndOwner(tablename, &table, &owner);
@@ -2584,7 +2567,7 @@ QSqlRecord QOCIDriver::record(const QString& tablename) const
else
table = table.toUpper();
- tmpStmt = stmt.arg(QLatin1Char('\'') + table + QLatin1Char('\''));
+ tmpStmt = stmt + "where a.table_name='"_L1 + table + u'\'';
if (owner.isEmpty()) {
owner = d->user;
}
@@ -2594,15 +2577,12 @@ QSqlRecord QOCIDriver::record(const QString& tablename) const
else
owner = owner.toUpper();
- tmpStmt += QLatin1String(" and a.owner='") + owner + QLatin1Char('\'');
+ tmpStmt += " and a.owner='"_L1 + owner + u'\'';
t.setForwardOnly(true);
t.exec(tmpStmt);
if (!t.next()) { // try and see if the tablename is a synonym
- stmt = stmt + QLatin1String(" join all_synonyms b "
- "on a.owner=b.table_owner and a.table_name=b.table_name "
- "where b.owner='") + owner +
- QLatin1String("' and b.synonym_name='") + table +
- QLatin1Char('\'');
+ stmt = stmt + " join all_synonyms b on a.owner=b.table_owner and a.table_name=b.table_name "
+ "where b.owner='"_L1 + owner + "' and b.synonym_name='"_L1 + table + u'\'';
t.setForwardOnly(true);
t.exec(stmt);
if (t.next())
@@ -2610,15 +2590,15 @@ QSqlRecord QOCIDriver::record(const QString& tablename) const
} else {
buildRecordInfo = true;
}
- QStringList keywords = QStringList() << QLatin1String("NUMBER") << QLatin1String("FLOAT") << QLatin1String("BINARY_FLOAT")
- << QLatin1String("BINARY_DOUBLE");
+ QStringList keywords = QStringList() << "NUMBER"_L1 << "FLOAT"_L1 << "BINARY_FLOAT"_L1
+ << "BINARY_DOUBLE"_L1;
if (buildRecordInfo) {
do {
- QVariant::Type ty = qDecodeOCIType(t.value(1).toString(), t.numericalPrecisionPolicy());
+ QMetaType ty = qDecodeOCIType(t.value(1).toString(), t.numericalPrecisionPolicy());
QSqlField f(t.value(0).toString(), ty);
- f.setRequired(t.value(5).toString() == QLatin1String("N"));
+ f.setRequired(t.value(5).toString() == "N"_L1);
f.setPrecision(t.value(4).toInt());
- if (d->serverVersion >= 9 && (ty == QVariant::String) && !t.isNull(3) && !keywords.contains(t.value(1).toString())) {
+ if (d->serverVersion >= 9 && (ty.id() == QMetaType::QString) && !t.isNull(3) && !keywords.contains(t.value(1).toString())) {
// Oracle9: data_length == size in bytes, char_length == amount of characters
f.setLength(t.value(7).toInt());
} else {
@@ -2638,11 +2618,11 @@ QSqlIndex QOCIDriver::primaryIndex(const QString& tablename) const
if (!isOpen())
return idx;
QSqlQuery t(createResult());
- QString stmt(QLatin1String("select b.column_name, b.index_name, a.table_name, a.owner "
+ QString stmt("select b.column_name, b.index_name, a.table_name, a.owner "
"from all_constraints a, all_ind_columns b "
"where a.constraint_type='P' "
"and b.index_name = a.index_name "
- "and b.index_owner = a.owner"));
+ "and b.index_owner = a.owner"_L1);
bool buildIndex = false;
QString table, owner, tmpStmt;
@@ -2653,7 +2633,7 @@ QSqlIndex QOCIDriver::primaryIndex(const QString& tablename) const
else
table = table.toUpper();
- tmpStmt = stmt + QLatin1String(" and a.table_name='") + table + QLatin1Char('\'');
+ tmpStmt = stmt + " and a.table_name='"_L1 + table + u'\'';
if (owner.isEmpty()) {
owner = d->user;
}
@@ -2663,13 +2643,13 @@ QSqlIndex QOCIDriver::primaryIndex(const QString& tablename) const
else
owner = owner.toUpper();
- tmpStmt += QLatin1String(" and a.owner='") + owner + QLatin1Char('\'');
+ tmpStmt += " and a.owner='"_L1 + owner + u'\'';
t.setForwardOnly(true);
t.exec(tmpStmt);
if (!t.next()) {
- stmt += QLatin1String(" and a.table_name=(select tname from sys.synonyms "
- "where sname='") + table + QLatin1String("' and creator=a.owner)");
+ stmt += " and a.table_name=(select tname from sys.synonyms where sname='"_L1
+ + table + "' and creator=a.owner)"_L1;
t.setForwardOnly(true);
t.exec(stmt);
if (t.next()) {
@@ -2684,10 +2664,10 @@ QSqlIndex QOCIDriver::primaryIndex(const QString& tablename) const
tt.setForwardOnly(true);
idx.setName(t.value(1).toString());
do {
- tt.exec(QLatin1String("select data_type from all_tab_columns where table_name='") +
- t.value(2).toString() + QLatin1String("' and column_name='") +
- t.value(0).toString() + QLatin1String("' and owner='") +
- owner + QLatin1Char('\''));
+ tt.exec("select data_type from all_tab_columns where table_name='"_L1 +
+ t.value(2).toString() + "' and column_name='"_L1 +
+ t.value(0).toString() + "' and owner='"_L1 +
+ owner + u'\'');
if (!tt.next()) {
return QSqlIndex();
}
@@ -2701,48 +2681,48 @@ QSqlIndex QOCIDriver::primaryIndex(const QString& tablename) const
QString QOCIDriver::formatValue(const QSqlField &field, bool trimStrings) const
{
- switch (field.type()) {
- case QVariant::DateTime: {
+ switch (field.metaType().id()) {
+ case QMetaType::QDateTime: {
QDateTime datetime = field.value().toDateTime();
QString datestring;
if (datetime.isValid()) {
- datestring = QLatin1String("TO_DATE('") + QString::number(datetime.date().year())
- + QLatin1Char('-')
- + QString::number(datetime.date().month()) + QLatin1Char('-')
- + QString::number(datetime.date().day()) + QLatin1Char(' ')
- + QString::number(datetime.time().hour()) + QLatin1Char(':')
- + QString::number(datetime.time().minute()) + QLatin1Char(':')
+ datestring = "TO_DATE('"_L1 + QString::number(datetime.date().year())
+ + u'-'
+ + QString::number(datetime.date().month()) + u'-'
+ + QString::number(datetime.date().day()) + u' '
+ + QString::number(datetime.time().hour()) + u':'
+ + QString::number(datetime.time().minute()) + u':'
+ QString::number(datetime.time().second())
- + QLatin1String("','YYYY-MM-DD HH24:MI:SS')");
+ + "','YYYY-MM-DD HH24:MI:SS')"_L1;
} else {
- datestring = QLatin1String("NULL");
+ datestring = "NULL"_L1;
}
return datestring;
}
- case QVariant::Time: {
+ case QMetaType::QTime: {
QDateTime datetime = field.value().toDateTime();
QString datestring;
if (datetime.isValid()) {
- datestring = QLatin1String("TO_DATE('")
- + QString::number(datetime.time().hour()) + QLatin1Char(':')
- + QString::number(datetime.time().minute()) + QLatin1Char(':')
+ datestring = "TO_DATE('"_L1
+ + QString::number(datetime.time().hour()) + u':'
+ + QString::number(datetime.time().minute()) + u':'
+ QString::number(datetime.time().second())
- + QLatin1String("','HH24:MI:SS')");
+ + "','HH24:MI:SS')"_L1;
} else {
- datestring = QLatin1String("NULL");
+ datestring = "NULL"_L1;
}
return datestring;
}
- case QVariant::Date: {
+ case QMetaType::QDate: {
QDate date = field.value().toDate();
QString datestring;
if (date.isValid()) {
- datestring = QLatin1String("TO_DATE('") + QString::number(date.year()) +
- QLatin1Char('-') +
- QString::number(date.month()) + QLatin1Char('-') +
- QString::number(date.day()) + QLatin1String("','YYYY-MM-DD')");
+ datestring = "TO_DATE('"_L1 + QString::number(date.year()) +
+ u'-' +
+ QString::number(date.month()) + u'-' +
+ QString::number(date.day()) + "','YYYY-MM-DD')"_L1;
} else {
- datestring = QLatin1String("NULL");
+ datestring = "NULL"_L1;
}
return datestring;
}
@@ -2761,12 +2741,21 @@ QVariant QOCIDriver::handle() const
QString QOCIDriver::escapeIdentifier(const QString &identifier, IdentifierType type) const
{
QString res = identifier;
- if(!identifier.isEmpty() && !isIdentifierEscaped(identifier, type)) {
- res.replace(QLatin1Char('"'), QLatin1String("\"\""));
- res.prepend(QLatin1Char('"')).append(QLatin1Char('"'));
- res.replace(QLatin1Char('.'), QLatin1String("\".\""));
+ if (!identifier.isEmpty() && !isIdentifierEscaped(identifier, type)) {
+ res.replace(u'"', "\"\""_L1);
+ res.replace(u'.', "\".\""_L1);
+ res = u'"' + res + u'"';
}
return res;
}
+int QOCIDriver::maximumIdentifierLength(IdentifierType type) const
+{
+ Q_D(const QOCIDriver);
+ Q_UNUSED(type);
+ return d->serverVersion > 12 ? 128 : 30;
+}
+
QT_END_NAMESPACE
+
+#include "moc_qsql_oci_p.cpp"
diff --git a/src/plugins/sqldrivers/oci/qsql_oci_p.h b/src/plugins/sqldrivers/oci/qsql_oci_p.h
index 295c131f1a..91fef9de7b 100644
--- a/src/plugins/sqldrivers/oci/qsql_oci_p.h
+++ b/src/plugins/sqldrivers/oci/qsql_oci_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtSql module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QSQL_OCI_H
#define QSQL_OCI_H
@@ -75,10 +39,10 @@ class Q_EXPORT_SQLDRIVER_OCI QOCIDriver : public QSqlDriver
friend class QOCIResultPrivate;
public:
- explicit QOCIDriver(QObject* parent = 0);
- QOCIDriver(OCIEnv* env, OCISvcCtx* ctx, QObject* parent = 0);
+ explicit QOCIDriver(QObject *parent = nullptr);
+ QOCIDriver(OCIEnv *env, OCISvcCtx *ctx, QObject *parent = nullptr);
~QOCIDriver();
- bool hasFeature(DriverFeature f) const;
+ bool hasFeature(DriverFeature f) const override;
bool open(const QString &db,
const QString &user,
const QString &password,
@@ -94,6 +58,7 @@ public:
bool trimStrings) const override;
QVariant handle() const override;
QString escapeIdentifier(const QString &identifier, IdentifierType) const override;
+ int maximumIdentifierLength(IdentifierType type) const override;
protected:
bool beginTransaction() override;
diff --git a/src/plugins/sqldrivers/odbc/.prev_CMakeLists.txt b/src/plugins/sqldrivers/odbc/.prev_CMakeLists.txt
deleted file mode 100644
index 692d1fc294..0000000000
--- a/src/plugins/sqldrivers/odbc/.prev_CMakeLists.txt
+++ /dev/null
@@ -1,32 +0,0 @@
-# Generated from odbc.pro.
-
-#####################################################################
-## QODBCDriverPlugin Plugin:
-#####################################################################
-
-qt_add_plugin(QODBCDriverPlugin
- OUTPUT_NAME qsqlodbc
- TYPE sqldrivers
- SOURCES
- main.cpp
- qsql_odbc.cpp qsql_odbc_p.h
- DEFINES
- QT_NO_CAST_FROM_ASCII
- QT_NO_CAST_TO_ASCII
- PUBLIC_LIBRARIES
- ODBC::ODBC
- Qt::Core
- Qt::CorePrivate
- Qt::SqlPrivate
-)
-
-#### Keys ignored in scope 1:.:.:odbc.pro:<TRUE>:
-# OTHER_FILES = "odbc.json"
-
-## Scopes:
-#####################################################################
-
-qt_extend_target(QODBCDriverPlugin CONDITION UNIX
- DEFINES
- UNICODE
-)
diff --git a/src/plugins/sqldrivers/odbc/CMakeLists.txt b/src/plugins/sqldrivers/odbc/CMakeLists.txt
index 5c163181c5..7812aced2c 100644
--- a/src/plugins/sqldrivers/odbc/CMakeLists.txt
+++ b/src/plugins/sqldrivers/odbc/CMakeLists.txt
@@ -1,33 +1,33 @@
-# Generated from odbc.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## QODBCDriverPlugin Plugin:
#####################################################################
-qt_find_package(ODBC) # special case
-qt_add_plugin(QODBCDriverPlugin
+qt_find_package(ODBC)
+
+qt_internal_add_plugin(QODBCDriverPlugin
OUTPUT_NAME qsqlodbc
- TYPE sqldrivers
+ PLUGIN_TYPE sqldrivers
SOURCES
main.cpp
qsql_odbc.cpp qsql_odbc_p.h
DEFINES
QT_NO_CAST_FROM_ASCII
QT_NO_CAST_TO_ASCII
- PUBLIC_LIBRARIES
+ QT_NO_CONTEXTLESS_CONNECT
+ LIBRARIES
ODBC::ODBC
Qt::Core
Qt::CorePrivate
Qt::SqlPrivate
)
-#### Keys ignored in scope 1:.:.:odbc.pro:<TRUE>:
-# OTHER_FILES = "odbc.json"
-
## Scopes:
#####################################################################
-qt_extend_target(QODBCDriverPlugin CONDITION UNIX
+qt_internal_extend_target(QODBCDriverPlugin CONDITION UNIX
DEFINES
UNICODE
)
diff --git a/src/plugins/sqldrivers/odbc/main.cpp b/src/plugins/sqldrivers/odbc/main.cpp
index e712514a88..0310be0c64 100644
--- a/src/plugins/sqldrivers/odbc/main.cpp
+++ b/src/plugins/sqldrivers/odbc/main.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <qsqldriverplugin.h>
#include <qstringlist.h>
@@ -43,6 +7,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
class QODBCDriverPlugin : public QSqlDriverPlugin
{
Q_OBJECT
@@ -51,7 +17,7 @@ class QODBCDriverPlugin : public QSqlDriverPlugin
public:
QODBCDriverPlugin();
- QSqlDriver* create(const QString &);
+ QSqlDriver* create(const QString &) override;
};
QODBCDriverPlugin::QODBCDriverPlugin()
@@ -61,7 +27,7 @@ QODBCDriverPlugin::QODBCDriverPlugin()
QSqlDriver* QODBCDriverPlugin::create(const QString &name)
{
- if (name == QLatin1String("QODBC")) {
+ if (name == "QODBC"_L1) {
QODBCDriver* driver = new QODBCDriver();
return driver;
}
diff --git a/src/plugins/sqldrivers/odbc/odbc.pro b/src/plugins/sqldrivers/odbc/odbc.pro
deleted file mode 100644
index 17844f27d2..0000000000
--- a/src/plugins/sqldrivers/odbc/odbc.pro
+++ /dev/null
@@ -1,12 +0,0 @@
-TARGET = qsqlodbc
-
-HEADERS += $$PWD/qsql_odbc_p.h
-SOURCES += $$PWD/qsql_odbc.cpp $$PWD/main.cpp
-
-QMAKE_USE += odbc
-unix: DEFINES += UNICODE
-
-OTHER_FILES += odbc.json
-
-PLUGIN_CLASS_NAME = QODBCDriverPlugin
-include(../qsqldriverbase.pri)
diff --git a/src/plugins/sqldrivers/odbc/qsql_odbc.cpp b/src/plugins/sqldrivers/odbc/qsql_odbc.cpp
index 72b2133327..976911d458 100644
--- a/src/plugins/sqldrivers/odbc/qsql_odbc.cpp
+++ b/src/plugins/sqldrivers/odbc/qsql_odbc.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtSql module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qsql_odbc_p.h"
#include <qsqlrecord.h>
@@ -44,72 +8,104 @@
#include <qt_windows.h>
#endif
#include <qcoreapplication.h>
-#include <qvariant.h>
#include <qdatetime.h>
+#include <qlist.h>
+#include <qloggingcategory.h>
+#include <qmath.h>
#include <qsqlerror.h>
#include <qsqlfield.h>
#include <qsqlindex.h>
+#include <qstringconverter.h>
#include <qstringlist.h>
+#include <qvariant.h>
#include <qvarlengtharray.h>
-#include <qvector.h>
-#include <qmath.h>
#include <QDebug>
#include <QSqlQuery>
#include <QtSql/private/qsqldriver_p.h>
#include <QtSql/private/qsqlresult_p.h>
+#include "private/qtools_p.h"
QT_BEGIN_NAMESPACE
+static Q_LOGGING_CATEGORY(lcOdbc, "qt.sql.odbc")
+
+using namespace Qt::StringLiterals;
+
+// non-standard ODBC SQL data type from SQL Server sometimes used instead of SQL_TIME
+#ifndef SQL_SS_TIME2
+#define SQL_SS_TIME2 (-154)
+#endif
+
// undefine this to prevent initial check of the ODBC driver
#define ODBC_CHECK_DRIVER
-static const int COLNAMESIZE = 256;
-static const SQLSMALLINT TABLENAMESIZE = 128;
+static constexpr int COLNAMESIZE = 256;
+static constexpr SQLSMALLINT TABLENAMESIZE = 128;
//Map Qt parameter types to ODBC types
-static const SQLSMALLINT qParamType[4] = { SQL_PARAM_INPUT, SQL_PARAM_INPUT, SQL_PARAM_OUTPUT, SQL_PARAM_INPUT_OUTPUT };
+static constexpr SQLSMALLINT qParamType[4] = { SQL_PARAM_INPUT, SQL_PARAM_INPUT, SQL_PARAM_OUTPUT, SQL_PARAM_INPUT_OUTPUT };
-inline static QString fromSQLTCHAR(const QVarLengthArray<SQLTCHAR>& input, int size=-1)
+class SqlStmtHandle
{
- QString result;
+public:
+ SqlStmtHandle(SQLHANDLE hDbc)
+ {
+ SQLAllocHandle(SQL_HANDLE_STMT, hDbc, &stmtHandle);
+ }
+ ~SqlStmtHandle()
+ {
+ if (stmtHandle != SQL_NULL_HSTMT)
+ SQLFreeHandle(SQL_HANDLE_STMT, stmtHandle);
+ }
+ SQLHANDLE handle() const
+ {
+ return stmtHandle;
+ }
+ bool isValid() const
+ {
+ return stmtHandle != SQL_NULL_HSTMT;
+ }
+ SQLHANDLE stmtHandle = SQL_NULL_HSTMT;
+};
+template<typename C, int SIZE = sizeof(SQLTCHAR)>
+inline static QString fromSQLTCHAR(const C &input, qsizetype size = -1)
+{
// Remove any trailing \0 as some drivers misguidedly append one
- int realsize = qMin(size, input.size());
- if(realsize > 0 && input[realsize-1] == 0)
+ qsizetype realsize = qMin(size, input.size());
+ if (realsize > 0 && input[realsize - 1] == 0)
realsize--;
- switch(sizeof(SQLTCHAR)) {
- case 1:
- result=QString::fromUtf8((const char *)input.constData(), realsize);
- break;
- case 2:
- result=QString::fromUtf16((const ushort *)input.constData(), realsize);
- break;
- case 4:
- result=QString::fromUcs4((const uint *)input.constData(), realsize);
- break;
- default:
- qCritical("sizeof(SQLTCHAR) is %d. Don't know how to handle this.", int(sizeof(SQLTCHAR)));
- }
- return result;
+ if constexpr (SIZE == 1)
+ return QString::fromUtf8(reinterpret_cast<const char *>(input.constData()), realsize);
+ else if constexpr (SIZE == 2)
+ return QString::fromUtf16(reinterpret_cast<const char16_t *>(input.constData()), realsize);
+ else if constexpr (SIZE == 4)
+ return QString::fromUcs4(reinterpret_cast<const char32_t *>(input.constData()), realsize);
+ else
+ static_assert(QtPrivate::value_dependent_false<SIZE>(),
+ "Don't know how to handle sizeof(SQLTCHAR) != 1/2/4");
+}
+
+template<int SIZE = sizeof(SQLTCHAR)>
+QStringConverter::Encoding encodingForSqlTChar()
+{
+ if constexpr (SIZE == 1)
+ return QStringConverter::Utf8;
+ else if constexpr (SIZE == 2)
+ return QStringConverter::Utf16;
+ else if constexpr (SIZE == 4)
+ return QStringConverter::Utf32;
+ else
+ static_assert(QtPrivate::value_dependent_false<SIZE>(),
+ "Don't know how to handle sizeof(SQLTCHAR) != 1/2/4");
}
-inline static QVarLengthArray<SQLTCHAR> toSQLTCHAR(const QString &input)
+inline static QVarLengthArray<SQLTCHAR> toSQLTCHAR(QStringView input)
{
QVarLengthArray<SQLTCHAR> result;
- result.resize(input.size());
- switch(sizeof(SQLTCHAR)) {
- case 1:
- memcpy(result.data(), input.toUtf8().data(), input.size());
- break;
- case 2:
- memcpy(result.data(), input.unicode(), input.size() * 2);
- break;
- case 4:
- memcpy(result.data(), input.toUcs4().data(), input.size() * 4);
- break;
- default:
- qCritical("sizeof(SQLTCHAR) is %d. Don't know how to handle this.", int(sizeof(SQLTCHAR)));
- }
- result.append(0); // make sure it's null terminated, doesn't matter if it already is, it does if it isn't.
+ QStringEncoder enc(encodingForSqlTChar());
+ result.resize(enc.requiredSpace(input.size()));
+ const auto end = enc.appendToBuffer(reinterpret_cast<char *>(result.data()), input);
+ result.resize((end - reinterpret_cast<char *>(result.data())) / sizeof(SQLTCHAR));
return result;
}
@@ -118,23 +114,19 @@ class QODBCDriverPrivate : public QSqlDriverPrivate
Q_DECLARE_PUBLIC(QODBCDriver)
public:
- enum DefaultCase{Lower, Mixed, Upper, Sensitive};
- QODBCDriverPrivate()
- : QSqlDriverPrivate(), hEnv(0), hDbc(0), unicode(false), useSchema(false), disconnectCount(0), datetime_precision(19),
- isFreeTDSDriver(false), hasSQLFetchScroll(true), hasMultiResultSets(false), isQuoteInitialized(false), quote(QLatin1Char('"'))
- {
- }
+ enum class DefaultCase {Lower, Mixed, Upper, Sensitive};
+ using QSqlDriverPrivate::QSqlDriverPrivate;
- SQLHANDLE hEnv;
- SQLHANDLE hDbc;
+ SQLHANDLE hEnv = nullptr;
+ SQLHANDLE hDbc = nullptr;
- bool unicode;
- bool useSchema;
- int disconnectCount;
- int datetime_precision;
- bool isFreeTDSDriver;
- bool hasSQLFetchScroll;
- bool hasMultiResultSets;
+ int disconnectCount = 0;
+ int datetimePrecision = 19;
+ bool unicode = false;
+ bool useSchema = false;
+ bool isFreeTDSDriver = false;
+ bool hasSQLFetchScroll = true;
+ bool hasMultiResultSets = false;
bool checkDriver() const;
void checkUnicode();
@@ -143,15 +135,18 @@ public:
void checkHasMultiResults();
void checkSchemaUsage();
void checkDateTimePrecision();
+ void checkDefaultCase();
bool setConnectionOptions(const QString& connOpts);
void splitTableQualifier(const QString &qualifier, QString &catalog,
- QString &schema, QString &table);
- DefaultCase defaultCase() const;
+ QString &schema, QString &table) const;
QString adjustCase(const QString&) const;
QChar quoteChar();
+ SQLRETURN sqlFetchNext(const SqlStmtHandle &hStmt) const;
+ SQLRETURN sqlFetchNext(SQLHANDLE hStmt) const;
private:
- bool isQuoteInitialized;
- QChar quote;
+ bool isQuoteInitialized = false;
+ QChar quote = u'"';
+ DefaultCase m_defaultCase = DefaultCase::Mixed;
};
class QODBCResultPrivate;
@@ -194,10 +189,7 @@ class QODBCResultPrivate: public QSqlResultPrivate
public:
Q_DECLARE_SQLDRIVER_PRIVATE(QODBCDriver)
QODBCResultPrivate(QODBCResult *q, const QODBCDriver *db)
- : QSqlResultPrivate(q, db),
- hStmt(0),
- useSchema(false),
- hasSQLFetchScroll(true)
+ : QSqlResultPrivate(q, db)
{
unicode = drv_d_func()->unicode;
useSchema = drv_d_func()->useSchema;
@@ -210,16 +202,15 @@ public:
SQLHANDLE dpEnv() const { return drv_d_func() ? drv_d_func()->hEnv : 0;}
SQLHANDLE dpDbc() const { return drv_d_func() ? drv_d_func()->hDbc : 0;}
- SQLHANDLE hStmt;
-
- bool unicode;
- bool useSchema;
+ SQLHANDLE hStmt = nullptr;
QSqlRecord rInf;
- QVector<QVariant> fieldCache;
- int fieldCacheIdx;
- int disconnectCount;
- bool hasSQLFetchScroll;
+ QVariantList fieldCache;
+ int fieldCacheIdx = 0;
+ int disconnectCount = 0;
+ bool hasSQLFetchScroll = true;
+ bool unicode = false;
+ bool useSchema = false;
bool isStmtHandleValid() const;
void updateStmtHandleState();
@@ -235,163 +226,171 @@ void QODBCResultPrivate::updateStmtHandleState()
disconnectCount = drv_d_func() ? drv_d_func()->disconnectCount : 0;
}
-static QString qWarnODBCHandle(int handleType, SQLHANDLE handle, int *nativeCode = 0)
+struct DiagRecord
+{
+ QString description;
+ QString sqlState;
+ QString errorCode;
+};
+static QList<DiagRecord> qWarnODBCHandle(int handleType, SQLHANDLE handle)
{
- SQLINTEGER nativeCode_ = 0;
+ SQLINTEGER nativeCode = 0;
SQLSMALLINT msgLen = 0;
+ SQLSMALLINT i = 1;
SQLRETURN r = SQL_NO_DATA;
- SQLTCHAR state_[SQL_SQLSTATE_SIZE+1];
- QVarLengthArray<SQLTCHAR> description_(SQL_MAX_MESSAGE_LENGTH);
- QString result;
- int i = 1;
+ QVarLengthArray<SQLTCHAR, SQL_SQLSTATE_SIZE + 1> state(SQL_SQLSTATE_SIZE + 1);
+ QVarLengthArray<SQLTCHAR, SQL_MAX_MESSAGE_LENGTH + 1> description(SQL_MAX_MESSAGE_LENGTH + 1);
+ QList<DiagRecord> result;
- description_[0] = 0;
+ if (!handle)
+ return result;
do {
r = SQLGetDiagRec(handleType,
handle,
i,
- state_,
- &nativeCode_,
- 0,
- 0,
+ state.data(),
+ &nativeCode,
+ description.data(),
+ description.size(),
&msgLen);
- if ((r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) && msgLen > 0)
- description_.resize(msgLen+1);
- r = SQLGetDiagRec(handleType,
- handle,
- i,
- state_,
- &nativeCode_,
- description_.data(),
- description_.size(),
- &msgLen);
- if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) {
- if (nativeCode)
- *nativeCode = nativeCode_;
- const QString tmpstore = fromSQLTCHAR(description_, msgLen);
- if(result != tmpstore) {
- if(!result.isEmpty())
- result += QLatin1Char(' ');
- result += tmpstore;
- }
+ if (msgLen >= description.size()) {
+ description.resize(msgLen + 1); // incl. \0 termination
+ continue;
+ }
+ if (SQL_SUCCEEDED(r)) {
+ result.push_back({fromSQLTCHAR(description, msgLen),
+ fromSQLTCHAR(state),
+ QString::number(nativeCode)});
} else if (r == SQL_ERROR || r == SQL_INVALID_HANDLE) {
- return result;
+ break;
}
++i;
} while (r != SQL_NO_DATA);
return result;
}
-static QString qODBCWarn(const SQLHANDLE hStmt, const SQLHANDLE envHandle = 0,
- const SQLHANDLE pDbC = 0, int *nativeCode = 0)
+static QList<DiagRecord> qODBCWarn(const SQLHANDLE hStmt,
+ const SQLHANDLE envHandle = nullptr,
+ const SQLHANDLE pDbC = nullptr)
{
- QString result;
- if (envHandle)
- result += qWarnODBCHandle(SQL_HANDLE_ENV, envHandle, nativeCode);
- if (pDbC) {
- const QString dMessage = qWarnODBCHandle(SQL_HANDLE_DBC, pDbC, nativeCode);
- if (!dMessage.isEmpty()) {
- if (!result.isEmpty())
- result += QLatin1Char(' ');
- result += dMessage;
- }
- }
- if (hStmt) {
- const QString hMessage = qWarnODBCHandle(SQL_HANDLE_STMT, hStmt, nativeCode);
- if (!hMessage.isEmpty()) {
- if (!result.isEmpty())
- result += QLatin1Char(' ');
- result += hMessage;
- }
- }
+ QList<DiagRecord> result;
+ result.append(qWarnODBCHandle(SQL_HANDLE_ENV, envHandle));
+ result.append(qWarnODBCHandle(SQL_HANDLE_DBC, pDbC));
+ result.append(qWarnODBCHandle(SQL_HANDLE_STMT, hStmt));
return result;
}
-static QString qODBCWarn(const QODBCResultPrivate* odbc, int *nativeCode = 0)
+static QList<DiagRecord> qODBCWarn(const QODBCResultPrivate *odbc)
{
- return qODBCWarn(odbc->hStmt, odbc->dpEnv(), odbc->dpDbc(), nativeCode);
+ return qODBCWarn(odbc->hStmt, odbc->dpEnv(), odbc->dpDbc());
}
-static QString qODBCWarn(const QODBCDriverPrivate* odbc, int *nativeCode = 0)
+static QList<DiagRecord> qODBCWarn(const QODBCDriverPrivate *odbc)
{
- return qODBCWarn(0, odbc->hEnv, odbc->hDbc, nativeCode);
+ return qODBCWarn(nullptr, odbc->hEnv, odbc->hDbc);
}
-static void qSqlWarning(const QString& message, const QODBCResultPrivate* odbc)
+static DiagRecord combineRecords(const QList<DiagRecord> &records)
{
- qWarning() << message << "\tError:" << qODBCWarn(odbc);
+ const auto add = [](const DiagRecord &a, const DiagRecord &b) {
+ return DiagRecord{a.description + u' ' + b.description,
+ a.sqlState + u';' + b.sqlState,
+ a.errorCode + u';' + b.errorCode};
+ };
+ if (records.isEmpty())
+ return {};
+ return std::accumulate(std::next(records.begin()), records.end(), records.front(), add);
}
-static void qSqlWarning(const QString &message, const QODBCDriverPrivate *odbc)
+static QSqlError errorFromDiagRecords(const QString &err,
+ QSqlError::ErrorType type,
+ const QList<DiagRecord> &records)
{
- qWarning() << message << "\tError:" << qODBCWarn(odbc);
+ if (records.empty())
+ return QSqlError("QODBC: unknown error"_L1, {}, type, {});
+ const auto combined = combineRecords(records);
+ return QSqlError("QODBC: "_L1 + err, combined.description + ", "_L1 + combined.sqlState, type,
+ combined.errorCode);
}
-static void qSqlWarning(const QString &message, const SQLHANDLE hStmt)
+static QString errorStringFromDiagRecords(const QList<DiagRecord>& records)
{
- qWarning() << message << "\tError:" << qODBCWarn(hStmt);
+ const auto combined = combineRecords(records);
+ return combined.description;
}
-static QSqlError qMakeError(const QString& err, QSqlError::ErrorType type, const QODBCResultPrivate* p)
+template<class T>
+static void qSqlWarning(const QString &message, T &&val)
{
- int nativeCode = -1;
- QString message = qODBCWarn(p, &nativeCode);
- return QSqlError(QLatin1String("QODBC: ") + err, message, type,
- nativeCode != -1 ? QString::number(nativeCode) : QString());
+ const auto addMsg = errorStringFromDiagRecords(qODBCWarn(val));
+ if (addMsg.isEmpty())
+ qCWarning(lcOdbc) << message;
+ else
+ qCWarning(lcOdbc) << message << "\tError:" << addMsg;
}
-static QSqlError qMakeError(const QString& err, QSqlError::ErrorType type,
- const QODBCDriverPrivate* p)
+static QSqlError qMakeError(const QString &err,
+ QSqlError::ErrorType type,
+ const QODBCResultPrivate *p)
{
- int nativeCode = -1;
- QString message = qODBCWarn(p, &nativeCode);
- return QSqlError(QLatin1String("QODBC: ") + err, message, type,
- nativeCode != -1 ? QString::number(nativeCode) : QString());
+ return errorFromDiagRecords(err, type, qODBCWarn(p));
}
-static QVariant::Type qDecodeODBCType(SQLSMALLINT sqltype, bool isSigned = true)
+static QSqlError qMakeError(const QString &err,
+ QSqlError::ErrorType type,
+ const QODBCDriverPrivate *p)
{
- QVariant::Type type = QVariant::Invalid;
+ return errorFromDiagRecords(err, type, qODBCWarn(p));
+}
+
+static QMetaType qDecodeODBCType(SQLSMALLINT sqltype, bool isSigned = true)
+{
+ int type = QMetaType::UnknownType;
switch (sqltype) {
case SQL_DECIMAL:
case SQL_NUMERIC:
- case SQL_REAL:
- case SQL_FLOAT:
- case SQL_DOUBLE:
- type = QVariant::Double;
+ case SQL_FLOAT: // 24 or 53 bits precision
+ case SQL_DOUBLE:// 53 bits
+ type = QMetaType::Double;
+ break;
+ case SQL_REAL: // 24 bits
+ type = QMetaType::Float;
break;
case SQL_SMALLINT:
+ type = isSigned ? QMetaType::Short : QMetaType::UShort;
+ break;
case SQL_INTEGER:
case SQL_BIT:
- type = isSigned ? QVariant::Int : QVariant::UInt;
+ type = isSigned ? QMetaType::Int : QMetaType::UInt;
break;
case SQL_TINYINT:
- type = QVariant::UInt;
+ type = QMetaType::UInt;
break;
case SQL_BIGINT:
- type = isSigned ? QVariant::LongLong : QVariant::ULongLong;
+ type = isSigned ? QMetaType::LongLong : QMetaType::ULongLong;
break;
case SQL_BINARY:
case SQL_VARBINARY:
case SQL_LONGVARBINARY:
- type = QVariant::ByteArray;
+ type = QMetaType::QByteArray;
break;
case SQL_DATE:
case SQL_TYPE_DATE:
- type = QVariant::Date;
+ type = QMetaType::QDate;
break;
+ case SQL_SS_TIME2:
case SQL_TIME:
case SQL_TYPE_TIME:
- type = QVariant::Time;
+ type = QMetaType::QTime;
break;
case SQL_TIMESTAMP:
case SQL_TYPE_TIMESTAMP:
- type = QVariant::DateTime;
+ type = QMetaType::QDateTime;
break;
case SQL_WCHAR:
case SQL_WVARCHAR:
case SQL_WLONGVARCHAR:
- type = QVariant::String;
+ type = QMetaType::QString;
break;
case SQL_CHAR:
case SQL_VARCHAR:
@@ -399,128 +398,78 @@ static QVariant::Type qDecodeODBCType(SQLSMALLINT sqltype, bool isSigned = true)
case SQL_GUID:
#endif
case SQL_LONGVARCHAR:
- type = QVariant::String;
+ type = QMetaType::QString;
break;
default:
- type = QVariant::ByteArray;
+ type = QMetaType::QByteArray;
break;
}
- return type;
+ return QMetaType(type);
}
-static QString qGetStringData(SQLHANDLE hStmt, int column, int colSize, bool unicode = false)
+template <typename CT>
+static QVariant getStringDataImpl(SQLHANDLE hStmt, SQLUSMALLINT column, qsizetype colSize, SQLSMALLINT targetType)
{
QString fieldVal;
SQLRETURN r = SQL_ERROR;
SQLLEN lengthIndicator = 0;
-
- // NB! colSize must be a multiple of 2 for unicode enabled DBs
- if (colSize <= 0) {
- colSize = 256;
- } else if (colSize > 65536) { // limit buffer size to 64 KB
- colSize = 65536;
- } else {
- colSize++; // make sure there is room for more than the 0 termination
- }
- if(unicode) {
+ QVarLengthArray<CT> buf(colSize);
+ while (true) {
r = SQLGetData(hStmt,
- column+1,
- SQL_C_TCHAR,
- NULL,
- 0,
- &lengthIndicator);
- if ((r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) && lengthIndicator > 0)
- colSize = int(lengthIndicator / sizeof(SQLTCHAR) + 1);
- QVarLengthArray<SQLTCHAR> buf(colSize);
- memset(buf.data(), 0, colSize*sizeof(SQLTCHAR));
- while (true) {
- r = SQLGetData(hStmt,
- column+1,
- SQL_C_TCHAR,
- (SQLPOINTER)buf.data(),
- colSize*sizeof(SQLTCHAR),
- &lengthIndicator);
- if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) {
- if (lengthIndicator == SQL_NULL_DATA) {
- fieldVal.clear();
- break;
- }
- // starting with ODBC Native Client 2012, SQL_NO_TOTAL is returned
- // instead of the length (which sometimes was wrong in older versions)
- // see link for more info: http://msdn.microsoft.com/en-us/library/jj219209.aspx
- // if length indicator equals SQL_NO_TOTAL, indicating that
- // more data can be fetched, but size not known, collect data
- // and fetch next block
- if (lengthIndicator == SQL_NO_TOTAL) {
- fieldVal += fromSQLTCHAR(buf, colSize);
- continue;
- }
- // if SQL_SUCCESS_WITH_INFO is returned, indicating that
- // more data can be fetched, the length indicator does NOT
- // contain the number of bytes returned - it contains the
- // total number of bytes that CAN be fetched
- int rSize = (r == SQL_SUCCESS_WITH_INFO) ? colSize : int(lengthIndicator / sizeof(SQLTCHAR));
- fieldVal += fromSQLTCHAR(buf, rSize);
- if (lengthIndicator < SQLLEN(colSize*sizeof(SQLTCHAR))) {
- // workaround for Drivermanagers that don't return SQL_NO_DATA
- break;
- }
- } else if (r == SQL_NO_DATA) {
- break;
- } else {
- qWarning() << "qGetStringData: Error while fetching data (" << qWarnODBCHandle(SQL_HANDLE_STMT, hStmt) << ')';
- fieldVal.clear();
- break;
+ column + 1,
+ targetType,
+ SQLPOINTER(buf.data()), SQLINTEGER(buf.size() * sizeof(CT)),
+ &lengthIndicator);
+ if (SQL_SUCCEEDED(r)) {
+ if (lengthIndicator == SQL_NULL_DATA) {
+ return {};
}
- }
- } else {
- r = SQLGetData(hStmt,
- column+1,
- SQL_C_CHAR,
- NULL,
- 0,
- &lengthIndicator);
- if ((r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) && lengthIndicator > 0)
- colSize = lengthIndicator + 1;
- QVarLengthArray<SQLCHAR> buf(colSize);
- while (true) {
- r = SQLGetData(hStmt,
- column+1,
- SQL_C_CHAR,
- (SQLPOINTER)buf.data(),
- colSize,
- &lengthIndicator);
- if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) {
- if (lengthIndicator == SQL_NULL_DATA || lengthIndicator == SQL_NO_TOTAL) {
- fieldVal.clear();
- break;
- }
- // if SQL_SUCCESS_WITH_INFO is returned, indicating that
- // more data can be fetched, the length indicator does NOT
- // contain the number of bytes returned - it contains the
- // total number of bytes that CAN be fetched
- int rSize = (r == SQL_SUCCESS_WITH_INFO) ? colSize : lengthIndicator;
- // Remove any trailing \0 as some drivers misguidedly append one
- int realsize = qMin(rSize, buf.size());
- if (realsize > 0 && buf[realsize - 1] == 0)
- realsize--;
- fieldVal += QString::fromUtf8(reinterpret_cast<const char *>(buf.constData()), realsize);
- if (lengthIndicator < SQLLEN(colSize)) {
- // workaround for Drivermanagers that don't return SQL_NO_DATA
- break;
- }
- } else if (r == SQL_NO_DATA) {
- break;
- } else {
- qWarning() << "qGetStringData: Error while fetching data (" << qWarnODBCHandle(SQL_HANDLE_STMT, hStmt) << ')';
- fieldVal.clear();
+ // starting with ODBC Native Client 2012, SQL_NO_TOTAL is returned
+ // instead of the length (which sometimes was wrong in older versions)
+ // see link for more info: http://msdn.microsoft.com/en-us/library/jj219209.aspx
+ // if length indicator equals SQL_NO_TOTAL, indicating that
+ // more data can be fetched, but size not known, collect data
+ // and fetch next block
+ if (lengthIndicator == SQL_NO_TOTAL) {
+ fieldVal += fromSQLTCHAR<QVarLengthArray<CT>, sizeof(CT)>(buf, buf.size());
+ continue;
+ }
+ // if SQL_SUCCESS_WITH_INFO is returned, indicating that
+ // more data can be fetched, the length indicator does NOT
+ // contain the number of bytes returned - it contains the
+ // total number of bytes that CAN be fetched
+ const qsizetype rSize = (r == SQL_SUCCESS_WITH_INFO)
+ ? buf.size()
+ : qsizetype(lengthIndicator / sizeof(CT));
+ fieldVal += fromSQLTCHAR<QVarLengthArray<CT>, sizeof(CT)>(buf, rSize);
+ // lengthIndicator does not contain the termination character
+ if (lengthIndicator < SQLLEN((buf.size() - 1) * sizeof(CT))) {
+ // workaround for Drivermanagers that don't return SQL_NO_DATA
break;
}
+ } else if (r == SQL_NO_DATA) {
+ break;
+ } else {
+ qSqlWarning("QODBC::getStringData: Error while fetching data"_L1, hStmt);
+ return {};
}
}
return fieldVal;
}
+static QVariant qGetStringData(SQLHANDLE hStmt, SQLUSMALLINT column, int colSize, bool unicode)
+{
+ if (colSize <= 0) {
+ colSize = 256; // default Prealloc size of QVarLengthArray
+ } else if (colSize > 65536) { // limit buffer size to 64 KB
+ colSize = 65536;
+ } else {
+ colSize++; // make sure there is room for more than the 0 termination
+ }
+ return unicode ? getStringDataImpl<SQLTCHAR>(hStmt, column, colSize, SQL_C_TCHAR)
+ : getStringDataImpl<SQLCHAR>(hStmt, column, colSize, SQL_C_CHAR);
+}
+
static QVariant qGetBinaryData(SQLHANDLE hStmt, int column)
{
QByteArray fieldVal;
@@ -532,19 +481,19 @@ static QVariant qGetBinaryData(SQLHANDLE hStmt, int column)
SQLLEN lengthIndicator = 0;
SQLRETURN r = SQL_ERROR;
- QVarLengthArray<SQLTCHAR> colName(COLNAMESIZE);
+ QVarLengthArray<SQLTCHAR, COLNAMESIZE> colName(COLNAMESIZE);
r = SQLDescribeCol(hStmt,
column + 1,
- colName.data(),
- COLNAMESIZE,
+ colName.data(), SQLSMALLINT(colName.size()),
&colNameLen,
&colType,
&colSize,
&colScale,
&nullable);
if (r != SQL_SUCCESS)
- qWarning() << "qGetBinaryData: Unable to describe column" << column;
+ qSqlWarning(("QODBC::qGetBinaryData: Unable to describe column %1"_L1)
+ .arg(QString::number(column)), hStmt);
// SQLDescribeCol may return 0 if size cannot be determined
if (!colSize)
colSize = 255;
@@ -559,10 +508,10 @@ static QVariant qGetBinaryData(SQLHANDLE hStmt, int column)
const_cast<char *>(fieldVal.constData() + read),
colSize,
&lengthIndicator);
- if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO)
+ if (!SQL_SUCCEEDED(r))
break;
if (lengthIndicator == SQL_NULL_DATA)
- return QVariant(QVariant::ByteArray);
+ return QVariant(QMetaType(QMetaType::QByteArray));
if (lengthIndicator > SQLLEN(colSize) || lengthIndicator == SQL_NO_TOTAL) {
read += colSize;
colSize = 65536;
@@ -588,10 +537,10 @@ static QVariant qGetIntData(SQLHANDLE hStmt, int column, bool isSigned = true)
(SQLPOINTER)&intbuf,
sizeof(intbuf),
&lengthIndicator);
- if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO)
- return QVariant(QVariant::Invalid);
+ if (!SQL_SUCCEEDED(r))
+ return QVariant();
if (lengthIndicator == SQL_NULL_DATA)
- return QVariant(QVariant::Int);
+ return QVariant(QMetaType::fromType<int>());
if (isSigned)
return int(intbuf);
else
@@ -608,11 +557,11 @@ static QVariant qGetDoubleData(SQLHANDLE hStmt, int column)
(SQLPOINTER) &dblbuf,
0,
&lengthIndicator);
- if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) {
- return QVariant(QVariant::Invalid);
+ if (!SQL_SUCCEEDED(r)) {
+ return QVariant();
}
- if(lengthIndicator == SQL_NULL_DATA)
- return QVariant(QVariant::Double);
+ if (lengthIndicator == SQL_NULL_DATA)
+ return QVariant(QMetaType::fromType<double>());
return (double) dblbuf;
}
@@ -628,10 +577,10 @@ static QVariant qGetBigIntData(SQLHANDLE hStmt, int column, bool isSigned = true
(SQLPOINTER) &lngbuf,
sizeof(lngbuf),
&lengthIndicator);
- if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO)
- return QVariant(QVariant::Invalid);
+ if (!SQL_SUCCEEDED(r))
+ return QVariant();
if (lengthIndicator == SQL_NULL_DATA)
- return QVariant(QVariant::LongLong);
+ return QVariant(QMetaType::fromType<qlonglong>());
if (isSigned)
return qint64(lngbuf);
@@ -644,28 +593,25 @@ static bool isAutoValue(const SQLHANDLE hStmt, int column)
SQLLEN nNumericAttribute = 0; // Check for auto-increment
const SQLRETURN r = ::SQLColAttribute(hStmt, column + 1, SQL_DESC_AUTO_UNIQUE_VALUE,
0, 0, 0, &nNumericAttribute);
- if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) {
- qSqlWarning(QStringLiteral("qMakeField: Unable to get autovalue attribute for column ")
- + QString::number(column), hStmt);
+ if (!SQL_SUCCEEDED(r)) {
+ qSqlWarning(("QODBC::isAutoValue: Unable to get autovalue attribute for column %1"_L1)
+ .arg(QString::number(column)), hStmt);
return false;
}
return nNumericAttribute != SQL_FALSE;
}
-static QSqlField qMakeFieldInfo(const SQLHANDLE hStmt, int i, QString *errorMessage);
-
// creates a QSqlField from a valid hStmt generated
// by SQLColumns. The hStmt has to point to a valid position.
static QSqlField qMakeFieldInfo(const SQLHANDLE hStmt, const QODBCDriverPrivate* p)
{
- QString fname = qGetStringData(hStmt, 3, -1, p->unicode);
+ QString fname = qGetStringData(hStmt, 3, -1, p->unicode).toString();
int type = qGetIntData(hStmt, 4).toInt(); // column type
QSqlField f(fname, qDecodeODBCType(type, p));
QVariant var = qGetIntData(hStmt, 6);
f.setLength(var.isNull() ? -1 : var.toInt()); // column size
var = qGetIntData(hStmt, 8).toInt();
f.setPrecision(var.isNull() ? -1 : var.toInt()); // precision
- f.setSqlType(type);
int required = qGetIntData(hStmt, 10).toInt(); // nullable-flag
// required can be SQL_NO_NULLS, SQL_NULLABLE or SQL_NULLABLE_UNKNOWN
if (required == SQL_NO_NULLS)
@@ -676,16 +622,7 @@ static QSqlField qMakeFieldInfo(const SQLHANDLE hStmt, const QODBCDriverPrivate*
return f;
}
-static QSqlField qMakeFieldInfo(const QODBCResultPrivate* p, int i )
-{
- QString errorMessage;
- const QSqlField result = qMakeFieldInfo(p->hStmt, i, &errorMessage);
- if (!errorMessage.isEmpty())
- qSqlWarning(errorMessage, p);
- return result;
-}
-
-static QSqlField qMakeFieldInfo(const SQLHANDLE hStmt, int i, QString *errorMessage)
+static QSqlField qMakeFieldInfo(const QODBCResultPrivate *p, int i)
{
SQLSMALLINT colNameLen;
SQLSMALLINT colType;
@@ -693,12 +630,10 @@ static QSqlField qMakeFieldInfo(const SQLHANDLE hStmt, int i, QString *errorMess
SQLSMALLINT colScale;
SQLSMALLINT nullable;
SQLRETURN r = SQL_ERROR;
- QVarLengthArray<SQLTCHAR> colName(COLNAMESIZE);
- errorMessage->clear();
- r = SQLDescribeCol(hStmt,
+ QVarLengthArray<SQLTCHAR, COLNAMESIZE> colName(COLNAMESIZE);
+ r = SQLDescribeCol(p->hStmt,
i+1,
- colName.data(),
- (SQLSMALLINT)COLNAMESIZE,
+ colName.data(), SQLSMALLINT(colName.size()),
&colNameLen,
&colType,
&colSize,
@@ -706,12 +641,13 @@ static QSqlField qMakeFieldInfo(const SQLHANDLE hStmt, int i, QString *errorMess
&nullable);
if (r != SQL_SUCCESS) {
- *errorMessage = QStringLiteral("qMakeField: Unable to describe column ") + QString::number(i);
+ qSqlWarning(("QODBC::qMakeFieldInfo: Unable to describe column %1"_L1)
+ .arg(QString::number(i)), p);
return QSqlField();
}
SQLLEN unsignedFlag = SQL_FALSE;
- r = SQLColAttribute (hStmt,
+ r = SQLColAttribute (p->hStmt,
i + 1,
SQL_DESC_UNSIGNED,
0,
@@ -719,15 +655,14 @@ static QSqlField qMakeFieldInfo(const SQLHANDLE hStmt, int i, QString *errorMess
0,
&unsignedFlag);
if (r != SQL_SUCCESS) {
- qSqlWarning(QStringLiteral("qMakeField: Unable to get column attributes for column ")
- + QString::number(i), hStmt);
+ qSqlWarning(("QODBC::qMakeFieldInfo: Unable to get column attributes for column %1"_L1)
+ .arg(QString::number(i)), p);
}
const QString qColName(fromSQLTCHAR(colName, colNameLen));
// nullable can be SQL_NO_NULLS, SQL_NULLABLE or SQL_NULLABLE_UNKNOWN
- QVariant::Type type = qDecodeODBCType(colType, unsignedFlag == SQL_FALSE);
+ QMetaType type = qDecodeODBCType(colType, unsignedFlag == SQL_FALSE);
QSqlField f(qColName, type);
- f.setSqlType(colType);
f.setLength(colSize == 0 ? -1 : int(colSize));
f.setPrecision(colScale == 0 ? -1 : int(colScale));
if (nullable == SQL_NO_NULLS)
@@ -735,19 +670,24 @@ static QSqlField qMakeFieldInfo(const SQLHANDLE hStmt, int i, QString *errorMess
else if (nullable == SQL_NULLABLE)
f.setRequired(false);
// else we don't know
- f.setAutoValue(isAutoValue(hStmt, i));
- QVarLengthArray<SQLTCHAR> tableName(TABLENAMESIZE);
+ f.setAutoValue(isAutoValue(p->hStmt, i));
+ QVarLengthArray<SQLTCHAR, TABLENAMESIZE> tableName(TABLENAMESIZE);
SQLSMALLINT tableNameLen;
- r = SQLColAttribute(hStmt, i + 1, SQL_DESC_BASE_TABLE_NAME, tableName.data(),
- TABLENAMESIZE, &tableNameLen, 0);
+ r = SQLColAttribute(p->hStmt,
+ i + 1,
+ SQL_DESC_BASE_TABLE_NAME,
+ tableName.data(),
+ SQLSMALLINT(tableName.size() * sizeof(SQLTCHAR)), // SQLColAttribute needs/returns size in bytes
+ &tableNameLen,
+ 0);
if (r == SQL_SUCCESS)
- f.setTableName(fromSQLTCHAR(tableName, tableNameLen));
+ f.setTableName(fromSQLTCHAR(tableName, tableNameLen / sizeof(SQLTCHAR)));
return f;
}
static size_t qGetODBCVersion(const QString &connOpts)
{
- if (connOpts.contains(QLatin1String("SQL_ATTR_ODBC_VERSION=SQL_OV_ODBC3"), Qt::CaseInsensitive))
+ if (connOpts.contains("SQL_ATTR_ODBC_VERSION=SQL_OV_ODBC3"_L1, Qt::CaseInsensitive))
return SQL_OV_ODBC3;
return SQL_OV_ODBC2;
}
@@ -762,185 +702,202 @@ QChar QODBCDriverPrivate::quoteChar()
&driverResponse,
sizeof(driverResponse),
&length);
- if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO)
+ if (SQL_SUCCEEDED(r))
quote = QChar(driverResponse[0]);
else
- quote = QLatin1Char('"');
+ quote = u'"';
isQuoteInitialized = true;
}
return quote;
}
+SQLRETURN QODBCDriverPrivate::sqlFetchNext(const SqlStmtHandle &hStmt) const
+{
+ return sqlFetchNext(hStmt.handle());
+}
+
+SQLRETURN QODBCDriverPrivate::sqlFetchNext(SQLHANDLE hStmt) const
+{
+ if (hasSQLFetchScroll)
+ return SQLFetchScroll(hStmt, SQL_FETCH_NEXT, 0);
+ return SQLFetch(hStmt);
+}
+
+static SQLRETURN qt_string_SQLSetConnectAttr(SQLHDBC handle, SQLINTEGER attr, QStringView val)
+{
+ auto encoded = toSQLTCHAR(val);
+ return SQLSetConnectAttr(handle, attr,
+ encoded.data(),
+ SQLINTEGER(encoded.size() * sizeof(SQLTCHAR))); // size in bytes
+}
+
-bool QODBCDriverPrivate::setConnectionOptions(const QString& connOpts)
+bool QODBCDriverPrivate::setConnectionOptions(const QString &connOpts)
{
// Set any connection attributes
- const QStringList opts(connOpts.split(QLatin1Char(';'), QString::SkipEmptyParts));
SQLRETURN r = SQL_SUCCESS;
- for (int i = 0; i < opts.count(); ++i) {
- const QString tmp(opts.at(i));
+ for (const auto connOpt : QStringTokenizer{connOpts, u';'}) {
int idx;
- if ((idx = tmp.indexOf(QLatin1Char('='))) == -1) {
- qWarning() << "QODBCDriver::open: Illegal connect option value '" << tmp << '\'';
+ if ((idx = connOpt.indexOf(u'=')) == -1) {
+ qSqlWarning(("QODBCDriver::open: Illegal connect option value '%1'"_L1)
+ .arg(connOpt), this);
continue;
}
- const QString opt(tmp.left(idx));
- const QString val(tmp.mid(idx + 1).simplified());
+ const auto opt(connOpt.left(idx));
+ const auto val(connOpt.mid(idx + 1).trimmed());
SQLUINTEGER v = 0;
r = SQL_SUCCESS;
- if (opt.toUpper() == QLatin1String("SQL_ATTR_ACCESS_MODE")) {
- if (val.toUpper() == QLatin1String("SQL_MODE_READ_ONLY")) {
+ if (opt == "SQL_ATTR_ACCESS_MODE"_L1) {
+ if (val == "SQL_MODE_READ_ONLY"_L1) {
v = SQL_MODE_READ_ONLY;
- } else if (val.toUpper() == QLatin1String("SQL_MODE_READ_WRITE")) {
+ } else if (val == "SQL_MODE_READ_WRITE"_L1) {
v = SQL_MODE_READ_WRITE;
} else {
- qWarning() << "QODBCDriver::open: Unknown option value '" << val << '\'';
+ qSqlWarning(("QODBCDriver::open: Unknown option value '%1'"_L1)
+ .arg(val), this);
continue;
}
r = SQLSetConnectAttr(hDbc, SQL_ATTR_ACCESS_MODE, (SQLPOINTER) size_t(v), 0);
- } else if (opt.toUpper() == QLatin1String("SQL_ATTR_CONNECTION_TIMEOUT")) {
+ } else if (opt == "SQL_ATTR_CONNECTION_TIMEOUT"_L1) {
v = val.toUInt();
r = SQLSetConnectAttr(hDbc, SQL_ATTR_CONNECTION_TIMEOUT, (SQLPOINTER) size_t(v), 0);
- } else if (opt.toUpper() == QLatin1String("SQL_ATTR_LOGIN_TIMEOUT")) {
+ } else if (opt == "SQL_ATTR_LOGIN_TIMEOUT"_L1) {
v = val.toUInt();
r = SQLSetConnectAttr(hDbc, SQL_ATTR_LOGIN_TIMEOUT, (SQLPOINTER) size_t(v), 0);
- } else if (opt.toUpper() == QLatin1String("SQL_ATTR_CURRENT_CATALOG")) {
- val.utf16(); // 0 terminate
- r = SQLSetConnectAttr(hDbc, SQL_ATTR_CURRENT_CATALOG,
- toSQLTCHAR(val).data(),
- val.length()*sizeof(SQLTCHAR));
- } else if (opt.toUpper() == QLatin1String("SQL_ATTR_METADATA_ID")) {
- if (val.toUpper() == QLatin1String("SQL_TRUE")) {
+ } else if (opt == "SQL_ATTR_CURRENT_CATALOG"_L1) {
+ r = qt_string_SQLSetConnectAttr(hDbc, SQL_ATTR_CURRENT_CATALOG, val);
+ } else if (opt == "SQL_ATTR_METADATA_ID"_L1) {
+ if (val == "SQL_TRUE"_L1) {
v = SQL_TRUE;
- } else if (val.toUpper() == QLatin1String("SQL_FALSE")) {
+ } else if (val == "SQL_FALSE"_L1) {
v = SQL_FALSE;
} else {
- qWarning() << "QODBCDriver::open: Unknown option value '" << val << '\'';
+ qSqlWarning(("QODBCDriver::open: Unknown option value '%1'"_L1)
+ .arg(val), this);
continue;
}
r = SQLSetConnectAttr(hDbc, SQL_ATTR_METADATA_ID, (SQLPOINTER) size_t(v), 0);
- } else if (opt.toUpper() == QLatin1String("SQL_ATTR_PACKET_SIZE")) {
+ } else if (opt == "SQL_ATTR_PACKET_SIZE"_L1) {
v = val.toUInt();
r = SQLSetConnectAttr(hDbc, SQL_ATTR_PACKET_SIZE, (SQLPOINTER) size_t(v), 0);
- } else if (opt.toUpper() == QLatin1String("SQL_ATTR_TRACEFILE")) {
- val.utf16(); // 0 terminate
- r = SQLSetConnectAttr(hDbc, SQL_ATTR_TRACEFILE,
- toSQLTCHAR(val).data(),
- val.length()*sizeof(SQLTCHAR));
- } else if (opt.toUpper() == QLatin1String("SQL_ATTR_TRACE")) {
- if (val.toUpper() == QLatin1String("SQL_OPT_TRACE_OFF")) {
+ } else if (opt == "SQL_ATTR_TRACEFILE"_L1) {
+ r = qt_string_SQLSetConnectAttr(hDbc, SQL_ATTR_TRACEFILE, val);
+ } else if (opt == "SQL_ATTR_TRACE"_L1) {
+ if (val == "SQL_OPT_TRACE_OFF"_L1) {
v = SQL_OPT_TRACE_OFF;
- } else if (val.toUpper() == QLatin1String("SQL_OPT_TRACE_ON")) {
+ } else if (val == "SQL_OPT_TRACE_ON"_L1) {
v = SQL_OPT_TRACE_ON;
} else {
- qWarning() << "QODBCDriver::open: Unknown option value '" << val << '\'';
+ qSqlWarning(("QODBCDriver::open: Unknown option value '%1'"_L1)
+ .arg(val), this);
continue;
}
r = SQLSetConnectAttr(hDbc, SQL_ATTR_TRACE, (SQLPOINTER) size_t(v), 0);
- } else if (opt.toUpper() == QLatin1String("SQL_ATTR_CONNECTION_POOLING")) {
- if (val == QLatin1String("SQL_CP_OFF"))
+ } else if (opt == "SQL_ATTR_CONNECTION_POOLING"_L1) {
+ if (val == "SQL_CP_OFF"_L1)
v = SQL_CP_OFF;
- else if (val.toUpper() == QLatin1String("SQL_CP_ONE_PER_DRIVER"))
+ else if (val == "SQL_CP_ONE_PER_DRIVER"_L1)
v = SQL_CP_ONE_PER_DRIVER;
- else if (val.toUpper() == QLatin1String("SQL_CP_ONE_PER_HENV"))
+ else if (val == "SQL_CP_ONE_PER_HENV"_L1)
v = SQL_CP_ONE_PER_HENV;
- else if (val.toUpper() == QLatin1String("SQL_CP_DEFAULT"))
+ else if (val == "SQL_CP_DEFAULT"_L1)
v = SQL_CP_DEFAULT;
else {
- qWarning() << "QODBCDriver::open: Unknown option value '" << val << '\'';
+ qSqlWarning(("QODBCDriver::open: Unknown option value '%1'"_L1)
+ .arg(val), this);
continue;
}
r = SQLSetConnectAttr(hDbc, SQL_ATTR_CONNECTION_POOLING, (SQLPOINTER) size_t(v), 0);
- } else if (opt.toUpper() == QLatin1String("SQL_ATTR_CP_MATCH")) {
- if (val.toUpper() == QLatin1String("SQL_CP_STRICT_MATCH"))
+ } else if (opt == "SQL_ATTR_CP_MATCH"_L1) {
+ if (val == "SQL_CP_STRICT_MATCH"_L1)
v = SQL_CP_STRICT_MATCH;
- else if (val.toUpper() == QLatin1String("SQL_CP_RELAXED_MATCH"))
+ else if (val == "SQL_CP_RELAXED_MATCH"_L1)
v = SQL_CP_RELAXED_MATCH;
- else if (val.toUpper() == QLatin1String("SQL_CP_MATCH_DEFAULT"))
+ else if (val == "SQL_CP_MATCH_DEFAULT"_L1)
v = SQL_CP_MATCH_DEFAULT;
else {
- qWarning() << "QODBCDriver::open: Unknown option value '" << val << '\'';
+ qSqlWarning(("QODBCDriver::open: Unknown option value '%1'"_L1)
+ .arg(val), this);
continue;
}
r = SQLSetConnectAttr(hDbc, SQL_ATTR_CP_MATCH, (SQLPOINTER) size_t(v), 0);
- } else if (opt.toUpper() == QLatin1String("SQL_ATTR_ODBC_VERSION")) {
+ } else if (opt == "SQL_ATTR_ODBC_VERSION"_L1) {
// Already handled in QODBCDriver::open()
continue;
} else {
- qWarning() << "QODBCDriver::open: Unknown connection attribute '" << opt << '\'';
+ qSqlWarning(("QODBCDriver::open: Unknown connection attribute '%1'"_L1)
+ .arg(opt), this);
}
- if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO)
- qSqlWarning(QString::fromLatin1("QODBCDriver::open: Unable to set connection attribute'%1'").arg(
- opt), this);
+ if (!SQL_SUCCEEDED(r))
+ qSqlWarning(("QODBCDriver::open: Unable to set connection attribute '%1'"_L1)
+ .arg(opt), this);
}
return true;
}
-void QODBCDriverPrivate::splitTableQualifier(const QString & qualifier, QString &catalog,
- QString &schema, QString &table)
+void QODBCDriverPrivate::splitTableQualifier(const QString &qualifier, QString &catalog,
+ QString &schema, QString &table) const
{
+ Q_Q(const QODBCDriver);
+ const auto adjustName = [&](const QString &name) {
+ if (q->isIdentifierEscaped(name, QSqlDriver::TableName))
+ return q->stripDelimiters(name, QSqlDriver::TableName);
+ return adjustCase(name);
+ };
+ catalog.clear();
+ schema.clear();
+ table.clear();
if (!useSchema) {
- table = qualifier;
+ table = adjustName(qualifier);
return;
}
- QStringList l = qualifier.split(QLatin1Char('.'));
- if (l.count() > 3)
- return; // can't possibly be a valid table qualifier
- int i = 0, n = l.count();
- if (n == 1) {
- table = qualifier;
- } else {
- for (QStringList::Iterator it = l.begin(); it != l.end(); ++it) {
- if (n == 3) {
- if (i == 0) {
- catalog = *it;
- } else if (i == 1) {
- schema = *it;
- } else if (i == 2) {
- table = *it;
- }
- } else if (n == 2) {
- if (i == 0) {
- schema = *it;
- } else if (i == 1) {
- table = *it;
- }
- }
- i++;
- }
+ const QList<QStringView> l = QStringView(qualifier).split(u'.');
+ switch (l.count()) {
+ case 1:
+ table = adjustName(qualifier);
+ break;
+ case 2:
+ schema = adjustName(l.at(0).toString());
+ table = adjustName(l.at(1).toString());
+ break;
+ case 3:
+ catalog = adjustName(l.at(0).toString());
+ schema = adjustName(l.at(1).toString());
+ table = adjustName(l.at(2).toString());
+ break;
+ default:
+ qSqlWarning(("QODBCDriver::splitTableQualifier: Unable to split table qualifier '%1'"_L1)
+ .arg(qualifier), this);
+ break;
}
}
-QODBCDriverPrivate::DefaultCase QODBCDriverPrivate::defaultCase() const
+void QODBCDriverPrivate::checkDefaultCase()
{
- DefaultCase ret;
+ m_defaultCase = DefaultCase::Mixed; //arbitrary case if driver cannot be queried
SQLUSMALLINT casing;
- int r = SQLGetInfo(hDbc,
- SQL_IDENTIFIER_CASE,
- &casing,
- sizeof(casing),
- NULL);
- if ( r != SQL_SUCCESS)
- ret = Mixed;//arbitrary case if driver cannot be queried
- else {
+ SQLRETURN r = SQLGetInfo(hDbc,
+ SQL_IDENTIFIER_CASE,
+ &casing,
+ sizeof(casing),
+ NULL);
+ if (r == SQL_SUCCESS) {
switch (casing) {
- case (SQL_IC_UPPER):
- ret = Upper;
- break;
- case (SQL_IC_LOWER):
- ret = Lower;
- break;
- case (SQL_IC_SENSITIVE):
- ret = Sensitive;
- break;
- case (SQL_IC_MIXED):
- default:
- ret = Mixed;
- break;
+ case SQL_IC_UPPER:
+ m_defaultCase = DefaultCase::Upper;
+ break;
+ case SQL_IC_LOWER:
+ m_defaultCase = DefaultCase::Lower;
+ break;
+ case SQL_IC_SENSITIVE:
+ m_defaultCase = DefaultCase::Sensitive;
+ break;
+ case SQL_IC_MIXED:
+ m_defaultCase = DefaultCase::Mixed;
+ break;
}
}
- return ret;
}
/*
@@ -949,20 +906,16 @@ QODBCDriverPrivate::DefaultCase QODBCDriverPrivate::defaultCase() const
*/
QString QODBCDriverPrivate::adjustCase(const QString &identifier) const
{
- QString ret = identifier;
- switch(defaultCase()) {
- case (Lower):
- ret = identifier.toLower();
- break;
- case (Upper):
- ret = identifier.toUpper();
- break;
- case(Mixed):
- case(Sensitive):
- default:
- ret = identifier;
+ switch (m_defaultCase) {
+ case DefaultCase::Lower:
+ return identifier.toLower();
+ case DefaultCase::Upper:
+ return identifier.toUpper();
+ case DefaultCase::Mixed:
+ case DefaultCase::Sensitive:
+ break;
}
- return ret;
+ return identifier;
}
////////////////////////////////////////////////////////////////////////////
@@ -978,8 +931,7 @@ QODBCResult::~QODBCResult()
if (d->hStmt && d->isStmtHandleValid() && driver() && driver()->isOpen()) {
SQLRETURN r = SQLFreeHandle(SQL_HANDLE_STMT, d->hStmt);
if (r != SQL_SUCCESS)
- qSqlWarning(QLatin1String("QODBCDriver: Unable to free statement handle ")
- + QString::number(r), d);
+ qSqlWarning(("QODBCResult: Unable to free statement handle "_L1), d);
}
}
@@ -998,7 +950,7 @@ bool QODBCResult::reset (const QString& query)
if (d->hStmt && d->isStmtHandleValid()) {
r = SQLFreeHandle(SQL_HANDLE_STMT, d->hStmt);
if (r != SQL_SUCCESS) {
- qSqlWarning(QLatin1String("QODBCResult::reset: Unable to free statement handle"), d);
+ qSqlWarning("QODBCResult::reset: Unable to free statement handle"_L1, d);
return false;
}
}
@@ -1006,7 +958,7 @@ bool QODBCResult::reset (const QString& query)
d->dpDbc(),
&d->hStmt);
if (r != SQL_SUCCESS) {
- qSqlWarning(QLatin1String("QODBCResult::reset: Unable to allocate statement handle"), d);
+ qSqlWarning("QODBCResult::reset: Unable to allocate statement handle"_L1, d);
return false;
}
@@ -1023,17 +975,20 @@ bool QODBCResult::reset (const QString& query)
(SQLPOINTER)SQL_CURSOR_STATIC,
SQL_IS_UINTEGER);
}
- if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) {
+ if (!SQL_SUCCEEDED(r)) {
setLastError(qMakeError(QCoreApplication::translate("QODBCResult",
"QODBCResult::reset: Unable to set 'SQL_CURSOR_STATIC' as statement attribute. "
"Please check your ODBC driver configuration"), QSqlError::StatementError, d));
return false;
}
- r = SQLExecDirect(d->hStmt,
- toSQLTCHAR(query).data(),
- (SQLINTEGER) query.length());
- if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO && r!= SQL_NO_DATA) {
+ {
+ auto encoded = toSQLTCHAR(query);
+ r = SQLExecDirect(d->hStmt,
+ encoded.data(),
+ SQLINTEGER(encoded.size()));
+ }
+ if (!SQL_SUCCEEDED(r) && r!= SQL_NO_DATA) {
setLastError(qMakeError(QCoreApplication::translate("QODBCResult",
"Unable to execute statement"), QSqlError::StatementError, d));
return false;
@@ -1041,14 +996,14 @@ bool QODBCResult::reset (const QString& query)
SQLULEN isScrollable = 0;
r = SQLGetStmtAttr(d->hStmt, SQL_ATTR_CURSOR_SCROLLABLE, &isScrollable, SQL_IS_INTEGER, 0);
- if(r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO)
+ if (SQL_SUCCEEDED(r))
setForwardOnly(isScrollable == SQL_NONSCROLLABLE);
SQLSMALLINT count = 0;
SQLNumResultCols(d->hStmt, &count);
if (count) {
setSelect(true);
- for (int i = 0; i < count; ++i) {
+ for (SQLSMALLINT i = 0; i < count; ++i) {
d->rInf.append(qMakeFieldInfo(d, i));
}
d->fieldCache.resize(count);
@@ -1110,7 +1065,7 @@ bool QODBCResult::fetchNext()
else
r = SQLFetch(d->hStmt);
- if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) {
+ if (!SQL_SUCCEEDED(r)) {
if (r != SQL_NO_DATA)
setLastError(qMakeError(QCoreApplication::translate("QODBCResult",
"Unable to fetch next"), QSqlError::ConnectionError, d));
@@ -1207,7 +1162,8 @@ QVariant QODBCResult::data(int field)
{
Q_D(QODBCResult);
if (field >= d->rInf.count() || field < 0) {
- qWarning() << "QODBCResult::data: column" << field << "out of range";
+ qSqlWarning(("QODBCResult::data: column %1 out of range"_L1)
+ .arg(QString::number(field)), d);
return QVariant();
}
if (field < d->fieldCacheIdx)
@@ -1220,20 +1176,22 @@ QVariant QODBCResult::data(int field)
// some servers do not support fetching column n after we already
// fetched column n+1, so cache all previous columns here
const QSqlField info = d->rInf.field(i);
- switch (info.type()) {
- case QVariant::LongLong:
+ switch (info.metaType().id()) {
+ case QMetaType::LongLong:
d->fieldCache[i] = qGetBigIntData(d->hStmt, i);
break;
- case QVariant::ULongLong:
+ case QMetaType::ULongLong:
d->fieldCache[i] = qGetBigIntData(d->hStmt, i, false);
break;
- case QVariant::Int:
+ case QMetaType::Int:
+ case QMetaType::Short:
d->fieldCache[i] = qGetIntData(d->hStmt, i);
- break;
- case QVariant::UInt:
+ break;
+ case QMetaType::UInt:
+ case QMetaType::UShort:
d->fieldCache[i] = qGetIntData(d->hStmt, i, false);
break;
- case QVariant::Date:
+ case QMetaType::QDate:
DATE_STRUCT dbuf;
r = SQLGetData(d->hStmt,
i + 1,
@@ -1241,12 +1199,12 @@ QVariant QODBCResult::data(int field)
(SQLPOINTER)&dbuf,
0,
&lengthIndicator);
- if ((r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) && (lengthIndicator != SQL_NULL_DATA))
+ if (SQL_SUCCEEDED(r) && (lengthIndicator != SQL_NULL_DATA))
d->fieldCache[i] = QVariant(QDate(dbuf.year, dbuf.month, dbuf.day));
else
- d->fieldCache[i] = QVariant(QVariant::Date);
+ d->fieldCache[i] = QVariant(QMetaType::fromType<QDate>());
break;
- case QVariant::Time:
+ case QMetaType::QTime:
TIME_STRUCT tbuf;
r = SQLGetData(d->hStmt,
i + 1,
@@ -1254,12 +1212,12 @@ QVariant QODBCResult::data(int field)
(SQLPOINTER)&tbuf,
0,
&lengthIndicator);
- if ((r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) && (lengthIndicator != SQL_NULL_DATA))
+ if (SQL_SUCCEEDED(r) && (lengthIndicator != SQL_NULL_DATA))
d->fieldCache[i] = QVariant(QTime(tbuf.hour, tbuf.minute, tbuf.second));
else
- d->fieldCache[i] = QVariant(QVariant::Time);
+ d->fieldCache[i] = QVariant(QMetaType::fromType<QTime>());
break;
- case QVariant::DateTime:
+ case QMetaType::QDateTime:
TIMESTAMP_STRUCT dtbuf;
r = SQLGetData(d->hStmt,
i + 1,
@@ -1267,19 +1225,19 @@ QVariant QODBCResult::data(int field)
(SQLPOINTER)&dtbuf,
0,
&lengthIndicator);
- if ((r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) && (lengthIndicator != SQL_NULL_DATA))
+ if (SQL_SUCCEEDED(r) && (lengthIndicator != SQL_NULL_DATA))
d->fieldCache[i] = QVariant(QDateTime(QDate(dtbuf.year, dtbuf.month, dtbuf.day),
QTime(dtbuf.hour, dtbuf.minute, dtbuf.second, dtbuf.fraction / 1000000)));
else
- d->fieldCache[i] = QVariant(QVariant::DateTime);
+ d->fieldCache[i] = QVariant(QMetaType::fromType<QDateTime>());
break;
- case QVariant::ByteArray:
+ case QMetaType::QByteArray:
d->fieldCache[i] = qGetBinaryData(d->hStmt, i);
break;
- case QVariant::String:
+ case QMetaType::QString:
d->fieldCache[i] = qGetStringData(d->hStmt, i, info.length(), d->unicode);
break;
- case QVariant::Double:
+ case QMetaType::Double:
switch(numericalPrecisionPolicy()) {
case QSql::LowPrecisionInt32:
d->fieldCache[i] = qGetIntData(d->hStmt, i);
@@ -1291,12 +1249,13 @@ QVariant QODBCResult::data(int field)
d->fieldCache[i] = qGetDoubleData(d->hStmt, i);
break;
case QSql::HighPrecision:
- d->fieldCache[i] = qGetStringData(d->hStmt, i, info.length(), false);
+ const int extra = info.precision() > 0 ? 1 : 0;
+ d->fieldCache[i] = qGetStringData(d->hStmt, i, info.length() + extra, false);
break;
}
break;
default:
- d->fieldCache[i] = QVariant(qGetStringData(d->hStmt, i, info.length(), false));
+ d->fieldCache[i] = qGetStringData(d->hStmt, i, info.length(), false);
break;
}
d->fieldCacheIdx = field + 1;
@@ -1309,7 +1268,7 @@ bool QODBCResult::isNull(int field)
Q_D(const QODBCResult);
if (field < 0 || field >= d->fieldCache.size())
return true;
- if (field <= d->fieldCacheIdx) {
+ if (field >= d->fieldCacheIdx) {
// since there is no good way to find out whether the value is NULL
// without fetching the field we'll fetch it here.
// (data() also sets the NULL flag)
@@ -1330,8 +1289,7 @@ int QODBCResult::numRowsAffected()
SQLRETURN r = SQLRowCount(d->hStmt, &affectedRowCount);
if (r == SQL_SUCCESS)
return affectedRowCount;
- else
- qSqlWarning(QLatin1String("QODBCResult::numRowsAffected: Unable to count affected rows"), d);
+ qSqlWarning("QODBCResult::numRowsAffected: Unable to count affected rows"_L1, d);
return -1;
}
@@ -1346,7 +1304,7 @@ bool QODBCResult::prepare(const QString& query)
if (d->hStmt && d->isStmtHandleValid()) {
r = SQLFreeHandle(SQL_HANDLE_STMT, d->hStmt);
if (r != SQL_SUCCESS) {
- qSqlWarning(QLatin1String("QODBCResult::prepare: Unable to close statement"), d);
+ qSqlWarning("QODBCResult::prepare: Unable to close statement"_L1, d);
return false;
}
}
@@ -1354,7 +1312,7 @@ bool QODBCResult::prepare(const QString& query)
d->dpDbc(),
&d->hStmt);
if (r != SQL_SUCCESS) {
- qSqlWarning(QLatin1String("QODBCResult::prepare: Unable to allocate statement handle"), d);
+ qSqlWarning("QODBCResult::prepare: Unable to allocate statement handle"_L1, d);
return false;
}
@@ -1371,16 +1329,19 @@ bool QODBCResult::prepare(const QString& query)
(SQLPOINTER)SQL_CURSOR_STATIC,
SQL_IS_UINTEGER);
}
- if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) {
+ if (!SQL_SUCCEEDED(r)) {
setLastError(qMakeError(QCoreApplication::translate("QODBCResult",
"QODBCResult::reset: Unable to set 'SQL_CURSOR_STATIC' as statement attribute. "
"Please check your ODBC driver configuration"), QSqlError::StatementError, d));
return false;
}
- r = SQLPrepare(d->hStmt,
- toSQLTCHAR(query).data(),
- (SQLINTEGER) query.length());
+ {
+ auto encoded = toSQLTCHAR(query);
+ r = SQLPrepare(d->hStmt,
+ encoded.data(),
+ SQLINTEGER(encoded.size()));
+ }
if (r != SQL_SUCCESS) {
setLastError(qMakeError(QCoreApplication::translate("QODBCResult",
@@ -1400,30 +1361,28 @@ bool QODBCResult::exec()
d->fieldCacheIdx = 0;
if (!d->hStmt) {
- qSqlWarning(QLatin1String("QODBCResult::exec: No statement handle available"), d);
+ qSqlWarning("QODBCResult::exec: No statement handle available"_L1, d);
return false;
}
if (isSelect())
SQLCloseCursor(d->hStmt);
- QVector<QVariant>& values = boundValues();
- QVector<QByteArray> tmpStorage(values.count(), QByteArray()); // holds temporary buffers
- QVarLengthArray<SQLLEN, 32> indicators(values.count());
- memset(indicators.data(), 0, indicators.size() * sizeof(SQLLEN));
+ QVariantList &values = boundValues();
+ QByteArrayList tmpStorage(values.count(), QByteArray()); // targets for SQLBindParameter()
+ QVarLengthArray<SQLLEN, 32> indicators(values.count(), 0);
// bind parameters - only positional binding allowed
- int i;
SQLRETURN r;
- for (i = 0; i < values.count(); ++i) {
+ for (qsizetype i = 0; i < values.count(); ++i) {
if (bindValueType(i) & QSql::Out)
values[i].detach();
const QVariant &val = values.at(i);
SQLLEN *ind = &indicators[i];
- if (val.isNull())
+ if (QSqlResultPrivate::isVariantNull(val))
*ind = SQL_NULL_DATA;
- switch (val.userType()) {
- case QVariant::Date: {
+ switch (val.typeId()) {
+ case QMetaType::QDate: {
QByteArray &ba = tmpStorage[i];
ba.resize(sizeof(DATE_STRUCT));
DATE_STRUCT *dt = (DATE_STRUCT *)const_cast<char *>(ba.constData());
@@ -1442,7 +1401,7 @@ bool QODBCResult::exec()
0,
*ind == SQL_NULL_DATA ? ind : NULL);
break; }
- case QVariant::Time: {
+ case QMetaType::QTime: {
QByteArray &ba = tmpStorage[i];
ba.resize(sizeof(TIME_STRUCT));
TIME_STRUCT *dt = (TIME_STRUCT *)const_cast<char *>(ba.constData());
@@ -1461,23 +1420,25 @@ bool QODBCResult::exec()
0,
*ind == SQL_NULL_DATA ? ind : NULL);
break; }
- case QVariant::DateTime: {
+ case QMetaType::QDateTime: {
QByteArray &ba = tmpStorage[i];
ba.resize(sizeof(TIMESTAMP_STRUCT));
- TIMESTAMP_STRUCT * dt = (TIMESTAMP_STRUCT *)const_cast<char *>(ba.constData());
- QDateTime qdt = val.toDateTime();
- dt->year = qdt.date().year();
- dt->month = qdt.date().month();
- dt->day = qdt.date().day();
- dt->hour = qdt.time().hour();
- dt->minute = qdt.time().minute();
- dt->second = qdt.time().second();
-
- int precision = d->drv_d_func()->datetime_precision - 20; // (20 includes a separating period)
+ TIMESTAMP_STRUCT *dt = reinterpret_cast<TIMESTAMP_STRUCT *>(const_cast<char *>(ba.constData()));
+ const QDateTime qdt = val.toDateTime();
+ const QDate qdate = qdt.date();
+ const QTime qtime = qdt.time();
+ dt->year = qdate.year();
+ dt->month = qdate.month();
+ dt->day = qdate.day();
+ dt->hour = qtime.hour();
+ dt->minute = qtime.minute();
+ dt->second = qtime.second();
+ // (20 includes a separating period)
+ const int precision = d->drv_d_func()->datetimePrecision - 20;
if (precision <= 0) {
dt->fraction = 0;
} else {
- dt->fraction = qdt.time().msec() * 1000000;
+ dt->fraction = qtime.msec() * 1000000;
// (How many leading digits do we want to keep? With SQL Server 2005, this should be 3: 123000000)
int keep = (int)qPow(10.0, 9 - qMin(9, precision));
@@ -1489,13 +1450,13 @@ bool QODBCResult::exec()
qParamType[bindValueType(i) & QSql::InOut],
SQL_C_TIMESTAMP,
SQL_TIMESTAMP,
- d->drv_d_func()->datetime_precision,
+ d->drv_d_func()->datetimePrecision,
precision,
(void *) dt,
0,
*ind == SQL_NULL_DATA ? ind : NULL);
break; }
- case QVariant::Int:
+ case QMetaType::Int:
r = SQLBindParameter(d->hStmt,
i + 1,
qParamType[bindValueType(i) & QSql::InOut],
@@ -1507,7 +1468,7 @@ bool QODBCResult::exec()
0,
*ind == SQL_NULL_DATA ? ind : NULL);
break;
- case QVariant::UInt:
+ case QMetaType::UInt:
r = SQLBindParameter(d->hStmt,
i + 1,
qParamType[bindValueType(i) & QSql::InOut],
@@ -1519,7 +1480,31 @@ bool QODBCResult::exec()
0,
*ind == SQL_NULL_DATA ? ind : NULL);
break;
- case QVariant::Double:
+ case QMetaType::Short:
+ r = SQLBindParameter(d->hStmt,
+ i + 1,
+ qParamType[bindValueType(i) & QSql::InOut],
+ SQL_C_SSHORT,
+ SQL_SMALLINT,
+ 0,
+ 0,
+ const_cast<void *>(val.constData()),
+ 0,
+ *ind == SQL_NULL_DATA ? ind : NULL);
+ break;
+ case QMetaType::UShort:
+ r = SQLBindParameter(d->hStmt,
+ i + 1,
+ qParamType[bindValueType(i) & QSql::InOut],
+ SQL_C_USHORT,
+ SQL_NUMERIC,
+ 15,
+ 0,
+ const_cast<void *>(val.constData()),
+ 0,
+ *ind == SQL_NULL_DATA ? ind : NULL);
+ break;
+ case QMetaType::Double:
r = SQLBindParameter(d->hStmt,
i + 1,
qParamType[bindValueType(i) & QSql::InOut],
@@ -1531,7 +1516,19 @@ bool QODBCResult::exec()
0,
*ind == SQL_NULL_DATA ? ind : NULL);
break;
- case QVariant::LongLong:
+ case QMetaType::Float:
+ r = SQLBindParameter(d->hStmt,
+ i + 1,
+ qParamType[bindValueType(i) & QSql::InOut],
+ SQL_C_FLOAT,
+ SQL_REAL,
+ 0,
+ 0,
+ const_cast<void *>(val.constData()),
+ 0,
+ *ind == SQL_NULL_DATA ? ind : NULL);
+ break;
+ case QMetaType::LongLong:
r = SQLBindParameter(d->hStmt,
i + 1,
qParamType[bindValueType(i) & QSql::InOut],
@@ -1543,7 +1540,7 @@ bool QODBCResult::exec()
0,
*ind == SQL_NULL_DATA ? ind : NULL);
break;
- case QVariant::ULongLong:
+ case QMetaType::ULongLong:
r = SQLBindParameter(d->hStmt,
i + 1,
qParamType[bindValueType(i) & QSql::InOut],
@@ -1555,7 +1552,7 @@ bool QODBCResult::exec()
0,
*ind == SQL_NULL_DATA ? ind : NULL);
break;
- case QVariant::ByteArray:
+ case QMetaType::QByteArray:
if (*ind != SQL_NULL_DATA) {
*ind = val.toByteArray().size();
}
@@ -1570,7 +1567,7 @@ bool QODBCResult::exec()
val.toByteArray().size(),
ind);
break;
- case QVariant::Bool:
+ case QMetaType::Bool:
r = SQLBindParameter(d->hStmt,
i + 1,
qParamType[bindValueType(i) & QSql::InOut],
@@ -1582,38 +1579,39 @@ bool QODBCResult::exec()
0,
*ind == SQL_NULL_DATA ? ind : NULL);
break;
- case QVariant::String:
+ case QMetaType::QString:
if (d->unicode) {
QByteArray &ba = tmpStorage[i];
- QString str = val.toString();
+ {
+ const auto encoded = toSQLTCHAR(val.toString());
+ ba = QByteArray(reinterpret_cast<const char *>(encoded.data()),
+ encoded.size() * sizeof(SQLTCHAR));
+ }
+
if (*ind != SQL_NULL_DATA)
- *ind = str.length() * sizeof(SQLTCHAR);
- int strSize = str.length() * sizeof(SQLTCHAR);
+ *ind = ba.size();
if (bindValueType(i) & QSql::Out) {
- const QVarLengthArray<SQLTCHAR> a(toSQLTCHAR(str));
- ba = QByteArray((const char *)a.constData(), a.size() * sizeof(SQLTCHAR));
r = SQLBindParameter(d->hStmt,
i + 1,
qParamType[bindValueType(i) & QSql::InOut],
SQL_C_TCHAR,
- strSize > 254 ? SQL_WLONGVARCHAR : SQL_WVARCHAR,
+ ba.size() > 254 ? SQL_WLONGVARCHAR : SQL_WVARCHAR,
0, // god knows... don't change this!
0,
- ba.data(),
+ const_cast<char *>(ba.constData()), // don't detach
ba.size(),
ind);
break;
}
- ba = QByteArray ((const char *)toSQLTCHAR(str).constData(), str.size()*sizeof(SQLTCHAR));
r = SQLBindParameter(d->hStmt,
i + 1,
qParamType[bindValueType(i) & QSql::InOut],
SQL_C_TCHAR,
- strSize > 254 ? SQL_WLONGVARCHAR : SQL_WVARCHAR,
- strSize,
+ ba.size() > 254 ? SQL_WLONGVARCHAR : SQL_WVARCHAR,
+ ba.size(),
0,
- const_cast<char *>(ba.constData()),
+ const_cast<char *>(ba.constData()), // don't detach
ba.size(),
ind);
break;
@@ -1638,7 +1636,7 @@ bool QODBCResult::exec()
ind);
break;
}
- // fall through
+ Q_FALLTHROUGH();
default: {
QByteArray &ba = tmpStorage[i];
if (*ind != SQL_NULL_DATA)
@@ -1656,15 +1654,15 @@ bool QODBCResult::exec()
break; }
}
if (r != SQL_SUCCESS) {
- qWarning() << "QODBCResult::exec: unable to bind variable:" << qODBCWarn(d);
+ qSqlWarning("QODBCResult::exec: unable to bind variable:"_L1, d);
setLastError(qMakeError(QCoreApplication::translate("QODBCResult",
"Unable to bind variable"), QSqlError::StatementError, d));
return false;
}
}
r = SQLExecute(d->hStmt);
- if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO && r != SQL_NO_DATA) {
- qWarning() << "QODBCResult::exec: Unable to execute statement:" << qODBCWarn(d);
+ if (!SQL_SUCCEEDED(r) && r != SQL_NO_DATA) {
+ qSqlWarning("QODBCResult::exec: Unable to execute statement:"_L1, d);
setLastError(qMakeError(QCoreApplication::translate("QODBCResult",
"Unable to execute statement"), QSqlError::StatementError, d));
return false;
@@ -1672,14 +1670,14 @@ bool QODBCResult::exec()
SQLULEN isScrollable = 0;
r = SQLGetStmtAttr(d->hStmt, SQL_ATTR_CURSOR_SCROLLABLE, &isScrollable, SQL_IS_INTEGER, 0);
- if(r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO)
+ if (SQL_SUCCEEDED(r))
setForwardOnly(isScrollable == SQL_NONSCROLLABLE);
SQLSMALLINT count = 0;
SQLNumResultCols(d->hStmt, &count);
if (count) {
setSelect(true);
- for (int i = 0; i < count; ++i) {
+ for (SQLSMALLINT i = 0; i < count; ++i) {
d->rInf.append(qMakeFieldInfo(d, i));
}
d->fieldCache.resize(count);
@@ -1693,49 +1691,53 @@ bool QODBCResult::exec()
if (!hasOutValues())
return true;
- for (i = 0; i < values.count(); ++i) {
- switch (values.at(i).userType()) {
- case QVariant::Date: {
+ for (qsizetype i = 0; i < values.count(); ++i) {
+ switch (values.at(i).typeId()) {
+ case QMetaType::QDate: {
DATE_STRUCT ds = *((DATE_STRUCT *)const_cast<char *>(tmpStorage.at(i).constData()));
values[i] = QVariant(QDate(ds.year, ds.month, ds.day));
break; }
- case QVariant::Time: {
+ case QMetaType::QTime: {
TIME_STRUCT dt = *((TIME_STRUCT *)const_cast<char *>(tmpStorage.at(i).constData()));
values[i] = QVariant(QTime(dt.hour, dt.minute, dt.second));
break; }
- case QVariant::DateTime: {
+ case QMetaType::QDateTime: {
TIMESTAMP_STRUCT dt = *((TIMESTAMP_STRUCT*)
const_cast<char *>(tmpStorage.at(i).constData()));
values[i] = QVariant(QDateTime(QDate(dt.year, dt.month, dt.day),
QTime(dt.hour, dt.minute, dt.second, dt.fraction / 1000000)));
break; }
- case QVariant::Bool:
- case QVariant::Int:
- case QVariant::UInt:
- case QVariant::Double:
- case QVariant::ByteArray:
- case QVariant::LongLong:
- case QVariant::ULongLong:
+ case QMetaType::Bool:
+ case QMetaType::Short:
+ case QMetaType::UShort:
+ case QMetaType::Int:
+ case QMetaType::UInt:
+ case QMetaType::Float:
+ case QMetaType::Double:
+ case QMetaType::QByteArray:
+ case QMetaType::LongLong:
+ case QMetaType::ULongLong:
//nothing to do
break;
- case QVariant::String:
+ case QMetaType::QString:
if (d->unicode) {
if (bindValueType(i) & QSql::Out) {
- const QByteArray &first = tmpStorage.at(i);
- QVarLengthArray<SQLTCHAR> array;
- array.append((const SQLTCHAR *)first.constData(), first.size());
- values[i] = fromSQLTCHAR(array, first.size()/sizeof(SQLTCHAR));
+ const QByteArray &bytes = tmpStorage.at(i);
+ const auto strSize = bytes.size() / sizeof(SQLTCHAR);
+ QVarLengthArray<SQLTCHAR> string(strSize);
+ memcpy(string.data(), bytes.data(), strSize * sizeof(SQLTCHAR));
+ values[i] = fromSQLTCHAR(string);
}
break;
}
- // fall through
+ Q_FALLTHROUGH();
default: {
if (bindValueType(i) & QSql::Out)
values[i] = tmpStorage.at(i);
break; }
}
if (indicators[i] == SQL_NULL_DATA)
- values[i] = QVariant(QVariant::Type(values[i].userType()));
+ values[i] = QVariant(values[i].metaType());
}
return true;
}
@@ -1756,13 +1758,13 @@ QVariant QODBCResult::lastInsertId() const
switch (driver()->dbmsType()) {
case QSqlDriver::MSSqlServer:
case QSqlDriver::Sybase:
- sql = QLatin1String("SELECT @@IDENTITY;");
+ sql = "SELECT @@IDENTITY;"_L1;
break;
case QSqlDriver::MySqlServer:
- sql = QLatin1String("SELECT LAST_INSERT_ID();");
+ sql = "SELECT LAST_INSERT_ID();"_L1;
break;
case QSqlDriver::PostgreSQL:
- sql = QLatin1String("SELECT lastval();");
+ sql = "SELECT lastval();"_L1;
break;
default:
break;
@@ -1773,9 +1775,9 @@ QVariant QODBCResult::lastInsertId() const
if (qry.exec(sql) && qry.next())
return qry.value(0);
- qSqlWarning(QLatin1String("QODBCResult::lastInsertId: Unable to get lastInsertId"), d);
+ qSqlWarning("QODBCResult::lastInsertId: Unable to get lastInsertId"_L1, d);
} else {
- qSqlWarning(QLatin1String("QODBCResult::lastInsertId: not implemented for this DBMS"), d);
+ qSqlWarning("QODBCResult::lastInsertId: not implemented for this DBMS"_L1, d);
}
return QVariant();
@@ -1784,7 +1786,7 @@ QVariant QODBCResult::lastInsertId() const
QVariant QODBCResult::handle() const
{
Q_D(const QODBCResult);
- return QVariant(qRegisterMetaType<SQLHANDLE>("SQLHANDLE"), &d->hStmt);
+ return QVariant(QMetaType::fromType<SQLHANDLE>(), &d->hStmt);
}
bool QODBCResult::nextResult()
@@ -1800,9 +1802,7 @@ bool QODBCResult::nextResult()
SQLRETURN r = SQLMoreResults(d->hStmt);
if (r != SQL_SUCCESS) {
if (r == SQL_SUCCESS_WITH_INFO) {
- int nativeCode = -1;
- QString message = qODBCWarn(d, &nativeCode);
- qWarning() << "QODBCResult::nextResult():" << message;
+ qSqlWarning("QODBCResult::nextResult:"_L1, d);
} else {
if (r != SQL_NO_DATA)
setLastError(qMakeError(QCoreApplication::translate("QODBCResult",
@@ -1815,7 +1815,7 @@ bool QODBCResult::nextResult()
SQLNumResultCols(d->hStmt, &count);
if (count) {
setSelect(true);
- for (int i = 0; i < count; ++i) {
+ for (SQLSMALLINT i = 0; i < count; ++i) {
d->rInf.append(qMakeFieldInfo(d, i));
}
d->fieldCache.resize(count);
@@ -1921,6 +1921,18 @@ bool QODBCDriver::open(const QString & db,
int,
const QString& connOpts)
{
+ const auto ensureEscaped = [](QString arg) -> QString {
+ QChar quoteChar;
+ if (arg.startsWith(u'"'))
+ quoteChar = u'\'';
+ else if (arg.startsWith(u'\''))
+ quoteChar = u'"';
+ else if (arg.contains(u';'))
+ quoteChar = u'"';
+ else
+ return arg;
+ return quoteChar + arg + quoteChar;
+ };
Q_D(QODBCDriver);
if (isOpen())
close();
@@ -1928,8 +1940,8 @@ bool QODBCDriver::open(const QString & db,
r = SQLAllocHandle(SQL_HANDLE_ENV,
SQL_NULL_HANDLE,
&d->hEnv);
- if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) {
- qSqlWarning(QLatin1String("QODBCDriver::open: Unable to allocate environment"), d);
+ if (!SQL_SUCCEEDED(r)) {
+ qSqlWarning("QODBCDriver::open: Unable to allocate environment"_L1, d);
setOpenError(true);
return false;
}
@@ -1940,8 +1952,8 @@ bool QODBCDriver::open(const QString & db,
r = SQLAllocHandle(SQL_HANDLE_DBC,
d->hEnv,
&d->hDbc);
- if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) {
- qSqlWarning(QLatin1String("QODBCDriver::open: Unable to allocate connection"), d);
+ if (!SQL_SUCCEEDED(r)) {
+ qSqlWarning("QODBCDriver::open: Unable to allocate connection"_L1, d);
setOpenError(true);
cleanup();
return false;
@@ -1955,32 +1967,32 @@ bool QODBCDriver::open(const QString & db,
// Create the connection string
QString connQStr;
// support the "DRIVER={SQL SERVER};SERVER=blah" syntax
- if (db.contains(QLatin1String(".dsn"), Qt::CaseInsensitive))
- connQStr = QLatin1String("FILEDSN=") + db;
- else if (db.contains(QLatin1String("DRIVER="), Qt::CaseInsensitive)
- || db.contains(QLatin1String("SERVER="), Qt::CaseInsensitive))
+ if (db.contains(".dsn"_L1, Qt::CaseInsensitive))
+ connQStr = "FILEDSN="_L1 + ensureEscaped(db);
+ else if (db.contains("DRIVER="_L1, Qt::CaseInsensitive)
+ || db.contains("SERVER="_L1, Qt::CaseInsensitive))
connQStr = db;
else
- connQStr = QLatin1String("DSN=") + db;
+ connQStr = "DSN="_L1 + ensureEscaped(db);
if (!user.isEmpty())
- connQStr += QLatin1String(";UID=") + user;
+ connQStr += ";UID="_L1 + ensureEscaped(user);
if (!password.isEmpty())
- connQStr += QLatin1String(";PWD=") + password;
+ connQStr += ";PWD="_L1 + ensureEscaped(password);
SQLSMALLINT cb;
- QVarLengthArray<SQLTCHAR> connOut(1024);
- memset(connOut.data(), 0, connOut.size() * sizeof(SQLTCHAR));
- r = SQLDriverConnect(d->hDbc,
- NULL,
- toSQLTCHAR(connQStr).data(),
- (SQLSMALLINT)connQStr.length(),
- connOut.data(),
- 1024,
- &cb,
- /*SQL_DRIVER_NOPROMPT*/0);
-
- if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) {
+ QVarLengthArray<SQLTCHAR, 1024> connOut(1024);
+ {
+ auto encoded = toSQLTCHAR(connQStr);
+ r = SQLDriverConnect(d->hDbc,
+ nullptr,
+ encoded.data(), SQLSMALLINT(encoded.size()),
+ connOut.data(), SQLSMALLINT(connOut.size()),
+ &cb,
+ /*SQL_DRIVER_NOPROMPT*/0);
+ }
+
+ if (!SQL_SUCCEEDED(r)) {
setLastError(qMakeError(tr("Unable to connect"), QSqlError::ConnectionError, d));
setOpenError(true);
cleanup();
@@ -2001,11 +2013,12 @@ bool QODBCDriver::open(const QString & db,
d->checkHasSQLFetchScroll();
d->checkHasMultiResults();
d->checkDateTimePrecision();
+ d->checkDefaultCase();
setOpen(true);
setOpenError(false);
if (d->dbmsType == MSSqlServer) {
QSqlQuery i(createResult());
- i.exec(QLatin1String("SET QUOTED_IDENTIFIER ON"));
+ i.exec("SET QUOTED_IDENTIFIER ON"_L1);
}
return true;
}
@@ -2022,26 +2035,26 @@ void QODBCDriver::cleanup()
Q_D(QODBCDriver);
SQLRETURN r;
- if(d->hDbc) {
+ if (d->hDbc) {
// Open statements/descriptors handles are automatically cleaned up by SQLDisconnect
if (isOpen()) {
r = SQLDisconnect(d->hDbc);
if (r != SQL_SUCCESS)
- qSqlWarning(QLatin1String("QODBCDriver::disconnect: Unable to disconnect datasource"), d);
+ qSqlWarning("QODBCDriver::disconnect: Unable to disconnect datasource"_L1, d);
else
d->disconnectCount++;
}
r = SQLFreeHandle(SQL_HANDLE_DBC, d->hDbc);
if (r != SQL_SUCCESS)
- qSqlWarning(QLatin1String("QODBCDriver::cleanup: Unable to free connection handle"), d);
+ qSqlWarning("QODBCDriver::cleanup: Unable to free connection handle"_L1, d);
d->hDbc = 0;
}
if (d->hEnv) {
r = SQLFreeHandle(SQL_HANDLE_ENV, d->hEnv);
if (r != SQL_SUCCESS)
- qSqlWarning(QLatin1String("QODBCDriver::cleanup: Unable to free environment handle"), d);
+ qSqlWarning("QODBCDriver::cleanup: Unable to free environment handle"_L1, d);
d->hEnv = 0;
}
}
@@ -2059,7 +2072,7 @@ void QODBCDriverPrivate::checkUnicode()
(SQLPOINTER)&fFunc,
sizeof(fFunc),
NULL);
- if ((r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) && (fFunc & SQL_CVT_WCHAR)) {
+ if (SQL_SUCCEEDED(r) && (fFunc & SQL_CVT_WCHAR)) {
unicode = true;
return;
}
@@ -2069,7 +2082,7 @@ void QODBCDriverPrivate::checkUnicode()
(SQLPOINTER)&fFunc,
sizeof(fFunc),
NULL);
- if ((r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) && (fFunc & SQL_CVT_WVARCHAR)) {
+ if (SQL_SUCCEEDED(r) && (fFunc & SQL_CVT_WVARCHAR)) {
unicode = true;
return;
}
@@ -2079,74 +2092,86 @@ void QODBCDriverPrivate::checkUnicode()
(SQLPOINTER)&fFunc,
sizeof(fFunc),
NULL);
- if ((r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) && (fFunc & SQL_CVT_WLONGVARCHAR)) {
+ if (SQL_SUCCEEDED(r) && (fFunc & SQL_CVT_WLONGVARCHAR)) {
unicode = true;
return;
}
- SQLHANDLE hStmt;
- r = SQLAllocHandle(SQL_HANDLE_STMT,
- hDbc,
- &hStmt);
-
- r = SQLExecDirect(hStmt, toSQLTCHAR(QLatin1String("select 'test'")).data(), SQL_NTS);
- if(r == SQL_SUCCESS) {
- r = SQLFetch(hStmt);
- if(r == SQL_SUCCESS) {
- QVarLengthArray<SQLWCHAR> buffer(10);
- r = SQLGetData(hStmt, 1, SQL_C_WCHAR, buffer.data(), buffer.size() * sizeof(SQLWCHAR), NULL);
- if(r == SQL_SUCCESS && fromSQLTCHAR(buffer) == QLatin1String("test")) {
+
+ SqlStmtHandle hStmt(hDbc);
+ // for databases which do not return something useful in SQLGetInfo and are picky about a
+ // 'SELECT' statement without 'FROM' but support VALUE(foo) statement like e.g. DB2 or Oracle
+ const std::array<QStringView, 3> statements = {
+ u"select 'test'",
+ u"values('test')",
+ u"select 'test' from dual",
+ };
+ for (const auto &statement : statements) {
+ auto encoded = toSQLTCHAR(statement);
+ r = SQLExecDirect(hStmt.handle(), encoded.data(), SQLINTEGER(encoded.size()));
+ if (r == SQL_SUCCESS)
+ break;
+ }
+ if (r == SQL_SUCCESS) {
+ r = SQLFetch(hStmt.handle());
+ if (r == SQL_SUCCESS) {
+ QVarLengthArray<SQLWCHAR, 10> buffer(10);
+ r = SQLGetData(hStmt.handle(), 1, SQL_C_WCHAR, buffer.data(),
+ buffer.size() * sizeof(SQLWCHAR), NULL);
+ if (r == SQL_SUCCESS && fromSQLTCHAR(buffer) == "test"_L1) {
unicode = true;
}
}
}
- r = SQLFreeHandle(SQL_HANDLE_STMT, hStmt);
}
bool QODBCDriverPrivate::checkDriver() const
{
#ifdef ODBC_CHECK_DRIVER
- static const SQLUSMALLINT reqFunc[] = {
+ static constexpr SQLUSMALLINT reqFunc[] = {
SQL_API_SQLDESCRIBECOL, SQL_API_SQLGETDATA, SQL_API_SQLCOLUMNS,
SQL_API_SQLGETSTMTATTR, SQL_API_SQLGETDIAGREC, SQL_API_SQLEXECDIRECT,
- SQL_API_SQLGETINFO, SQL_API_SQLTABLES, 0
+ SQL_API_SQLGETINFO, SQL_API_SQLTABLES
};
// these functions are optional
- static const SQLUSMALLINT optFunc[] = {
- SQL_API_SQLNUMRESULTCOLS, SQL_API_SQLROWCOUNT, 0
+ static constexpr SQLUSMALLINT optFunc[] = {
+ SQL_API_SQLNUMRESULTCOLS, SQL_API_SQLROWCOUNT
};
SQLRETURN r;
SQLUSMALLINT sup;
- int i;
// check the required functions
- for (i = 0; reqFunc[i] != 0; ++i) {
+ for (const SQLUSMALLINT func : reqFunc) {
- r = SQLGetFunctions(hDbc, reqFunc[i], &sup);
+ r = SQLGetFunctions(hDbc, func, &sup);
if (r != SQL_SUCCESS) {
- qSqlWarning(QLatin1String("QODBCDriver::checkDriver: Cannot get list of supported functions"), this);
+ qSqlWarning("QODBCDriver::checkDriver: Cannot get list of supported functions"_L1, this);
return false;
}
if (sup == SQL_FALSE) {
- qWarning () << "QODBCDriver::open: Warning - Driver doesn't support all needed functionality (" << reqFunc[i] <<
- ").\nPlease look at the Qt SQL Module Driver documentation for more information.";
+ qSqlWarning(("QODBCDriver::checkDriver: Driver doesn't support all needed "
+ "functionality (func id %1).\nPlease look at the Qt SQL Module "
+ "Driver documentation for more information."_L1)
+ .arg(QString::number(func)), this);
return false;
}
}
// these functions are optional and just generate a warning
- for (i = 0; optFunc[i] != 0; ++i) {
+ for (const SQLUSMALLINT func : optFunc) {
- r = SQLGetFunctions(hDbc, optFunc[i], &sup);
+ r = SQLGetFunctions(hDbc, func, &sup);
if (r != SQL_SUCCESS) {
- qSqlWarning(QLatin1String("QODBCDriver::checkDriver: Cannot get list of supported functions"), this);
+ qSqlWarning("QODBCDriver::checkDriver: Cannot get list of supported functions"_L1, this);
return false;
}
if (sup == SQL_FALSE) {
- qWarning() << "QODBCDriver::checkDriver: Warning - Driver doesn't support some non-critical functions (" << optFunc[i] << ')';
+ qSqlWarning(("QODBCDriver::checkDriver: Driver doesn't support some "
+ "non-critical functions (func id %1)."_L1)
+ .arg(QString::number(func)), this);
return true;
}
}
@@ -2165,33 +2190,32 @@ void QODBCDriverPrivate::checkSchemaUsage()
(SQLPOINTER) &val,
sizeof(val),
NULL);
- if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO)
+ if (SQL_SUCCEEDED(r))
useSchema = (val != 0);
}
void QODBCDriverPrivate::checkDBMS()
{
SQLRETURN r;
- QVarLengthArray<SQLTCHAR> serverString(200);
+ QVarLengthArray<SQLTCHAR, 200> serverString(200);
SQLSMALLINT t;
- memset(serverString.data(), 0, serverString.size() * sizeof(SQLTCHAR));
r = SQLGetInfo(hDbc,
SQL_DBMS_NAME,
serverString.data(),
SQLSMALLINT(serverString.size() * sizeof(SQLTCHAR)),
&t);
- if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) {
+ if (SQL_SUCCEEDED(r)) {
const QString serverType = fromSQLTCHAR(serverString, t / sizeof(SQLTCHAR));
- if (serverType.contains(QLatin1String("PostgreSQL"), Qt::CaseInsensitive))
+ if (serverType.contains("PostgreSQL"_L1, Qt::CaseInsensitive))
dbmsType = QSqlDriver::PostgreSQL;
- else if (serverType.contains(QLatin1String("Oracle"), Qt::CaseInsensitive))
+ else if (serverType.contains("Oracle"_L1, Qt::CaseInsensitive))
dbmsType = QSqlDriver::Oracle;
- else if (serverType.contains(QLatin1String("MySql"), Qt::CaseInsensitive))
+ else if (serverType.contains("MySql"_L1, Qt::CaseInsensitive))
dbmsType = QSqlDriver::MySqlServer;
- else if (serverType.contains(QLatin1String("Microsoft SQL Server"), Qt::CaseInsensitive))
+ else if (serverType.contains("Microsoft SQL Server"_L1, Qt::CaseInsensitive))
dbmsType = QSqlDriver::MSSqlServer;
- else if (serverType.contains(QLatin1String("Sybase"), Qt::CaseInsensitive))
+ else if (serverType.contains("Sybase"_L1, Qt::CaseInsensitive))
dbmsType = QSqlDriver::Sybase;
}
r = SQLGetInfo(hDbc,
@@ -2199,9 +2223,9 @@ void QODBCDriverPrivate::checkDBMS()
serverString.data(),
SQLSMALLINT(serverString.size() * sizeof(SQLTCHAR)),
&t);
- if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) {
+ if (SQL_SUCCEEDED(r)) {
const QString serverType = fromSQLTCHAR(serverString, t / sizeof(SQLTCHAR));
- isFreeTDSDriver = serverType.contains(QLatin1String("tdsodbc"), Qt::CaseInsensitive);
+ isFreeTDSDriver = serverType.contains("tdsodbc"_L1, Qt::CaseInsensitive);
unicode = unicode && !isFreeTDSDriver;
}
}
@@ -2210,46 +2234,42 @@ void QODBCDriverPrivate::checkHasSQLFetchScroll()
{
SQLUSMALLINT sup;
SQLRETURN r = SQLGetFunctions(hDbc, SQL_API_SQLFETCHSCROLL, &sup);
- if ((r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) || sup != SQL_TRUE) {
+ if ((!SQL_SUCCEEDED(r)) || sup != SQL_TRUE) {
hasSQLFetchScroll = false;
- qWarning("QODBCDriver::checkHasSQLFetchScroll: Warning - Driver doesn't support scrollable result sets, use forward only mode for queries");
+ qSqlWarning("QODBCDriver::checkHasSQLFetchScroll: Driver doesn't support "
+ "scrollable result sets, use forward only mode for queries"_L1, this);
}
}
void QODBCDriverPrivate::checkHasMultiResults()
{
- QVarLengthArray<SQLTCHAR> driverResponse(2);
+ QVarLengthArray<SQLTCHAR, 2> driverResponse(2);
SQLSMALLINT length;
SQLRETURN r = SQLGetInfo(hDbc,
SQL_MULT_RESULT_SETS,
driverResponse.data(),
SQLSMALLINT(driverResponse.size() * sizeof(SQLTCHAR)),
&length);
- if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO)
- hasMultiResultSets = fromSQLTCHAR(driverResponse, length/sizeof(SQLTCHAR)).startsWith(QLatin1Char('Y'));
+ if (SQL_SUCCEEDED(r))
+ hasMultiResultSets = fromSQLTCHAR(driverResponse, length / sizeof(SQLTCHAR)).startsWith(u'Y');
}
void QODBCDriverPrivate::checkDateTimePrecision()
{
SQLINTEGER columnSize;
- SQLHANDLE hStmt;
+ SqlStmtHandle hStmt(hDbc);
- SQLRETURN r = SQLAllocHandle(SQL_HANDLE_STMT, hDbc, &hStmt);
- if (r != SQL_SUCCESS) {
+ if (!hStmt.isValid())
return;
- }
- r = SQLGetTypeInfo(hStmt, SQL_TIMESTAMP);
- if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) {
- r = SQLFetch(hStmt);
- if ( r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO )
- {
- if (SQLGetData(hStmt, 3, SQL_INTEGER, &columnSize, sizeof(columnSize), 0) == SQL_SUCCESS) {
- datetime_precision = (int)columnSize;
- }
+ SQLRETURN r = SQLGetTypeInfo(hStmt.handle(), SQL_TIMESTAMP);
+ if (SQL_SUCCEEDED(r)) {
+ r = SQLFetch(hStmt.handle());
+ if (SQL_SUCCEEDED(r)) {
+ if (SQLGetData(hStmt.handle(), 3, SQL_INTEGER, &columnSize, sizeof(columnSize), 0) == SQL_SUCCESS)
+ datetimePrecision = (int)columnSize;
}
}
- SQLFreeHandle(SQL_HANDLE_STMT, hStmt);
}
QSqlResult *QODBCDriver::createResult() const
@@ -2261,7 +2281,7 @@ bool QODBCDriver::beginTransaction()
{
Q_D(QODBCDriver);
if (!isOpen()) {
- qWarning("QODBCDriver::beginTransaction: Database not open");
+ qSqlWarning("QODBCDriver::beginTransaction: Database not open"_L1, d);
return false;
}
SQLUINTEGER ac(SQL_AUTOCOMMIT_OFF);
@@ -2281,7 +2301,7 @@ bool QODBCDriver::commitTransaction()
{
Q_D(QODBCDriver);
if (!isOpen()) {
- qWarning("QODBCDriver::commitTransaction: Database not open");
+ qSqlWarning("QODBCDriver::commitTransaction: Database not open"_L1, d);
return false;
}
SQLRETURN r = SQLEndTran(SQL_HANDLE_DBC,
@@ -2299,7 +2319,7 @@ bool QODBCDriver::rollbackTransaction()
{
Q_D(QODBCDriver);
if (!isOpen()) {
- qWarning("QODBCDriver::rollbackTransaction: Database not open");
+ qSqlWarning("QODBCDriver::rollbackTransaction: Database not open"_L1, d);
return false;
}
SQLRETURN r = SQLEndTran(SQL_HANDLE_DBC,
@@ -2334,71 +2354,52 @@ QStringList QODBCDriver::tables(QSql::TableType type) const
QStringList tl;
if (!isOpen())
return tl;
- SQLHANDLE hStmt;
- SQLRETURN r = SQLAllocHandle(SQL_HANDLE_STMT,
- d->hDbc,
- &hStmt);
- if (r != SQL_SUCCESS) {
- qSqlWarning(QLatin1String("QODBCDriver::tables: Unable to allocate handle"), d);
+ SqlStmtHandle hStmt(d->hDbc);
+ if (!hStmt.isValid()) {
+ qSqlWarning("QODBCDriver::tables: Unable to allocate handle"_L1, d);
return tl;
}
- r = SQLSetStmtAttr(hStmt,
- SQL_ATTR_CURSOR_TYPE,
- (SQLPOINTER)SQL_CURSOR_FORWARD_ONLY,
- SQL_IS_UINTEGER);
+ SQLRETURN r = SQLSetStmtAttr(hStmt.handle(),
+ SQL_ATTR_CURSOR_TYPE,
+ (SQLPOINTER)SQL_CURSOR_FORWARD_ONLY,
+ SQL_IS_UINTEGER);
QStringList tableType;
if (type & QSql::Tables)
- tableType += QLatin1String("TABLE");
+ tableType += "TABLE"_L1;
if (type & QSql::Views)
- tableType += QLatin1String("VIEW");
+ tableType += "VIEW"_L1;
if (type & QSql::SystemTables)
- tableType += QLatin1String("SYSTEM TABLE");
+ tableType += "SYSTEM TABLE"_L1;
if (tableType.isEmpty())
return tl;
- QString joinedTableTypeString = tableType.join(QLatin1Char(','));
+ {
+ auto joinedTableTypeString = toSQLTCHAR(tableType.join(u','));
- r = SQLTables(hStmt,
- NULL,
- 0,
- NULL,
- 0,
- NULL,
- 0,
- toSQLTCHAR(joinedTableTypeString).data(),
- joinedTableTypeString.length() /* characters, not bytes */);
+ r = SQLTables(hStmt.handle(),
+ nullptr, 0,
+ nullptr, 0,
+ nullptr, 0,
+ joinedTableTypeString.data(), joinedTableTypeString.size());
+ }
if (r != SQL_SUCCESS)
- qSqlWarning(QLatin1String("QODBCDriver::tables Unable to execute table list"), d);
-
- if (d->hasSQLFetchScroll)
- r = SQLFetchScroll(hStmt,
- SQL_FETCH_NEXT,
- 0);
- else
- r = SQLFetch(hStmt);
+ qSqlWarning("QODBCDriver::tables Unable to execute table list"_L1,
+ hStmt.handle());
- if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO && r != SQL_NO_DATA) {
- qWarning() << "QODBCDriver::tables failed to retrieve table/view list: (" << r << "," << qWarnODBCHandle(SQL_HANDLE_STMT, hStmt) << ")";
+ r = d->sqlFetchNext(hStmt);
+ if (!SQL_SUCCEEDED(r) && r != SQL_NO_DATA) {
+ qSqlWarning("QODBCDriver::tables failed to retrieve table/view list"_L1,
+ hStmt.handle());
return QStringList();
}
while (r == SQL_SUCCESS) {
- QString fieldVal = qGetStringData(hStmt, 2, -1, false);
- tl.append(fieldVal);
-
- if (d->hasSQLFetchScroll)
- r = SQLFetchScroll(hStmt,
- SQL_FETCH_NEXT,
- 0);
- else
- r = SQLFetch(hStmt);
+ tl.append(qGetStringData(hStmt.handle(), 2, -1, d->unicode).toString());
+ r = d->sqlFetchNext(hStmt);
}
- r = SQLFreeHandle(SQL_HANDLE_STMT, hStmt);
- if (r!= SQL_SUCCESS)
- qSqlWarning(QLatin1String("QODBCDriver: Unable to free statement handle") + QString::number(r), d);
return tl;
}
@@ -2411,98 +2412,69 @@ QSqlIndex QODBCDriver::primaryIndex(const QString& tablename) const
bool usingSpecialColumns = false;
QSqlRecord rec = record(tablename);
- SQLHANDLE hStmt;
- SQLRETURN r = SQLAllocHandle(SQL_HANDLE_STMT,
- d->hDbc,
- &hStmt);
- if (r != SQL_SUCCESS) {
- qSqlWarning(QLatin1String("QODBCDriver::primaryIndex: Unable to list primary key"), d);
+ SqlStmtHandle hStmt(d->hDbc);
+ if (!hStmt.isValid()) {
+ qSqlWarning("QODBCDriver::primaryIndex: Unable to allocate handle"_L1, d);
return index;
}
QString catalog, schema, table;
- const_cast<QODBCDriverPrivate*>(d)->splitTableQualifier(tablename, catalog, schema, table);
-
- if (isIdentifierEscaped(catalog, QSqlDriver::TableName))
- catalog = stripDelimiters(catalog, QSqlDriver::TableName);
- else
- catalog = d->adjustCase(catalog);
+ d->splitTableQualifier(tablename, catalog, schema, table);
- if (isIdentifierEscaped(schema, QSqlDriver::TableName))
- schema = stripDelimiters(schema, QSqlDriver::TableName);
- else
- schema = d->adjustCase(schema);
-
- if (isIdentifierEscaped(table, QSqlDriver::TableName))
- table = stripDelimiters(table, QSqlDriver::TableName);
- else
- table = d->adjustCase(table);
-
- r = SQLSetStmtAttr(hStmt,
- SQL_ATTR_CURSOR_TYPE,
- (SQLPOINTER)SQL_CURSOR_FORWARD_ONLY,
- SQL_IS_UINTEGER);
- r = SQLPrimaryKeys(hStmt,
- catalog.length() == 0 ? NULL : toSQLTCHAR(catalog).data(),
- catalog.length(),
- schema.length() == 0 ? NULL : toSQLTCHAR(schema).data(),
- schema.length(),
- toSQLTCHAR(table).data(),
- table.length() /* in characters, not in bytes */);
+ SQLRETURN r = SQLSetStmtAttr(hStmt.handle(),
+ SQL_ATTR_CURSOR_TYPE,
+ (SQLPOINTER)SQL_CURSOR_FORWARD_ONLY,
+ SQL_IS_UINTEGER);
+ {
+ auto c = toSQLTCHAR(catalog);
+ auto s = toSQLTCHAR(schema);
+ auto t = toSQLTCHAR(table);
+ r = SQLPrimaryKeys(hStmt.handle(),
+ catalog.isEmpty() ? nullptr : c.data(), c.size(),
+ schema.isEmpty() ? nullptr : s.data(), s.size(),
+ t.data(), t.size());
+ }
// if the SQLPrimaryKeys() call does not succeed (e.g the driver
// does not support it) - try an alternative method to get hold of
// the primary index (e.g MS Access and FoxPro)
if (r != SQL_SUCCESS) {
- r = SQLSpecialColumns(hStmt,
- SQL_BEST_ROWID,
- catalog.length() == 0 ? NULL : toSQLTCHAR(catalog).data(),
- catalog.length(),
- schema.length() == 0 ? NULL : toSQLTCHAR(schema).data(),
- schema.length(),
- toSQLTCHAR(table).data(),
- table.length(),
- SQL_SCOPE_CURROW,
- SQL_NULLABLE);
+ auto c = toSQLTCHAR(catalog);
+ auto s = toSQLTCHAR(schema);
+ auto t = toSQLTCHAR(table);
+ r = SQLSpecialColumns(hStmt.handle(),
+ SQL_BEST_ROWID,
+ catalog.isEmpty() ? nullptr : c.data(), c.size(),
+ schema.isEmpty() ? nullptr : s.data(), s.size(),
+ t.data(), t.size(),
+ SQL_SCOPE_CURROW,
+ SQL_NULLABLE);
if (r != SQL_SUCCESS) {
- qSqlWarning(QLatin1String("QODBCDriver::primaryIndex: Unable to execute primary key list"), d);
+ qSqlWarning("QODBCDriver::primaryIndex: Unable to execute primary key list"_L1,
+ hStmt.handle());
} else {
usingSpecialColumns = true;
}
}
- if (d->hasSQLFetchScroll)
- r = SQLFetchScroll(hStmt,
- SQL_FETCH_NEXT,
- 0);
- else
- r = SQLFetch(hStmt);
+ r = d->sqlFetchNext(hStmt);
int fakeId = 0;
QString cName, idxName;
// Store all fields in a StringList because some drivers can't detail fields in this FETCH loop
while (r == SQL_SUCCESS) {
if (usingSpecialColumns) {
- cName = qGetStringData(hStmt, 1, -1, d->unicode); // column name
+ cName = qGetStringData(hStmt.handle(), 1, -1, d->unicode).toString(); // column name
idxName = QString::number(fakeId++); // invent a fake index name
} else {
- cName = qGetStringData(hStmt, 3, -1, d->unicode); // column name
- idxName = qGetStringData(hStmt, 5, -1, d->unicode); // pk index name
+ cName = qGetStringData(hStmt.handle(), 3, -1, d->unicode).toString(); // column name
+ idxName = qGetStringData(hStmt.handle(), 5, -1, d->unicode).toString(); // pk index name
}
index.append(rec.field(cName));
index.setName(idxName);
- if (d->hasSQLFetchScroll)
- r = SQLFetchScroll(hStmt,
- SQL_FETCH_NEXT,
- 0);
- else
- r = SQLFetch(hStmt);
-
+ r = d->sqlFetchNext(hStmt);
}
- r = SQLFreeHandle(SQL_HANDLE_STMT, hStmt);
- if (r!= SQL_SUCCESS)
- qSqlWarning(QLatin1String("QODBCDriver: Unable to free statement handle") + QString::number(r), d);
return index;
}
@@ -2513,72 +2485,39 @@ QSqlRecord QODBCDriver::record(const QString& tablename) const
if (!isOpen())
return fil;
- SQLHANDLE hStmt;
- QString catalog, schema, table;
- const_cast<QODBCDriverPrivate*>(d)->splitTableQualifier(tablename, catalog, schema, table);
-
- if (isIdentifierEscaped(catalog, QSqlDriver::TableName))
- catalog = stripDelimiters(catalog, QSqlDriver::TableName);
- else
- catalog = d->adjustCase(catalog);
-
- if (isIdentifierEscaped(schema, QSqlDriver::TableName))
- schema = stripDelimiters(schema, QSqlDriver::TableName);
- else
- schema = d->adjustCase(schema);
+ SqlStmtHandle hStmt(d->hDbc);
+ if (!hStmt.isValid()) {
+ qSqlWarning("QODBCDriver::record: Unable to allocate handle"_L1, d);
+ return fil;
+ }
- if (isIdentifierEscaped(table, QSqlDriver::TableName))
- table = stripDelimiters(table, QSqlDriver::TableName);
- else
- table = d->adjustCase(table);
+ QString catalog, schema, table;
+ d->splitTableQualifier(tablename, catalog, schema, table);
- SQLRETURN r = SQLAllocHandle(SQL_HANDLE_STMT,
- d->hDbc,
- &hStmt);
- if (r != SQL_SUCCESS) {
- qSqlWarning(QLatin1String("QODBCDriver::record: Unable to allocate handle"), d);
- return fil;
+ SQLRETURN r = SQLSetStmtAttr(hStmt.handle(),
+ SQL_ATTR_CURSOR_TYPE,
+ (SQLPOINTER)SQL_CURSOR_FORWARD_ONLY,
+ SQL_IS_UINTEGER);
+ {
+ auto c = toSQLTCHAR(catalog);
+ auto s = toSQLTCHAR(schema);
+ auto t = toSQLTCHAR(table);
+ r = SQLColumns(hStmt.handle(),
+ catalog.isEmpty() ? nullptr : c.data(), c.size(),
+ schema.isEmpty() ? nullptr : s.data(), s.size(),
+ t.data(), t.size(),
+ nullptr,
+ 0);
}
- r = SQLSetStmtAttr(hStmt,
- SQL_ATTR_CURSOR_TYPE,
- (SQLPOINTER)SQL_CURSOR_FORWARD_ONLY,
- SQL_IS_UINTEGER);
- r = SQLColumns(hStmt,
- catalog.length() == 0 ? NULL : toSQLTCHAR(catalog).data(),
- catalog.length(),
- schema.length() == 0 ? NULL : toSQLTCHAR(schema).data(),
- schema.length(),
- toSQLTCHAR(table).data(),
- table.length(),
- NULL,
- 0);
if (r != SQL_SUCCESS)
- qSqlWarning(QLatin1String("QODBCDriver::record: Unable to execute column list"), d);
-
- if (d->hasSQLFetchScroll)
- r = SQLFetchScroll(hStmt,
- SQL_FETCH_NEXT,
- 0);
- else
- r = SQLFetch(hStmt);
+ qSqlWarning("QODBCDriver::record: Unable to execute column list"_L1, hStmt.handle());
+ r = d->sqlFetchNext(hStmt);
// Store all fields in a StringList because some drivers can't detail fields in this FETCH loop
while (r == SQL_SUCCESS) {
-
- fil.append(qMakeFieldInfo(hStmt, d));
-
- if (d->hasSQLFetchScroll)
- r = SQLFetchScroll(hStmt,
- SQL_FETCH_NEXT,
- 0);
- else
- r = SQLFetch(hStmt);
+ fil.append(qMakeFieldInfo(hStmt.handle(), d));
+ r = d->sqlFetchNext(hStmt);
}
-
- r = SQLFreeHandle(SQL_HANDLE_STMT, hStmt);
- if (r!= SQL_SUCCESS)
- qSqlWarning(QLatin1String("QODBCDriver: Unable to free statement handle ") + QString::number(r), d);
-
return fil;
}
@@ -2587,33 +2526,33 @@ QString QODBCDriver::formatValue(const QSqlField &field,
{
QString r;
if (field.isNull()) {
- r = QLatin1String("NULL");
- } else if (field.type() == QVariant::DateTime) {
+ r = "NULL"_L1;
+ } else if (field.metaType().id() == QMetaType::QDateTime) {
// Use an escape sequence for the datetime fields
- if (field.value().toDateTime().isValid()){
- QDate dt = field.value().toDateTime().date();
- QTime tm = field.value().toDateTime().time();
+ const QDateTime dateTime = field.value().toDateTime();
+ if (dateTime.isValid()) {
+ const QDate dt = dateTime.date();
+ const QTime tm = dateTime.time();
// Dateformat has to be "yyyy-MM-dd hh:mm:ss", with leading zeroes if month or day < 10
- r = QLatin1String("{ ts '") +
- QString::number(dt.year()) + QLatin1Char('-') +
- QString::number(dt.month()).rightJustified(2, QLatin1Char('0'), true) +
- QLatin1Char('-') +
- QString::number(dt.day()).rightJustified(2, QLatin1Char('0'), true) +
- QLatin1Char(' ') +
+ r = "{ ts '"_L1 +
+ QString::number(dt.year()) + u'-' +
+ QString::number(dt.month()).rightJustified(2, u'0', true) +
+ u'-' +
+ QString::number(dt.day()).rightJustified(2, u'0', true) +
+ u' ' +
tm.toString() +
- QLatin1String("' }");
+ "' }"_L1;
} else
- r = QLatin1String("NULL");
- } else if (field.type() == QVariant::ByteArray) {
- QByteArray ba = field.value().toByteArray();
- QString res;
- static const char hexchars[] = "0123456789abcdef";
- for (int i = 0; i < ba.size(); ++i) {
- uchar s = (uchar) ba[i];
- res += QLatin1Char(hexchars[s >> 4]);
- res += QLatin1Char(hexchars[s & 0x0f]);
+ r = "NULL"_L1;
+ } else if (field.metaType().id() == QMetaType::QByteArray) {
+ const QByteArray ba = field.value().toByteArray();
+ r.reserve((ba.size() + 1) * 2);
+ r = "0x"_L1;
+ for (const char c : ba) {
+ const uchar s = uchar(c);
+ r += QLatin1Char(QtMiscUtils::toHexLower(s >> 4));
+ r += QLatin1Char(QtMiscUtils::toHexLower(s & 0x0f));
}
- r = QLatin1String("0x") + res;
} else {
r = QSqlDriver::formatValue(field, trimStrings);
}
@@ -2623,7 +2562,7 @@ QString QODBCDriver::formatValue(const QSqlField &field,
QVariant QODBCDriver::handle() const
{
Q_D(const QODBCDriver);
- return QVariant(qRegisterMetaType<SQLHANDLE>("SQLHANDLE"), &d->hDbc);
+ return QVariant(QMetaType::fromType<SQLHANDLE>(), &d->hDbc);
}
QString QODBCDriver::escapeIdentifier(const QString &identifier, IdentifierType) const
@@ -2631,10 +2570,11 @@ QString QODBCDriver::escapeIdentifier(const QString &identifier, IdentifierType)
Q_D(const QODBCDriver);
QChar quote = const_cast<QODBCDriverPrivate*>(d)->quoteChar();
QString res = identifier;
- if(!identifier.isEmpty() && !identifier.startsWith(quote) && !identifier.endsWith(quote) ) {
- res.replace(quote, QString(quote)+QString(quote));
- res.prepend(quote).append(quote);
- res.replace(QLatin1Char('.'), QString(quote)+QLatin1Char('.')+QString(quote));
+ if (!identifier.isEmpty() && !identifier.startsWith(quote) && !identifier.endsWith(quote) ) {
+ const QString quoteStr(quote);
+ res.replace(quote, quoteStr + quoteStr);
+ res.replace(u'.', quoteStr + u'.' + quoteStr);
+ res = quote + res + quote;
}
return res;
}
diff --git a/src/plugins/sqldrivers/odbc/qsql_odbc_p.h b/src/plugins/sqldrivers/odbc/qsql_odbc_p.h
index ccd0206f38..23703b5d03 100644
--- a/src/plugins/sqldrivers/odbc/qsql_odbc_p.h
+++ b/src/plugins/sqldrivers/odbc/qsql_odbc_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtSql module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QSQL_ODBC_H
#define QSQL_ODBC_H
diff --git a/src/plugins/sqldrivers/psql/.prev_CMakeLists.txt b/src/plugins/sqldrivers/psql/.prev_CMakeLists.txt
deleted file mode 100644
index f3cec6d302..0000000000
--- a/src/plugins/sqldrivers/psql/.prev_CMakeLists.txt
+++ /dev/null
@@ -1,24 +0,0 @@
-# Generated from psql.pro.
-
-#####################################################################
-## QPSQLDriverPlugin Plugin:
-#####################################################################
-
-qt_add_plugin(QPSQLDriverPlugin
- OUTPUT_NAME qsqlpsql
- TYPE sqldrivers
- SOURCES
- main.cpp
- qsql_psql.cpp qsql_psql_p.h
- DEFINES
- QT_NO_CAST_FROM_ASCII
- QT_NO_CAST_TO_ASCII
- PUBLIC_LIBRARIES
- PostgreSQL::PostgreSQL
- Qt::Core
- Qt::CorePrivate
- Qt::SqlPrivate
-)
-
-#### Keys ignored in scope 1:.:.:psql.pro:<TRUE>:
-# OTHER_FILES = "psql.json"
diff --git a/src/plugins/sqldrivers/psql/CMakeLists.txt b/src/plugins/sqldrivers/psql/CMakeLists.txt
index 03a2dc69c3..2f55ab4950 100644
--- a/src/plugins/sqldrivers/psql/CMakeLists.txt
+++ b/src/plugins/sqldrivers/psql/CMakeLists.txt
@@ -1,29 +1,36 @@
-# Generated from psql.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
-# FIXME cmake FindPostgreSQL is more exhaustive than the check we have for libpq-fe.h
-# it also checks for catalog/pg_type.h which is a more internal include, we should
-# add a way to tell cmake FindPostgreSQL to optionally only look for the libpq-fe.h one
-qt_find_package(PostgreSQL) # special case
+qt_find_package(PostgreSQL)
#####################################################################
## QPSQLDriverPlugin Plugin:
#####################################################################
-qt_add_plugin(QPSQLDriverPlugin
+qt_internal_add_plugin(QPSQLDriverPlugin
OUTPUT_NAME qsqlpsql
- TYPE sqldrivers
+ PLUGIN_TYPE sqldrivers
SOURCES
main.cpp
qsql_psql.cpp qsql_psql_p.h
DEFINES
QT_NO_CAST_FROM_ASCII
QT_NO_CAST_TO_ASCII
- PUBLIC_LIBRARIES
+ QT_NO_CONTEXTLESS_CONNECT
+ LIBRARIES
PostgreSQL::PostgreSQL
Qt::Core
Qt::CorePrivate
Qt::SqlPrivate
)
-#### Keys ignored in scope 1:.:.:psql.pro:<TRUE>:
-# OTHER_FILES = "psql.json"
+# PostgreSQL delivers header files that are not a part of PostgreSQL itself. When precompiled
+# headers are processed, MinGW uses 'pthread.h' from the PostgreSQL installation directory.
+# As result, we disable precompile headers for the plugin.
+# See also QTBUG-90850.
+if(MINGW)
+ set_target_properties(QPSQLDriverPlugin
+ PROPERTIES
+ DISABLE_PRECOMPILE_HEADERS ON
+ )
+endif()
diff --git a/src/plugins/sqldrivers/psql/main.cpp b/src/plugins/sqldrivers/psql/main.cpp
index c31e6f64b7..e473fe1edc 100644
--- a/src/plugins/sqldrivers/psql/main.cpp
+++ b/src/plugins/sqldrivers/psql/main.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <qsqldriverplugin.h>
#include <qstringlist.h>
@@ -43,6 +7,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
class QPSQLDriverPlugin : public QSqlDriverPlugin
{
Q_OBJECT
@@ -61,7 +27,7 @@ QPSQLDriverPlugin::QPSQLDriverPlugin()
QSqlDriver* QPSQLDriverPlugin::create(const QString &name)
{
- if (name == QLatin1String("QPSQL"))
+ if (name == "QPSQL"_L1)
return new QPSQLDriver;
return nullptr;
}
diff --git a/src/plugins/sqldrivers/psql/psql.pro b/src/plugins/sqldrivers/psql/psql.pro
deleted file mode 100644
index c44a6319c3..0000000000
--- a/src/plugins/sqldrivers/psql/psql.pro
+++ /dev/null
@@ -1,11 +0,0 @@
-TARGET = qsqlpsql
-
-HEADERS += $$PWD/qsql_psql_p.h
-SOURCES += $$PWD/qsql_psql.cpp $$PWD/main.cpp
-
-QMAKE_USE += psql
-
-OTHER_FILES += psql.json
-
-PLUGIN_CLASS_NAME = QPSQLDriverPlugin
-include(../qsqldriverbase.pri)
diff --git a/src/plugins/sqldrivers/psql/qsql_psql.cpp b/src/plugins/sqldrivers/psql/qsql_psql.cpp
index 27841d9494..7b9521fec6 100644
--- a/src/plugins/sqldrivers/psql/qsql_psql.cpp
+++ b/src/plugins/sqldrivers/psql/qsql_psql.cpp
@@ -1,47 +1,12 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtSql module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qsql_psql_p.h"
#include <qcoreapplication.h>
#include <qvariant.h>
#include <qdatetime.h>
+#include <qloggingcategory.h>
#include <qregularexpression.h>
#include <qsqlerror.h>
#include <qsqlfield.h>
@@ -101,6 +66,10 @@ Q_DECLARE_METATYPE(PGresult*)
QT_BEGIN_NAMESPACE
+static Q_LOGGING_CATEGORY(lcPsql, "qt.sql.postgresql")
+
+using namespace Qt::StringLiterals;
+
inline void qPQfreemem(void *buffer)
{
PQfreemem(buffer);
@@ -108,11 +77,11 @@ inline void qPQfreemem(void *buffer)
/* Missing declaration of PGRES_SINGLE_TUPLE for PSQL below 9.2 */
#if !defined PG_VERSION_NUM || PG_VERSION_NUM-0 < 90200
-static const int PGRES_SINGLE_TUPLE = 9;
+static constexpr int PGRES_SINGLE_TUPLE = 9;
#endif
typedef int StatementId;
-static const StatementId InvalidStatementId = 0;
+static constexpr StatementId InvalidStatementId = 0;
class QPSQLResultPrivate;
@@ -149,26 +118,16 @@ class QPSQLDriverPrivate final : public QSqlDriverPrivate
{
Q_DECLARE_PUBLIC(QPSQLDriver)
public:
- QPSQLDriverPrivate() : QSqlDriverPrivate(),
- connection(nullptr),
- isUtf8(false),
- pro(QPSQLDriver::Version6),
- sn(nullptr),
- pendingNotifyCheck(false),
- hasBackslashEscape(false),
- stmtCount(0),
- currentStmtId(InvalidStatementId)
- { dbmsType = QSqlDriver::PostgreSQL; }
-
- PGconn *connection;
- bool isUtf8;
- QPSQLDriver::Protocol pro;
- QSocketNotifier *sn;
+ QPSQLDriverPrivate() : QSqlDriverPrivate(QSqlDriver::PostgreSQL) {}
+
QStringList seid;
- mutable bool pendingNotifyCheck;
- bool hasBackslashEscape;
- int stmtCount;
- StatementId currentStmtId;
+ PGconn *connection = nullptr;
+ QSocketNotifier *sn = nullptr;
+ QPSQLDriver::Protocol pro = QPSQLDriver::Version6;
+ StatementId currentStmtId = InvalidStatementId;
+ StatementId stmtCount = InvalidStatementId;
+ mutable bool pendingNotifyCheck = false;
+ bool hasBackslashEscape = false;
void appendTables(QStringList &tl, QSqlQuery &t, QChar type);
PGresult *exec(const char *stmt);
@@ -184,6 +143,7 @@ public:
bool setEncodingUtf8();
void setDatestyle();
void setByteaOutput();
+ void setUtcTimeZone();
void detectBackslashEscape();
mutable QHash<int, QString> oidToTable;
};
@@ -200,10 +160,10 @@ void QPSQLDriverPrivate::appendTables(QStringList &tl, QSqlQuery &t, QChar type)
t.exec(query);
while (t.next()) {
QString schema = t.value(1).toString();
- if (schema.isEmpty() || schema == QLatin1String("public"))
+ if (schema.isEmpty() || schema == "public"_L1)
tl.append(t.value(0).toString());
else
- tl.append(t.value(0).toString().prepend(QLatin1Char('.')).prepend(schema));
+ tl.append(t.value(0).toString().prepend(u'.').prepend(schema));
}
}
@@ -218,7 +178,7 @@ PGresult *QPSQLDriverPrivate::exec(const char *stmt)
PGresult *QPSQLDriverPrivate::exec(const QString &stmt)
{
- return exec((isUtf8 ? stmt.toUtf8() : stmt.toLocal8Bit()).constData());
+ return exec(stmt.toUtf8().constData());
}
StatementId QPSQLDriverPrivate::sendQuery(const QString &stmt)
@@ -226,8 +186,7 @@ StatementId QPSQLDriverPrivate::sendQuery(const QString &stmt)
// Discard any prior query results that the application didn't eat.
// This is required for PQsendQuery()
discardResults();
- const int result = PQsendQuery(connection,
- (isUtf8 ? stmt.toUtf8() : stmt.toLocal8Bit()).constData());
+ const int result = PQsendQuery(connection, stmt.toUtf8().constData());
currentStmtId = result ? generateStatementId() : InvalidStatementId;
return currentStmtId;
}
@@ -252,8 +211,8 @@ PGresult *QPSQLDriverPrivate::getResult(StatementId stmtId) const
if (stmtId != currentStmtId) {
// If you change the following warning, remember to update it
// on sql-driver.html page too.
- qWarning("QPSQLDriver::getResult: Query results lost - "
- "probably discarded on executing another SQL query.");
+ qCWarning(lcPsql, "QPSQLDriver::getResult: Query results lost - "
+ "probably discarded on executing another SQL query.");
return nullptr;
}
PGresult *result = PQgetResult(connection);
@@ -277,7 +236,7 @@ void QPSQLDriverPrivate::discardResults() const
StatementId QPSQLDriverPrivate::generateStatementId()
{
- int stmtId = ++stmtCount;
+ StatementId stmtId = ++stmtCount;
if (stmtId <= 0)
stmtId = stmtCount = 1;
return stmtId;
@@ -288,34 +247,27 @@ void QPSQLDriverPrivate::checkPendingNotifications() const
Q_Q(const QPSQLDriver);
if (seid.size() && !pendingNotifyCheck) {
pendingNotifyCheck = true;
- QMetaObject::invokeMethod(const_cast<QPSQLDriver*>(q), "_q_handleNotification", Qt::QueuedConnection, Q_ARG(int,0));
+ QMetaObject::invokeMethod(const_cast<QPSQLDriver*>(q), &QPSQLDriver::_q_handleNotification, Qt::QueuedConnection);
}
}
-class QPSQLResultPrivate : public QSqlResultPrivate
+class QPSQLResultPrivate final : public QSqlResultPrivate
{
Q_DECLARE_PUBLIC(QPSQLResult)
public:
Q_DECLARE_SQLDRIVER_PRIVATE(QPSQLDriver)
- QPSQLResultPrivate(QPSQLResult *q, const QPSQLDriver *drv)
- : QSqlResultPrivate(q, drv),
- result(nullptr),
- stmtId(InvalidStatementId),
- currentSize(-1),
- canFetchMoreRows(false),
- preparedQueriesEnabled(false)
- { }
-
- QString fieldSerial(int i) const override { return QLatin1Char('$') + QString::number(i + 1); }
+ using QSqlResultPrivate::QSqlResultPrivate;
+
+ QString fieldSerial(qsizetype i) const override { return QString("$%1"_L1).arg(i + 1); }
void deallocatePreparedStmt();
- PGresult *result;
std::queue<PGresult*> nextResultSets;
QString preparedStmtId;
- StatementId stmtId;
- int currentSize;
- bool canFetchMoreRows;
- bool preparedQueriesEnabled;
+ PGresult *result = nullptr;
+ StatementId stmtId = InvalidStatementId;
+ int currentSize = -1;
+ bool canFetchMoreRows = false;
+ bool preparedQueriesEnabled = false;
bool processResults();
};
@@ -324,13 +276,13 @@ static QSqlError qMakeError(const QString &err, QSqlError::ErrorType type,
const QPSQLDriverPrivate *p, PGresult *result = nullptr)
{
const char *s = PQerrorMessage(p->connection);
- QString msg = p->isUtf8 ? QString::fromUtf8(s) : QString::fromLocal8Bit(s);
+ QString msg = QString::fromUtf8(s);
QString errorCode;
if (result) {
errorCode = QString::fromLatin1(PQresultErrorField(result, PG_DIAG_SQLSTATE));
msg += QString::fromLatin1("(%1)").arg(errorCode);
}
- return QSqlError(QLatin1String("QPSQL: ") + err, msg, type, errorCode);
+ return QSqlError("QPSQL: "_L1 + err, msg, type, errorCode);
}
bool QPSQLResultPrivate::processResults()
@@ -380,15 +332,15 @@ bool QPSQLResultPrivate::processResults()
return false;
}
-static QVariant::Type qDecodePSQLType(int t)
+static QMetaType qDecodePSQLType(int t)
{
- QVariant::Type type = QVariant::Invalid;
+ int type = QMetaType::UnknownType;
switch (t) {
case QBOOLOID:
- type = QVariant::Bool;
+ type = QMetaType::Bool;
break;
case QINT8OID:
- type = QVariant::LongLong;
+ type = QMetaType::LongLong;
break;
case QINT2OID:
case QINT4OID:
@@ -396,34 +348,34 @@ static QVariant::Type qDecodePSQLType(int t)
case QREGPROCOID:
case QXIDOID:
case QCIDOID:
- type = QVariant::Int;
+ type = QMetaType::Int;
break;
case QNUMERICOID:
case QFLOAT4OID:
case QFLOAT8OID:
- type = QVariant::Double;
+ type = QMetaType::Double;
break;
case QABSTIMEOID:
case QRELTIMEOID:
case QDATEOID:
- type = QVariant::Date;
+ type = QMetaType::QDate;
break;
case QTIMEOID:
case QTIMETZOID:
- type = QVariant::Time;
+ type = QMetaType::QTime;
break;
case QTIMESTAMPOID:
case QTIMESTAMPTZOID:
- type = QVariant::DateTime;
+ type = QMetaType::QDateTime;
break;
case QBYTEAOID:
- type = QVariant::ByteArray;
+ type = QMetaType::QByteArray;
break;
default:
- type = QVariant::String;
+ type = QMetaType::QString;
break;
}
- return type;
+ return QMetaType(type);
}
void QPSQLResultPrivate::deallocatePreparedStmt()
@@ -432,8 +384,10 @@ void QPSQLResultPrivate::deallocatePreparedStmt()
const QString stmt = QStringLiteral("DEALLOCATE ") + preparedStmtId;
PGresult *result = drv_d_func()->exec(stmt);
- if (PQresultStatus(result) != PGRES_COMMAND_OK)
- qWarning("Unable to free statement: %s", PQerrorMessage(drv_d_func()->connection));
+ if (PQresultStatus(result) != PGRES_COMMAND_OK) {
+ const QString msg = QString::fromUtf8(PQerrorMessage(drv_d_func()->connection));
+ qCWarning(lcPsql, "Unable to free statement: %ls.", qUtf16Printable(msg));
+ }
PQclear(result);
}
preparedStmtId.clear();
@@ -643,28 +597,28 @@ QVariant QPSQLResult::data(int i)
{
Q_D(const QPSQLResult);
if (i >= PQnfields(d->result)) {
- qWarning("QPSQLResult::data: column %d out of range", i);
+ qCWarning(lcPsql, "QPSQLResult::data: column %d out of range.", i);
return QVariant();
}
const int currentRow = isForwardOnly() ? 0 : at();
int ptype = PQftype(d->result, i);
- QVariant::Type type = qDecodePSQLType(ptype);
+ QMetaType type = qDecodePSQLType(ptype);
if (PQgetisnull(d->result, currentRow, i))
- return QVariant(type);
+ return QVariant(type, nullptr);
const char *val = PQgetvalue(d->result, currentRow, i);
- switch (type) {
- case QVariant::Bool:
+ switch (type.id()) {
+ case QMetaType::Bool:
return QVariant((bool)(val[0] == 't'));
- case QVariant::String:
- return d->drv_d_func()->isUtf8 ? QString::fromUtf8(val) : QString::fromLatin1(val);
- case QVariant::LongLong:
+ case QMetaType::QString:
+ return QString::fromUtf8(val);
+ case QMetaType::LongLong:
if (val[0] == '-')
return QByteArray::fromRawData(val, qstrlen(val)).toLongLong();
else
return QByteArray::fromRawData(val, qstrlen(val)).toULongLong();
- case QVariant::Int:
+ case QMetaType::Int:
return atoi(val);
- case QVariant::Double: {
+ case QMetaType::Double: {
if (ptype == QNUMERICOID) {
if (numericalPrecisionPolicy() == QSql::HighPrecision)
return QString::fromLatin1(val);
@@ -691,35 +645,32 @@ QVariant QPSQLResult::data(int i)
}
return dbl;
}
- case QVariant::Date:
#if QT_CONFIG(datestring)
+ case QMetaType::QDate:
return QVariant(QDate::fromString(QString::fromLatin1(val), Qt::ISODate));
-#else
- return QVariant(QString::fromLatin1(val));
-#endif
- case QVariant::Time:
-#if QT_CONFIG(datestring)
+ case QMetaType::QTime:
return QVariant(QTime::fromString(QString::fromLatin1(val), Qt::ISODate));
+ case QMetaType::QDateTime: {
+ QString tzString(QString::fromLatin1(val));
+ if (!tzString.endsWith(u'Z'))
+ tzString.append(u'Z'); // make UTC
+ return QVariant(QDateTime::fromString(tzString, Qt::ISODate));
+ }
#else
+ case QMetaType::QDate:
+ case QMetaType::QTime:
+ case QMetaType::QDateTime:
return QVariant(QString::fromLatin1(val));
#endif
- case QVariant::DateTime:
-#if QT_CONFIG(datestring)
- return QVariant(QDateTime::fromString(QString::fromLatin1(val),
- Qt::ISODate).toLocalTime());
-#else
- return QVariant(QString::fromLatin1(val));
-#endif
- case QVariant::ByteArray: {
+ case QMetaType::QByteArray: {
size_t len;
- unsigned char *data = PQunescapeBytea((const unsigned char*)val, &len);
- QByteArray ba(reinterpret_cast<const char *>(data), int(len));
+ unsigned char *data = PQunescapeBytea(reinterpret_cast<const unsigned char *>(val), &len);
+ QByteArray ba(reinterpret_cast<const char *>(data), len);
qPQfreemem(data);
return QVariant(ba);
}
default:
- case QVariant::Invalid:
- qWarning("QPSQLResult::data: unknown data type");
+ qCWarning(lcPsql, "QPSQLResult::data: unhandled data type %d.", type.id());
}
return QVariant();
}
@@ -798,10 +749,7 @@ QSqlRecord QPSQLResult::record() const
int count = PQnfields(d->result);
QSqlField f;
for (int i = 0; i < count; ++i) {
- if (d->drv_d_func()->isUtf8)
- f.setName(QString::fromUtf8(PQfname(d->result, i)));
- else
- f.setName(QString::fromLocal8Bit(PQfname(d->result, i)));
+ f.setName(QString::fromUtf8(PQfname(d->result, i)));
const int tableOid = PQftable(d->result, i);
// WARNING: We cannot execute any other SQL queries on
// the same db connection while forward-only mode is active
@@ -821,8 +769,8 @@ QSqlRecord QPSQLResult::record() const
f.setTableName(QString());
}
int ptype = PQftype(d->result, i);
- f.setType(qDecodePSQLType(ptype));
- f.setValue(QVariant(f.type())); // only set in setType() when it's invalid before
+ f.setMetaType(qDecodePSQLType(ptype));
+ f.setValue(QVariant(f.metaType())); // only set in setType() when it's invalid before
int len = PQfsize(d->result, i);
int precision = PQfmod(d->result, i);
@@ -852,7 +800,6 @@ QSqlRecord QPSQLResult::record() const
f.setLength(len);
f.setPrecision(precision);
- f.setSqlType(ptype);
info.append(f);
}
return info;
@@ -864,7 +811,7 @@ void QPSQLResult::virtual_hook(int id, void *data)
QSqlResult::virtual_hook(id, data);
}
-static QString qCreateParamString(const QVector<QVariant> &boundValues, const QSqlDriver *driver)
+static QString qCreateParamString(const QList<QVariant> &boundValues, const QSqlDriver *driver)
{
if (boundValues.isEmpty())
return QString();
@@ -872,13 +819,13 @@ static QString qCreateParamString(const QVector<QVariant> &boundValues, const QS
QString params;
QSqlField f;
for (const QVariant &val : boundValues) {
- f.setType(val.type());
- if (val.isNull())
+ f.setMetaType(val.metaType());
+ if (QSqlResultPrivate::isVariantNull(val))
f.clear();
else
f.setValue(val);
if (!params.isNull())
- params.append(QLatin1String(", "));
+ params.append(", "_L1);
params.append(driver->formatValue(f));
}
return params;
@@ -886,7 +833,7 @@ static QString qCreateParamString(const QVector<QVariant> &boundValues, const QS
QString qMakePreparedStmtId()
{
- static QBasicAtomicInt qPreparedStmtCount = Q_BASIC_ATOMIC_INITIALIZER(0);
+ Q_CONSTINIT static QBasicAtomicInt qPreparedStmtCount = Q_BASIC_ATOMIC_INITIALIZER(0);
QString id = QStringLiteral("qpsqlpstmt_") + QString::number(qPreparedStmtCount.fetchAndAddRelaxed(1) + 1, 16);
return id;
}
@@ -969,7 +916,7 @@ void QPSQLDriverPrivate::setDatestyle()
PGresult *result = exec("SET DATESTYLE TO 'ISO'");
int status = PQresultStatus(result);
if (status != PGRES_COMMAND_OK)
- qWarning("%s", PQerrorMessage(connection));
+ qCWarning(lcPsql) << QString::fromUtf8(PQerrorMessage(connection));
PQclear(result);
}
@@ -982,11 +929,20 @@ void QPSQLDriverPrivate::setByteaOutput()
PGresult *result = exec("SET bytea_output TO escape");
int status = PQresultStatus(result);
if (status != PGRES_COMMAND_OK)
- qWarning("%s", PQerrorMessage(connection));
+ qCWarning(lcPsql) << QString::fromUtf8(PQerrorMessage(connection));
PQclear(result);
}
}
+void QPSQLDriverPrivate::setUtcTimeZone()
+{
+ PGresult *result = exec("SET TIME ZONE 'UTC'");
+ int status = PQresultStatus(result);
+ if (status != PGRES_COMMAND_OK)
+ qCWarning(lcPsql) << QString::fromUtf8(PQerrorMessage(connection));
+ PQclear(result);
+}
+
void QPSQLDriverPrivate::detectBackslashEscape()
{
// standard_conforming_strings option introduced in 8.2
@@ -998,7 +954,7 @@ void QPSQLDriverPrivate::detectBackslashEscape()
PGresult *result = exec(QStringLiteral("SELECT '\\\\' x"));
int status = PQresultStatus(result);
if (status == PGRES_COMMAND_OK || status == PGRES_TUPLES_OK)
- if (QString::fromLatin1(PQgetvalue(result, 0, 0)) == QLatin1String("\\"))
+ if (QString::fromLatin1(PQgetvalue(result, 0, 0)) == "\\"_L1)
hasBackslashEscape = true;
PQclear(result);
}
@@ -1082,14 +1038,14 @@ static QPSQLDriver::Protocol qFindPSQLVersion(const QString &versionString)
// increasing the first part of the version, e.g. 10 to 11.
// Before version 10, a major release was indicated by increasing either
// the first or second part of the version number, e.g. 9.5 to 9.6.
- int vMaj = match.capturedRef(1).toInt();
+ int vMaj = match.capturedView(1).toInt();
int vMin;
if (vMaj >= 10) {
vMin = 0;
} else {
- if (match.capturedRef(2).isEmpty())
+ if (match.capturedView(2).isEmpty())
return QPSQLDriver::VersionUnknown;
- vMin = match.capturedRef(2).toInt();
+ vMin = match.capturedView(2).toInt();
}
return qMakePSQLVersion(vMaj, vMin);
}
@@ -1110,9 +1066,9 @@ QPSQLDriver::Protocol QPSQLDriverPrivate::getPSQLVersion()
QPSQLDriver::Protocol clientVersion =
#if defined(PG_MAJORVERSION)
- qFindPSQLVersion(QLatin1String(PG_MAJORVERSION));
+ qFindPSQLVersion(PG_MAJORVERSION ""_L1);
#elif defined(PG_VERSION)
- qFindPSQLVersion(QLatin1String(PG_VERSION));
+ qFindPSQLVersion(PG_VERSION ""_L1);
#else
QPSQLDriver::VersionUnknown;
#endif
@@ -1120,16 +1076,16 @@ QPSQLDriver::Protocol QPSQLDriverPrivate::getPSQLVersion()
if (serverVersion == QPSQLDriver::VersionUnknown) {
serverVersion = clientVersion;
if (serverVersion != QPSQLDriver::VersionUnknown)
- qWarning("The server version of this PostgreSQL is unknown, falling back to the client version.");
+ qCWarning(lcPsql, "The server version of this PostgreSQL is unknown, "
+ "falling back to the client version.");
}
// Keep the old behavior unchanged
if (serverVersion == QPSQLDriver::VersionUnknown)
serverVersion = QPSQLDriver::Version6;
- if (serverVersion < QPSQLDriver::Version7_3) {
- qWarning("This version of PostgreSQL is not supported and may not work.");
- }
+ if (serverVersion < QPSQLDriver::Version7_3)
+ qCWarning(lcPsql, "This version of PostgreSQL is not supported and may not work.");
return serverVersion;
}
@@ -1155,8 +1111,7 @@ QPSQLDriver::QPSQLDriver(PGconn *conn, QObject *parent)
QPSQLDriver::~QPSQLDriver()
{
Q_D(QPSQLDriver);
- if (d->connection)
- PQfinish(d->connection);
+ PQfinish(d->connection);
}
QVariant QPSQLDriver::handle() const
@@ -1176,6 +1131,7 @@ bool QPSQLDriver::hasFeature(DriverFeature f) const
case EventNotifications:
case MultipleResultSets:
case BLOB:
+ case Unicode:
return true;
case PreparedQueries:
case PositionalPlaceholders:
@@ -1186,8 +1142,6 @@ bool QPSQLDriver::hasFeature(DriverFeature f) const
case FinishQuery:
case CancelQuery:
return false;
- case Unicode:
- return d->isUtf8;
}
return false;
}
@@ -1200,9 +1154,9 @@ bool QPSQLDriver::hasFeature(DriverFeature f) const
*/
static QString qQuote(QString s)
{
- s.replace(QLatin1Char('\\'), QLatin1String("\\\\"));
- s.replace(QLatin1Char('\''), QLatin1String("\\'"));
- s.append(QLatin1Char('\'')).prepend(QLatin1Char('\''));
+ s.replace(u'\\', "\\\\"_L1);
+ s.replace(u'\'', "\\'"_L1);
+ s.append(u'\'').prepend(u'\'');
return s;
}
@@ -1214,25 +1168,24 @@ bool QPSQLDriver::open(const QString &db,
const QString &connOpts)
{
Q_D(QPSQLDriver);
- if (isOpen())
- close();
+ close();
QString connectString;
if (!host.isEmpty())
- connectString.append(QLatin1String("host=")).append(qQuote(host));
+ connectString.append("host="_L1).append(qQuote(host));
if (!db.isEmpty())
- connectString.append(QLatin1String(" dbname=")).append(qQuote(db));
+ connectString.append(" dbname="_L1).append(qQuote(db));
if (!user.isEmpty())
- connectString.append(QLatin1String(" user=")).append(qQuote(user));
+ connectString.append(" user="_L1).append(qQuote(user));
if (!password.isEmpty())
- connectString.append(QLatin1String(" password=")).append(qQuote(password));
+ connectString.append(" password="_L1).append(qQuote(password));
if (port != -1)
- connectString.append(QLatin1String(" port=")).append(qQuote(QString::number(port)));
+ connectString.append(" port="_L1).append(qQuote(QString::number(port)));
// add any connect options - the server will handle error detection
if (!connOpts.isEmpty()) {
QString opt = connOpts;
- opt.replace(QLatin1Char(';'), QLatin1Char(' '), Qt::CaseInsensitive);
- connectString.append(QLatin1Char(' ')).append(opt);
+ opt.replace(';'_L1, ' '_L1, Qt::CaseInsensitive);
+ connectString.append(u' ').append(opt);
}
d->connection = PQconnectdb(std::move(connectString).toLocal8Bit().constData());
@@ -1246,9 +1199,16 @@ bool QPSQLDriver::open(const QString &db,
d->pro = d->getPSQLVersion();
d->detectBackslashEscape();
- d->isUtf8 = d->setEncodingUtf8();
+ if (!d->setEncodingUtf8()) {
+ setLastError(qMakeError(tr("Unable to set client encoding to 'UNICODE'"), QSqlError::ConnectionError, d));
+ setOpenError(true);
+ PQfinish(d->connection);
+ d->connection = nullptr;
+ return false;
+ }
d->setDatestyle();
d->setByteaOutput();
+ d->setUtcTimeZone();
setOpen(true);
setOpenError(false);
@@ -1258,21 +1218,18 @@ bool QPSQLDriver::open(const QString &db,
void QPSQLDriver::close()
{
Q_D(QPSQLDriver);
- if (isOpen()) {
-
- d->seid.clear();
- if (d->sn) {
- disconnect(d->sn, SIGNAL(activated(int)), this, SLOT(_q_handleNotification(int)));
- delete d->sn;
- d->sn = nullptr;
- }
- if (d->connection)
- PQfinish(d->connection);
- d->connection = nullptr;
- setOpen(false);
- setOpenError(false);
+ d->seid.clear();
+ if (d->sn) {
+ disconnect(d->sn, &QSocketNotifier::activated, this, &QPSQLDriver::_q_handleNotification);
+ delete d->sn;
+ d->sn = nullptr;
}
+
+ PQfinish(d->connection);
+ d->connection = nullptr;
+ setOpen(false);
+ setOpenError(false);
}
QSqlResult *QPSQLDriver::createResult() const
@@ -1284,7 +1241,7 @@ bool QPSQLDriver::beginTransaction()
{
Q_D(QPSQLDriver);
if (!isOpen()) {
- qWarning("QPSQLDriver::beginTransaction: Database not open");
+ qCWarning(lcPsql, "QPSQLDriver::beginTransaction: Database not open.");
return false;
}
PGresult *res = d->exec("BEGIN");
@@ -1302,7 +1259,7 @@ bool QPSQLDriver::commitTransaction()
{
Q_D(QPSQLDriver);
if (!isOpen()) {
- qWarning("QPSQLDriver::commitTransaction: Database not open");
+ qCWarning(lcPsql, "QPSQLDriver::commitTransaction: Database not open.");
return false;
}
PGresult *res = d->exec("COMMIT");
@@ -1312,7 +1269,7 @@ bool QPSQLDriver::commitTransaction()
// XXX
// This hack is used to tell if the transaction has succeeded for the protocol versions of
// PostgreSQL below. For 7.x and other protocol versions we are left in the dark.
- // This hack can dissapear once there is an API to query this sort of information.
+ // This hack can disappear once there is an API to query this sort of information.
if (d->pro >= QPSQLDriver::Version8) {
transaction_failed = qstrcmp(PQcmdStatus(res), "ROLLBACK") == 0;
}
@@ -1331,7 +1288,7 @@ bool QPSQLDriver::rollbackTransaction()
{
Q_D(QPSQLDriver);
if (!isOpen()) {
- qWarning("QPSQLDriver::rollbackTransaction: Database not open");
+ qCWarning(lcPsql, "QPSQLDriver::rollbackTransaction: Database not open.");
return false;
}
PGresult *res = d->exec("ROLLBACK");
@@ -1355,9 +1312,9 @@ QStringList QPSQLDriver::tables(QSql::TableType type) const
t.setForwardOnly(true);
if (type & QSql::Tables)
- const_cast<QPSQLDriverPrivate*>(d)->appendTables(tl, t, QLatin1Char('r'));
+ const_cast<QPSQLDriverPrivate*>(d)->appendTables(tl, t, u'r');
if (type & QSql::Views)
- const_cast<QPSQLDriverPrivate*>(d)->appendTables(tl, t, QLatin1Char('v'));
+ const_cast<QPSQLDriverPrivate*>(d)->appendTables(tl, t, u'v');
if (type & QSql::SystemTables) {
t.exec(QStringLiteral("SELECT relname FROM pg_class WHERE (relkind = 'r') "
"AND (relname LIKE 'pg_%') "));
@@ -1370,7 +1327,7 @@ QStringList QPSQLDriver::tables(QSql::TableType type) const
static void qSplitTableName(QString &tablename, QString &schema)
{
- int dot = tablename.indexOf(QLatin1Char('.'));
+ qsizetype dot = tablename.indexOf(u'.');
if (dot == -1)
return;
schema = tablename.left(dot);
@@ -1458,8 +1415,8 @@ QSqlRecord QPSQLDriver::record(const QString &tablename) const
precision = -1;
}
QString defVal = query.value(5).toString();
- if (!defVal.isEmpty() && defVal.at(0) == QLatin1Char('\'')) {
- const int end = defVal.lastIndexOf(QLatin1Char('\''));
+ if (!defVal.isEmpty() && defVal.at(0) == u'\'') {
+ const qsizetype end = defVal.lastIndexOf(u'\'');
if (end > 0)
defVal = defVal.mid(1, end - 1);
}
@@ -1468,7 +1425,6 @@ QSqlRecord QPSQLDriver::record(const QString &tablename) const
f.setLength(len);
f.setPrecision(precision);
f.setDefaultValue(defVal);
- f.setSqlType(query.value(1).toInt());
info.append(f);
}
@@ -1492,45 +1448,41 @@ QString QPSQLDriver::formatValue(const QSqlField &field, bool trimStrings) const
if (field.isNull()) {
r = nullStr();
} else {
- switch (int(field.type())) {
- case QVariant::DateTime:
-#if QT_CONFIG(datestring)
- if (field.value().toDateTime().isValid()) {
+ switch (field.metaType().id()) {
+ case QMetaType::QDateTime: {
+ const auto dt = field.value().toDateTime();
+ if (dt.isValid()) {
// we force the value to be considered with a timezone information, and we force it to be UTC
// this is safe since postgresql stores only the UTC value and not the timezone offset (only used
// while parsing), so we have correct behavior in both case of with timezone and without tz
- r = QStringLiteral("TIMESTAMP WITH TIME ZONE ") + QLatin1Char('\'') +
- QLocale::c().toString(field.value().toDateTime().toUTC(), u"yyyy-MM-ddThh:mm:ss.zzz") +
- QLatin1Char('Z') + QLatin1Char('\'');
+ r = QStringLiteral("TIMESTAMP WITH TIME ZONE ") + u'\'' +
+ QLocale::c().toString(dt.toUTC(), u"yyyy-MM-ddThh:mm:ss.zzz") +
+ u'Z' + u'\'';
} else {
r = nullStr();
}
-#else
- r = nullStr();
-#endif // datestring
break;
- case QVariant::Time:
-#if QT_CONFIG(datestring)
- if (field.value().toTime().isValid()) {
- r = QLatin1Char('\'') + field.value().toTime().toString(u"hh:mm:ss.zzz") + QLatin1Char('\'');
- } else
-#endif
- {
+ }
+ case QMetaType::QTime: {
+ const auto t = field.value().toTime();
+ if (t.isValid())
+ r = u'\'' + QLocale::c().toString(t, u"hh:mm:ss.zzz") + u'\'';
+ else
r = nullStr();
- }
break;
- case QVariant::String:
+ }
+ case QMetaType::QString:
r = QSqlDriver::formatValue(field, trimStrings);
if (d->hasBackslashEscape)
- r.replace(QLatin1Char('\\'), QLatin1String("\\\\"));
+ r.replace(u'\\', "\\\\"_L1);
break;
- case QVariant::Bool:
+ case QMetaType::Bool:
if (field.value().toBool())
r = QStringLiteral("TRUE");
else
r = QStringLiteral("FALSE");
break;
- case QVariant::ByteArray: {
+ case QMetaType::QByteArray: {
QByteArray ba(field.value().toByteArray());
size_t len;
#if defined PG_VERSION_NUM && PG_VERSION_NUM-0 >= 80200
@@ -1538,9 +1490,9 @@ QString QPSQLDriver::formatValue(const QSqlField &field, bool trimStrings) const
#else
unsigned char *data = PQescapeBytea((const unsigned char*)ba.constData(), ba.size(), &len);
#endif
- r += QLatin1Char('\'');
- r += QLatin1String((const char*)data);
- r += QLatin1Char('\'');
+ r += u'\'';
+ r += QLatin1StringView((const char*)data);
+ r += u'\'';
qPQfreemem(data);
break;
}
@@ -1549,13 +1501,13 @@ QString QPSQLDriver::formatValue(const QSqlField &field, bool trimStrings) const
if (r.isEmpty())
r = QSqlDriver::formatValue(field, trimStrings);
break;
- case QVariant::Double:
+ case QMetaType::Double:
assignSpecialPsqlFloatValue(field.value().toDouble(), &r);
if (r.isEmpty())
r = QSqlDriver::formatValue(field, trimStrings);
break;
- case QVariant::Uuid:
- r = QLatin1Char('\'') + field.value().toString() + QLatin1Char('\'');
+ case QMetaType::QUuid:
+ r = u'\'' + field.value().toString() + u'\'';
break;
default:
r = QSqlDriver::formatValue(field, trimStrings);
@@ -1568,10 +1520,10 @@ QString QPSQLDriver::formatValue(const QSqlField &field, bool trimStrings) const
QString QPSQLDriver::escapeIdentifier(const QString &identifier, IdentifierType) const
{
QString res = identifier;
- if (!identifier.isEmpty() && !identifier.startsWith(QLatin1Char('"')) && !identifier.endsWith(QLatin1Char('"')) ) {
- res.replace(QLatin1Char('"'), QLatin1String("\"\""));
- res.prepend(QLatin1Char('"')).append(QLatin1Char('"'));
- res.replace(QLatin1Char('.'), QLatin1String("\".\""));
+ if (!identifier.isEmpty() && !identifier.startsWith(u'"') && !identifier.endsWith(u'"') ) {
+ res.replace(u'"', "\"\""_L1);
+ res.replace(u'.', "\".\""_L1);
+ res = u'"' + res + u'"';
}
return res;
}
@@ -1592,25 +1544,24 @@ bool QPSQLDriver::subscribeToNotification(const QString &name)
{
Q_D(QPSQLDriver);
if (!isOpen()) {
- qWarning("QPSQLDriver::subscribeToNotificationImplementation: database not open.");
- return false;
- }
-
- if (d->seid.contains(name)) {
- qWarning("QPSQLDriver::subscribeToNotificationImplementation: already subscribing to '%s'.",
- qPrintable(name));
+ qCWarning(lcPsql, "QPSQLDriver::subscribeToNotification: Database not open.");
return false;
}
+ const bool alreadyContained = d->seid.contains(name);
int socket = PQsocket(d->connection);
if (socket) {
// Add the name to the list of subscriptions here so that QSQLDriverPrivate::exec knows
- // to check for notifications immediately after executing the LISTEN
- d->seid << name;
+ // to check for notifications immediately after executing the LISTEN. If it has already
+ // been subscribed then LISTEN Will do nothing. But we do the call anyway in case the
+ // connection was lost and this is a re-subscription.
+ if (!alreadyContained)
+ d->seid << name;
QString query = QStringLiteral("LISTEN ") + escapeIdentifier(name, QSqlDriver::TableName);
PGresult *result = d->exec(query);
if (PQresultStatus(result) != PGRES_COMMAND_OK) {
- d->seid.removeLast();
+ if (!alreadyContained)
+ d->seid.removeLast();
setLastError(qMakeError(tr("Unable to subscribe"), QSqlError::StatementError, d, result));
PQclear(result);
return false;
@@ -1618,11 +1569,12 @@ bool QPSQLDriver::subscribeToNotification(const QString &name)
PQclear(result);
if (!d->sn) {
- d->sn = new QSocketNotifier(socket, QSocketNotifier::Read);
- connect(d->sn, SIGNAL(activated(int)), this, SLOT(_q_handleNotification(int)));
+ d->sn = new QSocketNotifier(socket, QSocketNotifier::Read, this);
+ connect(d->sn, &QSocketNotifier::activated, this, &QPSQLDriver::_q_handleNotification);
}
} else {
- qWarning("QPSQLDriver::subscribeToNotificationImplementation: PQsocket didn't return a valid socket to listen on");
+ qCWarning(lcPsql, "QPSQLDriver::subscribeToNotificationImplementation: "
+ "PQsocket didn't return a valid socket to listen on.");
return false;
}
@@ -1633,13 +1585,13 @@ bool QPSQLDriver::unsubscribeFromNotification(const QString &name)
{
Q_D(QPSQLDriver);
if (!isOpen()) {
- qWarning("QPSQLDriver::unsubscribeFromNotificationImplementation: database not open.");
+ qCWarning(lcPsql, "QPSQLDriver::unsubscribeFromNotification: Database not open.");
return false;
}
if (!d->seid.contains(name)) {
- qWarning("QPSQLDriver::unsubscribeFromNotificationImplementation: not subscribed to '%s'.",
- qPrintable(name));
+ qCWarning(lcPsql, "QPSQLDriver::unsubscribeFromNotification: not subscribed to '%ls'.",
+ qUtf16Printable(name));
return false;
}
@@ -1655,7 +1607,7 @@ bool QPSQLDriver::unsubscribeFromNotification(const QString &name)
d->seid.removeAll(name);
if (d->seid.isEmpty()) {
- disconnect(d->sn, SIGNAL(activated(int)), this, SLOT(_q_handleNotification(int)));
+ disconnect(d->sn, &QSocketNotifier::activated, this, &QPSQLDriver::_q_handleNotification);
delete d->sn;
d->sn = nullptr;
}
@@ -1669,7 +1621,7 @@ QStringList QPSQLDriver::subscribedToNotifications() const
return d->seid;
}
-void QPSQLDriver::_q_handleNotification(int)
+void QPSQLDriver::_q_handleNotification()
{
Q_D(QPSQLDriver);
d->pendingNotifyCheck = false;
@@ -1677,22 +1629,24 @@ void QPSQLDriver::_q_handleNotification(int)
PGnotify *notify = nullptr;
while ((notify = PQnotifies(d->connection)) != nullptr) {
- QString name(QLatin1String(notify->relname));
+ QString name(QLatin1StringView(notify->relname));
if (d->seid.contains(name)) {
QString payload;
#if defined PG_VERSION_NUM && PG_VERSION_NUM-0 >= 70400
if (notify->extra)
- payload = d->isUtf8 ? QString::fromUtf8(notify->extra) : QString::fromLatin1(notify->extra);
+ payload = QString::fromUtf8(notify->extra);
#endif
QSqlDriver::NotificationSource source = (notify->be_pid == PQbackendPID(d->connection)) ? QSqlDriver::SelfSource : QSqlDriver::OtherSource;
emit notification(name, source, payload);
}
else
- qWarning("QPSQLDriver: received notification for '%s' which isn't subscribed to.",
- qPrintable(name));
+ qCWarning(lcPsql, "QPSQLDriver: received notification for '%ls' which isn't subscribed to.",
+ qUtf16Printable(name));
qPQfreemem(notify);
}
}
QT_END_NAMESPACE
+
+#include "moc_qsql_psql_p.cpp"
diff --git a/src/plugins/sqldrivers/psql/qsql_psql_p.h b/src/plugins/sqldrivers/psql/qsql_psql_p.h
index 9ac1fb50d7..4ff83bee21 100644
--- a/src/plugins/sqldrivers/psql/qsql_psql_p.h
+++ b/src/plugins/sqldrivers/psql/qsql_psql_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtSql module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QSQL_PSQL_H
#define QSQL_PSQL_H
@@ -130,7 +94,7 @@ protected:
bool rollbackTransaction() override;
private Q_SLOTS:
- void _q_handleNotification(int);
+ void _q_handleNotification();
};
QT_END_NAMESPACE
diff --git a/src/plugins/sqldrivers/qsqldriverbase.pri b/src/plugins/sqldrivers/qsqldriverbase.pri
deleted file mode 100644
index 4b78fa9454..0000000000
--- a/src/plugins/sqldrivers/qsqldriverbase.pri
+++ /dev/null
@@ -1,9 +0,0 @@
-QT = core core-private sql-private
-
-# For QMAKE_USE in the parent projects.
-include($$shadowed($$PWD)/qtsqldrivers-config.pri)
-
-PLUGIN_TYPE = sqldrivers
-load(qt_plugin)
-
-DEFINES += QT_NO_CAST_TO_ASCII QT_NO_CAST_FROM_ASCII
diff --git a/src/plugins/sqldrivers/qt_cmdline.cmake b/src/plugins/sqldrivers/qt_cmdline.cmake
new file mode 100644
index 0000000000..2bb1fc64eb
--- /dev/null
+++ b/src/plugins/sqldrivers/qt_cmdline.cmake
@@ -0,0 +1,22 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+qt_commandline_option(mysql_config TYPE string)
+qt_commandline_option(psql_config TYPE string)
+qt_commandline_option(sqlite CONTROLS_FEATURE TYPE enum NAME system-sqlite MAPPING qt no system yes)
+qt_commandline_option(sql-db2 TYPE boolean)
+qt_commandline_option(sql-ibase TYPE boolean)
+qt_commandline_option(sql-mysql TYPE boolean)
+qt_commandline_option(sql-oci TYPE boolean)
+qt_commandline_option(sql-odbc TYPE boolean)
+qt_commandline_option(sql-psql TYPE boolean)
+qt_commandline_option(sql-sqlite TYPE boolean)
+qt_commandline_option(sql-mimer TYPE boolean)
+qt_commandline_option(plugin-sql-db2 TYPE void NAME sql-db2)
+qt_commandline_option(plugin-sql-ibase TYPE void NAME sql-ibase)
+qt_commandline_option(plugin-sql-mysql TYPE void NAME sql-mysql)
+qt_commandline_option(plugin-sql-oci TYPE void NAME sql-oci)
+qt_commandline_option(plugin-sql-odbc TYPE void NAME sql-odbc)
+qt_commandline_option(plugin-sql-psql TYPE void NAME sql-psql)
+qt_commandline_option(plugin-sql-sqlite TYPE void NAME sql-sqlite)
+qt_commandline_option(plugin-sql-mimer TYPE void NAME sql-mimer)
diff --git a/src/plugins/sqldrivers/sqldrivers.pro b/src/plugins/sqldrivers/sqldrivers.pro
deleted file mode 100644
index f1db8f65a2..0000000000
--- a/src/plugins/sqldrivers/sqldrivers.pro
+++ /dev/null
@@ -1,14 +0,0 @@
-TEMPLATE = subdirs
-
-sqldrivers_standalone {
- _QMAKE_CACHE_ = $$shadowed($$SQLDRV_SRC_TREE)/.qmake.conf
- load(qt_configure)
-}
-
-qtConfig(sql-psql) : SUBDIRS += psql
-qtConfig(sql-mysql) : SUBDIRS += mysql
-qtConfig(sql-odbc) : SUBDIRS += odbc
-qtConfig(sql-oci) : SUBDIRS += oci
-qtConfig(sql-db2) : SUBDIRS += db2
-qtConfig(sql-sqlite) : SUBDIRS += sqlite
-qtConfig(sql-ibase) : SUBDIRS += ibase
diff --git a/src/plugins/sqldrivers/sqlite/.prev_CMakeLists.txt b/src/plugins/sqldrivers/sqlite/.prev_CMakeLists.txt
deleted file mode 100644
index d258c23821..0000000000
--- a/src/plugins/sqldrivers/sqlite/.prev_CMakeLists.txt
+++ /dev/null
@@ -1,93 +0,0 @@
-# Generated from sqlite.pro.
-
-#####################################################################
-## QSQLiteDriverPlugin Plugin:
-#####################################################################
-
-qt_add_plugin(QSQLiteDriverPlugin
- OUTPUT_NAME qsqlite
- TYPE sqldrivers
- SOURCES
- qsql_sqlite.cpp qsql_sqlite_p.h
- smain.cpp
- DEFINES
- QT_NO_CAST_FROM_ASCII
- QT_NO_CAST_TO_ASCII
- PUBLIC_LIBRARIES
- Qt::Core
- Qt::CorePrivate
- Qt::SqlPrivate
-)
-
-#### Keys ignored in scope 1:.:.:sqlite.pro:<TRUE>:
-# OTHER_FILES = "sqlite.json"
-# QT_FOR_CONFIG = "sqldrivers-private"
-
-## Scopes:
-#####################################################################
-
-qt_extend_target(QSQLiteDriverPlugin CONDITION QT_FEATURE_system_sqlite
- PUBLIC_LIBRARIES
- sqlite
-)
-
-qt_extend_target(QSQLiteDriverPlugin CONDITION NOT QT_FEATURE_system_sqlite
- SOURCES
- ../../../3rdparty/sqlite/sqlite3.c
- DEFINES
- SQLITE_ENABLE_COLUMN_METADATA
- SQLITE_ENABLE_FTS3
- SQLITE_ENABLE_FTS3_PARENTHESIS
- SQLITE_ENABLE_FTS5
- SQLITE_ENABLE_JSON1
- SQLITE_ENABLE_RTREE
- SQLITE_OMIT_COMPLETE
- INCLUDE_DIRECTORIES
- ../../../3rdparty/sqlite
-)
-
-qt_extend_target(QSQLiteDriverPlugin CONDITION CMAKE_BUILD_TYPE STREQUAL Release AND NOT QT_FEATURE_system_sqlite
- DEFINES
- NDEBUG
-)
-
-qt_extend_target(QSQLiteDriverPlugin CONDITION NOT CONFIG___contains___largefile AND NOT QT_FEATURE_system_sqlite
- DEFINES
- SQLITE_DISABLE_LFS
-)
-
-qt_extend_target(QSQLiteDriverPlugin CONDITION QT_FEATURE_posix_fallocate AND NOT QT_FEATURE_system_sqlite
- DEFINES
- HAVE_POSIX_FALLOCATE=1
-)
-
-qt_extend_target(QSQLiteDriverPlugin CONDITION WINRT AND NOT QT_FEATURE_system_sqlite
- DEFINES
- SQLITE_OS_WINRT
-)
-
-#### Keys ignored in scope 8:.:../../../3rdparty:../../../3rdparty/sqlite.pri:WINRT:
-# QMAKE_CFLAGS = "-Gy"
-
-qt_extend_target(QSQLiteDriverPlugin CONDITION QNX AND NOT QT_FEATURE_system_sqlite
- DEFINES
- _QNX_SOURCE
-)
-
-qt_extend_target(QSQLiteDriverPlugin CONDITION UNIX AND NOT QT_FEATURE_system_sqlite AND NOT WINRT AND NOT winphone
- DEFINES
- HAVE_USLEEP=1
-)
-
-qt_extend_target(QSQLiteDriverPlugin CONDITION QT_FEATURE_dlopen AND NOT QT_FEATURE_system_sqlite
- PUBLIC_LIBRARIES
- ${CMAKE_DL_LIBS}
-)
-
-qt_extend_target(QSQLiteDriverPlugin CONDITION NOT QT_FEATURE_dlopen AND NOT QT_FEATURE_system_sqlite
- DEFINES
- SQLITE_OMIT_LOAD_EXTENSION
-)
-
-#### Keys ignored in scope 13:.:../../../3rdparty:../../../3rdparty/sqlite.pri:INTEGRITY:
-# QMAKE_CFLAGS = "-include" "qplatformdefs.h"
diff --git a/src/plugins/sqldrivers/sqlite/CMakeLists.txt b/src/plugins/sqldrivers/sqlite/CMakeLists.txt
index d1453638b3..4203a5c437 100644
--- a/src/plugins/sqldrivers/sqlite/CMakeLists.txt
+++ b/src/plugins/sqldrivers/sqlite/CMakeLists.txt
@@ -1,34 +1,107 @@
-# Generated from sqlite.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## QSQLiteDriverPlugin Plugin:
#####################################################################
-qt_add_plugin(QSQLiteDriverPlugin
+qt_internal_add_plugin(QSQLiteDriverPlugin
OUTPUT_NAME qsqlite
- TYPE sqldrivers
+ PLUGIN_TYPE sqldrivers
SOURCES
qsql_sqlite.cpp qsql_sqlite_p.h
+ qsql_sqlite_vfs.cpp qsql_sqlite_vfs_p.h
smain.cpp
DEFINES
QT_NO_CAST_FROM_ASCII
QT_NO_CAST_TO_ASCII
- LIBRARIES # special case
- SQLite::SQLite3 # special case
- PUBLIC_LIBRARIES
+ QT_NO_CONTEXTLESS_CONNECT
+ LIBRARIES
Qt::Core
Qt::CorePrivate
Qt::SqlPrivate
)
-#### Keys ignored in scope 1:.:.:sqlite.pro:<TRUE>:
-# OTHER_FILES = "sqlite.json"
-# QT_FOR_CONFIG = "sqldrivers-private"
-
## Scopes:
#####################################################################
-# special case begin
-# Remove non-system-sqlite code
-# qt_extend_target(qsqlite CONDITION QT_FEATURE_system_sqlite
-# special case end
+qt_internal_extend_target(QSQLiteDriverPlugin CONDITION QT_FEATURE_system_sqlite
+ LIBRARIES
+ SQLite::SQLite3
+)
+
+if (NOT QT_FEATURE_system_sqlite)
+ # On newer compilers compiling sqlite.c produces warnings
+ qt_disable_warnings(QSQLiteDriverPlugin)
+endif()
+
+if(QT_FEATURE_system_sqlite)
+ qt_internal_force_macos_intel_arch(QSQLiteDriverPlugin)
+endif()
+
+qt_internal_extend_target(QSQLiteDriverPlugin CONDITION NOT QT_FEATURE_system_sqlite AND VXWORKS
+ DEFINES
+ SQLITE_OS_UNIX=1
+)
+
+qt_internal_extend_target(QSQLiteDriverPlugin CONDITION NOT QT_FEATURE_system_sqlite
+ SOURCES
+ ../../../3rdparty/sqlite/sqlite3.c
+ DEFINES
+ SQLITE_ENABLE_COLUMN_METADATA
+ SQLITE_ENABLE_FTS3
+ SQLITE_ENABLE_FTS3_PARENTHESIS
+ SQLITE_ENABLE_FTS4
+ SQLITE_ENABLE_FTS5
+ SQLITE_ENABLE_GEOPOLY
+ SQLITE_ENABLE_JSON1
+ SQLITE_ENABLE_MATH_FUNCTIONS
+ SQLITE_ENABLE_RTREE
+ SQLITE_OMIT_COMPLETE
+ INCLUDE_DIRECTORIES
+ ../../../3rdparty/sqlite
+)
+
+qt_internal_extend_target(QSQLiteDriverPlugin CONDITION CMAKE_BUILD_TYPE STREQUAL Release AND NOT QT_FEATURE_system_sqlite
+ DEFINES
+ NDEBUG
+)
+
+qt_internal_extend_target(QSQLiteDriverPlugin CONDITION NOT QT_FEATURE_largefile AND NOT QT_FEATURE_system_sqlite
+ DEFINES
+ SQLITE_DISABLE_LFS
+)
+
+qt_internal_extend_target(QSQLiteDriverPlugin CONDITION QT_FEATURE_posix_fallocate AND NOT QT_FEATURE_system_sqlite
+ DEFINES
+ HAVE_POSIX_FALLOCATE=1
+)
+
+qt_internal_extend_target(QSQLiteDriverPlugin CONDITION QNX AND NOT QT_FEATURE_system_sqlite
+ DEFINES
+ _QNX_SOURCE
+)
+
+qt_internal_extend_target(QSQLiteDriverPlugin CONDITION UNIX AND NOT QT_FEATURE_system_sqlite
+ DEFINES
+ 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}
+)
+
+qt_internal_extend_target(QSQLiteDriverPlugin CONDITION NOT QT_FEATURE_dlopen AND NOT QT_FEATURE_system_sqlite
+ DEFINES
+ SQLITE_OMIT_LOAD_EXTENSION
+)
+
+qt_internal_extend_target(QSQLiteDriverPlugin CONDITION NOT QT_FEATURE_thread AND NOT QT_FEATURE_system_sqlite
+ DEFINES
+ SQLITE_THREADSAFE=0
+)
diff --git a/src/plugins/sqldrivers/sqlite/qsql_sqlite.cpp b/src/plugins/sqldrivers/sqlite/qsql_sqlite.cpp
index 009e8a39ef..c574772fd7 100644
--- a/src/plugins/sqldrivers/sqlite/qsql_sqlite.cpp
+++ b/src/plugins/sqldrivers/sqlite/qsql_sqlite.cpp
@@ -1,47 +1,13 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtSql module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qsql_sqlite_p.h"
#include <qcoreapplication.h>
#include <qdatetime.h>
-#include <qvariant.h>
+#include <qdebug.h>
+#include <qlist.h>
+#include <qloggingcategory.h>
#include <qsqlerror.h>
#include <qsqlfield.h>
#include <qsqlindex.h>
@@ -49,8 +15,7 @@
#include <QtSql/private/qsqlcachedresult_p.h>
#include <QtSql/private/qsqldriver_p.h>
#include <qstringlist.h>
-#include <qvector.h>
-#include <qdebug.h>
+#include <qvariant.h>
#if QT_CONFIG(regularexpression)
#include <qcache.h>
#include <qregularexpression.h>
@@ -74,35 +39,26 @@ Q_DECLARE_METATYPE(sqlite3_stmt*)
QT_BEGIN_NAMESPACE
-static QString _q_escapeIdentifier(const QString &identifier)
-{
- QString res = identifier;
- if (!identifier.isEmpty() && !identifier.startsWith(QLatin1Char('"')) && !identifier.endsWith(QLatin1Char('"'))) {
- res.replace(QLatin1Char('"'), QLatin1String("\"\""));
- res.prepend(QLatin1Char('"')).append(QLatin1Char('"'));
- res.replace(QLatin1Char('.'), QLatin1String("\".\""));
- }
- return res;
-}
+static Q_LOGGING_CATEGORY(lcSqlite, "qt.sql.sqlite")
+
+using namespace Qt::StringLiterals;
-static QVariant::Type qGetColumnType(const QString &tpName)
+static int qGetColumnType(const QString &tpName)
{
const QString typeName = tpName.toLower();
- if (typeName == QLatin1String("integer")
- || typeName == QLatin1String("int"))
- return QVariant::Int;
- if (typeName == QLatin1String("double")
- || typeName == QLatin1String("float")
- || typeName == QLatin1String("real")
- || typeName.startsWith(QLatin1String("numeric")))
- return QVariant::Double;
- if (typeName == QLatin1String("blob"))
- return QVariant::ByteArray;
- if (typeName == QLatin1String("boolean")
- || typeName == QLatin1String("bool"))
- return QVariant::Bool;
- return QVariant::String;
+ if (typeName == "integer"_L1 || typeName == "int"_L1)
+ return QMetaType::Int;
+ if (typeName == "double"_L1
+ || typeName == "float"_L1
+ || typeName == "real"_L1
+ || typeName.startsWith("numeric"_L1))
+ return QMetaType::Double;
+ if (typeName == "blob"_L1)
+ return QMetaType::QByteArray;
+ if (typeName == "boolean"_L1 || typeName == "bool"_L1)
+ return QMetaType::Bool;
+ return QMetaType::QString;
}
static QSqlError qMakeError(sqlite3 *access, const QString &descr, QSqlError::ErrorType type,
@@ -144,42 +100,86 @@ class QSQLiteDriverPrivate : public QSqlDriverPrivate
Q_DECLARE_PUBLIC(QSQLiteDriver)
public:
- inline QSQLiteDriverPrivate() : QSqlDriverPrivate(), access(0) { dbmsType = QSqlDriver::SQLite; }
- sqlite3 *access;
- QList <QSQLiteResult *> results;
+ inline QSQLiteDriverPrivate() : QSqlDriverPrivate(QSqlDriver::SQLite) {}
+ bool isIdentifierEscaped(QStringView identifier) const;
+ QSqlIndex getTableInfo(QSqlQuery &query, const QString &tableName,
+ bool onlyPIndex = false) const;
+
+ sqlite3 *access = nullptr;
+ QList<QSQLiteResult *> results;
QStringList notificationid;
};
+bool QSQLiteDriverPrivate::isIdentifierEscaped(QStringView identifier) const
+{
+ return identifier.size() > 2
+ && ((identifier.startsWith(u'"') && identifier.endsWith(u'"'))
+ || (identifier.startsWith(u'`') && identifier.endsWith(u'`'))
+ || (identifier.startsWith(u'[') && identifier.endsWith(u']')));
+}
-class QSQLiteResultPrivate: public QSqlCachedResultPrivate
+QSqlIndex QSQLiteDriverPrivate::getTableInfo(QSqlQuery &query, const QString &tableName,
+ bool onlyPIndex) const
+{
+ Q_Q(const QSQLiteDriver);
+ QString schema;
+ QString table = q->escapeIdentifier(tableName, QSqlDriver::TableName);
+ const auto indexOfSeparator = table.indexOf(u'.');
+ if (indexOfSeparator > -1) {
+ auto leftName = QStringView{table}.first(indexOfSeparator);
+ auto rightName = QStringView{table}.sliced(indexOfSeparator + 1);
+ if (isIdentifierEscaped(leftName) && isIdentifierEscaped(rightName)) {
+ schema = leftName.toString() + u'.';
+ table = rightName.toString();
+ }
+ }
+
+ query.exec("PRAGMA "_L1 + schema + "table_info ("_L1 + table + u')');
+ QSqlIndex ind;
+ while (query.next()) {
+ bool isPk = query.value(5).toInt();
+ if (onlyPIndex && !isPk)
+ continue;
+ QString typeName = query.value(2).toString().toLower();
+ QString defVal = query.value(4).toString();
+ if (!defVal.isEmpty() && defVal.at(0) == u'\'') {
+ const int end = defVal.lastIndexOf(u'\'');
+ if (end > 0)
+ defVal = defVal.mid(1, end - 1);
+ }
+
+ QSqlField fld(query.value(1).toString(), QMetaType(qGetColumnType(typeName)), tableName);
+ if (isPk && (typeName == "integer"_L1))
+ // INTEGER PRIMARY KEY fields are auto-generated in sqlite
+ // INT PRIMARY KEY is not the same as INTEGER PRIMARY KEY!
+ fld.setAutoValue(true);
+ fld.setRequired(query.value(3).toInt() != 0);
+ fld.setDefaultValue(defVal);
+ ind.append(fld);
+ }
+ return ind;
+}
+
+class QSQLiteResultPrivate : public QSqlCachedResultPrivate
{
Q_DECLARE_PUBLIC(QSQLiteResult)
public:
Q_DECLARE_SQLDRIVER_PRIVATE(QSQLiteDriver)
- QSQLiteResultPrivate(QSQLiteResult *q, const QSQLiteDriver *drv);
+ using QSqlCachedResultPrivate::QSqlCachedResultPrivate;
void cleanup();
bool fetchNext(QSqlCachedResult::ValueCache &values, int idx, bool initialFetch);
// initializes the recordInfo and the cache
void initColumns(bool emptyResultset);
void finalize();
- sqlite3_stmt *stmt;
-
- bool skippedStatus; // the status of the fetchNext() that's skipped
- bool skipRow; // skip the next fetchNext()?
+ sqlite3_stmt *stmt = nullptr;
QSqlRecord rInf;
- QVector<QVariant> firstRow;
+ QList<QVariant> firstRow;
+ bool skippedStatus = false; // the status of the fetchNext() that's skipped
+ bool skipRow = false; // skip the next fetchNext()?
};
-QSQLiteResultPrivate::QSQLiteResultPrivate(QSQLiteResult *q, const QSQLiteDriver *drv)
- : QSqlCachedResultPrivate(q, drv),
- stmt(0),
- skippedStatus(false),
- skipRow(false)
-{
-}
-
void QSQLiteResultPrivate::cleanup()
{
Q_Q(QSQLiteResult);
@@ -198,7 +198,7 @@ void QSQLiteResultPrivate::finalize()
return;
sqlite3_finalize(stmt);
- stmt = 0;
+ stmt = nullptr;
}
void QSQLiteResultPrivate::initColumns(bool emptyResultset)
@@ -213,17 +213,17 @@ void QSQLiteResultPrivate::initColumns(bool emptyResultset)
for (int i = 0; i < nCols; ++i) {
QString colName = QString(reinterpret_cast<const QChar *>(
sqlite3_column_name16(stmt, i))
- ).remove(QLatin1Char('"'));
+ ).remove(u'"');
const QString tableName = QString(reinterpret_cast<const QChar *>(
sqlite3_column_table_name16(stmt, i))
- ).remove(QLatin1Char('"'));
+ ).remove(u'"');
// must use typeName for resolving the type to match QSqliteDriver::record
QString typeName = QString(reinterpret_cast<const QChar *>(
sqlite3_column_decltype16(stmt, i)));
// sqlite3_column_type is documented to have undefined behavior if the result set is empty
int stp = emptyResultset ? -1 : sqlite3_column_type(stmt, i);
- QVariant::Type fieldType;
+ int fieldType;
if (!typeName.isEmpty()) {
fieldType = qGetColumnType(typeName);
@@ -231,26 +231,25 @@ void QSQLiteResultPrivate::initColumns(bool emptyResultset)
// Get the proper type for the field based on stp value
switch (stp) {
case SQLITE_INTEGER:
- fieldType = QVariant::Int;
+ fieldType = QMetaType::Int;
break;
case SQLITE_FLOAT:
- fieldType = QVariant::Double;
+ fieldType = QMetaType::Double;
break;
case SQLITE_BLOB:
- fieldType = QVariant::ByteArray;
+ fieldType = QMetaType::QByteArray;
break;
case SQLITE_TEXT:
- fieldType = QVariant::String;
+ fieldType = QMetaType::QString;
break;
case SQLITE_NULL:
default:
- fieldType = QVariant::Invalid;
+ fieldType = QMetaType::UnknownType;
break;
}
}
- QSqlField fld(colName, fieldType, tableName);
- fld.setSqlType(stp);
+ QSqlField fld(colName, QMetaType(fieldType), tableName);
rInf.append(fld);
}
}
@@ -258,20 +257,18 @@ void QSQLiteResultPrivate::initColumns(bool emptyResultset)
bool QSQLiteResultPrivate::fetchNext(QSqlCachedResult::ValueCache &values, int idx, bool initialFetch)
{
Q_Q(QSQLiteResult);
- int res;
- int i;
if (skipRow) {
// already fetched
Q_ASSERT(!initialFetch);
skipRow = false;
- for(int i=0;i<firstRow.count();i++)
+ for(int i=0;i<firstRow.size();i++)
values[i]=firstRow[i];
return skippedStatus;
}
skipRow = initialFetch;
- if(initialFetch) {
+ if (initialFetch) {
firstRow.clear();
firstRow.resize(sqlite3_column_count(stmt));
}
@@ -282,8 +279,7 @@ bool QSQLiteResultPrivate::fetchNext(QSqlCachedResult::ValueCache &values, int i
q->setAt(QSql::AfterLastRow);
return false;
}
- res = sqlite3_step(stmt);
-
+ int res = sqlite3_step(stmt);
switch(res) {
case SQLITE_ROW:
// check to see if should fill out columns
@@ -292,7 +288,7 @@ bool QSQLiteResultPrivate::fetchNext(QSqlCachedResult::ValueCache &values, int i
initColumns(false);
if (idx < 0 && !initialFetch)
return true;
- for (i = 0; i < rInf.count(); ++i) {
+ for (int i = 0; i < rInf.count(); ++i) {
switch (sqlite3_column_type(stmt, i)) {
case SQLITE_BLOB:
values[i + idx] = QByteArray(static_cast<const char *>(
@@ -318,7 +314,7 @@ bool QSQLiteResultPrivate::fetchNext(QSqlCachedResult::ValueCache &values, int i
};
break;
case SQLITE_NULL:
- values[i + idx] = QVariant(QVariant::String);
+ values[i + idx] = QVariant(QMetaType::fromType<QString>());
break;
default:
values[i + idx] = QString(reinterpret_cast<const QChar *>(
@@ -394,13 +390,14 @@ bool QSQLiteResult::prepare(const QString &query)
setSelect(false);
- const void *pzTail = NULL;
+ const void *pzTail = nullptr;
+ const auto size = int((query.size() + 1) * sizeof(QChar));
#if (SQLITE_VERSION_NUMBER >= 3003011)
- int res = sqlite3_prepare16_v2(d->drv_d_func()->access, query.constData(), (query.size() + 1) * sizeof(QChar),
+ int res = sqlite3_prepare16_v2(d->drv_d_func()->access, query.constData(), size,
&d->stmt, &pzTail);
#else
- int res = sqlite3_prepare16(d->access, query.constData(), (query.size() + 1) * sizeof(QChar),
+ int res = sqlite3_prepare16(d->access, query.constData(), size,
&d->stmt, &pzTail);
#endif
@@ -422,15 +419,15 @@ bool QSQLiteResult::execBatch(bool arrayBind)
{
Q_UNUSED(arrayBind);
Q_D(QSqlResult);
- QScopedValueRollback<QVector<QVariant>> valuesScope(d->values);
- QVector<QVariant> values = d->values;
- if (values.count() == 0)
+ QScopedValueRollback<QList<QVariant>> valuesScope(d->values);
+ QList<QVariant> values = d->values;
+ if (values.size() == 0)
return false;
- for (int i = 0; i < values.at(0).toList().count(); ++i) {
+ for (int i = 0; i < values.at(0).toList().size(); ++i) {
d->values.clear();
- QScopedValueRollback<QHash<QString, QVector<int>>> indexesScope(d->indexes);
- QHash<QString, QVector<int>>::const_iterator it = d->indexes.constBegin();
+ QScopedValueRollback<QHash<QString, QList<int>>> indexesScope(d->indexes);
+ auto it = d->indexes.constBegin();
while (it != d->indexes.constEnd()) {
bindValue(it.key(), values.at(it.value().first()).toList().at(i), QSql::In);
++it;
@@ -444,7 +441,7 @@ bool QSQLiteResult::execBatch(bool arrayBind)
bool QSQLiteResult::exec()
{
Q_D(QSQLiteResult);
- QVector<QVariant> values = boundValues();
+ QList<QVariant> values = boundValues();
d->skippedStatus = false;
d->skipRow = false;
@@ -461,16 +458,16 @@ bool QSQLiteResult::exec()
}
int paramCount = sqlite3_bind_parameter_count(d->stmt);
- bool paramCountIsValid = paramCount == values.count();
+ bool paramCountIsValid = paramCount == values.size();
#if (SQLITE_VERSION_NUMBER >= 3003011)
// In the case of the reuse of a named placeholder
// We need to check explicitly that paramCount is greater than or equal to 1, as sqlite
// can end up in a case where for virtual tables it returns 0 even though it
// has parameters
- if (paramCount >= 1 && paramCount < values.count()) {
- const auto countIndexes = [](int counter, const QVector<int> &indexList) {
- return counter + indexList.length();
+ if (paramCount >= 1 && paramCount < values.size()) {
+ const auto countIndexes = [](int counter, const QList<int> &indexList) {
+ return counter + indexList.size();
};
const int bindParamCount = std::accumulate(d->indexes.cbegin(),
@@ -478,16 +475,21 @@ bool QSQLiteResult::exec()
0,
countIndexes);
- paramCountIsValid = bindParamCount == values.count();
+ paramCountIsValid = bindParamCount == values.size();
// When using named placeholders, it will reuse the index for duplicated
- // placeholders. So we need to ensure the QVector has only one instance of
+ // placeholders. So we need to ensure the QList has only one instance of
// each value as SQLite will do the rest for us.
- QVector<QVariant> prunedValues;
- QVector<int> handledIndexes;
+ QList<QVariant> prunedValues;
+ QList<int> handledIndexes;
for (int i = 0, currentIndex = 0; i < values.size(); ++i) {
if (handledIndexes.contains(i))
continue;
- const auto placeHolder = QString::fromUtf8(sqlite3_bind_parameter_name(d->stmt, currentIndex + 1));
+ const char *parameterName = sqlite3_bind_parameter_name(d->stmt, currentIndex + 1);
+ if (!parameterName) {
+ paramCountIsValid = false;
+ continue;
+ }
+ const auto placeHolder = QString::fromUtf8(parameterName);
const auto &indexes = d->indexes.value(placeHolder);
handledIndexes << indexes;
prunedValues << values.at(indexes.first());
@@ -500,53 +502,57 @@ bool QSQLiteResult::exec()
if (paramCountIsValid) {
for (int i = 0; i < paramCount; ++i) {
res = SQLITE_OK;
- const QVariant value = values.at(i);
+ const QVariant &value = values.at(i);
- if (value.isNull()) {
+ if (QSqlResultPrivate::isVariantNull(value)) {
res = sqlite3_bind_null(d->stmt, i + 1);
} else {
switch (value.userType()) {
- case QVariant::ByteArray: {
+ case QMetaType::QByteArray: {
const QByteArray *ba = static_cast<const QByteArray*>(value.constData());
res = sqlite3_bind_blob(d->stmt, i + 1, ba->constData(),
ba->size(), SQLITE_STATIC);
break; }
- case QVariant::Int:
- case QVariant::Bool:
+ case QMetaType::Int:
+ case QMetaType::Bool:
res = sqlite3_bind_int(d->stmt, i + 1, value.toInt());
break;
- case QVariant::Double:
+ case QMetaType::Double:
res = sqlite3_bind_double(d->stmt, i + 1, value.toDouble());
break;
- case QVariant::UInt:
- case QVariant::LongLong:
+ case QMetaType::UInt:
+ case QMetaType::LongLong:
res = sqlite3_bind_int64(d->stmt, i + 1, value.toLongLong());
break;
- case QVariant::DateTime: {
+ case QMetaType::QDateTime: {
const QDateTime dateTime = value.toDateTime();
const QString str = dateTime.toString(Qt::ISODateWithMs);
- res = sqlite3_bind_text16(d->stmt, i + 1, str.utf16(),
- str.size() * sizeof(ushort), SQLITE_TRANSIENT);
+ res = sqlite3_bind_text16(d->stmt, i + 1, str.data(),
+ int(str.size() * sizeof(ushort)),
+ SQLITE_TRANSIENT);
break;
}
- case QVariant::Time: {
+ case QMetaType::QTime: {
const QTime time = value.toTime();
const QString str = time.toString(u"hh:mm:ss.zzz");
- res = sqlite3_bind_text16(d->stmt, i + 1, str.utf16(),
- str.size() * sizeof(ushort), SQLITE_TRANSIENT);
+ res = sqlite3_bind_text16(d->stmt, i + 1, str.data(),
+ int(str.size() * sizeof(ushort)),
+ SQLITE_TRANSIENT);
break;
}
- case QVariant::String: {
+ case QMetaType::QString: {
// lifetime of string == lifetime of its qvariant
const QString *str = static_cast<const QString*>(value.constData());
- res = sqlite3_bind_text16(d->stmt, i + 1, str->utf16(),
- (str->size()) * sizeof(QChar), SQLITE_STATIC);
+ res = sqlite3_bind_text16(d->stmt, i + 1, str->unicode(),
+ int(str->size()) * sizeof(QChar),
+ SQLITE_STATIC);
break; }
default: {
- QString str = value.toString();
+ const QString str = value.toString();
// SQLITE_TRANSIENT makes sure that sqlite buffers the data
- res = sqlite3_bind_text16(d->stmt, i + 1, str.utf16(),
- (str.size()) * sizeof(QChar), SQLITE_TRANSIENT);
+ res = sqlite3_bind_text16(d->stmt, i + 1, str.data(),
+ int(str.size()) * sizeof(QChar),
+ SQLITE_TRANSIENT);
break; }
}
}
@@ -658,6 +664,30 @@ static void _q_regexp_cleanup(void *cache)
}
#endif
+static void _q_lower(sqlite3_context* context, int argc, sqlite3_value** argv)
+{
+ if (Q_UNLIKELY(argc != 1)) {
+ sqlite3_result_text(context, nullptr, 0, nullptr);
+ return;
+ }
+ const QString lower = QString::fromUtf8(
+ reinterpret_cast<const char*>(sqlite3_value_text(argv[0]))).toLower();
+ const QByteArray ba = lower.toUtf8();
+ sqlite3_result_text(context, ba.data(), ba.size(), SQLITE_TRANSIENT);
+}
+
+static void _q_upper(sqlite3_context* context, int argc, sqlite3_value** argv)
+{
+ if (Q_UNLIKELY(argc != 1)) {
+ sqlite3_result_text(context, nullptr, 0, nullptr);
+ return;
+ }
+ const QString upper = QString::fromUtf8(
+ reinterpret_cast<const char*>(sqlite3_value_text(argv[0]))).toUpper();
+ const QByteArray ba = upper.toUtf8();
+ sqlite3_result_text(context, ba.data(), ba.size(), SQLITE_TRANSIENT);
+}
+
QSQLiteDriver::QSQLiteDriver(QObject * parent)
: QSqlDriver(*new QSQLiteDriverPrivate, parent)
{
@@ -723,36 +753,48 @@ bool QSQLiteDriver::open(const QString & db, const QString &, const QString &, c
bool sharedCache = false;
bool openReadOnlyOption = false;
bool openUriOption = false;
+ bool useExtendedResultCodes = true;
+ bool useQtVfs = false;
+ bool useQtCaseFolding = false;
+ bool openNoFollow = false;
#if QT_CONFIG(regularexpression)
- static const QLatin1String regexpConnectOption = QLatin1String("QSQLITE_ENABLE_REGEXP");
+ static const auto regexpConnectOption = "QSQLITE_ENABLE_REGEXP"_L1;
bool defineRegexp = false;
int regexpCacheSize = 25;
#endif
- const auto opts = conOpts.splitRef(QLatin1Char(';'));
+ const auto opts = QStringView{conOpts}.split(u';', Qt::SkipEmptyParts);
for (auto option : opts) {
option = option.trimmed();
- if (option.startsWith(QLatin1String("QSQLITE_BUSY_TIMEOUT"))) {
+ if (option.startsWith("QSQLITE_BUSY_TIMEOUT"_L1)) {
option = option.mid(20).trimmed();
- if (option.startsWith(QLatin1Char('='))) {
+ if (option.startsWith(u'=')) {
bool ok;
const int nt = option.mid(1).trimmed().toInt(&ok);
if (ok)
timeOut = nt;
}
- } else if (option == QLatin1String("QSQLITE_OPEN_READONLY")) {
+ } else if (option == "QSQLITE_USE_QT_VFS"_L1) {
+ useQtVfs = true;
+ } else if (option == "QSQLITE_OPEN_READONLY"_L1) {
openReadOnlyOption = true;
- } else if (option == QLatin1String("QSQLITE_OPEN_URI")) {
+ } else if (option == "QSQLITE_OPEN_URI"_L1) {
openUriOption = true;
- } else if (option == QLatin1String("QSQLITE_ENABLE_SHARED_CACHE")) {
+ } else if (option == "QSQLITE_ENABLE_SHARED_CACHE"_L1) {
sharedCache = true;
+ } else if (option == "QSQLITE_NO_USE_EXTENDED_RESULT_CODES"_L1) {
+ useExtendedResultCodes = false;
+ } else if (option == "QSQLITE_ENABLE_NON_ASCII_CASE_FOLDING"_L1) {
+ useQtCaseFolding = true;
+ } else if (option == "QSQLITE_OPEN_NOFOLLOW"_L1) {
+ openNoFollow = true;
}
#if QT_CONFIG(regularexpression)
else if (option.startsWith(regexpConnectOption)) {
option = option.mid(regexpConnectOption.size()).trimmed();
if (option.isEmpty()) {
defineRegexp = true;
- } else if (option.startsWith(QLatin1Char('='))) {
+ } else if (option.startsWith(u'=')) {
bool ok = false;
const int cacheSize = option.mid(1).trimmed().toInt(&ok);
if (ok) {
@@ -763,28 +805,45 @@ bool QSQLiteDriver::open(const QString & db, const QString &, const QString &, c
}
}
#endif
+ else
+ qCWarning(lcSqlite, "Unsupported option '%ls'", qUtf16Printable(option.toString()));
}
int openMode = (openReadOnlyOption ? SQLITE_OPEN_READONLY : (SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE));
openMode |= (sharedCache ? SQLITE_OPEN_SHAREDCACHE : SQLITE_OPEN_PRIVATECACHE);
if (openUriOption)
openMode |= SQLITE_OPEN_URI;
+ if (openNoFollow) {
+#if defined(SQLITE_OPEN_NOFOLLOW)
+ openMode |= SQLITE_OPEN_NOFOLLOW;
+#else
+ qCWarning(lcSqlite, "SQLITE_OPEN_NOFOLLOW not supported with the SQLite version %s", sqlite3_libversion());
+#endif
+ }
openMode |= SQLITE_OPEN_NOMUTEX;
- const int res = sqlite3_open_v2(db.toUtf8().constData(), &d->access, openMode, NULL);
+ const int res = sqlite3_open_v2(db.toUtf8().constData(), &d->access, openMode, useQtVfs ? "QtVFS" : nullptr);
if (res == SQLITE_OK) {
sqlite3_busy_timeout(d->access, timeOut);
+ sqlite3_extended_result_codes(d->access, useExtendedResultCodes);
setOpen(true);
setOpenError(false);
#if QT_CONFIG(regularexpression)
if (defineRegexp) {
auto cache = new QCache<QString, QRegularExpression>(regexpCacheSize);
- sqlite3_create_function_v2(d->access, "regexp", 2, SQLITE_UTF8, cache, &_q_regexp, NULL,
- NULL, &_q_regexp_cleanup);
+ sqlite3_create_function_v2(d->access, "regexp", 2, SQLITE_UTF8, cache,
+ &_q_regexp, nullptr,
+ nullptr, &_q_regexp_cleanup);
}
#endif
+ if (useQtCaseFolding) {
+ sqlite3_create_function_v2(d->access, "lower", 1, SQLITE_UTF8, nullptr,
+ &_q_lower, nullptr, nullptr, nullptr);
+ sqlite3_create_function_v2(d->access, "upper", 1, SQLITE_UTF8, nullptr,
+ &_q_upper, nullptr, nullptr, nullptr);
+ }
return true;
} else {
setLastError(qMakeError(d->access, tr("Error opening database"),
@@ -793,7 +852,7 @@ bool QSQLiteDriver::open(const QString & db, const QString &, const QString &, c
if (d->access) {
sqlite3_close(d->access);
- d->access = 0;
+ d->access = nullptr;
}
return false;
@@ -804,19 +863,19 @@ void QSQLiteDriver::close()
{
Q_D(QSQLiteDriver);
if (isOpen()) {
- for (QSQLiteResult *result : qAsConst(d->results))
+ for (QSQLiteResult *result : std::as_const(d->results))
result->d_func()->finalize();
- if (d->access && (d->notificationid.count() > 0)) {
+ if (d->access && (d->notificationid.size() > 0)) {
d->notificationid.clear();
- sqlite3_update_hook(d->access, NULL, NULL);
+ sqlite3_update_hook(d->access, nullptr, nullptr);
}
const int res = sqlite3_close(d->access);
if (res != SQLITE_OK)
setLastError(qMakeError(d->access, tr("Error closing database"), QSqlError::ConnectionError, res));
- d->access = 0;
+ d->access = nullptr;
setOpen(false);
setOpenError(false);
}
@@ -833,7 +892,7 @@ bool QSQLiteDriver::beginTransaction()
return false;
QSqlQuery q(createResult());
- if (!q.exec(QLatin1String("BEGIN"))) {
+ if (!q.exec("BEGIN"_L1)) {
setLastError(QSqlError(tr("Unable to begin transaction"),
q.lastError().databaseText(), QSqlError::TransactionError));
return false;
@@ -848,7 +907,7 @@ bool QSQLiteDriver::commitTransaction()
return false;
QSqlQuery q(createResult());
- if (!q.exec(QLatin1String("COMMIT"))) {
+ if (!q.exec("COMMIT"_L1)) {
setLastError(QSqlError(tr("Unable to commit transaction"),
q.lastError().databaseText(), QSqlError::TransactionError));
return false;
@@ -863,7 +922,7 @@ bool QSQLiteDriver::rollbackTransaction()
return false;
QSqlQuery q(createResult());
- if (!q.exec(QLatin1String("ROLLBACK"))) {
+ if (!q.exec("ROLLBACK"_L1)) {
setLastError(QSqlError(tr("Unable to rollback transaction"),
q.lastError().databaseText(), QSqlError::TransactionError));
return false;
@@ -881,14 +940,14 @@ QStringList QSQLiteDriver::tables(QSql::TableType type) const
QSqlQuery q(createResult());
q.setForwardOnly(true);
- QString sql = QLatin1String("SELECT name FROM sqlite_master WHERE %1 "
- "UNION ALL SELECT name FROM sqlite_temp_master WHERE %1");
+ QString sql = "SELECT name FROM sqlite_master WHERE %1 "
+ "UNION ALL SELECT name FROM sqlite_temp_master WHERE %1"_L1;
if ((type & QSql::Tables) && (type & QSql::Views))
- sql = sql.arg(QLatin1String("type='table' OR type='view'"));
+ sql = sql.arg("type='table' OR type='view'"_L1);
else if (type & QSql::Tables)
- sql = sql.arg(QLatin1String("type='table'"));
+ sql = sql.arg("type='table'"_L1);
else if (type & QSql::Views)
- sql = sql.arg(QLatin1String("type='view'"));
+ sql = sql.arg("type='view'"_L1);
else
sql.clear();
@@ -899,74 +958,32 @@ QStringList QSQLiteDriver::tables(QSql::TableType type) const
if (type & QSql::SystemTables) {
// there are no internal tables beside this one:
- res.append(QLatin1String("sqlite_master"));
+ res.append("sqlite_master"_L1);
}
return res;
}
-static QSqlIndex qGetTableInfo(QSqlQuery &q, const QString &tableName, bool onlyPIndex = false)
-{
- QString schema;
- QString table(tableName);
- int indexOfSeparator = tableName.indexOf(QLatin1Char('.'));
- if (indexOfSeparator > -1) {
- schema = tableName.left(indexOfSeparator).append(QLatin1Char('.'));
- table = tableName.mid(indexOfSeparator + 1);
- }
- q.exec(QLatin1String("PRAGMA ") + schema + QLatin1String("table_info (") + _q_escapeIdentifier(table) + QLatin1Char(')'));
-
- QSqlIndex ind;
- while (q.next()) {
- bool isPk = q.value(5).toInt();
- if (onlyPIndex && !isPk)
- continue;
- QString typeName = q.value(2).toString().toLower();
- QString defVal = q.value(4).toString();
- if (!defVal.isEmpty() && defVal.at(0) == QLatin1Char('\'')) {
- const int end = defVal.lastIndexOf(QLatin1Char('\''));
- if (end > 0)
- defVal = defVal.mid(1, end - 1);
- }
-
- QSqlField fld(q.value(1).toString(), qGetColumnType(typeName), tableName);
- if (isPk && (typeName == QLatin1String("integer")))
- // INTEGER PRIMARY KEY fields are auto-generated in sqlite
- // INT PRIMARY KEY is not the same as INTEGER PRIMARY KEY!
- fld.setAutoValue(true);
- fld.setRequired(q.value(3).toInt() != 0);
- fld.setDefaultValue(defVal);
- ind.append(fld);
- }
- return ind;
-}
-
-QSqlIndex QSQLiteDriver::primaryIndex(const QString &tblname) const
+QSqlIndex QSQLiteDriver::primaryIndex(const QString &tablename) const
{
+ Q_D(const QSQLiteDriver);
if (!isOpen())
return QSqlIndex();
- QString table = tblname;
- if (isIdentifierEscaped(table, QSqlDriver::TableName))
- table = stripDelimiters(table, QSqlDriver::TableName);
-
QSqlQuery q(createResult());
q.setForwardOnly(true);
- return qGetTableInfo(q, table, true);
+ return d->getTableInfo(q, tablename, true);
}
-QSqlRecord QSQLiteDriver::record(const QString &tbl) const
+QSqlRecord QSQLiteDriver::record(const QString &tablename) const
{
+ Q_D(const QSQLiteDriver);
if (!isOpen())
return QSqlRecord();
- QString table = tbl;
- if (isIdentifierEscaped(table, QSqlDriver::TableName))
- table = stripDelimiters(table, QSqlDriver::TableName);
-
QSqlQuery q(createResult());
q.setForwardOnly(true);
- return qGetTableInfo(q, table);
+ return d->getTableInfo(q, tablename);
}
QVariant QSQLiteDriver::handle() const
@@ -977,8 +994,52 @@ QVariant QSQLiteDriver::handle() const
QString QSQLiteDriver::escapeIdentifier(const QString &identifier, IdentifierType type) const
{
+ Q_D(const QSQLiteDriver);
+ if (identifier.isEmpty() || isIdentifierEscaped(identifier, type))
+ return identifier;
+
+ const auto indexOfSeparator = identifier.indexOf(u'.');
+ if (indexOfSeparator > -1) {
+ auto leftName = QStringView{identifier}.first(indexOfSeparator);
+ auto rightName = QStringView{identifier}.sliced(indexOfSeparator + 1);
+ const QStringView leftEnclose = d->isIdentifierEscaped(leftName) ? u"" : u"\"";
+ const QStringView rightEnclose = d->isIdentifierEscaped(rightName) ? u"" : u"\"";
+ if (leftEnclose.isEmpty() || rightEnclose.isEmpty())
+ return (leftEnclose + leftName + leftEnclose + u'.' + rightEnclose + rightName
+ + rightEnclose);
+ }
+ return u'"' + identifier + u'"';
+}
+
+bool QSQLiteDriver::isIdentifierEscaped(const QString &identifier, IdentifierType type) const
+{
+ Q_D(const QSQLiteDriver);
Q_UNUSED(type);
- return _q_escapeIdentifier(identifier);
+ return d->isIdentifierEscaped(QStringView{identifier});
+}
+
+QString QSQLiteDriver::stripDelimiters(const QString &identifier, IdentifierType type) const
+{
+ Q_D(const QSQLiteDriver);
+ const auto indexOfSeparator = identifier.indexOf(u'.');
+ if (indexOfSeparator > -1) {
+ auto leftName = QStringView{identifier}.first(indexOfSeparator);
+ auto rightName = QStringView{identifier}.sliced(indexOfSeparator + 1);
+ const auto leftEscaped = d->isIdentifierEscaped(leftName);
+ const auto rightEscaped = d->isIdentifierEscaped(rightName);
+ if (leftEscaped || rightEscaped) {
+ if (leftEscaped)
+ leftName = leftName.sliced(1).chopped(1);
+ if (rightEscaped)
+ rightName = rightName.sliced(1).chopped(1);
+ return leftName + u'.' + rightName;
+ }
+ }
+
+ if (isIdentifierEscaped(identifier, type))
+ return identifier.mid(1, identifier.size() - 2);
+
+ return identifier;
}
static void handle_sqlite_callback(void *qobj,int aoperation, char const *adbname, char const *atablename,
@@ -997,18 +1058,19 @@ bool QSQLiteDriver::subscribeToNotification(const QString &name)
{
Q_D(QSQLiteDriver);
if (!isOpen()) {
- qWarning("Database not open.");
+ qCWarning(lcSqlite, "QSQLiteDriver::subscribeToNotification: Database not open.");
return false;
}
if (d->notificationid.contains(name)) {
- qWarning("Already subscribing to '%s'.", qPrintable(name));
+ qCWarning(lcSqlite, "QSQLiteDriver::subscribeToNotification: Already subscribing to '%ls'.",
+ qUtf16Printable(name));
return false;
}
//sqlite supports only one notification callback, so only the first is registered
d->notificationid << name;
- if (d->notificationid.count() == 1)
+ if (d->notificationid.size() == 1)
sqlite3_update_hook(d->access, &handle_sqlite_callback, reinterpret_cast<void *> (this));
return true;
@@ -1018,18 +1080,19 @@ bool QSQLiteDriver::unsubscribeFromNotification(const QString &name)
{
Q_D(QSQLiteDriver);
if (!isOpen()) {
- qWarning("Database not open.");
+ qCWarning(lcSqlite, "QSQLiteDriver::unsubscribeFromNotification: Database not open.");
return false;
}
if (!d->notificationid.contains(name)) {
- qWarning("Not subscribed to '%s'.", qPrintable(name));
+ qCWarning(lcSqlite, "QSQLiteDriver::unsubscribeFromNotification: Not subscribed to '%ls'.",
+ qUtf16Printable(name));
return false;
}
d->notificationid.removeAll(name);
if (d->notificationid.isEmpty())
- sqlite3_update_hook(d->access, NULL, NULL);
+ sqlite3_update_hook(d->access, nullptr, nullptr);
return true;
}
@@ -1048,3 +1111,5 @@ void QSQLiteDriver::handleNotification(const QString &tableName, qint64 rowid)
}
QT_END_NAMESPACE
+
+#include "moc_qsql_sqlite_p.cpp"
diff --git a/src/plugins/sqldrivers/sqlite/qsql_sqlite_p.h b/src/plugins/sqldrivers/sqlite/qsql_sqlite_p.h
index c7952bca9a..db6b76cb69 100644
--- a/src/plugins/sqldrivers/sqlite/qsql_sqlite_p.h
+++ b/src/plugins/sqldrivers/sqlite/qsql_sqlite_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtSql module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QSQL_SQLITE_H
#define QSQL_SQLITE_H
@@ -90,9 +54,12 @@ public:
QStringList tables(QSql::TableType) const override;
QSqlRecord record(const QString& tablename) const override;
- QSqlIndex primaryIndex(const QString &table) const override;
+ QSqlIndex primaryIndex(const QString &tablename) const override;
QVariant handle() const override;
- QString escapeIdentifier(const QString &identifier, IdentifierType) const override;
+
+ QString escapeIdentifier(const QString &identifier, IdentifierType type) const override;
+ bool isIdentifierEscaped(const QString &identifier, IdentifierType type) const override;
+ QString stripDelimiters(const QString &identifier, IdentifierType type) const override;
bool subscribeToNotification(const QString &name) override;
bool unsubscribeFromNotification(const QString &name) override;
diff --git a/src/plugins/sqldrivers/sqlite/qsql_sqlite_vfs.cpp b/src/plugins/sqldrivers/sqlite/qsql_sqlite_vfs.cpp
new file mode 100644
index 0000000000..bbba3cd14f
--- /dev/null
+++ b/src/plugins/sqldrivers/sqlite/qsql_sqlite_vfs.cpp
@@ -0,0 +1,258 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qsql_sqlite_vfs_p.h"
+
+#include <QFile>
+
+#include <limits.h> // defines PATH_MAX on unix
+#include <sqlite3.h>
+#include <stdio.h> // defines FILENAME_MAX everywhere
+
+#ifndef PATH_MAX
+# define PATH_MAX FILENAME_MAX
+#endif
+#if SQLITE_VERSION_NUMBER < 3040000
+typedef const char *sqlite3_filename;
+#endif
+
+namespace {
+struct Vfs : sqlite3_vfs {
+ sqlite3_vfs *pVfs;
+ sqlite3_io_methods ioMethods;
+};
+
+struct File : sqlite3_file {
+ class QtFile : public QFile {
+ public:
+ QtFile(const QString &name, bool removeOnClose)
+ : QFile(name)
+ , removeOnClose(removeOnClose)
+ {}
+
+ ~QtFile() override
+ {
+ if (removeOnClose)
+ remove();
+ }
+ private:
+ bool removeOnClose;
+ };
+ QtFile *pFile;
+};
+
+
+int xClose(sqlite3_file *sfile)
+{
+ auto file = static_cast<File *>(sfile);
+ delete file->pFile;
+ file->pFile = nullptr;
+ return SQLITE_OK;
+}
+
+int xRead(sqlite3_file *sfile, void *ptr, int iAmt, sqlite3_int64 iOfst)
+{
+ auto file = static_cast<File *>(sfile);
+ if (!file->pFile->seek(iOfst))
+ return SQLITE_IOERR_READ;
+
+ auto sz = file->pFile->read(static_cast<char *>(ptr), iAmt);
+ if (sz < iAmt) {
+ memset(static_cast<char *>(ptr) + sz, 0, size_t(iAmt - sz));
+ return SQLITE_IOERR_SHORT_READ;
+ }
+ return SQLITE_OK;
+}
+
+int xWrite(sqlite3_file *sfile, const void *data, int iAmt, sqlite3_int64 iOfst)
+{
+ auto file = static_cast<File *>(sfile);
+ if (!file->pFile->seek(iOfst))
+ return SQLITE_IOERR_SEEK;
+ return file->pFile->write(reinterpret_cast<const char*>(data), iAmt) == iAmt ? SQLITE_OK : SQLITE_IOERR_WRITE;
+}
+
+int xTruncate(sqlite3_file *sfile, sqlite3_int64 size)
+{
+ auto file = static_cast<File *>(sfile);
+ return file->pFile->resize(size) ? SQLITE_OK : SQLITE_IOERR_TRUNCATE;
+}
+
+int xSync(sqlite3_file *sfile, int /*flags*/)
+{
+ static_cast<File *>(sfile)->pFile->flush();
+ return SQLITE_OK;
+}
+
+int xFileSize(sqlite3_file *sfile, sqlite3_int64 *pSize)
+{
+ auto file = static_cast<File *>(sfile);
+ *pSize = file->pFile->size();
+ return SQLITE_OK;
+}
+
+// No lock/unlock for QFile, QLockFile doesn't work for me
+
+int xLock(sqlite3_file *, int) { return SQLITE_OK; }
+
+int xUnlock(sqlite3_file *, int) { return SQLITE_OK; }
+
+int xCheckReservedLock(sqlite3_file *, int *pResOut)
+{
+ *pResOut = 0;
+ return SQLITE_OK;
+}
+
+int xFileControl(sqlite3_file *, int, void *) { return SQLITE_NOTFOUND; }
+
+int xSectorSize(sqlite3_file *)
+{
+ return 4096;
+}
+
+int xDeviceCharacteristics(sqlite3_file *)
+{
+ return 0; // no SQLITE_IOCAP_XXX
+}
+
+int xOpen(sqlite3_vfs *svfs, sqlite3_filename zName, sqlite3_file *sfile,
+ int flags, int *pOutFlags)
+{
+ auto vfs = static_cast<Vfs *>(svfs);
+ auto file = static_cast<File *>(sfile);
+ memset(file, 0, sizeof(File));
+ QIODeviceBase::OpenMode mode = QIODeviceBase::NotOpen;
+ if (!zName || (flags & SQLITE_OPEN_MEMORY))
+ return SQLITE_PERM;
+ if ((flags & SQLITE_OPEN_READONLY) &&
+ !(flags & SQLITE_OPEN_READWRITE) &&
+ !(flags & SQLITE_OPEN_CREATE) &&
+ !(flags & SQLITE_OPEN_DELETEONCLOSE)) {
+ mode |= QIODeviceBase::OpenModeFlag::ReadOnly;
+ } else {
+ /*
+ ** ^The [SQLITE_OPEN_EXCLUSIVE] flag is always used in conjunction
+ ** with the [SQLITE_OPEN_CREATE] flag, which are both directly
+ ** analogous to the O_EXCL and O_CREAT flags of the POSIX open()
+ ** API. The SQLITE_OPEN_EXCLUSIVE flag, when paired with the
+ ** SQLITE_OPEN_CREATE, is used to indicate that file should always
+ ** be created, and that it is an error if it already exists.
+ ** It is <i>not</i> used to indicate the file should be opened
+ ** for exclusive access.
+ */
+ if ((flags & SQLITE_OPEN_CREATE) && (flags & SQLITE_OPEN_EXCLUSIVE))
+ mode |= QIODeviceBase::OpenModeFlag::NewOnly;
+
+ if (flags & SQLITE_OPEN_READWRITE)
+ mode |= QIODeviceBase::OpenModeFlag::ReadWrite;
+ }
+
+ file->pMethods = &vfs->ioMethods;
+ file->pFile = new File::QtFile(QString::fromUtf8(zName), bool(flags & SQLITE_OPEN_DELETEONCLOSE));
+ if (!file->pFile->open(mode))
+ return SQLITE_CANTOPEN;
+ if (pOutFlags)
+ *pOutFlags = flags;
+
+ return SQLITE_OK;
+}
+
+int xDelete(sqlite3_vfs *, const char *zName, int)
+{
+ return QFile::remove(QString::fromUtf8(zName)) ? SQLITE_OK : SQLITE_ERROR;
+}
+
+int xAccess(sqlite3_vfs */*svfs*/, const char *zName, int flags, int *pResOut)
+{
+ *pResOut = 0;
+ switch (flags) {
+ case SQLITE_ACCESS_EXISTS:
+ case SQLITE_ACCESS_READ:
+ *pResOut = QFile::exists(QString::fromUtf8(zName));
+ break;
+ default:
+ break;
+ }
+ return SQLITE_OK;
+}
+
+int xFullPathname(sqlite3_vfs *, const char *zName, int nOut, char *zOut)
+{
+ if (!zName)
+ return SQLITE_ERROR;
+
+ int i = 0;
+ for (;zName[i] && i < nOut; ++i)
+ zOut[i] = zName[i];
+
+ if (i >= nOut)
+ return SQLITE_ERROR;
+
+ zOut[i] = '\0';
+ return SQLITE_OK;
+}
+
+int xRandomness(sqlite3_vfs *svfs, int nByte, char *zOut)
+{
+ auto vfs = static_cast<Vfs *>(svfs)->pVfs;
+ return vfs->xRandomness(vfs, nByte, zOut);
+}
+
+int xSleep(sqlite3_vfs *svfs, int microseconds)
+{
+ auto vfs = static_cast<Vfs *>(svfs)->pVfs;
+ return vfs->xSleep(vfs, microseconds);
+}
+
+int xCurrentTime(sqlite3_vfs *svfs, double *zOut)
+{
+ auto vfs = static_cast<Vfs *>(svfs)->pVfs;
+ return vfs->xCurrentTime(vfs, zOut);
+}
+
+int xGetLastError(sqlite3_vfs *, int, char *)
+{
+ return 0;
+}
+
+int xCurrentTimeInt64(sqlite3_vfs *svfs, sqlite3_int64 *zOut)
+{
+ auto vfs = static_cast<Vfs *>(svfs)->pVfs;
+ return vfs->xCurrentTimeInt64(vfs, zOut);
+}
+} // namespace {
+
+void register_qt_vfs()
+{
+ static Vfs vfs;
+ memset(&vfs, 0, sizeof(Vfs));
+ vfs.iVersion = 1;
+ vfs.szOsFile = sizeof(File);
+ vfs.mxPathname = PATH_MAX;
+ vfs.zName = "QtVFS";
+ vfs.xOpen = &xOpen;
+ vfs.xDelete = &xDelete;
+ vfs.xAccess = &xAccess;
+ vfs.xFullPathname = &xFullPathname;
+ vfs.xRandomness = &xRandomness;
+ vfs.xSleep = &xSleep;
+ vfs.xCurrentTime = &xCurrentTime;
+ vfs.xGetLastError = &xGetLastError;
+ vfs.xCurrentTimeInt64 = &xCurrentTimeInt64;
+ vfs.pVfs = sqlite3_vfs_find(nullptr);
+ vfs.ioMethods.iVersion = 1;
+ vfs.ioMethods.xClose = &xClose;
+ vfs.ioMethods.xRead = &xRead;
+ vfs.ioMethods.xWrite = &xWrite;
+ vfs.ioMethods.xTruncate = &xTruncate;
+ vfs.ioMethods.xSync = &xSync;
+ vfs.ioMethods.xFileSize = &xFileSize;
+ vfs.ioMethods.xLock = &xLock;
+ vfs.ioMethods.xUnlock = &xUnlock;
+ vfs.ioMethods.xCheckReservedLock = &xCheckReservedLock;
+ vfs.ioMethods.xFileControl = &xFileControl;
+ vfs.ioMethods.xSectorSize = &xSectorSize;
+ vfs.ioMethods.xDeviceCharacteristics = &xDeviceCharacteristics;
+
+ sqlite3_vfs_register(&vfs, 0);
+}
diff --git a/src/plugins/sqldrivers/sqlite/qsql_sqlite_vfs_p.h b/src/plugins/sqldrivers/sqlite/qsql_sqlite_vfs_p.h
new file mode 100644
index 0000000000..56024b3ecb
--- /dev/null
+++ b/src/plugins/sqldrivers/sqlite/qsql_sqlite_vfs_p.h
@@ -0,0 +1,21 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QSQL_SQLITE_VFS_H
+#define QSQL_SQLITE_VFS_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.
+//
+
+void register_qt_vfs();
+
+
+#endif // QSQL_SQLITE_VFS_H
diff --git a/src/plugins/sqldrivers/sqlite/smain.cpp b/src/plugins/sqldrivers/sqlite/smain.cpp
index 092813990c..0d201c38d3 100644
--- a/src/plugins/sqldrivers/sqlite/smain.cpp
+++ b/src/plugins/sqldrivers/sqlite/smain.cpp
@@ -1,48 +1,15 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <qsqldriverplugin.h>
#include <qstringlist.h>
#include "qsql_sqlite_p.h"
+#include "qsql_sqlite_vfs_p.h"
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
class QSQLiteDriverPlugin : public QSqlDriverPlugin
{
Q_OBJECT
@@ -57,15 +24,17 @@ public:
QSQLiteDriverPlugin::QSQLiteDriverPlugin()
: QSqlDriverPlugin()
{
+ register_qt_vfs();
}
QSqlDriver* QSQLiteDriverPlugin::create(const QString &name)
{
- if (name == QLatin1String("QSQLITE")) {
+ if (name == "QSQLITE"_L1) {
QSQLiteDriver* driver = new QSQLiteDriver();
return driver;
}
- return 0;
+
+ return nullptr;
}
QT_END_NAMESPACE
diff --git a/src/plugins/sqldrivers/sqlite/sqlite.pro b/src/plugins/sqldrivers/sqlite/sqlite.pro
deleted file mode 100644
index d7e19f97b1..0000000000
--- a/src/plugins/sqldrivers/sqlite/sqlite.pro
+++ /dev/null
@@ -1,18 +0,0 @@
-TARGET = qsqlite
-
-HEADERS += $$PWD/qsql_sqlite_p.h
-SOURCES += $$PWD/qsql_sqlite.cpp $$PWD/smain.cpp
-
-include($$OUT_PWD/../qtsqldrivers-config.pri)
-QT_FOR_CONFIG += sqldrivers-private
-
-qtConfig(system-sqlite) {
- QMAKE_USE += sqlite
-} else {
- include($$PWD/../../../3rdparty/sqlite.pri)
-}
-
-OTHER_FILES += sqlite.json
-
-PLUGIN_CLASS_NAME = QSQLiteDriverPlugin
-include(../qsqldriverbase.pri)
diff --git a/src/plugins/styles/.prev_CMakeLists.txt b/src/plugins/styles/.prev_CMakeLists.txt
deleted file mode 100644
index 73329915f6..0000000000
--- a/src/plugins/styles/.prev_CMakeLists.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-# Generated from styles.pro.
-
-if(QT_FEATURE_style_android)
- add_subdirectory(android)
-endif()
-if(QT_FEATURE_style_mac)
- add_subdirectory(mac)
-endif()
-if(QT_FEATURE_style_windowsvista)
- add_subdirectory(windowsvista)
-endif()
diff --git a/src/plugins/styles/CMakeLists.txt b/src/plugins/styles/CMakeLists.txt
index d24e3daff8..b809042c14 100644
--- a/src/plugins/styles/CMakeLists.txt
+++ b/src/plugins/styles/CMakeLists.txt
@@ -1,11 +1,12 @@
-# Generated from styles.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
if(QT_FEATURE_style_android)
- # add_subdirectory(android) # special case TODO
+ add_subdirectory(android)
endif()
if(QT_FEATURE_style_mac)
add_subdirectory(mac)
endif()
if(QT_FEATURE_style_windowsvista)
- add_subdirectory(windowsvista)
+ add_subdirectory(modernwindows)
endif()
diff --git a/src/plugins/styles/android/CMakeLists.txt b/src/plugins/styles/android/CMakeLists.txt
new file mode 100644
index 0000000000..b8bda6fd5f
--- /dev/null
+++ b/src/plugins/styles/android/CMakeLists.txt
@@ -0,0 +1,18 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## QAndroidStylePlugin Plugin:
+#####################################################################
+
+qt_internal_add_plugin(QAndroidStylePlugin
+ OUTPUT_NAME qandroidstyle
+ PLUGIN_TYPE styles
+ SOURCES
+ main.cpp
+ qandroidstyle.cpp qandroidstyle_p.h
+ LIBRARIES
+ Qt::Core
+ Qt::Gui
+ Qt::WidgetsPrivate
+)
diff --git a/src/plugins/styles/android/android.pro b/src/plugins/styles/android/android.pro
deleted file mode 100644
index 4ca35d8046..0000000000
--- a/src/plugins/styles/android/android.pro
+++ /dev/null
@@ -1,16 +0,0 @@
-TARGET = qandroidstyle
-
-QT += widgets-private
-
-SOURCES += \
- main.cpp \
- qandroidstyle.cpp
-
-HEADERS += \
- qandroidstyle_p.h
-
-DISTFILES += androidstyle.json
-
-PLUGIN_TYPE = styles
-PLUGIN_CLASS_NAME = QAndroidStylePlugin
-load(qt_plugin)
diff --git a/src/plugins/styles/android/main.cpp b/src/plugins/styles/android/main.cpp
index 2121538b0a..3be434e362 100644
--- a/src/plugins/styles/android/main.cpp
+++ b/src/plugins/styles/android/main.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtWidgets/qstyleplugin.h>
#include "qandroidstyle_p.h"
diff --git a/src/plugins/styles/android/qandroidstyle.cpp b/src/plugins/styles/android/qandroidstyle.cpp
index 1d0838daec..64940ed4d8 100644
--- a/src/plugins/styles/android/qandroidstyle.cpp
+++ b/src/plugins/styles/android/qandroidstyle.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 BogDan Vatra <bogdan@kde.org>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtWidgets module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and 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$
-**
-****************************************************************************/
+// Copyright (C) 2013 BogDan Vatra <bogdan@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qandroidstyle_p.h"
@@ -607,7 +571,7 @@ QSize QAndroidStyle::sizeFromContents(ContentsType ct,
if (qApp->styleSheet().isEmpty())
txt = hdr->fontMetrics.size(0, hdr->text);
else
- txt = qApp->fontMetrics().size(0, hdr->text);
+ txt = QFontMetrics(QApplication::font()).size(0, hdr->text);
sz.setHeight(margin + qMax(iconSize, txt.height()) + margin);
sz.setWidth((nullIcon ? 0 : margin) + iconSize
@@ -677,6 +641,9 @@ int QAndroidStyle::styleHint(QStyle::StyleHint hint, const QStyleOption *option,
case SH_RequestSoftwareInputPanel:
return RSIP_OnMouseClick;
+ case SH_SpinBox_SelectOnStep:
+ return 0;
+
default:
return QFusionStyle::styleHint(hint, option, widget, returnData);
}
@@ -845,7 +812,7 @@ int QAndroidStyle::Android9PatchDrawable::calculateStretch(int boundsLimit,
}
void QAndroidStyle::Android9PatchDrawable::extractIntArray(const QVariantList &values,
- QVector<int> & array)
+ QList<int> & array)
{
for (const QVariant &value : values)
array << value.toInt();
@@ -1167,7 +1134,7 @@ QAndroidStyle::AndroidStateDrawable::AndroidStateDrawable(const QVariantMap &dra
QAndroidStyle::AndroidStateDrawable::~AndroidStateDrawable()
{
- for (const StateType &type : qAsConst(m_states))
+ for (const StateType &type : std::as_const(m_states))
delete type.second;
}
@@ -1193,7 +1160,7 @@ QSize QAndroidStyle::AndroidStateDrawable::sizeImage(const QStyleOption *opt) co
const QAndroidStyle::AndroidDrawable * QAndroidStyle::AndroidStateDrawable::bestAndroidStateMatch(const QStyleOption *opt) const
{
- const AndroidDrawable *bestMatch = 0;
+ const AndroidDrawable *bestMatch = nullptr;
if (!opt) {
if (m_states.size())
return m_states[0].second;
@@ -1242,7 +1209,7 @@ const QAndroidStyle::AndroidDrawable * QAndroidStyle::AndroidStateDrawable::best
int QAndroidStyle::AndroidStateDrawable::extractState(const QVariantMap &value)
{
- QStyle::State state = QStyle::State_Enabled | QStyle::State_Active;;
+ QStyle::State state = QStyle::State_Enabled | QStyle::State_Active;
for (auto it = value.cbegin(), end = value.cend(); it != end; ++it) {
const QString &key = it.key();
bool val = it.value().toString() == QLatin1String("true");
@@ -1292,7 +1259,7 @@ int QAndroidStyle::AndroidStateDrawable::extractState(const QVariantMap &value)
void QAndroidStyle::AndroidStateDrawable::setPaddingLeftToSizeWidth()
{
- for (const StateType &type : qAsConst(m_states))
+ for (const StateType &type : std::as_const(m_states))
const_cast<AndroidDrawable *>(type.second)->setPaddingLeftToSizeWidth();
}
@@ -1318,7 +1285,7 @@ QAndroidStyle::AndroidLayerDrawable::AndroidLayerDrawable(const QVariantMap &dra
QAndroidStyle::AndroidLayerDrawable::~AndroidLayerDrawable()
{
- for (const LayerType &layer : qAsConst(m_layers))
+ for (const LayerType &layer : std::as_const(m_layers))
delete layer.second;
}
@@ -1352,9 +1319,10 @@ void QAndroidStyle::AndroidLayerDrawable::draw(QPainter *painter, const QStyleOp
QAndroidStyle::AndroidDrawable *QAndroidStyle::AndroidLayerDrawable::layer(int id) const
{
- for (const LayerType &layer : m_layers)
+ for (const LayerType &layer : m_layers) {
if (layer.first == id)
return layer.second;
+ }
return 0;
}
@@ -1407,7 +1375,7 @@ void QAndroidStyle::AndroidControl::drawControl(const QStyleOption *opt, QPainte
qDrawShadePanel(p, frame->rect, frame->palette, frame->state & State_Sunken,
frame->lineWidth);
} else {
- qDrawPlainRect(p, frame->rect, frame->palette.foreground().color(), frame->lineWidth);
+ qDrawPlainRect(p, frame->rect, frame->palette.windowText().color(), frame->lineWidth);
}
} else {
if (const QStyleOptionFocusRect *fropt = qstyleoption_cast<const QStyleOptionFocusRect *>(opt)) {
@@ -1421,13 +1389,13 @@ void QAndroidStyle::AndroidControl::drawControl(const QStyleOption *opt, QPainte
else
p->setPen(Qt::white);
} else {
- p->setPen(opt->palette.foreground().color());
+ p->setPen(opt->palette.windowText().color());
}
QRect focusRect = opt->rect.adjusted(1, 1, -1, -1);
p->drawRect(focusRect.adjusted(0, 0, -1, -1)); //draw pen inclusive
p->setPen(oldPen);
} else {
- p->fillRect(opt->rect, opt->palette.brush(QPalette::Background));
+ p->fillRect(opt->rect, opt->palette.window());
}
}
}
@@ -1619,10 +1587,11 @@ void QAndroidStyle::AndroidProgressBarControl::drawControl(const QStyleOption *o
if (m_progressDrawable->type() == QAndroidStyle::Layer) {
const double fraction = double(qint64(pb->progress) - pb->minimum) / (qint64(pb->maximum) - pb->minimum);
QAndroidStyle::AndroidDrawable *clipDrawable = static_cast<QAndroidStyle::AndroidLayerDrawable *>(m_progressDrawable)->layer(m_progressId);
+ const Qt::Orientation orientation = pb->state & QStyle::State_Horizontal ? Qt::Horizontal : Qt::Vertical;
if (clipDrawable->type() == QAndroidStyle::Clip)
- static_cast<AndroidClipDrawable *>(clipDrawable)->setFactor(fraction, pb->orientation);
+ static_cast<AndroidClipDrawable *>(clipDrawable)->setFactor(fraction, orientation);
else
- static_cast<AndroidLayerDrawable *>(m_progressDrawable)->setFactor(m_progressId, fraction, pb->orientation);
+ static_cast<AndroidLayerDrawable *>(m_progressDrawable)->setFactor(m_progressId, fraction, orientation);
}
m_progressDrawable->draw(p, option);
}
@@ -1634,7 +1603,7 @@ QRect QAndroidStyle::AndroidProgressBarControl::subElementRect(QStyle::SubElemen
{
if (const QStyleOptionProgressBar *progressBarOption =
qstyleoption_cast<const QStyleOptionProgressBar *>(option)) {
- const bool horizontal = progressBarOption->orientation == Qt::Vertical;
+ const bool horizontal = progressBarOption->state & QStyle::State_Horizontal;
if (!m_background)
return option->rect;
@@ -1676,12 +1645,12 @@ QSize QAndroidStyle::AndroidProgressBarControl::sizeFromContents(const QStyleOpt
if (const QStyleOptionProgressBar *progressBarOption =
qstyleoption_cast<const QStyleOptionProgressBar *>(opt)) {
- if (progressBarOption->orientation == Qt::Vertical) {
- if (sz.height() > m_maxSize.height())
- sz.setHeight(m_maxSize.height());
- } else {
+ if (progressBarOption->state & QStyle::State_Horizontal) {
if (sz.width() > m_maxSize.width())
sz.setWidth(m_maxSize.width());
+ } else {
+ if (sz.height() > m_maxSize.height())
+ sz.setHeight(m_maxSize.height());
}
}
return contentsSize;
diff --git a/src/plugins/styles/android/qandroidstyle_p.h b/src/plugins/styles/android/qandroidstyle_p.h
index 6cb30a2f79..38abc24b02 100644
--- a/src/plugins/styles/android/qandroidstyle_p.h
+++ b/src/plugins/styles/android/qandroidstyle_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 BogDan Vatra <bogdan@kde.org>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtWidgets module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and 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$
-**
-****************************************************************************/
+// Copyright (C) 2013 BogDan Vatra <bogdan@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QANDROIDSTYLE_P_H
#define QANDROIDSTYLE_P_H
@@ -89,9 +53,9 @@ public:
struct Android9PatchChunk
{
- QVector<int> xDivs;
- QVector<int> yDivs;
- QVector<int> colors;
+ QList<int> xDivs;
+ QList<int> yDivs;
+ QList<int> colors;
};
struct AndroidItemStateInfo
@@ -169,7 +133,7 @@ public:
static int calculateStretch(int boundsLimit, int startingPoint,
int srcSpace, int numStrechyPixelsRemaining,
int numFixedPixelsRemaining);
- void extractIntArray(const QVariantList &values, QVector<int> &array);
+ void extractIntArray(const QVariantList &values, QList<int> &array);
private:
Android9PatchChunk m_chunkData;
};
@@ -257,10 +221,10 @@ public:
virtual void drawControl(const QStyleOption *opt, QPainter *p, const QWidget *w);
virtual QRect subElementRect(SubElement subElement,
const QStyleOption *option,
- const QWidget *widget = 0) const;
+ const QWidget *widget = nullptr) const;
virtual QRect subControlRect(const QStyleOptionComplex *option,
SubControl sc,
- const QWidget *widget = 0) const;
+ const QWidget *widget = nullptr) const;
virtual QSize sizeFromContents(const QStyleOption *opt,
const QSize &contentsSize,
const QWidget *w) const;
@@ -294,7 +258,7 @@ public:
virtual void drawControl(const QStyleOption *option, QPainter *p, const QWidget *w);
virtual QRect subElementRect(SubElement subElement,
const QStyleOption *option,
- const QWidget *widget = 0) const;
+ const QWidget *widget = nullptr) const;
QSize sizeFromContents(const QStyleOption *opt,
const QSize &contentsSize,
@@ -315,7 +279,7 @@ public:
QSize sizeFromContents(const QStyleOption *opt,
const QSize &contentsSize, const QWidget *w) const;
QRect subControlRect(const QStyleOptionComplex *option, SubControl sc,
- const QWidget *widget = 0) const;
+ const QWidget *widget = nullptr) const;
private:
AndroidDrawable *m_seekBarThumb;
};
@@ -327,7 +291,7 @@ public:
virtual ~AndroidSpinnerControl(){}
virtual QRect subControlRect(const QStyleOptionComplex *option,
SubControl sc,
- const QWidget *widget = 0) const;
+ const QWidget *widget = nullptr) const;
};
typedef QList<AndroidItemStateInfo *> AndroidItemStateInfoList;
@@ -337,34 +301,34 @@ public:
~QAndroidStyle();
virtual void drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPainter *p,
- const QWidget *w = 0) const;
+ const QWidget *w = nullptr) const;
virtual void drawControl(QStyle::ControlElement element, const QStyleOption *opt, QPainter *p,
- const QWidget *w = 0) const;
+ const QWidget *w = nullptr) const;
virtual QRect subElementRect(SubElement subElement, const QStyleOption *option,
- const QWidget *widget = 0) const;
+ const QWidget *widget = nullptr) const;
virtual void drawComplexControl(ComplexControl cc, const QStyleOptionComplex *opt, QPainter *p,
- const QWidget *widget = 0) const;
+ const QWidget *widget = nullptr) const;
virtual SubControl hitTestComplexControl(ComplexControl cc, const QStyleOptionComplex *opt,
- const QPoint &pt, const QWidget *widget = 0) const;
+ const QPoint &pt, const QWidget *widget = nullptr) const;
virtual QRect subControlRect(ComplexControl cc, const QStyleOptionComplex *opt,
- SubControl sc, const QWidget *widget = 0) const;
+ SubControl sc, const QWidget *widget = nullptr) const;
- virtual int pixelMetric(PixelMetric metric, const QStyleOption *option = 0,
- const QWidget *widget = 0) const;
+ virtual int pixelMetric(PixelMetric metric, const QStyleOption *option = nullptr,
+ const QWidget *widget = nullptr) const;
virtual QSize sizeFromContents(ContentsType ct, const QStyleOption *opt,
- const QSize &contentsSize, const QWidget *w = 0) const;
+ const QSize &contentsSize, const QWidget *w = nullptr) const;
- virtual QPixmap standardPixmap(StandardPixmap standardPixmap, const QStyleOption *opt = 0,
- const QWidget *widget = 0) const;
+ virtual QPixmap standardPixmap(StandardPixmap standardPixmap, const QStyleOption *opt = nullptr,
+ const QWidget *widget = nullptr) const;
virtual QPixmap generatedIconPixmap(QIcon::Mode iconMode, const QPixmap &pixmap,
const QStyleOption *opt) const;
- int styleHint(StyleHint hint, const QStyleOption *option = 0, const QWidget *widget = 0,
- QStyleHintReturn *returnData = 0) const;
+ int styleHint(StyleHint hint, const QStyleOption *option = nullptr, const QWidget *widget = nullptr,
+ QStyleHintReturn *returnData = nullptr) const;
virtual QPalette standardPalette() const;
void polish(QWidget *widget);
diff --git a/src/plugins/styles/mac/CMakeLists.txt b/src/plugins/styles/mac/CMakeLists.txt
index 140d4e4c93..9dc8d01cc7 100644
--- a/src/plugins/styles/mac/CMakeLists.txt
+++ b/src/plugins/styles/mac/CMakeLists.txt
@@ -1,23 +1,25 @@
-# Generated from mac.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## QMacStylePlugin Plugin:
#####################################################################
-qt_add_plugin(QMacStylePlugin
+qt_internal_add_plugin(QMacStylePlugin
OUTPUT_NAME qmacstyle
- TYPE styles
+ PLUGIN_TYPE styles
SOURCES
main.mm
qmacstyle_mac.mm qmacstyle_mac_p.h
qmacstyle_mac_p_p.h
LIBRARIES
${FWAppKit}
- PUBLIC_LIBRARIES
Qt::Core
Qt::Gui
Qt::WidgetsPrivate
)
-#### Keys ignored in scope 1:.:.:mac.pro:<TRUE>:
-# DISTFILES = "macstyle.json"
+set_target_properties(QMacStylePlugin
+ PROPERTIES
+ DISABLE_PRECOMPILE_HEADERS ON
+)
diff --git a/src/plugins/styles/mac/mac.pro b/src/plugins/styles/mac/mac.pro
deleted file mode 100644
index 9044354c07..0000000000
--- a/src/plugins/styles/mac/mac.pro
+++ /dev/null
@@ -1,19 +0,0 @@
-TARGET = qmacstyle
-
-QT += widgets-private
-
-SOURCES += \
- main.mm \
- qmacstyle_mac.mm
-
-HEADERS += \
- qmacstyle_mac_p.h \
- qmacstyle_mac_p_p.h
-
-LIBS_PRIVATE += -framework AppKit
-
-DISTFILES += macstyle.json
-
-PLUGIN_TYPE = styles
-PLUGIN_CLASS_NAME = QMacStylePlugin
-load(qt_plugin)
diff --git a/src/plugins/styles/mac/macstyle.json b/src/plugins/styles/mac/macstyle.json
index 5897815eec..5d7a50a339 100644
--- a/src/plugins/styles/mac/macstyle.json
+++ b/src/plugins/styles/mac/macstyle.json
@@ -1,3 +1,3 @@
{
- "Keys": [ "macintosh" ]
+ "Keys": [ "macOS" ]
}
diff --git a/src/plugins/styles/mac/main.mm b/src/plugins/styles/mac/main.mm
index ae31bb95fb..5f4fbd9eb8 100644
--- a/src/plugins/styles/mac/main.mm
+++ b/src/plugins/styles/mac/main.mm
@@ -1,45 +1,11 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtWidgets/qstyleplugin.h>
#include "qmacstyle_mac_p.h"
+#include <QtCore/private/qcore_mac_p.h>
+
QT_BEGIN_NAMESPACE
class QMacStylePlugin : public QStylePlugin
@@ -53,7 +19,7 @@ public:
QStyle *QMacStylePlugin::create(const QString &key)
{
QMacAutoReleasePool pool;
- if (key.compare(QLatin1String("macintosh"), Qt::CaseInsensitive) == 0)
+ if (key.compare(QLatin1String("macos"), Qt::CaseInsensitive) == 0)
return new QMacStyle();
return 0;
diff --git a/src/plugins/styles/mac/qmacstyle_mac.mm b/src/plugins/styles/mac/qmacstyle_mac.mm
index e2599e8c6b..3f57f284e6 100644
--- a/src/plugins/styles/mac/qmacstyle_mac.mm
+++ b/src/plugins/styles/mac/qmacstyle_mac.mm
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtWidgets module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
/*
Note: The qdoc comments for QMacStyle are contained in
@@ -56,6 +20,7 @@
#include <QtCore/private/qcore_mac_p.h>
+#include <QtGui/qpainterpath.h>
#include <QtGui/private/qcoregraphics_p.h>
#include <QtGui/qpa/qplatformfontdatabase.h>
#include <QtGui/qpa/qplatformtheme.h>
@@ -79,11 +44,6 @@
QT_USE_NAMESPACE
-static QWindow *qt_getWindow(const QWidget *widget)
-{
- return widget ? widget->window()->windowHandle() : 0;
-}
-
@interface QT_MANGLE_NAMESPACE(QIndeterminateProgressIndicator) : NSProgressIndicator
@property (readonly, nonatomic) NSInteger animators;
@@ -194,46 +154,13 @@ const int QMacStylePrivate::PushButtonLeftOffset = 6;
const int QMacStylePrivate::PushButtonRightOffset = 12;
const int QMacStylePrivate::PushButtonContentPadding = 6;
-QVector<QPointer<QObject> > QMacStylePrivate::scrollBars;
+const int pushButtonBevelRectOffsets[3] = {
+ QMacStylePrivate::PushButtonLeftOffset, 5, 5
+};
-// Title bar gradient colors for Lion were determined by inspecting PSDs exported
-// using CoreUI's CoreThemeDocument; there is no public API to retrieve them
+QVector<QPointer<QObject> > QMacStylePrivate::scrollBars;
-static QLinearGradient titlebarGradientActive()
-{
- static QLinearGradient darkGradient = [](){
- QLinearGradient gradient;
- // FIXME: colors are chosen somewhat arbitrarily and could be fine-tuned,
- // or ideally determined by calling a native API.
- gradient.setColorAt(0, QColor(47, 47, 47));
- return gradient;
- }();
- static QLinearGradient lightGradient = [](){
- QLinearGradient gradient;
- gradient.setColorAt(0, QColor(235, 235, 235));
- gradient.setColorAt(0.5, QColor(210, 210, 210));
- gradient.setColorAt(0.75, QColor(195, 195, 195));
- gradient.setColorAt(1, QColor(180, 180, 180));
- return gradient;
- }();
- return qt_mac_applicationIsInDarkMode() ? darkGradient : lightGradient;
-}
-
-static QLinearGradient titlebarGradientInactive()
-{
- static QLinearGradient darkGradient = [](){
- QLinearGradient gradient;
- gradient.setColorAt(1, QColor(42, 42, 42));
- return gradient;
- }();
- static QLinearGradient lightGradient = [](){
- QLinearGradient gradient;
- gradient.setColorAt(0, QColor(250, 250, 250));
- gradient.setColorAt(1, QColor(225, 225, 225));
- return gradient;
- }();
- return qt_mac_applicationIsInDarkMode() ? darkGradient : lightGradient;
-}
+bool isDarkMode() { return QGuiApplicationPrivate::platformTheme()->colorScheme() == Qt::ColorScheme::Dark; }
#if QT_CONFIG(tabwidget)
/*
@@ -254,7 +181,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);
@@ -286,7 +213,7 @@ static const QColor titlebarSeparatorLineInactive(131, 131, 131);
static const QColor darkModeSeparatorLine(88, 88, 88);
// Gradient colors used for the dock widget title bar and
-// non-unifed tool bar bacground.
+// non-unifed tool bar background.
static const QColor lightMainWindowGradientBegin(240, 240, 240);
static const QColor lightMainWindowGradientEnd(200, 200, 200);
static const QColor darkMainWindowGradientBegin(47, 47, 47);
@@ -302,7 +229,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);
@@ -352,7 +278,7 @@ static const int closeButtonSize = 14;
static const qreal closeButtonCornerRadius = 2.0;
#endif // QT_CONFIG(tabbar)
-#ifndef QT_NO_ACCESSIBILITY // This ifdef to avoid "unused function" warning.
+#if QT_CONFIG(accessibility) // This ifdef to avoid "unused function" warning.
QBrush brushForToolButton(bool isOnKeyWindow)
{
// When a toolbutton in a toolbar is in the 'ON' state, we draw a
@@ -363,7 +289,7 @@ QBrush brushForToolButton(bool isOnKeyWindow)
return isOnKeyWindow ? QColor(0, 0, 0, 28) : QColor(0, 0, 0, 21);
}
-#endif // QT_NO_ACCESSIBILITY
+#endif // QT_CONFIG(accessibility)
static const int headerSectionArrowHeight = 6;
@@ -388,16 +314,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] = {
@@ -421,16 +346,14 @@ class AppearanceSync {
public:
AppearanceSync()
{
-#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;
NSAppearance.currentAppearance = [NSAppearance appearanceNamed:requiredAppearanceName];
}
}
-#endif // QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_14)
}
~AppearanceSync()
@@ -468,6 +391,7 @@ static bool setupSlider(NSSlider *slider, const QStyleOptionSlider *sl)
return false;
slider.frame = sl->rect.toCGRect();
+
slider.minValue = sl->minimum;
slider.maxValue = sl->maximum;
slider.intValue = sl->sliderPosition;
@@ -493,38 +417,11 @@ static bool setupSlider(NSSlider *slider, const QStyleOptionSlider *sl)
slider.numberOfTickMarks = 0;
}
- return true;
-}
+ // Ensure the values set above are reflected when asking
+ // the cell for its metrics and to draw itself.
+ [slider layoutSubtreeIfNeeded];
-static void fixStaleGeometry(NSSlider *slider)
-{
- // If it's later fixed in AppKit, this function is not needed.
- // On macOS Mojave we suddenly have NSSliderCell with a cached
- // (and stale) geometry, thus its -drawKnob, -drawBarInside:flipped:,
- // -drawTickMarks fail to render the slider properly. Setting the number
- // of tickmarks triggers an update in geometry.
-
- Q_ASSERT(slider);
-
- if (QOperatingSystemVersion::current() < QOperatingSystemVersion::MacOSMojave)
- return;
-
- NSSliderCell *cell = slider.cell;
- const NSRect barRect = [cell barRectFlipped:NO];
- const NSSize sliderSize = slider.frame.size;
- CGFloat difference = 0.;
- if (slider.vertical)
- difference = std::abs(sliderSize.height - barRect.size.height);
- else
- difference = std::abs(sliderSize.width - barRect.size.width);
-
- if (difference > 6.) {
- // Stale ...
- const auto nOfTicks = slider.numberOfTickMarks;
- // Non-zero, different from nOfTicks to force update
- slider.numberOfTickMarks = nOfTicks + 10;
- slider.numberOfTickMarks = nOfTicks;
- }
+ return true;
}
static bool isInMacUnifiedToolbarArea(QWindow *window, int windowY)
@@ -707,7 +604,7 @@ static inline bool isTreeView(const QWidget *widget)
static QString qt_mac_removeMnemonics(const QString &original)
{
- QString returnText(original.size(), 0);
+ QString returnText(original.size(), QChar(0));
int finalDest = 0;
int currPos = 0;
int l = original.length();
@@ -854,7 +751,8 @@ static inline int qt_mac_aqua_get_metric(QAquaMetric m)
return qt_mac_aqua_metrics[m];
}
-static QSize qt_aqua_get_known_size(QStyle::ContentsType ct, const QWidget *widg, QSize szHint,
+static QSize qt_aqua_get_known_size(QStyle::ContentsType ct, const QStyleOption *opt,
+ const QWidget *widg, QSize szHint,
QStyleHelper::WidgetSizePolicy sz)
{
QSize ret(-1, -1);
@@ -870,6 +768,8 @@ static QSize qt_aqua_get_known_size(QStyle::ContentsType ct, const QWidget *widg
return ret;
}
+ const bool isBigSurOrAbove = QOperatingSystemVersion::current() >= QOperatingSystemVersion::MacOSBigSur;
+
if (ct == QStyle::CT_CustomBase && widg) {
#if QT_CONFIG(pushbutton)
if (qobject_cast<const QPushButton *>(widg))
@@ -918,12 +818,9 @@ static QSize qt_aqua_get_known_size(QStyle::ContentsType ct, const QWidget *widg
switch (ct) {
#if QT_CONFIG(pushbutton)
case QStyle::CT_PushButton: {
- const QPushButton *psh = qobject_cast<const QPushButton *>(widg);
- // If this comparison is false, then the widget was not a push button.
- // This is bad and there's very little we can do since we were requested to find a
- // sensible size for a widget that pretends to be a QPushButton but is not.
- if(psh) {
- QString buttonText = qt_mac_removeMnemonics(psh->text());
+ const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt);
+ if (btn) {
+ QString buttonText = qt_mac_removeMnemonics(btn->text);
if (buttonText.contains(QLatin1Char('\n')))
ret = QSize(-1, -1);
else if (sz == QStyleHelper::SizeLarge)
@@ -933,11 +830,11 @@ static QSize qt_aqua_get_known_size(QStyle::ContentsType ct, const QWidget *widg
else if (sz == QStyleHelper::SizeMini)
ret = QSize(-1, qt_mac_aqua_get_metric(MiniPushButtonHeight));
- if (!psh->icon().isNull()){
+ if (!btn->icon.isNull()){
// If the button got an icon, and the icon is larger than the
// button, we can't decide on a default size
ret.setWidth(-1);
- if (ret.height() < psh->iconSize().height())
+ if (ret.height() < btn->iconSize.height())
ret.setHeight(-1);
}
else if (buttonText == QLatin1String("OK") || buttonText == QLatin1String("Cancel")){
@@ -951,18 +848,7 @@ static QSize qt_aqua_get_known_size(QStyle::ContentsType ct, const QWidget *widg
// or accept button (i.e., rightmost) and cancel button have the same width.
ret.setWidth(69);
}
- } else {
- // The only sensible thing to do is to return whatever the style suggests...
- if (sz == QStyleHelper::SizeLarge)
- ret = QSize(-1, qt_mac_aqua_get_metric(PushButtonHeight));
- else if (sz == QStyleHelper::SizeSmall)
- ret = QSize(-1, qt_mac_aqua_get_metric(SmallPushButtonHeight));
- else if (sz == QStyleHelper::SizeMini)
- ret = QSize(-1, qt_mac_aqua_get_metric(MiniPushButtonHeight));
- else
- // Since there's no default size we return the large size...
- ret = QSize(-1, qt_mac_aqua_get_metric(PushButtonHeight));
- }
+ }
#endif
#if 0 //Not sure we are applying the rules correctly for RadioButtons/CheckBoxes --Sam
} else if (ct == QStyle::CT_RadioButton) {
@@ -1018,19 +904,19 @@ static QSize qt_aqua_get_known_size(QStyle::ContentsType ct, const QWidget *widg
int width = 0, height = 0;
if (szHint == QSize(-1, -1)) { //just 'guess'..
#if QT_CONFIG(toolbutton)
- const QToolButton *bt = qobject_cast<const QToolButton *>(widg);
+ const QStyleOptionToolButton *bt = qstyleoption_cast<const QStyleOptionToolButton *>(opt);
// If this conversion fails then the widget was not what it claimed to be.
- if(bt) {
- if (!bt->icon().isNull()) {
- QSize iconSize = bt->iconSize();
- QSize pmSize = bt->icon().actualSize(QSize(32, 32), QIcon::Normal);
+ if (bt) {
+ if (!bt->icon.isNull()) {
+ QSize iconSize = bt->iconSize;
+ QSize pmSize = bt->icon.actualSize(QSize(32, 32), QIcon::Normal);
width = qMax(width, qMax(iconSize.width(), pmSize.width()));
height = qMax(height, qMax(iconSize.height(), pmSize.height()));
}
- if (!bt->text().isNull() && bt->toolButtonStyle() != Qt::ToolButtonIconOnly) {
- int text_width = bt->fontMetrics().horizontalAdvance(bt->text()),
- text_height = bt->fontMetrics().height();
- if (bt->toolButtonStyle() == Qt::ToolButtonTextUnderIcon) {
+ if (!bt->text.isNull() && bt->toolButtonStyle != Qt::ToolButtonIconOnly) {
+ int text_width = bt->fontMetrics.horizontalAdvance(bt->text),
+ text_height = bt->fontMetrics.height();
+ if (bt->toolButtonStyle == Qt::ToolButtonTextUnderIcon) {
width = qMax(width, text_width);
height += text_height;
} else {
@@ -1056,37 +942,39 @@ static QSize qt_aqua_get_known_size(QStyle::ContentsType ct, const QWidget *widg
break;
case QStyle::CT_Slider: {
int w = -1;
- const QSlider *sld = qobject_cast<const QSlider *>(widg);
+ const QStyleOptionSlider *sld = qstyleoption_cast<const QStyleOptionSlider *>(opt);
// If this conversion fails then the widget was not what it claimed to be.
- if(sld) {
+ if (sld) {
if (sz == QStyleHelper::SizeLarge) {
- if (sld->orientation() == Qt::Horizontal) {
+ if (sld->orientation == Qt::Horizontal) {
w = qt_mac_aqua_get_metric(HSliderHeight);
- if (sld->tickPosition() != QSlider::NoTicks)
+ if (sld->tickPosition != QSlider::NoTicks)
w += qt_mac_aqua_get_metric(HSliderTickHeight);
+ else if (isBigSurOrAbove)
+ w += 3;
} else {
w = qt_mac_aqua_get_metric(VSliderWidth);
- if (sld->tickPosition() != QSlider::NoTicks)
+ if (sld->tickPosition != QSlider::NoTicks)
w += qt_mac_aqua_get_metric(VSliderTickWidth);
}
} else if (sz == QStyleHelper::SizeSmall) {
- if (sld->orientation() == Qt::Horizontal) {
+ if (sld->orientation == Qt::Horizontal) {
w = qt_mac_aqua_get_metric(SmallHSliderHeight);
- if (sld->tickPosition() != QSlider::NoTicks)
+ if (sld->tickPosition != QSlider::NoTicks)
w += qt_mac_aqua_get_metric(SmallHSliderTickHeight);
} else {
w = qt_mac_aqua_get_metric(SmallVSliderWidth);
- if (sld->tickPosition() != QSlider::NoTicks)
+ if (sld->tickPosition != QSlider::NoTicks)
w += qt_mac_aqua_get_metric(SmallVSliderTickWidth);
}
} else if (sz == QStyleHelper::SizeMini) {
- if (sld->orientation() == Qt::Horizontal) {
+ if (sld->orientation == Qt::Horizontal) {
w = qt_mac_aqua_get_metric(MiniHSliderHeight);
- if (sld->tickPosition() != QSlider::NoTicks)
+ if (sld->tickPosition != QSlider::NoTicks)
w += qt_mac_aqua_get_metric(MiniHSliderTickHeight);
} else {
w = qt_mac_aqua_get_metric(MiniVSliderWidth);
- if (sld->tickPosition() != QSlider::NoTicks)
+ if (sld->tickPosition != QSlider::NoTicks)
w += qt_mac_aqua_get_metric(MiniVSliderTickWidth);
}
}
@@ -1098,7 +986,7 @@ static QSize qt_aqua_get_known_size(QStyle::ContentsType ct, const QWidget *widg
w = qt_mac_aqua_get_metric(HSliderHeight);
w += qt_mac_aqua_get_metric(HSliderTickHeight);
}
- if (sld->orientation() == Qt::Horizontal)
+ if (sld->orientation == Qt::Horizontal)
ret.setHeight(w);
else
ret.setWidth(w);
@@ -1127,7 +1015,7 @@ static QSize qt_aqua_get_known_size(QStyle::ContentsType ct, const QWidget *widg
#if QT_CONFIG(combobox)
case QStyle::CT_LineEdit:
if (!widg || !qobject_cast<QComboBox *>(widg->parentWidget())) {
- //should I take into account the font dimentions of the lineedit? -Sam
+ //should I take into account the font dimensions of the lineedit? -Sam
if (sz == QStyleHelper::SizeLarge)
ret = QSize(-1, 21);
else
@@ -1189,6 +1077,8 @@ static QStyleHelper::WidgetSizePolicy qt_aqua_guess_size(const QWidget *widg, QS
void QMacStylePrivate::drawFocusRing(QPainter *p, const QRectF &targetRect, int hMargin, int vMargin, const CocoaControl &cw) const
{
+ const bool isBigSurOrAbove = QOperatingSystemVersion::current() >= QOperatingSystemVersion::MacOSBigSur;
+
QPainterPath focusRingPath;
focusRingPath.setFillRule(Qt::OddEvenFill);
@@ -1200,6 +1090,8 @@ void QMacStylePrivate::drawFocusRing(QPainter *p, const QRectF &targetRect, int
case SegmentedControl_Middle:
case TextField: {
auto innerRect = targetRect;
+ if (cw.type == Button_SquareButton)
+ innerRect = cw.adjustedControlFrame(targetRect.adjusted(hMargin, vMargin, -hMargin, -vMargin));
if (cw.type == TextField)
innerRect = innerRect.adjusted(hMargin, vMargin, -hMargin, -vMargin).adjusted(0.5, 0.5, -0.5, -0.5);
const auto outerRect = innerRect.adjusted(-focusRingWidth, -focusRingWidth, focusRingWidth, focusRingWidth);
@@ -1234,15 +1126,49 @@ void QMacStylePrivate::drawFocusRing(QPainter *p, const QRectF &targetRect, int
focusRingPath.addEllipse(rbOuterRect);
break;
}
- case Button_PopupButton:
case Button_PullDown:
- case Button_PushButton:
+ case Button_PushButton: {
+ QRectF focusRect;
+ auto *pb = static_cast<NSButton *>(cocoaControl(cw));
+ const QRectF frameRect = cw.adjustedControlFrame(targetRect.adjusted(hMargin, vMargin, -hMargin, -vMargin));
+ pb.frame = frameRect.toCGRect();
+ focusRect = QRectF::fromCGRect([pb alignmentRectForFrame:pb.frame]);
+ if (cw.type == QMacStylePrivate::Button_PushButton) {
+ focusRect -= pushButtonShadowMargins[cw.size];
+ 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)
+ focusRect = focusRect.adjusted(0, 0, 0, -1);
+ else if (cw.size == QStyleHelper::SizeMini)
+ focusRect = focusRect.adjusted(0, -1, 0, 0);
+ }
+ if (isBigSurOrAbove)
+ focusRect = focusRect.translated(0, 1);
+ const qreal innerRadius = cw.type == Button_PushButton ? 3 : 4;
+ const qreal outerRadius = innerRadius + focusRingWidth;
+ hOffset = focusRect.left();
+ vOffset = focusRect.top();
+ const auto innerRect = focusRect.translated(-focusRect.topLeft());
+ const auto outerRect = innerRect.adjusted(-hMargin, -vMargin, hMargin, vMargin);
+ focusRingPath.addRoundedRect(innerRect, innerRadius, innerRadius);
+ focusRingPath.addRoundedRect(outerRect, outerRadius, outerRadius);
+ break;
+ }
+ case Button_PopupButton:
case SegmentedControl_Single: {
+ 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 = targetRect.left();
- vOffset = targetRect.top();
- const auto innerRect = targetRect.translated(-targetRect.topLeft());
+ hOffset = focusRect.left();
+ vOffset = focusRect.top();
+ const auto innerRect = focusRect.translated(-focusRect.topLeft());
const auto outerRect = innerRect.adjusted(-hMargin, -vMargin, hMargin, vMargin);
focusRingPath.addRoundedRect(innerRect, innerRadius, innerRadius);
focusRingPath.addRoundedRect(outerRect, outerRadius, outerRadius);
@@ -1291,7 +1217,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.
@@ -1496,9 +1422,9 @@ QStyleHelper::WidgetSizePolicy QMacStylePrivate::aquaSizeConstrain(const QStyleO
return QStyleHelper::SizeDefault;
}
- QSize large = qt_aqua_get_known_size(ct, widg, szHint, QStyleHelper::SizeLarge),
- small = qt_aqua_get_known_size(ct, widg, szHint, QStyleHelper::SizeSmall),
- mini = qt_aqua_get_known_size(ct, widg, szHint, QStyleHelper::SizeMini);
+ QSize large = qt_aqua_get_known_size(ct, option, widg, szHint, QStyleHelper::SizeLarge),
+ small = qt_aqua_get_known_size(ct, option, widg, szHint, QStyleHelper::SizeSmall),
+ mini = qt_aqua_get_known_size(ct, option, widg, szHint, QStyleHelper::SizeMini);
bool guess_size = false;
QStyleHelper::WidgetSizePolicy ret = QStyleHelper::SizeDefault;
QStyleHelper::WidgetSizePolicy wsp = QStyleHelper::widgetSizePolicy(widg);
@@ -1513,7 +1439,7 @@ QStyleHelper::WidgetSizePolicy QMacStylePrivate::aquaSizeConstrain(const QStyleO
if (guess_size)
ret = qt_aqua_guess_size(widg, large, small, mini);
- QSize *sz = 0;
+ QSize *sz = nullptr;
if (ret == QStyleHelper::SizeSmall)
sz = &small;
else if (ret == QStyleHelper::SizeLarge)
@@ -1548,7 +1474,7 @@ QStyleHelper::WidgetSizePolicy QMacStylePrivate::aquaSizeConstrain(const QStyleO
#endif
}
-uint qHash(const QMacStylePrivate::CocoaControl &cw, uint seed = 0)
+size_t qHash(const QMacStylePrivate::CocoaControl &cw, size_t seed = 0)
{
return ((cw.type << 2) | cw.size) ^ seed;
}
@@ -1594,15 +1520,18 @@ QRectF QMacStylePrivate::CocoaControl::adjustedControlFrame(const QRectF &rect)
const auto frameSize = defaultFrameSize();
if (type == QMacStylePrivate::Button_SquareButton) {
frameRect = rect.adjusted(3, 1, -3, -1)
- .adjusted(focusRingWidth, focusRingWidth, -focusRingWidth, -focusRingWidth);
+ .adjusted(focusRingWidth, focusRingWidth, -focusRingWidth, -focusRingWidth)
+ .adjusted(-6.5, 0, 6.5, 0);
} else if (type == QMacStylePrivate::Button_PushButton) {
// Start from the style option's top-left corner.
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 {
// Center in the style option's rect.
frameRect = QRectF(QPointF(0, (rect.height() - frameSize.height()) / 2.0),
@@ -1615,6 +1544,9 @@ QRectF QMacStylePrivate::CocoaControl::adjustedControlFrame(const QRectF &rect)
frameRect = frameRect.adjusted(0, 0, -4, 0).translated(2, 1);
else if (size == QStyleHelper::SizeMini)
frameRect = frameRect.adjusted(0, 0, -9, 0).translated(5, 0);
+ if (type == QMacStylePrivate::Button_PullDown)
+ frameRect = frameRect.adjusted(-pushButtonBevelRectOffsets[size], 0,
+ pushButtonBevelRectOffsets[size], 0);
} else if (type == QMacStylePrivate::ComboBox) {
frameRect = frameRect.adjusted(0, 0, -6, 0).translated(4, 0);
}
@@ -1653,24 +1585,24 @@ bool QMacStylePrivate::CocoaControl::getCocoaButtonTypeAndBezelStyle(NSButtonTyp
{
switch (type) {
case Button_CheckBox:
- *buttonType = NSSwitchButton;
- *bezelStyle = NSRegularSquareBezelStyle;
+ *buttonType = NSButtonTypeSwitch;
+ *bezelStyle = NSBezelStyleRegularSquare;
break;
case Button_Disclosure:
- *buttonType = NSOnOffButton;
- *bezelStyle = NSDisclosureBezelStyle;
+ *buttonType = NSButtonTypeOnOff;
+ *bezelStyle = NSBezelStyleDisclosure;
break;
case Button_RadioButton:
- *buttonType = NSRadioButton;
- *bezelStyle = NSRegularSquareBezelStyle;
+ *buttonType = NSButtonTypeRadio;
+ *bezelStyle = NSBezelStyleRegularSquare;
break;
case Button_SquareButton:
- *buttonType = NSPushOnPushOffButton;
- *bezelStyle = NSShadowlessSquareBezelStyle;
+ *buttonType = NSButtonTypePushOnPushOff;
+ *bezelStyle = NSBezelStyleShadowlessSquare;
break;
case Button_PushButton:
- *buttonType = NSPushOnPushOffButton;
- *bezelStyle = NSRoundedBezelStyle;
+ *buttonType = NSButtonTypeMomentaryPushIn;
+ *bezelStyle = NSBezelStyleRounded;
break;
default:
return false;
@@ -1683,13 +1615,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);
@@ -1808,10 +1742,6 @@ QRectF QMacStylePrivate::comboboxEditBounds(const QRectF &outerBounds, const Coc
QMacStylePrivate::QMacStylePrivate()
: backingStoreNSView(nil)
{
- if (auto *ssf = QGuiApplicationPrivate::platformTheme()->font(QPlatformTheme::SmallFont))
- smallSystemFont = *ssf;
- if (auto *msf = QGuiApplicationPrivate::platformTheme()->font(QPlatformTheme::MiniFont))
- miniSystemFont = *msf;
}
QMacStylePrivate::~QMacStylePrivate()
@@ -1829,13 +1759,9 @@ NSView *QMacStylePrivate::cocoaControl(CocoaControl widget) const
|| widget.size == QStyleHelper::SizeDefault)
return nil;
- if (widget.type == Box) {
- if (__builtin_available(macOS 10.14, *)) {
- if (qt_mac_applicationIsInDarkMode()) {
- // See render code in drawPrimitive(PE_FrameTabWidget)
- widget.type = Box_Dark;
- }
- }
+ if (widget.type == Box && isDarkMode()) {
+ // See render code in drawPrimitive(PE_FrameTabWidget)
+ widget.type = Box_Dark;
}
NSView *bv = cocoaControls.value(widget, nil);
@@ -1989,8 +1915,8 @@ NSCell *QMacStylePrivate::cocoaCell(CocoaControl widget) const
break;
case Button_Disclosure: {
NSButtonCell *bc = [[NSButtonCell alloc] init];
- bc.buttonType = NSOnOffButton;
- bc.bezelStyle = NSDisclosureBezelStyle;
+ bc.buttonType = NSButtonTypeOnOff;
+ bc.bezelStyle = NSBezelStyleDisclosure;
cell = bc;
break;
}
@@ -2080,7 +2006,6 @@ QMacStyle::QMacStyle()
QCoreApplication::sendEvent(o, &event);
});
-#if QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_14)
Q_D(QMacStyle);
// FIXME: Tie this logic into theme change, or even polish/unpolish
if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::MacOSMojave) {
@@ -2091,7 +2016,6 @@ QMacStyle::QMacStyle()
d->cocoaControls.clear();
});
}
-#endif
}
QMacStyle::~QMacStyle()
@@ -2112,6 +2036,14 @@ void QMacStyle::unpolish(QApplication *)
void QMacStyle::polish(QWidget* w)
{
+ Q_D(QMacStyle);
+ if (!d->smallSystemFont && QGuiApplicationPrivate::platformTheme()) {
+ if (auto *ssf = QGuiApplicationPrivate::platformTheme()->font(QPlatformTheme::SmallFont))
+ d->smallSystemFont = *ssf;
+ else
+ d->smallSystemFont = QFont();
+ }
+
if (false
#if QT_CONFIG(menu)
|| qobject_cast<QMenu*>(w)
@@ -2224,25 +2156,6 @@ int QMacStyle::pixelMetric(PixelMetric metric, const QStyleOption *opt, const QW
case PM_FocusFrameHMargin:
ret = qt_mac_aqua_get_metric(FocusRectOutset);
break;
- case PM_DialogButtonsSeparator:
- ret = -5;
- break;
- case PM_DialogButtonsButtonHeight: {
- QSize sz;
- ret = d->aquaSizeConstrain(opt, 0, QStyle::CT_PushButton, QSize(-1, -1), &sz);
- if (sz == QSize(-1, -1))
- ret = 32;
- else
- ret = sz.height();
- break; }
- case PM_DialogButtonsButtonWidth: {
- QSize sz;
- ret = d->aquaSizeConstrain(opt, 0, QStyle::CT_PushButton, QSize(-1, -1), &sz);
- if (sz == QSize(-1, -1))
- ret = 70;
- else
- ret = sz.width();
- break; }
case PM_MenuBarHMargin:
ret = 8;
@@ -2489,7 +2402,7 @@ int QMacStyle::pixelMetric(PixelMetric metric, const QStyleOption *opt, const QW
aSize = QStyleHelper::SizeSmall;
else
aSize = QStyleHelper::SizeLarge;
- const QSize size = qt_aqua_get_known_size(CT_SizeGrip, widget, QSize(), aSize);
+ const QSize size = qt_aqua_get_known_size(CT_SizeGrip, opt, widget, QSize(), aSize);
ret = size.width();
break; }
case PM_MdiSubWindowFrameWidth:
@@ -2514,7 +2427,7 @@ int QMacStyle::pixelMetric(PixelMetric metric, const QStyleOption *opt, const QW
ret = 4;
break;
case PM_SplitterWidth:
- ret = qMax(7, QApplication::globalStrut().width());
+ ret = 7;
break;
case PM_LayoutLeftMargin:
case PM_LayoutTopMargin:
@@ -2569,10 +2482,13 @@ int QMacStyle::pixelMetric(PixelMetric metric, const QStyleOption *opt, const QW
case PM_ToolBarFrameWidth:
ret = 1;
break;
- case PM_ScrollView_ScrollBarOverlap:
- ret = [NSScroller preferredScrollerStyle] == NSScrollerStyleOverlay ?
- pixelMetric(PM_ScrollBarExtent, opt, widget) : 0;
+ case PM_ScrollView_ScrollBarOverlap: {
+ const QStyle *realStyle = widget ? widget->style() : proxy();
+ ret = realStyle->styleHint(SH_ScrollBar_Transient, opt, widget)
+ ? realStyle->pixelMetric(PM_ScrollBarExtent, opt, widget)
+ : 0;
break;
+ }
default:
ret = QCommonStyle::pixelMetric(metric, opt, widget);
break;
@@ -2584,7 +2500,7 @@ QPalette QMacStyle::standardPalette() const
{
auto platformTheme = QGuiApplicationPrivate::platformTheme();
auto styleNames = platformTheme->themeHint(QPlatformTheme::StyleNames);
- if (styleNames.toStringList().contains("macintosh"))
+ if (styleNames.toStringList().contains("macOS"))
return QPalette(); // Inherit everything from theme
else
return QStyle::standardPalette();
@@ -2623,7 +2539,7 @@ int QMacStyle::styleHint(StyleHint sh, const QStyleOption *opt, const QWidget *w
ret = true;
break;
case SH_Slider_AbsoluteSetButtons:
- ret = Qt::LeftButton|Qt::MidButton;
+ ret = Qt::LeftButton|Qt::MiddleButton;
break;
case SH_Slider_PageSetButtons:
ret = 0;
@@ -2656,7 +2572,8 @@ int QMacStyle::styleHint(StyleHint sh, const QStyleOption *opt, const QWidget *w
case SH_ScrollBar_LeftClickAbsolutePosition: {
NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
bool result = [defaults boolForKey:@"AppleScrollerPagingBehavior"];
- if(QApplication::keyboardModifiers() & Qt::AltModifier)
+ const QStyleOptionSlider *sliderOpt = qstyleoption_cast<const QStyleOptionSlider*>(opt);
+ if (sliderOpt && sliderOpt->keyboardModifiers & Qt::AltModifier)
ret = !result;
else
ret = result;
@@ -2687,7 +2604,7 @@ int QMacStyle::styleHint(StyleHint sh, const QStyleOption *opt, const QWidget *w
case SH_BlinkCursorWhenTextSelected:
ret = false;
break;
- case SH_ScrollBar_StopMouseOverSlider:
+ case SH_Slider_StopMouseOverSlider:
ret = true;
break;
case SH_ListViewExpand_SelectMouseType:
@@ -2751,7 +2668,7 @@ int QMacStyle::styleHint(StyleHint sh, const QStyleOption *opt, const QWidget *w
break;
case SH_FocusFrame_Mask: {
ret = true;
- if(QStyleHintReturnMask *mask = qstyleoption_cast<QStyleHintReturnMask*>(hret)) {
+ if (QStyleHintReturnMask *mask = qstyleoption_cast<QStyleHintReturnMask*>(hret)) {
const uchar fillR = 192, fillG = 191, fillB = 190;
QImage img;
@@ -2766,12 +2683,12 @@ int QMacStyle::styleHint(StyleHint sh, const QStyleOption *opt, const QWidget *w
}
const QRgb *sptr = (QRgb*)img.bits(), *srow;
- const int sbpl = img.bytesPerLine();
+ const qsizetype sbpl = img.bytesPerLine();
const int w = sbpl/4, h = img.height();
QImage img_mask(img.width(), img.height(), QImage::Format_ARGB32);
QRgb *dptr = (QRgb*)img_mask.bits(), *drow;
- const int dbpl = img_mask.bytesPerLine();
+ const qsizetype dbpl = img_mask.bytesPerLine();
for (int y = 0; y < h; ++y) {
srow = sptr+((y*sbpl)/4);
@@ -2839,9 +2756,6 @@ int QMacStyle::styleHint(StyleHint sh, const QStyleOption *opt, const QWidget *w
case SH_MessageBox_TextInteractionFlags:
ret = Qt::TextSelectableByMouse | Qt::LinksAccessibleByMouse | Qt::TextSelectableByKeyboard;
break;
- case SH_SpellCheckUnderlineStyle:
- ret = QTextCharFormat::DashUnderline;
- break;
case SH_MessageBox_CenterButtons:
ret = false;
break;
@@ -2882,7 +2796,7 @@ int QMacStyle::styleHint(StyleHint sh, const QStyleOption *opt, const QWidget *w
case SH_ScrollBar_Transient:
if ((qobject_cast<const QScrollBar *>(w) && w->parent() &&
qobject_cast<QAbstractScrollArea*>(w->parent()->parent()))
-#ifndef QT_NO_ACCESSIBILITY
+#if QT_CONFIG(accessibility)
|| (opt && QStyleHelper::hasAncestor(opt->styleObject, QAccessible::ScrollBar))
#endif
) {
@@ -2907,6 +2821,9 @@ int QMacStyle::styleHint(StyleHint sh, const QStyleOption *opt, const QWidget *w
case SH_Table_GridLineColor:
ret = int(qt_mac_toQColor(NSColor.gridColor).rgba());
break;
+ case SH_TabBar_AllowWheelScrolling:
+ ret = false;
+ break;
default:
ret = QCommonStyle::styleHint(sh, opt, w, hret);
break;
@@ -2967,7 +2884,8 @@ QPixmap QMacStyle::standardPixmap(StandardPixmap standardPixmap, const QStyleOpt
size = 64;
break;
}
- return icon.pixmap(qt_getWindow(widget), QSize(size, size));
+ qreal dpr = widget ? widget->devicePixelRatio() : qApp->devicePixelRatio();
+ return icon.pixmap(QSize(size, size), dpr);
}
void QMacStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPainter *p,
@@ -3037,7 +2955,7 @@ void QMacStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPai
}
#if QT_CONFIG(tabwidget)
QRegion region(tbb->rect);
- region -= tbb->tabBarRect;
+ region -= tbb->tabBarRect.adjusted(3, 0, -3, 0);
p->save();
p->setClipRegion(region);
QStyleOptionTabWidgetFrame twf;
@@ -3095,7 +3013,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:.
@@ -3104,7 +3022,7 @@ void QMacStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPai
// vertically and even worse, if QTabWidget has autoFillBackground
// set, this background overpaints NSBox making it to disappear.
// We trick our NSBox to render in a larger rectangle, so that
- // the actuall result (which is again smaller than requested),
+ // the actual result (which is again smaller than requested),
// more or less is what we really want. We'll have to adjust CTM
// and translate accordingly.
adjustedRect.adjust(0, 0, 6, 6);
@@ -3143,14 +3061,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());
@@ -3250,7 +3168,7 @@ void QMacStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPai
static const CFStringRef keys[] = { kCTFontAttributeName, kCTForegroundColorAttributeName };
static const int numValues = sizeof(keys) / sizeof(keys[0]);
const CFTypeRef values[] = { (CFTypeRef)checkmarkFont, (CFTypeRef)checkmarkColor };
- Q_STATIC_ASSERT((sizeof(values) / sizeof(values[0])) == numValues);
+ static_assert((sizeof(values) / sizeof(values[0])) == numValues);
QCFType<CFDictionaryRef> attributes = CFDictionaryCreate(kCFAllocatorDefault, (const void **)keys, (const void **)values,
numValues, NULL, NULL);
// U+2713: CHECK MARK
@@ -3273,8 +3191,8 @@ void QMacStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPai
const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
auto *tb = static_cast<NSButton *>(d->cocoaControl(cw));
tb.enabled = isEnabled;
- tb.state = (opt->state & State_NoChange) ? NSMixedState :
- (opt->state & State_On) ? NSOnState : NSOffState;
+ tb.state = (opt->state & State_NoChange) ? NSControlStateValueMixed :
+ (opt->state & State_On) ? NSControlStateValueOn : NSControlStateValueOff;
[tb highlight:isPressed];
const auto vOffset = [=] {
// As measured
@@ -3296,9 +3214,9 @@ void QMacStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPai
break;
const auto cw = QMacStylePrivate::CocoaControl(QMacStylePrivate::Button_Disclosure, QStyleHelper::SizeLarge);
NSButtonCell *triangleCell = static_cast<NSButtonCell *>(d->cocoaCell(cw));
- [triangleCell setState:(opt->state & State_Open) ? NSOnState : NSOffState];
+ [triangleCell setState:(opt->state & State_Open) ? NSControlStateValueOn : NSControlStateValueOff];
bool viewHasFocus = (w && w->hasFocus()) || (opt->state & State_HasFocus);
- [triangleCell setBackgroundStyle:((opt->state & State_Selected) && viewHasFocus) ? NSBackgroundStyleDark : NSBackgroundStyleLight];
+ [triangleCell setBackgroundStyle:((opt->state & State_Selected) && viewHasFocus) ? NSBackgroundStyleEmphasized : NSBackgroundStyleNormal];
d->setupNSGraphicsContext(cg, NO);
@@ -3337,7 +3255,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
@@ -3370,7 +3288,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
@@ -3435,17 +3353,7 @@ void QMacStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPai
} break;
#endif // QT_CONFIG(tabbar)
case PE_PanelStatusBar: {
- // Fill the status bar with the titlebar gradient.
- QLinearGradient linearGrad;
- if (w ? qt_macWindowMainWindow(w->window()) : (opt->state & QStyle::State_Active)) {
- linearGrad = titlebarGradientActive();
- } else {
- linearGrad = titlebarGradientInactive();
- }
-
- linearGrad.setStart(0, opt->rect.top());
- linearGrad.setFinalStop(0, opt->rect.bottom());
- p->fillRect(opt->rect, linearGrad);
+ p->fillRect(opt->rect, opt->palette.window());
// Draw the black separator line at the top of the status bar.
if (w ? qt_macWindowMainWindow(w->window()) : (opt->state & QStyle::State_Active))
@@ -3549,33 +3457,11 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
}
break;
- case CE_HeaderLabel:
- if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(opt)) {
- p->save();
- QRect textr = header->rect;
- if (!header->icon.isNull()) {
- QIcon::Mode mode = QIcon::Disabled;
- if (opt->state & State_Enabled)
- mode = QIcon::Normal;
- int iconExtent = proxy()->pixelMetric(PM_SmallIconSize);
- QPixmap pixmap = header->icon.pixmap(window, QSize(iconExtent, iconExtent), mode);
-
- QRect pixr = header->rect;
- pixr.setY(header->rect.center().y() - (pixmap.height() / pixmap.devicePixelRatio() - 1) / 2);
- proxy()->drawItemPixmap(p, pixr, Qt::AlignVCenter, pixmap);
- textr.translate(pixmap.width() / pixmap.devicePixelRatio() + 2, 0);
- }
-
- proxy()->drawItemText(p, textr, header->textAlignment | Qt::AlignVCenter, header->palette,
- header->state & State_Enabled, header->text, QPalette::ButtonText);
- p->restore();
- }
- break;
case CE_ToolButtonLabel:
if (const QStyleOptionToolButton *tb = qstyleoption_cast<const QStyleOptionToolButton *>(opt)) {
QStyleOptionToolButton myTb = *tb;
myTb.state &= ~State_AutoRaise;
-#ifndef QT_NO_ACCESSIBILITY
+#if QT_CONFIG(accessibility)
if (QStyleHelper::hasAncestor(opt->styleObject, QAccessible::ToolBar)) {
QRect cr = tb->rect;
int shiftX = 0;
@@ -3609,19 +3495,19 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
: QIcon::Disabled;
QIcon::State iconState = (tb->state & State_On) ? QIcon::On
: QIcon::Off;
- QPixmap pixmap = tb->icon.pixmap(window,
- tb->rect.size().boundedTo(tb->iconSize),
+ QPixmap pixmap = tb->icon.pixmap(tb->rect.size().boundedTo(tb->iconSize), p->device()->devicePixelRatio(),
iconMode, iconState);
// 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;
}
@@ -3665,7 +3551,7 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
QCommonStyle::drawControl(ce, &myTb, p, w);
}
} else
-#endif // QT_NO_ACCESSIBILITY
+#endif // QT_CONFIG(accessibility)
{
QCommonStyle::drawControl(ce, &myTb, p, w);
}
@@ -3708,14 +3594,27 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
auto *pb = static_cast<NSButton *>(d->cocoaControl(cw));
// Ensure same size and location as we used to have with HITheme.
- // This is more convoluted than we initialy thought. See for example
+ // This is more convoluted than we initially thought. See for example
// differences between plain and menu button frames.
const QRectF frameRect = cw.adjustedControlFrame(btn->rect);
pb.frame = frameRect.toCGRect();
pb.enabled = isEnabled;
+
+ // With the 'momentary push in' type this gives an impression of a
+ // button in a 'pressed' state (the 'momentary push in' does
+ // not show its state otherwise):
[pb highlight:isPressed];
- pb.state = isHighlighted && !isPressed ? NSOnState : NSOffState;
+
+
+ if (cw.type == QMacStylePrivate::Button_SquareButton) {
+ pb.state = isHighlighted && !isPressed ? NSControlStateValueOn : NSControlStateValueOff;
+ } else {
+ // For default/checked button this will give the required
+ // button accent color:
+ pb.keyEquivalent = isHighlighted ? @"\r" : @"";
+ }
+
d->drawNSViewInRect(pb, frameRect, p, ^(CGContextRef, const CGRect &r) {
[pb.cell drawBezelWithFrame:r inView:pb.superview];
});
@@ -3742,24 +3641,6 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
arrowOpt.rect = ar;
proxy()->drawPrimitive(PE_IndicatorArrowDown, &arrowOpt, p, w);
}
-
-
- if (btn->state & State_HasFocus) {
- // TODO Remove and use QFocusFrame instead.
- const int hMargin = proxy()->pixelMetric(QStyle::PM_FocusFrameHMargin, btn, w);
- const int vMargin = proxy()->pixelMetric(QStyle::PM_FocusFrameVMargin, btn, w);
- QRectF focusRect;
- if (cw.type == QMacStylePrivate::Button_SquareButton) {
- focusRect = frameRect;
- } else {
- focusRect = QRectF::fromCGRect([pb alignmentRectForFrame:pb.frame]);
- if (cw.type == QMacStylePrivate::Button_PushButton)
- focusRect -= pushButtonShadowMargins[cw.size];
- else if (cw.type == QMacStylePrivate::Button_PullDown)
- focusRect -= pullDownButtonShadowMargins[cw.size];
- }
- d->drawFocusRing(p, focusRect, hMargin, vMargin, cw);
- }
}
break;
case CE_PushButtonLabel:
@@ -3775,16 +3656,28 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
const bool hasText = !btn.text.isEmpty();
const bool isActive = btn.state & State_Active;
const bool isPressed = btn.state & State_Sunken;
+ const bool isDefault = (btn.features & QStyleOptionButton::DefaultButton && !d->autoDefaultButton)
+ || d->autoDefaultButton == btn.styleObject;
+ // 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
- || (isActive && isEnabled
- && ((btn.state & State_On)
- || ((btn.features & QStyleOptionButton::DefaultButton) && !d->autoDefaultButton)
- || d->autoDefaultButton == btn.styleObject)))
- btn.palette.setColor(QPalette::ButtonText, Qt::white);
+ if (isPressed || (isActive && isEnabled && ((btn.state & State_On) || isDefault)))
+ btn.palette.setColor(QPalette::ButtonText, Qt::white);
+ }
+
+ if (isEnabled && !isDarkMode() && QOperatingSystemVersion::current() > QOperatingSystemVersion::MacOSBigSur) {
+ if (!isDefault && !(btn.state & State_On)) {
+ // On macOS 12 it's a gray button, white text color (if set in the
+ // previous statement) would be almost invisible.
+ btn.palette.setColor(QPalette::ButtonText, Qt::black);
+ }
}
if ((!hasIcon && !hasMenu) || (hasIcon && !hasText)) {
@@ -3794,7 +3687,11 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
QRect textRect = itemTextRect(
btn.fontMetrics, freeContentRect, Qt::AlignCenter, isEnabled, btn.text);
if (hasMenu) {
- textRect.moveTo(w ? 15 : 11, textRect.top()); // Supports Qt Quick Controls
+ if (ct == QMacStylePrivate::Button_SquareButton)
+ textRect.moveTo(w ? 8 : 11, textRect.top());
+ else
+ textRect.moveTo(w ? (15 - pushButtonBevelRectOffsets[d->effectiveAquaSizeConstrain(b, w)])
+ : 11, textRect.top()); // Supports Qt Quick Controls
}
// Draw the icon:
if (hasIcon) {
@@ -3808,13 +3705,12 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
QIcon::State state = QIcon::Off;
if (btn.state & State_On)
state = QIcon::On;
- QPixmap pixmap = btn.icon.pixmap(window, btn.iconSize, mode, state);
- int pixmapWidth = pixmap.width() / pixmap.devicePixelRatio();
- int pixmapHeight = pixmap.height() / pixmap.devicePixelRatio();
- contentW += pixmapWidth + QMacStylePrivate::PushButtonContentPadding;
+ QPixmap pixmap = btn.icon.pixmap(btn.iconSize, p->device()->devicePixelRatio(), mode, state);
+ 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()
@@ -3886,16 +3782,11 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
// inFrame:withView:], -[drawRect:] or anything in between. Besides,
// there's no public API do draw the pressed state, AFAICS. We'll use
// a push NSButton instead and clip the CGContext.
- // NOTE/TODO: this is not true. On 10.13 NSSegmentedControl works with
- // some (black?) magic/magic dances, on 10.14 it simply works (was
- // it fixed in AppKit?). But, indeed, we cannot make a tab 'pressed'
- // with NSSegmentedControl (only selected), so we stay with buttons
- // (mixing buttons and NSSegmentedControl for such a simple thing
- // is too much work).
const auto cs = d->effectiveAquaSizeConstrain(opt, w);
// Extra hacks to get the proper pressed appreance when not selected or selected and inactive
const bool needsInactiveHack = (!isActive && isSelected);
+ const bool isBigSurOrAbove = QOperatingSystemVersion::current() >= QOperatingSystemVersion::MacOSBigSur;
const auto ct = !needsInactiveHack && (isSelected || tp == QStyleOptionTab::OnlyOneTab) ?
QMacStylePrivate::Button_PushButton :
QMacStylePrivate::Button_PopupButton;
@@ -3904,6 +3795,12 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
auto *pb = static_cast<NSButton *>(d->cocoaControl(cw));
auto vOffset = isPopupButton ? 1 : 2;
+ if (isBigSurOrAbove) {
+ // Make it 1, otherwise, offset is very visible compared
+ // to selected tab (which is not a popup button).
+ vOffset = 1;
+ }
+
if (tabDirection == QMacStylePrivate::East)
vOffset -= 1;
const auto outerAdjust = isPopupButton ? 1 : 4;
@@ -3920,16 +3817,35 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
frameRect = frameRect.adjusted(-innerAdjust, 0, outerAdjust, 0);
else
frameRect = frameRect.adjusted(-outerAdjust, 0, innerAdjust, 0);
+
+ if (isSelected && isBigSurOrAbove) {
+ // 1 pixed of 'roundness' is still visible on the right
+ // (the left is OK, it's rounded).
+ frameRect = frameRect.adjusted(0, 0, 1, 0);
+ }
+
break;
case QStyleOptionTab::Middle:
frameRect = frameRect.adjusted(-innerAdjust, 0, innerAdjust, 0);
+
+ if (isSelected && isBigSurOrAbove) {
+ // 1 pixel of 'roundness' is still visible on both
+ // sides - left and right.
+ frameRect = frameRect.adjusted(-1, 0, 1, 0);
+ }
break;
+ case QStyleOptionTab::Moving: // Moving tab treated like End
case QStyleOptionTab::End:
// Pressed state hack: tweak adjustments in preparation for flip below
if (isSelected || tabDirection == QMacStylePrivate::West)
frameRect = frameRect.adjusted(-innerAdjust, 0, outerAdjust, 0);
else
frameRect = frameRect.adjusted(-outerAdjust, 0, innerAdjust, 0);
+
+ if (isSelected && isBigSurOrAbove) {
+ // 1 pixel of 'roundness' is still visible on the left.
+ frameRect = frameRect.adjusted(-1, 0, 0, 0);
+ }
break;
case QStyleOptionTab::OnlyOneTab:
frameRect = frameRect.adjusted(-outerAdjust, 0, outerAdjust, 0);
@@ -3937,10 +3853,22 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
}
pb.frame = frameRect.toCGRect();
+ if (!isPopupButton) {
+ // Note: these days we use 'momentary push in' for Button_PushButton,
+ // but tabs are also rendered using NSButton/ButtonPushButton, and
+ // here we need 'push on/off' to make it work (tab highlight colors).
+ pb.buttonType = NSButtonTypePushOnPushOff;
+ }
+
pb.enabled = isEnabled;
[pb highlight:isPressed];
+
// Set off state when inactive. See needsInactiveHack for when it's selected
- pb.state = (isActive && isSelected && !isPressed) ? NSOnState : NSOffState;
+ // On macOS 12, don't set the Off state for selected tabs as it draws a gray backgorund even when highlighted
+ if (QOperatingSystemVersion::current() > QOperatingSystemVersion::MacOSBigSur)
+ pb.state = (isActive && isSelected) ? NSControlStateValueOn : NSControlStateValueOff;
+ else
+ pb.state = (isActive && isSelected && !isPressed) ? NSControlStateValueOn : NSControlStateValueOff;
const auto drawBezelBlock = ^(CGContextRef ctx, const CGRect &r) {
CGContextClipToRect(ctx, opt->rect.toCGRect());
@@ -3972,12 +3900,38 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
CGContextRotateCTM(ctx, M_PI_2);
}
- [pb.cell drawBezelWithFrame:r inView:pb.superview];
+ // Now, if it's a trick with a popup button, it has an arrow
+ // which makes no sense on tabs.
+ NSPopUpArrowPosition oldPosition = NSPopUpArrowAtCenter;
+ NSPopUpButtonCell *pbCell = nil;
+ auto rAdjusted = r;
+ if (isPopupButton && (tp == QStyleOptionTab::OnlyOneTab || isBigSurOrAbove)) {
+ // Note: starting from macOS BigSur NSPopupButton has this
+ // arrow 'button' in a different place and it became
+ // quite visible 'in between' inactive tabs.
+ pbCell = static_cast<NSPopUpButtonCell *>(pb.cell);
+ oldPosition = pbCell.arrowPosition;
+ pbCell.arrowPosition = NSPopUpNoArrow;
+ if (pb.state == NSControlStateValueOff) {
+ // NSPopUpButton in this state is smaller.
+ rAdjusted.origin.x -= 3;
+ rAdjusted.size.width += 6;
+ if (isBigSurOrAbove) {
+ if (tp == QStyleOptionTab::End)
+ rAdjusted.origin.x -= 2;
+ }
+ }
+ }
+
+ [pb.cell drawBezelWithFrame:rAdjusted inView:pb.superview];
+
+ if (pbCell) // Restore, we may reuse it for a ComboBox.
+ pbCell.arrowPosition = oldPosition;
};
if (needsInactiveHack) {
// First, render tab as non-selected tab on a pixamp
- const qreal pixelRatio = p->device()->devicePixelRatioF();
+ const qreal pixelRatio = p->device()->devicePixelRatio();
QImage tabPixmap(opt->rect.size() * pixelRatio, QImage::Format_ARGB32_Premultiplied);
tabPixmap.setDevicePixelRatio(pixelRatio);
tabPixmap.fill(Qt::transparent);
@@ -4029,32 +3983,12 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
}
p->restore();
}
-
- // TODO Needs size adjustment to fit the focus ring
- if (tabOpt->state & State_HasFocus) {
- QMacStylePrivate::CocoaControlType focusRingType;
- switch (tp) {
- case QStyleOptionTab::Beginning:
- focusRingType = verticalTabs ? QMacStylePrivate::SegmentedControl_Last
- : QMacStylePrivate::SegmentedControl_First;
- break;
- case QStyleOptionTab::Middle:
- focusRingType = QMacStylePrivate::SegmentedControl_Middle;
- break;
- case QStyleOptionTab::End:
- focusRingType = verticalTabs ? QMacStylePrivate::SegmentedControl_First
- : QMacStylePrivate::SegmentedControl_Last;
- break;
- case QStyleOptionTab::OnlyOneTab:
- focusRingType = QMacStylePrivate::SegmentedControl_Single;
- break;
- }
- }
}
break;
case CE_TabBarTabLabel:
if (const auto *tab = qstyleoption_cast<const QStyleOptionTab *>(opt)) {
QStyleOptionTab myTab = *tab;
+ const auto foregroundRole = w ? w->foregroundRole() : QPalette::WindowText;
const auto tabDirection = QMacStylePrivate::tabDirection(tab->shape);
const bool verticalTabs = tabDirection == QMacStylePrivate::East
|| tabDirection == QMacStylePrivate::West;
@@ -4068,11 +4002,11 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
if (!myTab.documentMode && (myTab.state & State_Selected) && (myTab.state & State_Active))
if (const auto *tabBar = qobject_cast<const QTabBar *>(w))
if (!tabBar->tabTextColor(tabBar->currentIndex()).isValid())
- myTab.palette.setColor(QPalette::WindowText, Qt::white);
+ myTab.palette.setColor(foregroundRole, Qt::white);
if (myTab.documentMode && isDarkMode()) {
bool active = (myTab.state & State_Selected) && (myTab.state & State_Active);
- myTab.palette.setColor(QPalette::WindowText, active ? Qt::white : Qt::gray);
+ myTab.palette.setColor(foregroundRole, active ? Qt::white : Qt::gray);
}
int heightOffset = 0;
@@ -4101,12 +4035,7 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
}
// fill title bar background
- QLinearGradient linearGrad;
- linearGrad.setStart(QPointF(0, 0));
- linearGrad.setFinalStop(QPointF(0, 2 * effectiveRect.height()));
- linearGrad.setColorAt(0, opt->palette.button().color());
- linearGrad.setColorAt(1, opt->palette.dark().color());
- p->fillRect(effectiveRect, linearGrad);
+ p->fillRect(effectiveRect, opt->palette.window());
// draw horizontal line at bottom
p->setPen(opt->palette.dark().color());
@@ -4121,7 +4050,7 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
titleRect.width());
const auto text = p->fontMetrics().elidedText(dwOpt->title, Qt::ElideRight, titleRect.width());
- proxy()->drawItemText(p, titleRect, Qt::AlignCenter, dwOpt->palette,
+ proxy()->drawItemText(p, titleRect, Qt::AlignCenter | Qt::TextHideMnemonic, dwOpt->palette,
dwOpt->state & State_Enabled, text, QPalette::WindowText);
}
p->restore();
@@ -4133,20 +4062,32 @@ 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)) {
+ // 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;
+ }
}
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));
@@ -4253,14 +4194,13 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
iconSize = comboBox->iconSize();
}
#endif
- QPixmap pixmap = mi->icon.pixmap(window, iconSize, mode);
- int pixw = pixmap.width() / pixmap.devicePixelRatio();
- int pixh = pixmap.height() / pixmap.devicePixelRatio();
+ QPixmap pixmap = mi->icon.pixmap(iconSize, p->device()->devicePixelRatio(), mode);
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;
@@ -4271,7 +4211,7 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
yPos += 1;
const bool isSubMenu = mi->menuItemType == QStyleOptionMenuItem::SubMenu;
- const int tabwidth = isSubMenu ? 9 : mi->tabWidth;
+ const int tabwidth = isSubMenu ? 9 : mi->reservedShortcutWidth;
QString rightMarginText;
if (isSubMenu)
@@ -4289,9 +4229,25 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
if (!rightMarginText.isEmpty()) {
p->setFont(qt_app_fonts_hash()->value("QMenuItem", p->font()));
int xp = mi->rect.right() - tabwidth - macRightBorder + 2;
- if (!isSubMenu)
+ if (isSubMenu) {
+ p->drawText(xp, yPos, tabwidth, mi->rect.height(), text_flags | Qt::AlignRight, rightMarginText);
+ } else {
xp -= macItemHMargin + macItemFrame + 3; // Adjust for shortcut
- p->drawText(xp, yPos, tabwidth, mi->rect.height(), text_flags | Qt::AlignRight, rightMarginText);
+ // try to render modifier part of shortcut string right aligned, key part left aligned
+ const QKeySequence seq = QKeySequence::fromString(rightMarginText, QKeySequence::NativeText);
+ if (seq.count() == 1) { // one-combo sequence, the right most character is the key
+ // we don't know which key of all menu items is the widest, so use the widest possible
+ const int maxKeyWidth = p->fontMetrics().maxWidth();
+ const QChar key = rightMarginText.at(rightMarginText.length() - 1);
+ const QString modifiers = rightMarginText.left(rightMarginText.size() - 1);
+ p->drawText(xp + tabwidth - maxKeyWidth, yPos, maxKeyWidth, mi->rect.height(), text_flags, key);
+ // don't clip the shortcuts; maxKeyWidth might be more than what we have been allotted by the menu
+ p->drawText(xp, yPos, tabwidth - maxKeyWidth, mi->rect.height(),
+ text_flags | Qt::AlignRight | Qt::TextDontClip, modifiers);
+ } else { // draw the whole thing left-aligned for complex or unparsable cases
+ p->drawText(xp, yPos, tabwidth, mi->rect.height(), text_flags, rightMarginText);
+ }
+ }
}
if (!s.isEmpty()) {
@@ -4333,8 +4289,10 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
// line-break the string if it doesn't fit the given rect. It's better to draw outside
// the rect and possibly overlap something than to have part of the text disappear.
[s.toNSString() drawAtPoint:CGPointMake(xpos, yPos)
- withAttributes:@{ NSFontAttributeName:f, NSForegroundColorAttributeName:c,
- NSObliquenessAttributeName: [NSNumber numberWithDouble: myFont.italic() ? 0.3 : 0.0]}];
+ withAttributes:@{ NSFontAttributeName:f, NSForegroundColorAttributeName:c,
+ NSObliquenessAttributeName: [NSNumber numberWithDouble: myFont.italic() ? 0.3 : 0.0],
+ NSUnderlineStyleAttributeName: [NSNumber numberWithInt: myFont.underline() ? NSUnderlineStyleSingle
+ : NSUnderlineStyleNone]}];
d->restoreNSGraphicsContext(cgCtx);
} else {
@@ -4361,7 +4319,7 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
drawItemPixmap(p, mi->rect,
Qt::AlignCenter | Qt::TextHideMnemonic | Qt::TextDontClip
| Qt::TextSingleLine,
- mi->icon.pixmap(window, QSize(iconExtent, iconExtent),
+ mi->icon.pixmap(QSize(iconExtent, iconExtent), p->device()->devicePixelRatio(),
(mi->state & State_Enabled) ? QIcon::Normal : QIcon::Disabled));
} else {
drawItemText(p, mi->rect,
@@ -4379,7 +4337,7 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
case CE_ProgressBarContents:
if (const QStyleOptionProgressBar *pb = qstyleoption_cast<const QStyleOptionProgressBar *>(opt)) {
const bool isIndeterminate = (pb->minimum == 0 && pb->maximum == 0);
- const bool vertical = pb->orientation == Qt::Vertical;
+ const bool vertical = !(pb->state & QStyle::State_Horizontal);
const bool inverted = pb->invertedAppearance;
bool reverse = (!vertical && (pb->direction == Qt::RightToLeft));
if (inverted)
@@ -4516,7 +4474,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
@@ -4541,7 +4499,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;
}
@@ -4556,24 +4514,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();
@@ -4635,15 +4593,13 @@ QRect QMacStyle::subElementRect(SubElement sr, const QStyleOption *opt,
auto frameRect = cw.adjustedControlFrame(btn->rect);
if (sr == SE_PushButtonContents) {
frameRect -= cw.titleMargins();
- } else {
+ } else if (cw.type != QMacStylePrivate::Button_SquareButton) {
auto *pb = static_cast<NSButton *>(d->cocoaControl(cw));
- if (cw.type != QMacStylePrivate::Button_SquareButton) {
- frameRect = QRectF::fromCGRect([pb alignmentRectForFrame:pb.frame]);
- if (cw.type == QMacStylePrivate::Button_PushButton)
- frameRect -= pushButtonShadowMargins[cw.size];
- else if (cw.type == QMacStylePrivate::Button_PullDown)
- frameRect -= pullDownButtonShadowMargins[cw.size];
- }
+ frameRect = QRectF::fromCGRect([pb alignmentRectForFrame:frameRect.toCGRect()]);
+ if (cw.type == QMacStylePrivate::Button_PushButton)
+ frameRect -= pushButtonShadowMargins[cw.size];
+ else if (cw.type == QMacStylePrivate::Button_PullDown)
+ frameRect -= pullDownButtonShadowMargins[cw.size];
}
rect = frameRect.toRect();
}
@@ -4884,14 +4840,24 @@ QRect QMacStyle::subElementRect(SubElement sr, const QStyleOption *opt,
= qstyleoption_cast<const QStyleOptionButton *>(opt)) {
if ((buttonOpt->features & QStyleOptionButton::Flat))
break; // leave rect alone
+ if ((buttonOpt->features & QStyleOptionButton::CommandLinkButton)) {
+ rect = opt->rect;
+ if (controlSize == QStyleHelper::SizeLarge)
+ rect.adjust(+6, +4, -6, -8);
+ else if (controlSize == QStyleHelper::SizeSmall)
+ rect.adjust(+5, +4, -5, -6);
+ else
+ rect.adjust(+1, 0, -1, -2);
+ break;
+ }
}
rect = opt->rect;
if (controlSize == QStyleHelper::SizeLarge) {
- rect.adjust(+6, +4, -6, -8);
+ rect.adjust(0, +4, 0, -8);
} else if (controlSize == QStyleHelper::SizeSmall) {
- rect.adjust(+5, +4, -5, -6);
+ rect.adjust(0, +4, 0, -6);
} else {
- rect.adjust(+1, 0, -1, -2);
+ rect.adjust(0, 0, 0, -2);
}
break;
case SE_RadioButtonLayoutItem:
@@ -5130,7 +5096,7 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex
if (const QStyleOptionSlider *sb = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
const bool drawTrack = sb->subControls & SC_ScrollBarGroove;
- const bool drawKnob = sb->subControls & SC_ScrollBarSlider;
+ const bool drawKnob = sb->subControls & SC_ScrollBarSlider && sb->minimum != sb->maximum;
if (!drawTrack && !drawKnob)
break;
@@ -5144,7 +5110,8 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex
const auto cocoaSize = d->effectiveAquaSizeConstrain(opt, widget);
const CGFloat maxExpandScale = expandedKnobWidths[cocoaSize] / knobWidths[cocoaSize];
- const bool isTransient = proxy()->styleHint(SH_ScrollBar_Transient, opt, widget);
+ const QStyle *realStyle = widget ? widget->style() : proxy();
+ const bool isTransient = realStyle->styleHint(SH_ScrollBar_Transient, opt, widget);
if (!isTransient)
d->stopAnimation(opt->styleObject);
bool wasActive = false;
@@ -5330,9 +5297,18 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex
CGPoint pressPoint;
if (isPressed) {
- const CGRect knobRect = [slider.cell knobRectFlipped:NO];
+ const CGRect knobRect = [slider.cell knobRectFlipped:slider.isFlipped];
pressPoint.x = CGRectGetMidX(knobRect);
pressPoint.y = CGRectGetMidY(knobRect);
+
+ // The only way to tell a NSSlider/NSSliderCell to render as pressed
+ // is to start tracking. But this API has some weird behaviors that
+ // we have to account for. First of all, the pressed state will not
+ // be visually reflected unless we start tracking twice. And secondly
+ // if we don't track twice, the state of one render-pass will affect
+ // the render pass of other sliders, even if we set up the shared
+ // NSSlider with a new slider value.
+ [slider.cell startTrackingAt:pressPoint inView:slider];
[slider.cell startTrackingAt:pressPoint inView:slider];
}
@@ -5362,7 +5338,7 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex
}
#if 0
- // FIXME: Sadly, this part doesn't work. It seems to somehow polute the
+ // FIXME: Sadly, this part doesn't work. It seems to somehow pollute the
// NSSlider's internal state and, when we need to use the "else" part,
// the slider's frame is not in sync with its cell dimensions.
const bool drawAllParts = drawKnob && drawBar && (!hasTicks || drawTicks);
@@ -5379,9 +5355,6 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex
} else
#endif
{
- [slider calcSize];
- if (!hasDoubleTicks)
- fixStaleGeometry(slider);
NSSliderCell *cell = slider.cell;
const int numberOfTickMarks = slider.numberOfTickMarks;
@@ -5389,9 +5362,20 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex
if (hasDoubleTicks)
slider.numberOfTickMarks = 0;
- const CGRect barRect = [cell barRectFlipped:hasTicks];
+ const CGRect barRect = [cell barRectFlipped:slider.isFlipped];
if (drawBar) {
- [cell drawBarInside:barRect flipped:!verticalFlip];
+ if (!isHorizontal && !sl->upsideDown && (hasDoubleTicks || !hasTicks)) {
+ // The logic behind verticalFlip and upsideDown is the twisted one.
+ // Bar is the only part of the cell affected by this 'flipped'
+ // parameter in the call below, all other parts (knob, etc.) 'fixed'
+ // by scaling/translating. With ticks on one side it's not a problem
+ // at all - the bar is gray anyway. Without ticks or with ticks on
+ // the both sides, for inverted appearance and vertical orientation -
+ // we must flip so that knob and blue filling work in accordance.
+ [cell drawBarInside:barRect flipped:true];
+ } else {
+ [cell drawBarInside:barRect flipped:!verticalFlip];
+ }
// This ain't HIG kosher: force unfilled bar look.
if (hasDoubleTicks)
slider.numberOfTickMarks = numberOfTickMarks;
@@ -5429,8 +5413,12 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex
}
});
- if (isPressed)
+ if (isPressed) {
+ // We stop twice to be on the safe side, even if one seems to be enough.
+ // See startTracking above for why we do this.
[slider.cell stopTracking:pressPoint at:pressPoint inView:slider mouseIsUp:NO];
+ [slider.cell stopTracking:pressPoint at:pressPoint inView:slider mouseIsUp:NO];
+ }
}
break;
#if QT_CONFIG(spinbox)
@@ -5492,7 +5480,7 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex
const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
auto *cc = static_cast<NSControl *>(d->cocoaControl(cw));
cc.enabled = isEnabled;
- QRectF frameRect = cw.adjustedControlFrame(combo->rect);;
+ QRectF frameRect = cw.adjustedControlFrame(combo->rect);
if (cw.type == QMacStylePrivate::Button_PopupButton) {
// Non-editable QComboBox
auto *pb = static_cast<NSPopUpButton *>(cc);
@@ -5562,19 +5550,10 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex
QPainterPath outerFramePath = d->windowPanelPath(outerFrameRect);
p->fillPath(outerFramePath, opt->palette.dark());
- const auto frameAdjust = 1.0 / p->device()->devicePixelRatioF();
+ const auto frameAdjust = 1.0 / p->device()->devicePixelRatio();
const auto innerFrameRect = outerFrameRect.adjusted(frameAdjust, frameAdjust, -frameAdjust, 0);
QPainterPath innerFramePath = d->windowPanelPath(innerFrameRect);
- if (isActive) {
- QLinearGradient g;
- g.setStart(QPointF(0, 0));
- g.setFinalStop(QPointF(0, 2 * opt->rect.height()));
- g.setColorAt(0, opt->palette.button().color());
- g.setColorAt(1, opt->palette.dark().color());
- p->fillPath(innerFramePath, g);
- } else {
- p->fillPath(innerFramePath, opt->palette.button());
- }
+ p->fillPath(innerFramePath, opt->palette.button());
if (titlebar->subControls & (SC_TitleBarCloseButton
| SC_TitleBarMaxButton
@@ -5608,7 +5587,7 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex
const auto iconPos = tr.x() - titlebar->icon.actualSize(iconSize).width() - qRound(titleBarIconTitleSpacing);
// Only render the icon if it'll be fully visible
if (iconPos < tr.right() - titleBarIconTitleSpacing)
- p->drawPixmap(iconPos, tr.y(), titlebar->icon.pixmap(window, iconSize, QIcon::Normal));
+ p->drawPixmap(iconPos, tr.y(), titlebar->icon.pixmap(iconSize, QIcon::Normal));
}
if (!titlebar->text.isEmpty())
@@ -5637,8 +5616,8 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex
const bool rtl = groupBox.direction == Qt::RightToLeft;
const int alignment = Qt::TextHideMnemonic | (rtl ? Qt::AlignRight : Qt::AlignLeft);
const QFont savedFont = p->font();
- if (!flat)
- p->setFont(d->smallSystemFont);
+ if (!flat && d->smallSystemFont)
+ p->setFont(*d->smallSystemFont);
proxy()->drawItemText(p, rect, alignment, groupBox.palette, groupBox.state & State_Enabled, groupBox.text, QPalette::WindowText);
if (!flat)
p->setFont(savedFont);
@@ -5648,7 +5627,7 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex
case CC_ToolButton:
if (const QStyleOptionToolButton *tb
= qstyleoption_cast<const QStyleOptionToolButton *>(opt)) {
-#ifndef QT_NO_ACCESSIBILITY
+#if QT_CONFIG(accessibility)
if (QStyleHelper::hasAncestor(opt->styleObject, QAccessible::ToolBar)) {
if (tb->subControls & SC_ToolButtonMenu) {
QStyleOption arrowOpt = *tb;
@@ -5674,7 +5653,7 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex
}
proxy()->drawControl(CE_ToolButtonLabel, opt, p, widget);
} else
-#endif // QT_NO_ACCESSIBILITY
+#endif // QT_CONFIG(accessibility)
{
auto bflags = tb->state;
if (tb->subControls & SC_ToolButton)
@@ -5692,12 +5671,12 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex
const auto cs = d->effectiveAquaSizeConstrain(opt, widget);
const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
auto *pb = static_cast<NSButton *>(d->cocoaControl(cw));
- pb.bezelStyle = NSShadowlessSquareBezelStyle; // TODO Use NSTexturedRoundedBezelStyle in the future.
+ pb.bezelStyle = NSBezelStyleShadowlessSquare; // TODO Use NSTexturedRoundedBezelStyle in the future.
pb.frame = opt->rect.toCGRect();
- pb.buttonType = NSPushOnPushOffButton;
+ pb.buttonType = NSButtonTypePushOnPushOff;
pb.enabled = isEnabled;
[pb highlight:isPressed];
- pb.state = isHighlighted && !isPressed ? NSOnState : NSOffState;
+ pb.state = isHighlighted && !isPressed ? NSControlStateValueOn : NSControlStateValueOff;
const auto buttonRect = proxy()->subControlRect(cc, tb, SC_ToolButton, widget);
d->drawNSViewInRect(pb, buttonRect, p, ^(CGContextRef, const CGRect &rect) {
[pb.cell drawBezelWithFrame:rect inView:pb];
@@ -5764,10 +5743,9 @@ QStyle::SubControl QMacStyle::hitTestComplexControl(ComplexControl cc,
if (!setupSlider(slider, sl))
break;
- [slider calcSize];
NSSliderCell *cell = slider.cell;
- const auto barRect = QRectF::fromCGRect([cell barRectFlipped:hasTicks]);
- const auto knobRect = QRectF::fromCGRect([cell knobRectFlipped:NO]);
+ const auto barRect = QRectF::fromCGRect([cell barRectFlipped:slider.isFlipped]);
+ const auto knobRect = QRectF::fromCGRect([cell knobRectFlipped:slider.isFlipped]);
if (knobRect.contains(pt)) {
sc = SC_SliderHandle;
} else if (barRect.contains(pt)) {
@@ -5869,10 +5847,9 @@ QRect QMacStyle::subControlRect(ComplexControl cc, const QStyleOptionComplex *op
if (!setupSlider(slider, sl))
break;
- [slider calcSize];
NSSliderCell *cell = slider.cell;
if (sc == SC_SliderHandle) {
- ret = QRectF::fromCGRect([cell knobRectFlipped:NO]).toRect();
+ ret = QRectF::fromCGRect([cell knobRectFlipped:slider.isFlipped]).toRect();
if (isHorizontal) {
ret.setTop(sl->rect.top());
ret.setBottom(sl->rect.bottom());
@@ -5881,7 +5858,7 @@ QRect QMacStyle::subControlRect(ComplexControl cc, const QStyleOptionComplex *op
ret.setRight(sl->rect.right());
}
} else if (sc == SC_SliderGroove) {
- ret = QRectF::fromCGRect([cell barRectFlipped:hasTicks]).toRect();
+ ret = QRectF::fromCGRect([cell barRectFlipped:slider.isFlipped]).toRect();
} else if (hasTicks && sc == SC_SliderTickmarks) {
const auto tickMarkRect = QRectF::fromCGRect([cell rectOfTickMarkAtIndex:0]);
if (isHorizontal)
@@ -5923,7 +5900,7 @@ QRect QMacStyle::subControlRect(ComplexControl cc, const QStyleOptionComplex *op
qreal controlsSpacing = lastButtonRect.right() + titleBarButtonSpacing;
if (!titlebar->icon.isNull()) {
const auto iconSize = proxy()->pixelMetric(PM_SmallIconSize);
- const auto actualIconSize = titlebar->icon.actualSize(QSize(iconSize, iconSize)).width();;
+ const auto actualIconSize = titlebar->icon.actualSize(QSize(iconSize, iconSize)).width();
controlsSpacing += actualIconSize + titleBarIconTitleSpacing;
}
@@ -6004,7 +5981,9 @@ QRect QMacStyle::subControlRect(ComplexControl cc, const QStyleOptionComplex *op
const int margin = flat || hasNoText ? 0 : 9;
ret = groupBox->rect.adjusted(margin, 0, -margin, 0);
- const QFontMetricsF fm = flat || fontIsSet ? QFontMetricsF(groupBox->fontMetrics) : QFontMetricsF(d->smallSystemFont);
+ const QFontMetricsF fm = flat || fontIsSet || !d->smallSystemFont
+ ? QFontMetricsF(groupBox->fontMetrics)
+ : QFontMetricsF(*d->smallSystemFont);
const QSizeF s = fm.size(Qt::AlignHCenter | Qt::AlignVCenter, qt_mac_removeMnemonics(groupBox->text), 0, nullptr);
const int tw = qCeil(s.width());
const int h = qCeil(fm.height());
@@ -6158,7 +6137,7 @@ QRect QMacStyle::subControlRect(ComplexControl cc, const QStyleOptionComplex *op
case CC_ToolButton:
ret = QCommonStyle::subControlRect(cc, opt, sc, widget);
if (sc == SC_ToolButtonMenu) {
-#ifndef QT_NO_ACCESSIBILITY
+#if QT_CONFIG(accessibility)
if (QStyleHelper::hasAncestor(opt->styleObject, QAccessible::ToolBar))
ret.adjust(-toolButtonArrowMargin, 0, 0, 0);
#endif
@@ -6314,14 +6293,16 @@ QSize QMacStyle::sizeFromContents(ContentsType ct, const QStyleOption *opt,
break;
#endif
case QStyle::CT_PushButton: {
- if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt))
+ bool isFlat = false;
+ if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
if (btn->features & QStyleOptionButton::CommandLinkButton)
return QCommonStyle::sizeFromContents(ct, opt, sz, widget);
+ isFlat = btn->features & QStyleOptionButton::Flat;
+ }
// By default, we fit the contents inside a normal rounded push button.
// Do this by add enough space around the contents so that rounded
// borders (including highlighting when active) will show.
- // TODO Use QFocusFrame and get rid of these horrors.
QSize macsz;
const auto controlSize = d->effectiveAquaSizeConstrain(opt, widget, CT_PushButton, sz, &macsz);
// FIXME See comment in CT_PushButton case in qt_aqua_get_known_size().
@@ -6332,12 +6313,24 @@ QSize QMacStyle::sizeFromContents(ContentsType ct, const QStyleOption *opt,
// All values as measured from HIThemeGetButtonBackgroundBounds()
if (controlSize != QStyleHelper::SizeMini)
sz.rwidth() += 12; // We like 12 over here.
- if (controlSize == QStyleHelper::SizeLarge && sz.height() > 16)
- sz.rheight() += pushButtonDefaultHeight[QStyleHelper::SizeLarge] - 16;
- else if (controlSize == QStyleHelper::SizeMini)
- sz.setHeight(24); // FIXME Our previous HITheme-based logic returned this.
- else
- sz.setHeight(pushButtonDefaultHeight[controlSize]);
+
+ if (controlSize == QStyleHelper::SizeLarge) {
+ if (!isFlat)
+ sz.rwidth() -= 12;
+ if (sz.height() > 16)
+ sz.rheight() += pushButtonDefaultHeight[QStyleHelper::SizeLarge] - 16;
+ else
+ sz.setHeight(pushButtonDefaultHeight[QStyleHelper::SizeLarge]);
+ } else {
+ if (!isFlat)
+ sz.rwidth() -= 10;
+ if (controlSize == QStyleHelper::SizeMini)
+ sz.setHeight(24);
+ else
+ sz.setHeight(pushButtonDefaultHeight[QStyleHelper::SizeSmall]);
+ }
+ if (isFlat)
+ sz.rwidth() -= 13;
break;
}
case QStyle::CT_MenuItem:
@@ -6408,9 +6401,9 @@ QSize QMacStyle::sizeFromContents(ContentsType ct, const QStyleOption *opt,
if (const auto *cb = qstyleoption_cast<const QStyleOptionComboBox *>(opt)) {
const auto controlSize = d->effectiveAquaSizeConstrain(opt, widget);
if (!cb->editable) {
- // Same as CT_PushButton, because we have to fit the focus
+ // See CT_PushButton; we have to fit the focus
// ring and a non-editable combo box is a NSPopUpButton.
- sz.rwidth() += QMacStylePrivate::PushButtonLeftOffset + QMacStylePrivate::PushButtonRightOffset + 12;
+ sz.rwidth() += QMacStylePrivate::PushButtonLeftOffset + QMacStylePrivate::PushButtonRightOffset + 24;
// All values as measured from HIThemeGetButtonBackgroundBounds()
if (controlSize != QStyleHelper::SizeMini)
sz.rwidth() += 12; // We like 12 over here.
@@ -6503,7 +6496,7 @@ QSize QMacStyle::sizeFromContents(ContentsType ct, const QStyleOption *opt,
void QMacStyle::drawItemText(QPainter *p, const QRect &r, int flags, const QPalette &pal,
bool enabled, const QString &text, QPalette::ColorRole textRole) const
{
- if(flags & Qt::TextShowMnemonic)
+ if (flags & Qt::TextShowMnemonic)
flags |= Qt::TextHideMnemonic;
QCommonStyle::drawItemText(p, r, flags, pal, enabled, text, textRole);
}
@@ -6511,8 +6504,8 @@ void QMacStyle::drawItemText(QPainter *p, const QRect &r, int flags, const QPale
bool QMacStyle::event(QEvent *e)
{
Q_D(QMacStyle);
- if(e->type() == QEvent::FocusIn) {
- QWidget *f = 0;
+ if (e->type() == QEvent::FocusIn) {
+ QWidget *f = nullptr;
QWidget *focusWidget = QApplication::focusWidget();
#if QT_CONFIG(graphicsview)
if (QGraphicsView *graphicsView = qobject_cast<QGraphicsView *>(focusWidget)) {
@@ -6534,14 +6527,14 @@ bool QMacStyle::event(QEvent *e)
f = focusWidget;
}
if (f) {
- if(!d->focusWidget)
+ if (!d->focusWidget)
d->focusWidget = new QFocusFrame(f);
d->focusWidget->setWidget(f);
- } else if(d->focusWidget) {
+ } else if (d->focusWidget) {
d->focusWidget->setWidget(0);
}
- } else if(e->type() == QEvent::FocusOut) {
- if(d->focusWidget)
+ } else if (e->type() == QEvent::FocusOut) {
+ if (d->focusWidget)
d->focusWidget->setWidget(0);
}
return false;
@@ -6555,7 +6548,7 @@ QIcon QMacStyle::standardIcon(StandardPixmap standardIcon, const QStyleOption *o
return QCommonStyle::standardIcon(standardIcon, opt, widget);
case SP_ToolBarHorizontalExtensionButton:
case SP_ToolBarVerticalExtensionButton: {
- QPixmap pixmap(QLatin1String(":/qt-project.org/styles/macstyle/images/toolbar-ext.png"));
+ QPixmap pixmap(QLatin1String(":/qt-project.org/styles/macstyle/images/toolbar-ext-macstyle.png"));
if (standardIcon == SP_ToolBarVerticalExtensionButton) {
QPixmap pix2(pixmap.height(), pixmap.width());
pix2.setDevicePixelRatio(pixmap.devicePixelRatio());
diff --git a/src/plugins/styles/mac/qmacstyle_mac_p.h b/src/plugins/styles/mac/qmacstyle_mac_p.h
index 88f104cccf..99c8d1fec4 100644
--- a/src/plugins/styles/mac/qmacstyle_mac_p.h
+++ b/src/plugins/styles/mac/qmacstyle_mac_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtWidgets module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QMACSTYLE_MAC_P_H
#define QMACSTYLE_MAC_P_H
@@ -77,28 +41,28 @@ public:
void polish(QPalette &pal);
void drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPainter *p,
- const QWidget *w = 0) const;
+ const QWidget *w = nullptr) const;
void drawControl(ControlElement element, const QStyleOption *opt, QPainter *p,
- const QWidget *w = 0) const;
- QRect subElementRect(SubElement r, const QStyleOption *opt, const QWidget *widget = 0) const;
+ const QWidget *w = nullptr) const;
+ QRect subElementRect(SubElement r, const QStyleOption *opt, const QWidget *widget = nullptr) const;
void drawComplexControl(ComplexControl cc, const QStyleOptionComplex *opt, QPainter *p,
- const QWidget *w = 0) const;
+ const QWidget *w = nullptr) const;
SubControl hitTestComplexControl(ComplexControl cc, const QStyleOptionComplex *opt,
- const QPoint &pt, const QWidget *w = 0) const;
+ const QPoint &pt, const QWidget *w = nullptr) const;
QRect subControlRect(ComplexControl cc, const QStyleOptionComplex *opt, SubControl sc,
- const QWidget *w = 0) const;
+ const QWidget *w = nullptr) const;
QSize sizeFromContents(ContentsType ct, const QStyleOption *opt,
- const QSize &contentsSize, const QWidget *w = 0) const;
+ const QSize &contentsSize, const QWidget *w = nullptr) const;
- int pixelMetric(PixelMetric pm, const QStyleOption *opt = 0, const QWidget *widget = 0) const;
+ int pixelMetric(PixelMetric pm, const QStyleOption *opt = 0, const QWidget *widget = nullptr) const;
QPalette standardPalette() const;
- virtual int styleHint(StyleHint sh, const QStyleOption *opt = 0, const QWidget *w = 0,
- QStyleHintReturn *shret = 0) const;
+ virtual int styleHint(StyleHint sh, const QStyleOption *opt = 0, const QWidget *w = nullptr,
+ QStyleHintReturn *shret = nullptr) const;
QPixmap standardPixmap(StandardPixmap sp, const QStyleOption *opt,
- const QWidget *widget = 0) const;
+ const QWidget *widget = nullptr) const;
QPixmap generatedIconPixmap(QIcon::Mode iconMode, const QPixmap &pixmap,
const QStyleOption *opt) const;
@@ -108,11 +72,11 @@ public:
bool event(QEvent *e);
- QIcon standardIcon(StandardPixmap standardIcon, const QStyleOption *opt = 0,
- const QWidget *widget = 0) const;
+ QIcon standardIcon(StandardPixmap standardIcon, const QStyleOption *opt = nullptr,
+ const QWidget *widget = nullptr) const;
int layoutSpacing(QSizePolicy::ControlType control1, QSizePolicy::ControlType control2,
- Qt::Orientation orientation, const QStyleOption *option = 0,
- const QWidget *widget = 0) const;
+ Qt::Orientation orientation, const QStyleOption *option = nullptr,
+ const QWidget *widget = nullptr) const;
private:
Q_DISABLE_COPY_MOVE(QMacStyle)
diff --git a/src/plugins/styles/mac/qmacstyle_mac_p_p.h b/src/plugins/styles/mac/qmacstyle_mac_p_p.h
index 274936bd79..0dcfce2f0c 100644
--- a/src/plugins/styles/mac/qmacstyle_mac_p_p.h
+++ b/src/plugins/styles/mac/qmacstyle_mac_p_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtWidgets module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QMACSTYLE_MAC_P_P_H
@@ -45,12 +9,11 @@
#include <QtCore/qdebug.h>
#include <QtCore/qhash.h>
+#include <QtCore/qlist.h>
#include <QtCore/qmap.h>
#include <QtCore/qmath.h>
-#include <QtCore/qpair.h>
#include <QtCore/qpointer.h>
#include <QtCore/qtextstream.h>
-#include <QtCore/qvector.h>
#include <QtGui/private/qpainter_p.h>
@@ -291,15 +254,14 @@ public:
public:
mutable QPointer<QObject> autoDefaultButton;
- static QVector<QPointer<QObject> > scrollBars;
+ static QList<QPointer<QObject> > scrollBars;
mutable QPointer<QFocusFrame> focusWidget;
mutable NSView *backingStoreNSView;
mutable QHash<CocoaControl, NSView *> cocoaControls;
mutable QHash<CocoaControl, NSCell *> cocoaCells;
- QFont smallSystemFont;
- QFont miniSystemFont;
+ std::optional<QFont> smallSystemFont;
QMacKeyValueObserver appearanceObserver;
};
diff --git a/src/plugins/styles/windowsvista/CMakeLists.txt b/src/plugins/styles/modernwindows/CMakeLists.txt
index 008fa624fe..985bce3a2d 100644
--- a/src/plugins/styles/windowsvista/CMakeLists.txt
+++ b/src/plugins/styles/modernwindows/CMakeLists.txt
@@ -1,27 +1,27 @@
-# Generated from windowsvista.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## QWindowsVistaStylePlugin Plugin:
#####################################################################
-qt_add_plugin(QWindowsVistaStylePlugin
- OUTPUT_NAME qwindowsvistastyle
- TYPE styles
+qt_internal_add_plugin(QModernWindowsStylePlugin
+ OUTPUT_NAME qmodernwindowsstyle
+ PLUGIN_TYPE styles
SOURCES
main.cpp
qwindowsvistastyle.cpp qwindowsvistastyle_p.h
+ qwindows11style.cpp qwindows11style_p.h
qwindowsvistastyle_p_p.h
- qwindowsxpstyle.cpp qwindowsxpstyle_p.h
- qwindowsxpstyle_p_p.h
+ qwindowsvistaanimation.cpp qwindowsvistaanimation_p.h
+ qwindowsthemedata.cpp qwindowsthemedata_p.h
+
LIBRARIES
gdi32
user32
uxtheme
- PUBLIC_LIBRARIES
Qt::Core
Qt::Gui
+ Qt::GuiPrivate
Qt::WidgetsPrivate
)
-
-#### Keys ignored in scope 1:.:.:windowsvista.pro:<TRUE>:
-# DISTFILES = "windowsvistastyle.json"
diff --git a/src/plugins/styles/modernwindows/main.cpp b/src/plugins/styles/modernwindows/main.cpp
new file mode 100644
index 0000000000..a4d8e60385
--- /dev/null
+++ b/src/plugins/styles/modernwindows/main.cpp
@@ -0,0 +1,36 @@
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <QtWidgets/private/qtwidgetsglobal_p.h>
+#include <QtWidgets/qstyleplugin.h>
+#include <QtCore/qoperatingsystemversion.h>
+#include "qwindowsvistastyle_p.h"
+#include "qwindows11style_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QModernWindowsStylePlugin : public QStylePlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QStyleFactoryInterface" FILE "modernwindowsstyles.json")
+public:
+ QStyle *create(const QString &key) override;
+};
+
+QStyle *QModernWindowsStylePlugin::create(const QString &key)
+{
+ bool isWin11OrAbove = QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows11;
+ if (isWin11OrAbove && key.compare(QLatin1String("windows11"), Qt::CaseInsensitive) == 0) {
+ return new QWindows11Style();
+ } else if (!isWin11OrAbove && key.compare(QLatin1String("windows11"), Qt::CaseInsensitive) == 0) {
+ qWarning("QWindows11Style: Style is only supported on Windows11 and above");
+ return new QWindowsVistaStyle();
+ } else if (key.compare(QLatin1String("windowsvista"), Qt::CaseInsensitive) == 0) {
+ return new QWindowsVistaStyle();
+ }
+ return nullptr;
+}
+
+QT_END_NAMESPACE
+
+#include "main.moc"
diff --git a/src/plugins/styles/modernwindows/modernwindowsstyles.json b/src/plugins/styles/modernwindows/modernwindowsstyles.json
new file mode 100644
index 0000000000..e9cef558e8
--- /dev/null
+++ b/src/plugins/styles/modernwindows/modernwindowsstyles.json
@@ -0,0 +1,3 @@
+{
+ "Keys": [ "windowsvista", "windows11" ]
+}
diff --git a/src/plugins/styles/modernwindows/qwindows11style.cpp b/src/plugins/styles/modernwindows/qwindows11style.cpp
new file mode 100644
index 0000000000..f352b7e1af
--- /dev/null
+++ b/src/plugins/styles/modernwindows/qwindows11style.cpp
@@ -0,0 +1,2116 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qwindows11style_p.h"
+#include <qstylehints.h>
+#include <private/qstyleanimation_p.h>
+#include <private/qstylehelper_p.h>
+#include <private/qapplication_p.h>
+#include <qstyleoption.h>
+#include <qpainter.h>
+#include <QGraphicsDropShadowEffect>
+
+#include "qdrawutil.h"
+#include <chrono>
+
+QT_BEGIN_NAMESPACE
+
+const static int topLevelRoundingRadius = 8; //Radius for toplevel items like popups for round corners
+const static int secondLevelRoundingRadius = 4; //Radius for second level items like hovered menu item round corners
+
+enum WINUI3Color {
+ subtleHighlightColor, //Subtle highlight based on alpha used for hovered elements
+ subtlePressedColor, //Subtle highlight based on alpha used for pressed elements
+ frameColorLight, //Color of frame around flyouts and controls except for Checkbox and Radiobutton
+ frameColorStrong, //Color of frame around Checkbox and Radiobuttons
+ controlStrongFill, //Color of controls with strong filling such as the right side of a slider
+ controlStrokeSecondary,
+ controlStrokePrimary,
+ controlFillTertiary, //Color of filled sunken controls
+ controlFillSecondary, //Color of filled hovered controls
+ menuPanelFill, //Color of menu panel
+ textOnAccentPrimary, //Color of text on controls filled in accent color
+ textOnAccentSecondary, //Color of text of sunken controls in accent color
+ controlTextSecondary, //Color of text of sunken controls
+ controlStrokeOnAccentSecondary, //Color of frame around Buttons in accent color
+ controlFillSolid, //Color for solid fill
+ surfaceStroke, //Color of MDI window frames
+};
+
+const static QColor WINUI3ColorsLight [] {
+ QColor(0x00,0x00,0x00,0x09), //subtleHighlightColor
+ QColor(0x00,0x00,0x00,0x06), //subtlePressedColor
+ QColor(0x00,0x00,0x00,0x0F), //frameColorLight
+ QColor(0x00,0x00,0x00,0x9c), //frameColorStrong
+ QColor(0x00,0x00,0x00,0x72), //controlStrongFill
+ QColor(0x00,0x00,0x00,0x29), //controlStrokeSecondary
+ QColor(0x00,0x00,0x00,0x14), //controlStrokePrimary
+ QColor(0xF9,0xF9,0xF9,0x00), //controlFillTertiary
+ QColor(0xF9,0xF9,0xF9,0x80), //controlFillSecondary
+ QColor(0xFF,0xFF,0xFF,0xFF), //menuPanelFill
+ QColor(0xFF,0xFF,0xFF,0xFF), //textOnAccentPrimary
+ QColor(0xFF,0xFF,0xFF,0x7F), //textOnAccentSecondary
+ QColor(0x00,0x00,0x00,0x7F), //controlTextSecondary
+ QColor(0x00,0x00,0x00,0x66), //controlStrokeOnAccentSecondary
+ QColor(0xFF,0xFF,0xFF,0xFF), //controlFillSolid
+ QColor(0x75,0x75,0x75,0x66), //surfaceStroke
+};
+
+const static QColor WINUI3ColorsDark[] {
+ QColor(0xFF,0xFF,0xFF,0x0F), //subtleHighlightColor
+ QColor(0xFF,0xFF,0xFF,0x0A), //subtlePressedColor
+ QColor(0xFF,0xFF,0xFF,0x12), //frameColorLight
+ QColor(0xFF,0xFF,0xFF,0x8B), //frameColorStrong
+ QColor(0xFF,0xFF,0xFF,0x8B), //controlStrongFill
+ QColor(0xFF,0xFF,0xFF,0x18), //controlStrokeSecondary
+ QColor(0xFF,0xFF,0xFF,0x12), //controlStrokePrimary
+ QColor(0xF9,0xF9,0xF9,0x00), //controlFillTertiary
+ QColor(0xF9,0xF9,0xF9,0x80), //controlFillSecondary
+ QColor(0x0F,0x0F,0x0F,0xFF), //menuPanelFill
+ QColor(0x00,0x00,0x00,0xFF), //textOnAccentPrimary
+ QColor(0x00,0x00,0x00,0x80), //textOnAccentSecondary
+ QColor(0xFF,0xFF,0xFF,0x87), //controlTextSecondary
+ QColor(0xFF,0xFF,0xFF,0x14), //controlStrokeOnAccentSecondary
+ QColor(0x45,0x45,0x45,0xFF), //controlFillSolid
+ QColor(0x75,0x75,0x75,0x66), //surfaceStroke
+};
+
+const static QColor* WINUI3Colors[] {
+ WINUI3ColorsLight,
+ WINUI3ColorsDark
+};
+
+const QColor shellCloseButtonColor(0xC4,0x2B,0x1C,0xFF); //Color of close Button in Titlebar
+
+#if QT_CONFIG(toolbutton)
+static void drawArrow(const QStyle *style, const QStyleOptionToolButton *toolbutton,
+ const QRect &rect, QPainter *painter, const QWidget *widget = nullptr)
+{
+ QStyle::PrimitiveElement pe;
+ switch (toolbutton->arrowType) {
+ case Qt::LeftArrow:
+ pe = QStyle::PE_IndicatorArrowLeft;
+ break;
+ case Qt::RightArrow:
+ pe = QStyle::PE_IndicatorArrowRight;
+ break;
+ case Qt::UpArrow:
+ pe = QStyle::PE_IndicatorArrowUp;
+ break;
+ case Qt::DownArrow:
+ pe = QStyle::PE_IndicatorArrowDown;
+ break;
+ default:
+ return;
+ }
+ QStyleOption arrowOpt = *toolbutton;
+ arrowOpt.rect = rect;
+ style->drawPrimitive(pe, &arrowOpt, painter, widget);
+}
+#endif // QT_CONFIG(toolbutton)
+/*!
+ \class QWindows11Style
+ \brief The QWindows11Style class provides a look and feel suitable for applications on Microsoft Windows 11.
+ \since 6.6
+ \ingroup appearance
+ \inmodule QtWidgets
+ \internal
+
+ \warning This style is only available on the Windows 11 platform and above.
+
+ \sa QWindows11Style QWindowsVistaStyle, QMacStyle, QFusionStyle
+*/
+
+/*!
+ Constructs a QWindows11Style object.
+*/
+QWindows11Style::QWindows11Style() : QWindowsVistaStyle(*new QWindows11StylePrivate)
+{
+}
+
+/*!
+ \internal
+ Constructs a QWindows11Style object.
+*/
+QWindows11Style::QWindows11Style(QWindows11StylePrivate &dd) : QWindowsVistaStyle(dd)
+{
+}
+
+/*!
+ Destructor.
+*/
+QWindows11Style::~QWindows11Style() = default;
+
+/*!
+ \internal
+ see drawPrimitive for comments on the animation support
+
+ */
+void QWindows11Style::drawComplexControl(ComplexControl control, const QStyleOptionComplex *option,
+ QPainter *painter, const QWidget *widget) const
+{
+ QWindows11StylePrivate *d = const_cast<QWindows11StylePrivate*>(d_func());
+
+ State state = option->state;
+ SubControls sub = option->subControls;
+ State flags = option->state;
+ if (widget && widget->testAttribute(Qt::WA_UnderMouse) && widget->isActiveWindow())
+ flags |= State_MouseOver;
+
+ painter->save();
+ painter->setRenderHint(QPainter::Antialiasing);
+ if (d->transitionsEnabled()) {
+ if (control == CC_Slider) {
+ if (const auto *slider = qstyleoption_cast<const QStyleOptionSlider *>(option)) {
+ QObject *styleObject = option->styleObject; // Can be widget or qquickitem
+
+ QRectF thumbRect = proxy()->subControlRect(CC_Slider, option, SC_SliderHandle, widget);
+ auto center = thumbRect.center();
+ const qreal outerRadius = qMin(8.0, (slider->orientation == Qt::Horizontal ? thumbRect.height() / 2.0 : thumbRect.width() / 2.0) - 1);
+
+ thumbRect.setWidth(outerRadius);
+ thumbRect.setHeight(outerRadius);
+ thumbRect.moveCenter(center);
+ QPointF cursorPos = widget ? widget->mapFromGlobal(QCursor::pos()) : QPointF();
+ bool isInsideHandle = thumbRect.contains(cursorPos);
+
+ bool oldIsInsideHandle = styleObject->property("_q_insidehandle").toBool();
+ int oldState = styleObject->property("_q_stylestate").toInt();
+ int oldActiveControls = styleObject->property("_q_stylecontrols").toInt();
+
+ QRectF oldRect = styleObject->property("_q_stylerect").toRect();
+ styleObject->setProperty("_q_insidehandle", isInsideHandle);
+ styleObject->setProperty("_q_stylestate", int(option->state));
+ styleObject->setProperty("_q_stylecontrols", int(option->activeSubControls));
+ styleObject->setProperty("_q_stylerect", option->rect);
+ if (option->styleObject->property("_q_end_radius").isNull())
+ option->styleObject->setProperty("_q_end_radius", outerRadius * 0.43);
+
+ bool doTransition = (((state & State_Sunken) != (oldState & State_Sunken)
+ || ((oldIsInsideHandle) != (isInsideHandle))
+ || oldActiveControls != int(option->activeSubControls))
+ && state & State_Enabled);
+
+ if (oldRect != option->rect) {
+ doTransition = false;
+ d->stopAnimation(styleObject);
+ styleObject->setProperty("_q_inner_radius", outerRadius * 0.43);
+ }
+
+ if (doTransition) {
+ QNumberStyleAnimation *t = new QNumberStyleAnimation(styleObject);
+ t->setStartValue(styleObject->property("_q_inner_radius").toFloat());
+ if (state & State_Sunken)
+ t->setEndValue(outerRadius * 0.29);
+ else if (isInsideHandle)
+ t->setEndValue(outerRadius * 0.71);
+ else
+ t->setEndValue(outerRadius * 0.43);
+
+ styleObject->setProperty("_q_end_radius", t->endValue());
+
+ t->setStartTime(d->animationTime());
+ t->setDuration(150);
+ d->startAnimation(t);
+ }
+ }
+ }
+ }
+
+ switch (control) {
+#if QT_CONFIG(spinbox)
+ case CC_SpinBox:
+ if (const QStyleOptionSpinBox *sb = qstyleoption_cast<const QStyleOptionSpinBox *>(option)) {
+ if (sb->frame && (sub & SC_SpinBoxFrame)) {
+ painter->save();
+ QRegion clipRegion = option->rect;
+ clipRegion -= option->rect.adjusted(2, 2, -2, -2);
+ painter->setClipRegion(clipRegion);
+ QColor lineColor = state & State_HasFocus ? option->palette.accent().color() : QColor(0,0,0);
+ painter->setPen(QPen(lineColor));
+ painter->drawLine(option->rect.bottomLeft() + QPointF(7,-0.5), option->rect.bottomRight() + QPointF(-7,-0.5));
+ painter->restore();
+ }
+ QRectF frameRect = option->rect;
+ frameRect.adjust(0.5,0.5,-0.5,-0.5);
+ QBrush fillColor = option->palette.brush(QPalette::Base);
+ painter->setBrush(fillColor);
+ painter->setPen(QPen(highContrastTheme == true ? sb->palette.buttonText().color() : WINUI3Colors[colorSchemeIndex][frameColorLight]));
+ painter->drawRoundedRect(frameRect.adjusted(2,2,-2,-2), secondLevelRoundingRadius, secondLevelRoundingRadius);
+ QPoint mousePos = widget ? widget->mapFromGlobal(QCursor::pos()) : QPoint();
+ QColor hoverColor = WINUI3Colors[colorSchemeIndex][subtleHighlightColor];
+ if (sub & SC_SpinBoxEditField) {
+ QRect rect = proxy()->subControlRect(CC_SpinBox, option, SC_SpinBoxEditField, widget).adjusted(0, 0, 0, 1);
+ if (rect.contains(mousePos) && !(state & State_HasFocus)) {
+ QBrush fillColor = QBrush(WINUI3Colors[colorSchemeIndex][subtleHighlightColor]);
+ painter->setBrush(fillColor);
+ painter->setPen(Qt::NoPen);
+ painter->drawRoundedRect(option->rect.adjusted(2,2,-2,-2), secondLevelRoundingRadius, secondLevelRoundingRadius);
+ }
+ }
+ if (sub & SC_SpinBoxUp) {
+ QRect rect = proxy()->subControlRect(CC_SpinBox, option, SC_SpinBoxUp, widget).adjusted(0, 0, 0, 1);
+ float scale = rect.width() >= 16 ? 1.0 : rect.width()/16.0;
+ if (rect.contains(mousePos)) {
+ painter->setPen(Qt::NoPen);
+ painter->setBrush(QBrush(hoverColor));
+ painter->drawRoundedRect(rect.adjusted(1,1,-1,-1),secondLevelRoundingRadius, secondLevelRoundingRadius);
+ }
+ painter->save();
+ painter->translate(rect.center());
+ painter->scale(scale,scale);
+ painter->translate(-rect.center());
+ painter->setFont(assetFont);
+ painter->setPen(sb->palette.buttonText().color());
+ painter->setBrush(Qt::NoBrush);
+ painter->drawText(rect,"\uE018", Qt::AlignVCenter | Qt::AlignHCenter);
+ painter->restore();
+ }
+ if (sub & SC_SpinBoxDown) {
+ QRect rect = proxy()->subControlRect(CC_SpinBox, option, SC_SpinBoxDown, widget);
+ float scale = rect.width() >= 16 ? 1.0 : rect.width()/16.0;
+ if (rect.contains(mousePos)) {
+ painter->setPen(Qt::NoPen);
+ painter->setBrush(QBrush(hoverColor));
+ painter->drawRoundedRect(rect.adjusted(1,1,-1,-1), secondLevelRoundingRadius, secondLevelRoundingRadius);
+ }
+ painter->save();
+ painter->translate(rect.center());
+ painter->scale(scale,scale);
+ painter->translate(-rect.center());
+ painter->setFont(assetFont);
+ painter->setPen(sb->palette.buttonText().color());
+ painter->setBrush(Qt::NoBrush);
+ painter->drawText(rect,"\uE019", Qt::AlignVCenter | Qt::AlignHCenter);
+ painter->restore();
+ }
+ }
+ break;
+#endif // QT_CONFIG(spinbox)
+#if QT_CONFIG(slider)
+ case CC_Slider:
+ if (const auto *slider = qstyleoption_cast<const QStyleOptionSlider *>(option)) {
+ QRectF slrect = slider->rect;
+ QRegion tickreg = slrect.toRect();
+
+ if (sub & SC_SliderGroove) {
+ QRectF rect = proxy()->subControlRect(CC_Slider, option, SC_SliderGroove, widget);
+ QRectF handleRect = proxy()->subControlRect(CC_Slider, option, SC_SliderHandle, widget);
+ QPointF handlePos = handleRect.center();
+ QRectF leftRect;
+ QRectF rightRect;
+
+ if (slider->orientation == Qt::Horizontal) {
+ rect = QRect(slrect.left(), rect.center().y() - 2, slrect.width() - 5, 4);
+ leftRect = QRect(rect.left(), rect.top(), (handlePos.x() - rect.left()), rect.height());
+ rightRect = QRect(handlePos.x(), rect.top(), (rect.width() - handlePos.x()), rect.height());
+ } else {
+ rect = QRect(rect.center().x() - 2, slrect.top(), 4, slrect.height() - 5);
+ rightRect = QRect(rect.left(), rect.top(), rect.width(), (handlePos.y() - rect.top()));
+ leftRect = QRect(rect.left(), handlePos.y(), rect.width(), (rect.height() - handlePos.y()));
+ }
+
+ painter->setPen(Qt::NoPen);
+ painter->setBrush(option->palette.accent());
+ painter->drawRoundedRect(leftRect,1,1);
+ painter->setBrush(QBrush(WINUI3Colors[colorSchemeIndex][controlStrongFill]));
+ painter->drawRoundedRect(rightRect,1,1);
+
+ painter->setPen(QPen(highContrastTheme == true ? slider->palette.buttonText().color() : WINUI3Colors[colorSchemeIndex][frameColorLight]));
+ painter->setBrush(Qt::NoBrush);
+ painter->drawRoundedRect(leftRect,1.5,1.5);
+ painter->drawRoundedRect(rightRect,1.5,1.5);
+
+ tickreg -= rect.toRect();
+ }
+ if (sub & SC_SliderTickmarks) {
+ int tickOffset = proxy()->pixelMetric(PM_SliderTickmarkOffset, slider, widget);
+ int ticks = slider->tickPosition;
+ int thickness = proxy()->pixelMetric(PM_SliderControlThickness, slider, widget);
+ int len = proxy()->pixelMetric(PM_SliderLength, slider, widget);
+ int available = proxy()->pixelMetric(PM_SliderSpaceAvailable, slider, widget);
+ int interval = slider->tickInterval;
+ if (interval <= 0) {
+ interval = slider->singleStep;
+ if (QStyle::sliderPositionFromValue(slider->minimum, slider->maximum, interval,
+ available)
+ - QStyle::sliderPositionFromValue(slider->minimum, slider->maximum,
+ 0, available) < 3)
+ interval = slider->pageStep;
+ }
+ if (!interval)
+ interval = 1;
+ int fudge = len / 2;
+ int pos;
+ int bothOffset = (ticks & QSlider::TicksAbove && ticks & QSlider::TicksBelow) ? 1 : 0;
+ painter->setPen(slider->palette.text().color());
+ QVarLengthArray<QLine, 32> lines;
+ int v = slider->minimum;
+ while (v <= slider->maximum + 1) {
+ if (v == slider->maximum + 1 && interval == 1)
+ break;
+ const int v_ = qMin(v, slider->maximum);
+ int tickLength = (v_ == slider->minimum || v_ >= slider->maximum) ? 4 : 3;
+ pos = QStyle::sliderPositionFromValue(slider->minimum, slider->maximum,
+ v_, available) + fudge;
+ if (slider->orientation == Qt::Horizontal) {
+ if (ticks & QSlider::TicksAbove) {
+ lines.append(QLine(pos, tickOffset - 1 - bothOffset,
+ pos, tickOffset - 1 - bothOffset - tickLength));
+ }
+
+ if (ticks & QSlider::TicksBelow) {
+ lines.append(QLine(pos, tickOffset + thickness + bothOffset,
+ pos, tickOffset + thickness + bothOffset + tickLength));
+ }
+ } else {
+ if (ticks & QSlider::TicksAbove) {
+ lines.append(QLine(tickOffset - 1 - bothOffset, pos,
+ tickOffset - 1 - bothOffset - tickLength, pos));
+ }
+
+ if (ticks & QSlider::TicksBelow) {
+ lines.append(QLine(tickOffset + thickness + bothOffset, pos,
+ tickOffset + thickness + bothOffset + tickLength, pos));
+ }
+ }
+ // in the case where maximum is max int
+ int nextInterval = v + interval;
+ if (nextInterval < v)
+ break;
+ v = nextInterval;
+ }
+ if (!lines.isEmpty()) {
+ painter->save();
+ painter->translate(slrect.topLeft());
+ painter->drawLines(lines.constData(), lines.size());
+ painter->restore();
+ }
+ }
+ if (sub & SC_SliderHandle) {
+ if (const auto *slider = qstyleoption_cast<const QStyleOptionSlider *>(option)) {
+ const QRectF rect = proxy()->subControlRect(CC_Slider, option, SC_SliderHandle, widget);
+ const QPointF center = rect.center();
+
+ const QNumberStyleAnimation* animation = qobject_cast<QNumberStyleAnimation*>(d->animation(option->styleObject));
+
+ if (animation != nullptr)
+ option->styleObject->setProperty("_q_inner_radius", animation->currentValue());
+ else
+ option->styleObject->setProperty("_q_inner_radius", option->styleObject->property("_q_end_radius"));
+
+ const qreal outerRadius = qMin(8.0,(slider->orientation == Qt::Horizontal ? rect.height() / 2.0 : rect.width() / 2.0) - 1);
+ const float innerRadius = option->styleObject->property("_q_inner_radius").toFloat();
+ painter->setRenderHint(QPainter::Antialiasing, true);
+ painter->setPen(Qt::NoPen);
+ painter->setBrush(QBrush(WINUI3Colors[colorSchemeIndex][controlFillSolid]));
+ painter->drawEllipse(center, outerRadius, outerRadius);
+ painter->setBrush(option->palette.accent());
+ painter->drawEllipse(center, innerRadius, innerRadius);
+
+ painter->setPen(QPen(WINUI3Colors[colorSchemeIndex][controlStrokeSecondary]));
+ painter->setBrush(Qt::NoBrush);
+ painter->drawEllipse(center, outerRadius + 0.5, outerRadius + 0.5);
+ painter->drawEllipse(center, innerRadius + 0.5, innerRadius + 0.5);
+ }
+ }
+ if (slider->state & State_HasFocus) {
+ QStyleOptionFocusRect fropt;
+ fropt.QStyleOption::operator=(*slider);
+ fropt.rect = subElementRect(SE_SliderFocusRect, slider, widget);
+ proxy()->drawPrimitive(PE_FrameFocusRect, &fropt, painter, widget);
+ }
+ }
+ break;
+#endif
+#if QT_CONFIG(combobox)
+ case CC_ComboBox:
+ if (const QStyleOptionComboBox *combobox = qstyleoption_cast<const QStyleOptionComboBox *>(option)) {
+ QBrush fillColor = state & State_MouseOver && !(state & State_HasFocus) ? QBrush(WINUI3Colors[colorSchemeIndex][subtleHighlightColor]) : option->palette.brush(QPalette::Base);
+ QRectF rect = option->rect.adjusted(2,2,-2,-2);
+ painter->setBrush(fillColor);
+ painter->setPen(Qt::NoPen);
+ painter->drawRoundedRect(rect, secondLevelRoundingRadius, secondLevelRoundingRadius);
+
+ rect.adjust(0.5,0.5,-0.5,-0.5);
+ painter->setBrush(Qt::NoBrush);
+ painter->setPen(highContrastTheme == true ? combobox->palette.buttonText().color() : WINUI3Colors[colorSchemeIndex][frameColorLight]);
+ painter->drawRoundedRect(rect, secondLevelRoundingRadius, secondLevelRoundingRadius);
+ if (sub & SC_ComboBoxArrow) {
+ QRectF rect = proxy()->subControlRect(CC_ComboBox, option, SC_ComboBoxArrow, widget).adjusted(-4, 0, -4, 1);
+ painter->setFont(assetFont);
+ painter->setPen(combobox->palette.text().color());
+ painter->drawText(rect,"\uE019", Qt::AlignVCenter | Qt::AlignHCenter);
+ }
+ if (combobox->editable) {
+ QColor lineColor = state & State_HasFocus ? option->palette.accent().color() : QColor(0,0,0);
+ painter->setPen(QPen(lineColor));
+ painter->drawLine(rect.bottomLeft() + QPoint(2,1), rect.bottomRight() + QPoint(-2,1));
+ if (state & State_HasFocus)
+ painter->drawLine(rect.bottomLeft() + QPoint(3,2), rect.bottomRight() + QPoint(-3,2));
+ }
+ }
+ break;
+#endif // QT_CONFIG(combobox)
+ case QStyle::CC_ScrollBar:
+ if (const QStyleOptionSlider *scrollbar = qstyleoption_cast<const QStyleOptionSlider *>(option)) {
+ QRectF rect = scrollbar->rect;
+ QPointF center = rect.center();
+
+ if (scrollbar->orientation == Qt::Vertical && rect.width()>24)
+ rect.marginsRemoved(QMargins(0,2,2,2));
+ else if (scrollbar->orientation == Qt::Horizontal && rect.height()>24)
+ rect.marginsRemoved(QMargins(2,0,2,2));
+
+ if (state & State_MouseOver) {
+ if (scrollbar->orientation == Qt::Vertical && rect.width()>24)
+ rect.setWidth(rect.width()/2);
+ else if (scrollbar->orientation == Qt::Horizontal && rect.height()>24)
+ rect.setHeight(rect.height()/2);
+ rect.moveCenter(center);
+ painter->setBrush(scrollbar->palette.base());
+ painter->setPen(Qt::NoPen);
+ painter->drawRoundedRect(rect, topLevelRoundingRadius, topLevelRoundingRadius);
+
+ painter->setBrush(Qt::NoBrush);
+ painter->setPen(WINUI3Colors[colorSchemeIndex][frameColorLight]);
+ painter->drawRoundedRect(rect.marginsRemoved(QMarginsF(0.5,0.5,0.5,0.5)), topLevelRoundingRadius + 0.5, topLevelRoundingRadius + 0.5);
+ }
+ if (sub & SC_ScrollBarSlider) {
+ QRectF rect = proxy()->subControlRect(CC_ScrollBar, option, SC_ScrollBarSlider, widget);
+ QPointF center = rect.center();
+ if (flags & State_MouseOver) {
+ if (scrollbar->orientation == Qt::Vertical)
+ rect.setWidth(rect.width()/2);
+ else
+ rect.setHeight(rect.height()/2);
+ }
+ else {
+ if (scrollbar->orientation == Qt::Vertical)
+ rect.setWidth(1);
+ else
+ rect.setHeight(1);
+
+ }
+ rect.moveCenter(center);
+ painter->setBrush(Qt::gray);
+ painter->setPen(Qt::NoPen);
+ painter->drawRoundedRect(rect, secondLevelRoundingRadius, secondLevelRoundingRadius);
+ }
+ if (sub & SC_ScrollBarAddLine) {
+ QRectF rect = proxy()->subControlRect(CC_ScrollBar, option, SC_ScrollBarAddLine, widget);
+ if (flags & State_MouseOver) {
+ painter->setFont(QFont("Segoe Fluent Icons",6));
+ painter->setPen(Qt::gray);
+ if (scrollbar->orientation == Qt::Vertical)
+ painter->drawText(rect,"\uEDDC", Qt::AlignVCenter | Qt::AlignHCenter);
+ else
+ painter->drawText(rect,"\uEDDA", Qt::AlignVCenter | Qt::AlignHCenter);
+ }
+ }
+ if (sub & SC_ScrollBarSubLine) {
+ QRectF rect = proxy()->subControlRect(CC_ScrollBar, option, SC_ScrollBarSubLine, widget);
+ if (flags & State_MouseOver) {
+ painter->setPen(Qt::gray);
+ if (scrollbar->orientation == Qt::Vertical)
+ painter->drawText(rect,"\uEDDB", Qt::AlignVCenter | Qt::AlignHCenter);
+ else
+ painter->drawText(rect,"\uEDD9", Qt::AlignVCenter | Qt::AlignHCenter);
+ }
+ }
+ }
+ break;
+ case CC_TitleBar:
+ if (const auto* titlebar = qstyleoption_cast<const QStyleOptionTitleBar*>(option)) {
+ painter->setPen(Qt::NoPen);
+ painter->setPen(QPen(WINUI3Colors[colorSchemeIndex][surfaceStroke]));
+ painter->setBrush(titlebar->palette.button());
+ painter->drawRect(titlebar->rect);
+
+ // draw title
+ QRect textRect = proxy()->subControlRect(CC_TitleBar, titlebar, SC_TitleBarLabel, widget);
+ painter->setPen(titlebar->palette.text().color());
+ // Note workspace also does elliding but it does not use the correct font
+ QString title = painter->fontMetrics().elidedText(titlebar->text, Qt::ElideRight, textRect.width() - 14);
+ painter->drawText(textRect.adjusted(1, 1, 1, 1), title, QTextOption(Qt::AlignHCenter | Qt::AlignVCenter));
+
+ QFont buttonFont = QFont(assetFont);
+ buttonFont.setPointSize(8);
+ // min button
+ if ((titlebar->subControls & SC_TitleBarMinButton) && (titlebar->titleBarFlags & Qt::WindowMinimizeButtonHint) &&
+ !(titlebar->titleBarState& Qt::WindowMinimized)) {
+ const QRect minButtonRect = proxy()->subControlRect(CC_TitleBar, titlebar, SC_TitleBarMinButton, widget);
+ if (minButtonRect.isValid()) {
+ bool hover = (titlebar->activeSubControls & SC_TitleBarMinButton) && (titlebar->state & State_MouseOver);
+ if (hover)
+ painter->fillRect(minButtonRect,WINUI3Colors[colorSchemeIndex][subtleHighlightColor]);
+ const QString textToDraw("\uE921");
+ painter->setPen(QPen(titlebar->palette.text().color()));
+ painter->setFont(buttonFont);
+ painter->drawText(minButtonRect, Qt::AlignVCenter | Qt::AlignHCenter, textToDraw);
+ }
+ }
+ // max button
+ if ((titlebar->subControls & SC_TitleBarMaxButton) && (titlebar->titleBarFlags & Qt::WindowMaximizeButtonHint) &&
+ !(titlebar->titleBarState & Qt::WindowMaximized)) {
+ const QRectF maxButtonRect = proxy()->subControlRect(CC_TitleBar, titlebar, SC_TitleBarMaxButton, widget);
+ if (maxButtonRect.isValid()) {
+ bool hover = (titlebar->activeSubControls & SC_TitleBarMaxButton) && (titlebar->state & State_MouseOver);
+ if (hover)
+ painter->fillRect(maxButtonRect,WINUI3Colors[colorSchemeIndex][subtleHighlightColor]);
+ const QString textToDraw("\uE922");
+ painter->setPen(QPen(titlebar->palette.text().color()));
+ painter->setFont(buttonFont);
+ painter->drawText(maxButtonRect, Qt::AlignVCenter | Qt::AlignHCenter, textToDraw);
+ }
+ }
+
+ // close button
+ if ((titlebar->subControls & SC_TitleBarCloseButton) && (titlebar->titleBarFlags & Qt::WindowSystemMenuHint)) {
+ const QRect closeButtonRect = proxy()->subControlRect(CC_TitleBar, titlebar, SC_TitleBarCloseButton, widget);
+ if (closeButtonRect.isValid()) {
+ bool hover = (titlebar->activeSubControls & SC_TitleBarCloseButton) && (titlebar->state & State_MouseOver);
+ if (hover)
+ painter->fillRect(closeButtonRect,shellCloseButtonColor);
+ const QString textToDraw("\uE8BB");
+ painter->setPen(QPen(hover ? titlebar->palette.highlightedText().color() : titlebar->palette.text().color()));
+ painter->setFont(buttonFont);
+ painter->drawText(closeButtonRect, Qt::AlignVCenter | Qt::AlignHCenter, textToDraw);
+ }
+ }
+
+ // normalize button
+ if ((titlebar->subControls & SC_TitleBarNormalButton) &&
+ (((titlebar->titleBarFlags & Qt::WindowMinimizeButtonHint) &&
+ (titlebar->titleBarState & Qt::WindowMinimized)) ||
+ ((titlebar->titleBarFlags & Qt::WindowMaximizeButtonHint) &&
+ (titlebar->titleBarState & Qt::WindowMaximized)))) {
+ const QRect normalButtonRect = proxy()->subControlRect(CC_TitleBar, titlebar, SC_TitleBarNormalButton, widget);
+ if (normalButtonRect.isValid()) {
+ bool hover = (titlebar->activeSubControls & SC_TitleBarNormalButton) && (titlebar->state & State_MouseOver);
+ if (hover)
+ painter->fillRect(normalButtonRect,WINUI3Colors[colorSchemeIndex][subtleHighlightColor]);
+ const QString textToDraw("\uE923");
+ painter->setPen(QPen(titlebar->palette.text().color()));
+ painter->setFont(buttonFont);
+ painter->drawText(normalButtonRect, Qt::AlignVCenter | Qt::AlignHCenter, textToDraw);
+ }
+ }
+
+ // context help button
+ if (titlebar->subControls & SC_TitleBarContextHelpButton
+ && (titlebar->titleBarFlags & Qt::WindowContextHelpButtonHint)) {
+ const QRect contextHelpButtonRect = proxy()->subControlRect(CC_TitleBar, titlebar, SC_TitleBarContextHelpButton, widget);
+ if (contextHelpButtonRect.isValid()) {
+ bool hover = (titlebar->activeSubControls & SC_TitleBarCloseButton) && (titlebar->state & State_MouseOver);
+ if (hover)
+ painter->fillRect(contextHelpButtonRect,WINUI3Colors[colorSchemeIndex][subtleHighlightColor]);
+ const QString textToDraw("\uE897");
+ painter->setPen(QPen(titlebar->palette.text().color()));
+ painter->setFont(buttonFont);
+ painter->drawText(contextHelpButtonRect, Qt::AlignVCenter | Qt::AlignHCenter, textToDraw);
+ }
+ }
+
+ // shade button
+ if (titlebar->subControls & SC_TitleBarShadeButton && (titlebar->titleBarFlags & Qt::WindowShadeButtonHint)) {
+ const QRect shadeButtonRect = proxy()->subControlRect(CC_TitleBar, titlebar, SC_TitleBarShadeButton, widget);
+ if (shadeButtonRect.isValid()) {
+ bool hover = (titlebar->activeSubControls & SC_TitleBarShadeButton) && (titlebar->state & State_MouseOver);
+ if (hover)
+ painter->fillRect(shadeButtonRect,WINUI3Colors[colorSchemeIndex][subtleHighlightColor]);
+ const QString textToDraw("\uE010");
+ painter->setPen(QPen(titlebar->palette.text().color()));
+ painter->setFont(buttonFont);
+ painter->drawText(shadeButtonRect, Qt::AlignVCenter | Qt::AlignHCenter, textToDraw);
+ }
+ }
+
+ // unshade button
+ if (titlebar->subControls & SC_TitleBarUnshadeButton && (titlebar->titleBarFlags & Qt::WindowShadeButtonHint)) {
+ const QRect unshadeButtonRect = proxy()->subControlRect(CC_TitleBar, titlebar, SC_TitleBarUnshadeButton, widget);
+ if (unshadeButtonRect.isValid()) {
+ bool hover = (titlebar->activeSubControls & SC_TitleBarUnshadeButton) && (titlebar->state & State_MouseOver);
+ if (hover)
+ painter->fillRect(unshadeButtonRect,WINUI3Colors[colorSchemeIndex][subtleHighlightColor]);
+ const QString textToDraw("\uE011");
+ painter->setPen(QPen(titlebar->palette.text().color()));
+ painter->setFont(buttonFont);
+ painter->drawText(unshadeButtonRect, Qt::AlignVCenter | Qt::AlignHCenter, textToDraw);
+ }
+ }
+
+ // window icon for system menu
+ if ((titlebar->subControls & SC_TitleBarSysMenu) && (titlebar->titleBarFlags & Qt::WindowSystemMenuHint)) {
+ const QRect iconRect = proxy()->subControlRect(CC_TitleBar, titlebar, SC_TitleBarSysMenu, widget);
+ if (iconRect.isValid()) {
+ if (!titlebar->icon.isNull()) {
+ titlebar->icon.paint(painter, iconRect);
+ } else {
+ QStyleOption tool = *titlebar;
+ QPixmap pm = proxy()->standardIcon(SP_TitleBarMenuButton, &tool, widget).pixmap(16, 16);
+ tool.rect = iconRect;
+ painter->save();
+ proxy()->drawItemPixmap(painter, iconRect, Qt::AlignCenter, pm);
+ painter->restore();
+ }
+ }
+ }
+ }
+ break;
+ default:
+ QWindowsVistaStyle::drawComplexControl(control, option, painter, widget);
+ }
+ painter->restore();
+}
+
+void QWindows11Style::drawPrimitive(PrimitiveElement element, const QStyleOption *option,
+ QPainter *painter,
+ const QWidget *widget) const {
+ QWindows11StylePrivate *d = const_cast<QWindows11StylePrivate*>(d_func());
+
+ int state = option->state;
+ painter->save();
+ painter->setRenderHint(QPainter::Antialiasing);
+ if (d->transitionsEnabled() && (element == PE_IndicatorCheckBox || element == PE_IndicatorRadioButton)) {
+ QObject *styleObject = option->styleObject; // Can be widget or qquickitem
+ if (styleObject) {
+ int oldState = styleObject->property("_q_stylestate").toInt();
+ styleObject->setProperty("_q_stylestate", int(option->state));
+ styleObject->setProperty("_q_stylerect", option->rect);
+ bool doTransition = (((state & State_Sunken) != (oldState & State_Sunken)
+ || ((state & State_MouseOver) != (oldState & State_MouseOver))
+ || (state & State_On) != (oldState & State_On))
+ && state & State_Enabled);
+ if (doTransition) {
+ if (element == PE_IndicatorRadioButton) {
+ QNumberStyleAnimation *t = new QNumberStyleAnimation(styleObject);
+ t->setStartValue(styleObject->property("_q_inner_radius").toFloat());
+ t->setEndValue(7.0f);
+ if (option->state & State_Sunken)
+ t->setEndValue(2.0f);
+ else if (option->state & State_MouseOver && !(option->state & State_On))
+ t->setEndValue(7.0f);
+ else if (option->state & State_MouseOver && (option->state & State_On))
+ t->setEndValue(5.0f);
+ else if (option->state & State_On)
+ t->setEndValue(4.0f);
+ styleObject->setProperty("_q_end_radius", t->endValue());
+ t->setStartTime(d->animationTime());
+ t->setDuration(150);
+ d->startAnimation(t);
+ }
+ else if (element == PE_IndicatorCheckBox) {
+ if ((oldState & State_Off && state & State_On) || (oldState & State_NoChange && state & State_On)) {
+ QNumberStyleAnimation *t = new QNumberStyleAnimation(styleObject);
+ t->setStartValue(0.0f);
+ t->setEndValue(1.0f);
+ t->setStartTime(d->animationTime());
+ t->setDuration(150);
+ d->startAnimation(t);
+ }
+ }
+ }
+ }
+ } else if (!d->transitionsEnabled() && element == PE_IndicatorRadioButton) {
+ QObject *styleObject = option->styleObject; // Can be widget or qquickitem
+ if (styleObject) {
+ styleObject->setProperty("_q_end_radius",7.0);
+ if (option->state & State_Sunken)
+ styleObject->setProperty("_q_end_radius",2.0);
+ else if (option->state & State_MouseOver && !(option->state & State_On))
+ styleObject->setProperty("_q_end_radius",7.0);
+ else if (option->state & State_MouseOver && (option->state & State_On))
+ styleObject->setProperty("_q_end_radius",5.0);
+ else if (option->state & State_On)
+ styleObject->setProperty("_q_end_radius",4.0);
+ }
+ }
+
+ switch (element) {
+ case PE_PanelTipLabel: {
+ QRectF tipRect = option->rect.marginsRemoved(QMargins(1,1,1,1));
+ painter->setPen(Qt::NoPen);
+ painter->setBrush(option->palette.toolTipBase());
+ painter->drawRoundedRect(tipRect, secondLevelRoundingRadius, secondLevelRoundingRadius);
+
+ painter->setPen(highContrastTheme == true ? option->palette.buttonText().color() : WINUI3Colors[colorSchemeIndex][frameColorLight]);
+ painter->setBrush(Qt::NoBrush);
+ painter->drawRoundedRect(tipRect.marginsAdded(QMarginsF(0.5,0.5,0.5,0.5)), secondLevelRoundingRadius, secondLevelRoundingRadius);
+ break;
+ }
+ case PE_FrameTabWidget:
+ if (const QStyleOptionTabWidgetFrame *frame = qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(option)) {
+ QRectF frameRect = frame->rect.marginsRemoved(QMargins(0,0,0,0));
+ painter->setPen(Qt::NoPen);
+ painter->setBrush(frame->palette.base());
+ painter->drawRoundedRect(frameRect, secondLevelRoundingRadius, secondLevelRoundingRadius);
+
+ painter->setPen(highContrastTheme == true ? frame->palette.buttonText().color() : WINUI3Colors[colorSchemeIndex][frameColorLight]);
+ painter->setBrush(Qt::NoBrush);
+ painter->drawRoundedRect(frameRect.marginsRemoved(QMarginsF(0.5,0.5,0.5,0.5)), secondLevelRoundingRadius, secondLevelRoundingRadius);
+ }
+ break;
+ case PE_FrameGroupBox:
+ if (const QStyleOptionFrame *frame = qstyleoption_cast<const QStyleOptionFrame *>(option)) {
+ QRectF frameRect = frame->rect;
+ frameRect.adjust(0.5,0.5,-0.5,-0.5);
+ painter->setPen(highContrastTheme == true ? frame->palette.buttonText().color() : WINUI3Colors[colorSchemeIndex][frameColorStrong]);
+ painter->setBrush(Qt::NoBrush);
+ if (frame->features & QStyleOptionFrame::Flat) {
+ QRect fr = frame->rect;
+ QPoint p1(fr.x(), fr.y() + 1);
+ QPoint p2(fr.x() + fr.width(), p1.y());
+ painter->drawLine(p1,p2);
+ } else {
+ painter->drawRoundedRect(frameRect.marginsRemoved(QMargins(1,1,1,1)), secondLevelRoundingRadius, secondLevelRoundingRadius);
+ }
+ }
+ break;
+ case PE_IndicatorCheckBox:
+ {
+ QNumberStyleAnimation* animation = qobject_cast<QNumberStyleAnimation*>(d->animation(option->styleObject));
+ QFontMetrics fm(assetFont);
+
+ QRectF rect = option->rect;
+ QPointF center = QPointF(rect.x() + rect.width() / 2, rect.y() + rect.height() / 2);
+ rect.setWidth(15);
+ rect.setHeight(15);
+ rect.moveCenter(center);
+
+ float clipWidth = animation != nullptr ? animation->currentValue() : 1.0f;
+ QRectF clipRect = fm.boundingRect("\uE001");
+ clipRect.moveCenter(center);
+ clipRect.setLeft(rect.x() + (rect.width() - clipRect.width()) / 2.0);
+ clipRect.setWidth(clipWidth * clipRect.width());
+
+
+ QBrush fillBrush = (option->state & State_On || option->state & State_NoChange) ? option->palette.accent() : option->palette.window();
+ if (state & State_MouseOver && (option->state & State_On || option->state & State_NoChange))
+ fillBrush.setColor(fillBrush.color().lighter(107));
+ else if (state & State_MouseOver && !(option->state & State_On || option->state & State_NoChange))
+ fillBrush.setColor(fillBrush.color().darker(107));
+ painter->setPen(Qt::NoPen);
+ painter->setBrush(fillBrush);
+ painter->drawRoundedRect(rect, secondLevelRoundingRadius, secondLevelRoundingRadius, Qt::AbsoluteSize);
+
+ painter->setPen(QPen(highContrastTheme == true ? option->palette.buttonText().color() : WINUI3Colors[colorSchemeIndex][frameColorStrong]));
+ painter->setBrush(Qt::NoBrush);
+ painter->drawRoundedRect(rect, secondLevelRoundingRadius + 0.5, secondLevelRoundingRadius + 0.5, Qt::AbsoluteSize);
+
+ painter->setFont(assetFont);
+ painter->setPen(option->palette.highlightedText().color());
+ painter->setBrush(option->palette.highlightedText().color());
+ if (option->state & State_On)
+ painter->drawText(clipRect, Qt::AlignVCenter | Qt::AlignLeft,"\uE001");
+ else if (option->state & State_NoChange)
+ painter->drawText(rect, Qt::AlignVCenter | Qt::AlignHCenter,"\uE108");
+ }
+ break;
+
+ case PE_IndicatorRadioButton:
+ {
+ if (option->styleObject->property("_q_end_radius").isNull())
+ option->styleObject->setProperty("_q_end_radius", option->state & State_On ? 4.0f :7.0f);
+ QNumberStyleAnimation* animation = qobject_cast<QNumberStyleAnimation*>(d->animation(option->styleObject));
+ if (animation != nullptr)
+ option->styleObject->setProperty("_q_inner_radius", animation->currentValue());
+ else
+ option->styleObject->setProperty("_q_inner_radius", option->styleObject->property("_q_end_radius"));
+ int innerRadius = option->styleObject->property("_q_inner_radius").toFloat();
+
+ QRectF rect = option->rect;
+ QPointF center = QPoint(rect.x() + rect.width() / 2, rect.y() + rect.height() / 2);
+ rect.setWidth(15);
+ rect.setHeight(15);
+ rect.moveCenter(center);
+ QRectF innerRect = rect;
+ innerRect.setWidth(8);
+ innerRect.setHeight(8);
+ innerRect.moveCenter(center);
+
+ painter->setPen(Qt::NoPen);
+ painter->setBrush(option->palette.accent());
+ if (option->state & State_MouseOver && option->state & State_Enabled)
+ painter->setBrush(QBrush(option->palette.accent().color().lighter(107)));
+ painter->drawEllipse(center, 7, 7);
+
+ painter->setPen(QPen(WINUI3Colors[colorSchemeIndex][frameColorStrong]));
+ painter->setBrush(Qt::NoBrush);
+ painter->drawEllipse(center, 7.5, 7.5);
+
+ painter->setPen(Qt::NoPen);
+ painter->setBrush(QBrush(option->palette.window()));
+ painter->drawEllipse(center,innerRadius, innerRadius);
+
+ painter->setPen(QPen(WINUI3Colors[colorSchemeIndex][frameColorStrong]));
+ painter->setBrush(Qt::NoBrush);
+ painter->drawEllipse(center,innerRadius + 0.5, innerRadius + 0.5);
+
+ painter->setPen(Qt::NoPen);
+ painter->setBrush(QBrush(option->palette.window()));
+ if (option->state & State_MouseOver && option->state & State_Enabled)
+ painter->setBrush(QBrush(option->palette.window().color().darker(107)));
+ painter->drawEllipse(center,innerRadius, innerRadius);
+ }
+ break;
+ case PE_PanelButtonBevel:{
+ QRectF rect = option->rect.marginsRemoved(QMargins(2,2,2,2));
+ rect.adjust(-0.5,-0.5,0.5,0.5);
+ painter->setBrush(Qt::NoBrush);
+ painter->setPen(QPen(WINUI3Colors[colorSchemeIndex][controlStrokePrimary]));
+ painter->drawRoundedRect(rect, secondLevelRoundingRadius, secondLevelRoundingRadius);
+
+ rect = option->rect.marginsRemoved(QMargins(2,2,2,2));
+ painter->setPen(Qt::NoPen);
+ if (!(state & (State_Raised)))
+ painter->setBrush(WINUI3Colors[colorSchemeIndex][controlFillTertiary]);
+ else if (state & State_MouseOver)
+ painter->setBrush(WINUI3Colors[colorSchemeIndex][controlFillSecondary]);
+ else
+ painter->setBrush(option->palette.button());
+ painter->drawRoundedRect(rect, secondLevelRoundingRadius, secondLevelRoundingRadius);
+ painter->setPen(QPen(WINUI3Colors[colorSchemeIndex][controlStrokeSecondary]));
+ if (state & State_Raised)
+ painter->drawLine(rect.bottomLeft() + QPoint(2,1), rect.bottomRight() + QPoint(-2,1));
+ }
+ break;
+ case PE_FrameDefaultButton:
+ painter->setPen(option->palette.accent().color());
+ painter->setBrush(Qt::NoBrush);
+ painter->drawRoundedRect(option->rect, secondLevelRoundingRadius, secondLevelRoundingRadius);
+ break;
+ case QStyle::PE_FrameMenu:
+ break;
+ case QStyle::PE_PanelMenu: {
+ QRect rect = option->rect;
+ QPen pen(WINUI3Colors[colorSchemeIndex][frameColorLight]);
+ painter->save();
+ painter->setPen(pen);
+ painter->setBrush(QBrush(WINUI3Colors[colorSchemeIndex][menuPanelFill]));
+ painter->setRenderHint(QPainter::Antialiasing);
+ painter->drawRoundedRect(rect.marginsRemoved(QMargins(2,2,12,2)), topLevelRoundingRadius, topLevelRoundingRadius);
+ painter->restore();
+ break;
+ }
+ case PE_PanelLineEdit:
+ if (widget && widget->objectName() == "qt_spinbox_lineedit")
+ break;
+ if (const auto *panel = qstyleoption_cast<const QStyleOptionFrame *>(option)) {
+ QBrush fillColor = state & State_MouseOver && !(state & State_HasFocus) ? QBrush(WINUI3Colors[colorSchemeIndex][subtleHighlightColor]) : option->palette.brush(QPalette::Base);
+ painter->setBrush(fillColor);
+ painter->setPen(Qt::NoPen);
+ QRectF frameRect = option->rect;
+ frameRect.adjust(0.5,0.5,-0.5,-0.5);
+ painter->drawRoundedRect(frameRect, secondLevelRoundingRadius, secondLevelRoundingRadius);
+ if (panel->lineWidth > 0)
+ proxy()->drawPrimitive(PE_FrameLineEdit, panel, painter, widget);
+ }
+ break;
+ case PE_FrameLineEdit: {
+ painter->setBrush(Qt::NoBrush);
+ painter->setPen(highContrastTheme == true ? option->palette.buttonText().color() : QPen(WINUI3Colors[colorSchemeIndex][frameColorLight]));
+ painter->drawRoundedRect(option->rect, secondLevelRoundingRadius, secondLevelRoundingRadius);
+ QRegion clipRegion = option->rect;
+ clipRegion -= option->rect.adjusted(2, 2, -2, -2);
+ painter->setClipRegion(clipRegion);
+ QColor lineColor = state & State_HasFocus ? option->palette.accent().color() : QColor(0,0,0);
+ painter->setPen(QPen(lineColor));
+ painter->drawLine(option->rect.bottomLeft() + QPointF(1,0.5), option->rect.bottomRight() + QPointF(-1,0.5));
+ }
+ break;
+ case PE_Frame: {
+ if (const auto *frame = qstyleoption_cast<const QStyleOptionFrame *>(option)) {
+ if (frame->frameShape == QFrame::NoFrame)
+ break;
+ QRectF rect = option->rect.adjusted(1,1,-1,-1);
+ if (widget && widget->inherits("QComboBoxPrivateContainer")) {
+ painter->setPen(Qt::NoPen);
+ painter->setBrush(WINUI3Colors[colorSchemeIndex][menuPanelFill]);
+ painter->drawRoundedRect(rect, secondLevelRoundingRadius, secondLevelRoundingRadius);
+
+ }
+ painter->setBrush(option->palette.base());
+ painter->setPen(Qt::NoPen);
+ painter->drawRoundedRect(rect, secondLevelRoundingRadius, secondLevelRoundingRadius);
+
+ painter->setBrush(Qt::NoBrush);
+ painter->setPen(QPen(WINUI3Colors[colorSchemeIndex][frameColorLight]));
+ painter->drawRoundedRect(rect.marginsRemoved(QMarginsF(0.5,0.5,0.5,0.5)), secondLevelRoundingRadius, secondLevelRoundingRadius);
+
+ if (widget && widget->inherits("QTextEdit")) {
+ QRegion clipRegion = option->rect;
+ QColor lineColor = state & State_HasFocus ? option->palette.accent().color() : QColor(0,0,0,255);
+ painter->setPen(QPen(lineColor));
+ painter->drawLine(option->rect.bottomLeft() + QPoint(1,-1), option->rect.bottomRight() + QPoint(-1,-1));
+ }
+ }
+ break;
+ }
+ case QStyle::PE_PanelItemViewRow:
+ if (const QStyleOptionViewItem *vopt = qstyleoption_cast<const QStyleOptionViewItem *>(option)) {
+ if ((vopt->state & State_Selected || vopt->state & State_MouseOver) && vopt->showDecorationSelected) {
+ painter->setBrush(WINUI3Colors[colorSchemeIndex][subtleHighlightColor]);
+ painter->setPen(Qt::NoPen);
+ painter->drawRoundedRect(vopt->rect.marginsRemoved(QMargins(0,2,-2,2)),2,2);
+ int offset = (widget && widget->inherits("QTreeView")) ? 2 : 0;
+ if (vopt->viewItemPosition == QStyleOptionViewItem::Beginning && option->state & State_Selected) {
+ painter->setPen(QPen(option->palette.accent().color()));
+ painter->drawLine(option->rect.x(),option->rect.y()+offset,option->rect.x(),option->rect.y() + option->rect.height()-2);
+ painter->drawLine(option->rect.x()+1,option->rect.y()+2,option->rect.x()+1,option->rect.y() + option->rect.height()-2);
+ }
+ }
+ }
+ break;
+ case QStyle::PE_Widget: {
+#if QT_CONFIG(dialogbuttonbox)
+ const QDialogButtonBox *buttonBox = nullptr;
+ if (qobject_cast<const QMessageBox *> (widget))
+ buttonBox = widget->findChild<const QDialogButtonBox *>(QLatin1String("qt_msgbox_buttonbox"));
+#if QT_CONFIG(inputdialog)
+ else if (qobject_cast<const QInputDialog *> (widget))
+ buttonBox = widget->findChild<const QDialogButtonBox *>(QLatin1String("qt_inputdlg_buttonbox"));
+#endif // QT_CONFIG(inputdialog)
+ if (buttonBox) {
+ painter->fillRect(option->rect,option->palette.window());
+ }
+#endif
+ break;
+ }
+ case QStyle::PE_FrameWindow:
+ if (const auto *frm = qstyleoption_cast<const QStyleOptionFrame *>(option)) {
+
+ QRectF rect= option->rect;
+ int fwidth = int((frm->lineWidth + frm->midLineWidth) / QWindowsStylePrivate::nativeMetricScaleFactor(widget));
+
+ QRectF bottomLeftCorner = QRectF(rect.left() + 1.0,
+ rect.bottom() - 1.0 - secondLevelRoundingRadius,
+ secondLevelRoundingRadius,
+ secondLevelRoundingRadius);
+ QRectF bottomRightCorner = QRectF(rect.right() - 1.0 - secondLevelRoundingRadius,
+ rect.bottom() - 1.0 - secondLevelRoundingRadius,
+ secondLevelRoundingRadius,
+ secondLevelRoundingRadius);
+
+ //Draw Mask
+ if (widget != nullptr) {
+ QBitmap mask(widget->width(), widget->height());
+ mask.clear();
+
+ QPainter maskPainter(&mask);
+ maskPainter.setRenderHint(QPainter::Antialiasing);
+ maskPainter.setBrush(Qt::color1);
+ maskPainter.setPen(Qt::NoPen);
+ maskPainter.drawRoundedRect(option->rect,secondLevelRoundingRadius,secondLevelRoundingRadius);
+ const_cast<QWidget*>(widget)->setMask(mask);
+ }
+
+ //Draw Window
+ painter->setPen(QPen(frm->palette.base(), fwidth));
+ painter->drawLine(QPointF(rect.left(), rect.top()),
+ QPointF(rect.left(), rect.bottom() - fwidth));
+ painter->drawLine(QPointF(rect.left() + fwidth, rect.bottom()),
+ QPointF(rect.right() - fwidth, rect.bottom()));
+ painter->drawLine(QPointF(rect.right(), rect.top()),
+ QPointF(rect.right(), rect.bottom() - fwidth));
+
+ painter->setPen(QPen(WINUI3Colors[colorSchemeIndex][surfaceStroke]));
+ painter->drawLine(QPointF(rect.left() + 0.5, rect.top() + 0.5),
+ QPointF(rect.left() + 0.5, rect.bottom() - 0.5 - secondLevelRoundingRadius));
+ painter->drawLine(QPointF(rect.left() + 0.5 + secondLevelRoundingRadius, rect.bottom() - 0.5),
+ QPointF(rect.right() - 0.5 - secondLevelRoundingRadius, rect.bottom() - 0.5));
+ painter->drawLine(QPointF(rect.right() - 0.5, rect.top() + 1.5),
+ QPointF(rect.right() - 0.5, rect.bottom() - 0.5 - secondLevelRoundingRadius));
+
+ painter->setPen(Qt::NoPen);
+ painter->setBrush(frm->palette.base());
+ painter->drawPie(bottomRightCorner.marginsAdded(QMarginsF(2.5,2.5,0.0,0.0)),
+ 270 * 16,90 * 16);
+ painter->drawPie(bottomLeftCorner.marginsAdded(QMarginsF(0.0,2.5,2.5,0.0)),
+ -90 * 16,-90 * 16);
+
+ painter->setPen(QPen(WINUI3Colors[colorSchemeIndex][surfaceStroke]));
+ painter->setBrush(Qt::NoBrush);
+ painter->drawArc(bottomRightCorner,
+ 0 * 16,-90 * 16);
+ painter->drawArc(bottomLeftCorner,
+ -90 * 16,-90 * 16);
+ }
+ break;
+ default:
+ QWindowsVistaStyle::drawPrimitive(element, option, painter, widget);
+ }
+ painter->restore();
+}
+
+/*!
+ \internal
+*/
+void QWindows11Style::drawControl(ControlElement element, const QStyleOption *option,
+ QPainter *painter, const QWidget *widget) const
+{
+ Q_D(const QWindows11Style);
+ QRect rect(option->rect);
+ State flags = option->state;
+
+ painter->save();
+ painter->setRenderHint(QPainter::Antialiasing);
+ switch (element) {
+ case QStyle::CE_TabBarTabShape:
+ if (const QStyleOptionTab *tab = qstyleoption_cast<const QStyleOptionTab *>(option)) {
+ QRectF tabRect = tab->rect.marginsRemoved(QMargins(2,2,0,0));
+ painter->setPen(Qt::NoPen);
+ painter->setBrush(tab->palette.base());
+ if (tab->state & State_MouseOver){
+ painter->setBrush(WINUI3Colors[colorSchemeIndex][subtleHighlightColor]);
+ } else if (tab->state & State_Selected) {
+ painter->setBrush(tab->palette.base());
+ } else {
+ painter->setBrush(tab->palette.window());
+ }
+ painter->drawRoundedRect(tabRect,2,2);
+
+ painter->setBrush(Qt::NoBrush);
+ painter->setPen(highContrastTheme == true ? tab->palette.buttonText().color() : WINUI3Colors[colorSchemeIndex][frameColorLight]);
+ painter->drawRoundedRect(tabRect.adjusted(0.5,0.5,-0.5,-0.5),2,2);
+
+ }
+ break;
+ case CE_ToolButtonLabel:
+ if (const QStyleOptionToolButton *toolbutton
+ = qstyleoption_cast<const QStyleOptionToolButton *>(option)) {
+ QRect rect = toolbutton->rect;
+ int shiftX = 0;
+ int shiftY = 0;
+ if (toolbutton->state & (State_Sunken | State_On)) {
+ shiftX = proxy()->pixelMetric(PM_ButtonShiftHorizontal, toolbutton, widget);
+ shiftY = proxy()->pixelMetric(PM_ButtonShiftVertical, toolbutton, widget);
+ }
+ // Arrow type always overrules and is always shown
+ bool hasArrow = toolbutton->features & QStyleOptionToolButton::Arrow;
+ if (((!hasArrow && toolbutton->icon.isNull()) && !toolbutton->text.isEmpty())
+ || toolbutton->toolButtonStyle == Qt::ToolButtonTextOnly) {
+ int alignment = Qt::AlignCenter | Qt::TextShowMnemonic;
+ if (!proxy()->styleHint(SH_UnderlineShortcut, toolbutton, widget))
+ alignment |= Qt::TextHideMnemonic;
+ rect.translate(shiftX, shiftY);
+ painter->setFont(toolbutton->font);
+ const QString text = d->toolButtonElideText(toolbutton, rect, alignment);
+ if (toolbutton->state & State_Raised)
+ painter->setPen(QPen(toolbutton->palette.buttonText().color()));
+ else
+ painter->setPen(QPen(WINUI3Colors[colorSchemeIndex][controlTextSecondary]));
+ proxy()->drawItemText(painter, rect, alignment, toolbutton->palette,
+ toolbutton->state & State_Enabled, text);
+ } else {
+ QPixmap pm;
+ QSize pmSize = toolbutton->iconSize;
+ if (!toolbutton->icon.isNull()) {
+ QIcon::State state = toolbutton->state & State_On ? QIcon::On : QIcon::Off;
+ QIcon::Mode mode;
+ if (!(toolbutton->state & State_Enabled))
+ mode = QIcon::Disabled;
+ else if ((toolbutton->state & State_MouseOver) && (toolbutton->state & State_AutoRaise))
+ mode = QIcon::Active;
+ else
+ mode = QIcon::Normal;
+ pm = toolbutton->icon.pixmap(toolbutton->rect.size().boundedTo(toolbutton->iconSize), painter->device()->devicePixelRatio(),
+ mode, state);
+ pmSize = pm.size() / pm.devicePixelRatio();
+ }
+
+ if (toolbutton->toolButtonStyle != Qt::ToolButtonIconOnly) {
+ painter->setFont(toolbutton->font);
+ QRect pr = rect,
+ tr = rect;
+ int alignment = Qt::TextShowMnemonic;
+ if (!proxy()->styleHint(SH_UnderlineShortcut, toolbutton, widget))
+ alignment |= Qt::TextHideMnemonic;
+
+ if (toolbutton->toolButtonStyle == Qt::ToolButtonTextUnderIcon) {
+ pr.setHeight(pmSize.height() + 4); //### 4 is currently hardcoded in QToolButton::sizeHint()
+ tr.adjust(0, pr.height() - 1, 0, -1);
+ pr.translate(shiftX, shiftY);
+ if (!hasArrow) {
+ proxy()->drawItemPixmap(painter, pr, Qt::AlignCenter, pm);
+ } else {
+ drawArrow(proxy(), toolbutton, pr, painter, widget);
+ }
+ alignment |= Qt::AlignCenter;
+ } else {
+ pr.setWidth(pmSize.width() + 4); //### 4 is currently hardcoded in QToolButton::sizeHint()
+ tr.adjust(pr.width(), 0, 0, 0);
+ pr.translate(shiftX, shiftY);
+ if (!hasArrow) {
+ proxy()->drawItemPixmap(painter, QStyle::visualRect(toolbutton->direction, rect, pr), Qt::AlignCenter, pm);
+ } else {
+ drawArrow(proxy(), toolbutton, pr, painter, widget);
+ }
+ alignment |= Qt::AlignLeft | Qt::AlignVCenter;
+ }
+ tr.translate(shiftX, shiftY);
+ const QString text = d->toolButtonElideText(toolbutton, tr, alignment);
+ if (toolbutton->state & State_Raised)
+ painter->setPen(QPen(toolbutton->palette.buttonText().color()));
+ else
+ painter->setPen(QPen(WINUI3Colors[colorSchemeIndex][controlTextSecondary]));
+ proxy()->drawItemText(painter, QStyle::visualRect(toolbutton->direction, rect, tr), alignment, toolbutton->palette,
+ toolbutton->state & State_Enabled, text);
+ } else {
+ rect.translate(shiftX, shiftY);
+ if (hasArrow) {
+ drawArrow(proxy(), toolbutton, rect, painter, widget);
+ } else {
+ proxy()->drawItemPixmap(painter, rect, Qt::AlignCenter, pm);
+ }
+ }
+ }
+ }
+ break;
+ case QStyle::CE_ShapedFrame:
+ if (const QStyleOptionFrame *f = qstyleoption_cast<const QStyleOptionFrame *>(option)) {
+ int frameShape = f->frameShape;
+ int frameShadow = QFrame::Plain;
+ if (f->state & QStyle::State_Sunken)
+ frameShadow = QFrame::Sunken;
+ else if (f->state & QStyle::State_Raised)
+ frameShadow = QFrame::Raised;
+
+ int lw = f->lineWidth;
+ int mlw = f->midLineWidth;
+
+ switch (frameShape) {
+ case QFrame::Box:
+ if (frameShadow == QFrame::Plain)
+ qDrawPlainRoundedRect(painter, f->rect, secondLevelRoundingRadius, secondLevelRoundingRadius, highContrastTheme == true ? f->palette.buttonText().color() : WINUI3Colors[colorSchemeIndex][frameColorStrong], lw);
+ else
+ qDrawShadeRect(painter, f->rect, f->palette, frameShadow == QFrame::Sunken, lw, mlw);
+ break;
+ case QFrame::Panel:
+ if (frameShadow == QFrame::Plain)
+ qDrawPlainRoundedRect(painter, f->rect, secondLevelRoundingRadius, secondLevelRoundingRadius, highContrastTheme == true ? f->palette.buttonText().color() : WINUI3Colors[colorSchemeIndex][frameColorStrong], lw);
+ else
+ qDrawShadePanel(painter, f->rect, f->palette, frameShadow == QFrame::Sunken, lw);
+ break;
+ default:
+ QWindowsVistaStyle::drawControl(element, option, painter, widget);
+ }
+ }
+ break;
+ case QStyle::CE_ProgressBarGroove:{
+ if (const QStyleOptionProgressBar* progbaropt = qstyleoption_cast<const QStyleOptionProgressBar*>(option)) {
+ if (const QProgressBar* bar = qobject_cast<const QProgressBar*>(widget)) {
+ QRect rect = subElementRect(SE_ProgressBarContents, progbaropt, widget);
+ QPointF center = rect.center();
+ if (bar->orientation() & Qt::Horizontal) {
+ rect.setHeight(1);
+ rect.moveTop(center.y());
+ } else {
+ rect.setWidth(1);
+ rect.moveLeft(center.x());
+ }
+ painter->setPen(Qt::NoPen);
+ painter->setBrush(Qt::gray);
+ painter->drawRect(rect);
+ }
+ }
+ break;
+ }
+ case QStyle::CE_ProgressBarContents:
+ if (const QStyleOptionProgressBar* progbaropt = qstyleoption_cast<const QStyleOptionProgressBar*>(option)) {
+ if (const QProgressBar* bar = qobject_cast<const QProgressBar*>(widget)) {
+ const qreal progressBarThickness = 3;
+ const qreal progressBarHalfThickness = progressBarThickness / 2.0;
+ QRectF rect = subElementRect(SE_ProgressBarContents, progbaropt, widget);
+ QRectF originalRect = rect;
+ QPointF center = rect.center();
+ bool isIndeterminate = progbaropt->maximum == 0 && progbaropt->minimum == 0;
+ float fillPercentage = 0;
+ const qreal offset = (bar->orientation() == Qt::Horizontal && int(rect.height()) % 2 == 0)
+ || (bar->orientation() == Qt::Vertical && int(rect.width()) % 2 == 0) ? 0.5 : 0.0;
+
+ if (!isIndeterminate) {
+ fillPercentage = ((float(progbaropt->progress) - float(progbaropt->minimum)) / (float(progbaropt->maximum) - float(progbaropt->minimum)));
+ if (bar->orientation() == Qt::Horizontal) {
+ rect.setHeight(progressBarThickness);
+ rect.moveTop(center.y() - progressBarHalfThickness - offset);
+ rect.setWidth(rect.width() * fillPercentage);
+ } else {
+ float oldHeight = rect.height();
+ rect.setWidth(progressBarThickness);
+ rect.moveLeft(center.x() - progressBarHalfThickness - offset);
+ rect.moveTop(oldHeight * (1.0f - fillPercentage));
+ rect.setHeight(oldHeight * fillPercentage);
+ }
+ } else {
+ auto elapsedTime = std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::system_clock::now());
+ fillPercentage = (elapsedTime.time_since_epoch().count() % 5000)/(5000.0f*0.75);
+ if (bar->orientation() == Qt::Horizontal) {
+ float barBegin = qMin(qMax(fillPercentage-0.25,0.0) * rect.width(), float(rect.width()));
+ float barEnd = qMin(fillPercentage * rect.width(), float(rect.width()));
+ rect = QRect(QPoint(rect.left() + barBegin, rect.top()), QPoint(rect.left() + barEnd, rect.bottom()));
+ rect.setHeight(progressBarThickness);
+ rect.moveTop(center.y() - progressBarHalfThickness - offset);
+ } else {
+ float barBegin = qMin(qMax(fillPercentage-0.25,0.0) * rect.height(), float(rect.height()));
+ float barEnd = qMin(fillPercentage * rect.height(), float(rect.height()));
+ rect = QRect(QPoint(rect.left(), rect.bottom() - barEnd), QPoint(rect.right(), rect.bottom() - barBegin));
+ rect.setWidth(progressBarThickness);
+ rect.moveLeft(center.x() - progressBarHalfThickness - offset);
+ }
+ const_cast<QWidget*>(widget)->update();
+ }
+ if (progbaropt->invertedAppearance && bar->orientation() == Qt::Horizontal)
+ rect.moveLeft(originalRect.width() * (1.0 - fillPercentage));
+ else if (progbaropt->invertedAppearance && bar->orientation() == Qt::Vertical)
+ rect.moveBottom(originalRect.height() * fillPercentage);
+ painter->setPen(Qt::NoPen);
+ painter->setBrush(progbaropt->palette.accent());
+ painter->drawRoundedRect(rect, secondLevelRoundingRadius, secondLevelRoundingRadius);
+ }
+ }
+ break;
+ case QStyle::CE_ProgressBarLabel:
+ if (const QStyleOptionProgressBar* progbaropt = qstyleoption_cast<const QStyleOptionProgressBar*>(option)) {
+ QRect rect = subElementRect(SE_ProgressBarLabel, progbaropt, widget);
+ painter->setPen(progbaropt->palette.text().color());
+ painter->drawText(rect, progbaropt->text,Qt::AlignVCenter|Qt::AlignLeft);
+ }
+ break;
+ case CE_PushButtonLabel:
+ if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(option)) {
+ QRect textRect = btn->rect;
+
+ int tf = Qt::AlignVCenter|Qt::TextShowMnemonic;
+ if (!proxy()->styleHint(SH_UnderlineShortcut, btn, widget))
+ tf |= Qt::TextHideMnemonic;
+
+ if (btn->features & QStyleOptionButton::HasMenu) {
+ int indicatorSize = proxy()->pixelMetric(PM_MenuButtonIndicator, btn, widget);
+ if (btn->direction == Qt::LeftToRight)
+ textRect = textRect.adjusted(0, 0, -indicatorSize, 0);
+ else
+ textRect = textRect.adjusted(indicatorSize, 0, 0, 0);
+ }
+ if (!btn->icon.isNull()) {
+ //Center both icon and text
+ QIcon::Mode mode = btn->state & State_Enabled ? QIcon::Normal : QIcon::Disabled;
+ if (mode == QIcon::Normal && btn->state & State_HasFocus)
+ mode = QIcon::Active;
+ QIcon::State state = QIcon::Off;
+ if (btn->state & State_On)
+ state = QIcon::On;
+
+ QPixmap pixmap = btn->icon.pixmap(btn->iconSize, painter->device()->devicePixelRatio(), mode, state);
+ int pixmapWidth = pixmap.width() / pixmap.devicePixelRatio();
+ int pixmapHeight = pixmap.height() / pixmap.devicePixelRatio();
+ int labelWidth = pixmapWidth;
+ int labelHeight = pixmapHeight;
+ int iconSpacing = 4;//### 4 is currently hardcoded in QPushButton::sizeHint()
+ if (!btn->text.isEmpty()) {
+ int textWidth = btn->fontMetrics.boundingRect(option->rect, tf, btn->text).width();
+ labelWidth += (textWidth + iconSpacing);
+ }
+
+ QRect iconRect = QRect(textRect.x() + (textRect.width() - labelWidth) / 2,
+ textRect.y() + (textRect.height() - labelHeight) / 2,
+ pixmapWidth, pixmapHeight);
+
+ iconRect = visualRect(btn->direction, textRect, iconRect);
+
+ if (btn->direction == Qt::RightToLeft) {
+ tf |= Qt::AlignRight;
+ textRect.setRight(iconRect.left() - iconSpacing / 2);
+ } else {
+ tf |= Qt::AlignLeft; //left align, we adjust the text-rect instead
+ textRect.setLeft(iconRect.left() + iconRect.width() + iconSpacing / 2);
+ }
+
+ if (btn->state & (State_On | State_Sunken))
+ iconRect.translate(proxy()->pixelMetric(PM_ButtonShiftHorizontal, option, widget),
+ proxy()->pixelMetric(PM_ButtonShiftVertical, option, widget));
+ painter->drawPixmap(iconRect, pixmap);
+ } else {
+ tf |= Qt::AlignHCenter;
+ }
+
+
+ if (btn->state & State_Sunken)
+ painter->setPen(flags & State_On ? QPen(WINUI3Colors[colorSchemeIndex][textOnAccentSecondary]) : QPen(WINUI3Colors[colorSchemeIndex][controlTextSecondary]));
+ else
+ painter->setPen(flags & State_On ? QPen(WINUI3Colors[colorSchemeIndex][textOnAccentPrimary]) : QPen(btn->palette.buttonText().color()));
+ proxy()->drawItemText(painter, textRect, tf, option->palette,btn->state & State_Enabled, btn->text);
+ }
+ break;
+ case CE_PushButtonBevel:
+ if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(option)) {
+ if (btn->features.testFlag(QStyleOptionButton::Flat)) {
+ painter->setPen(Qt::NoPen);
+ if (flags & (State_Sunken | State_On)) {
+ painter->setBrush(WINUI3Colors[colorSchemeIndex][subtlePressedColor]);
+ }
+ else if (flags & State_MouseOver) {
+ painter->setBrush(WINUI3Colors[colorSchemeIndex][subtleHighlightColor]);
+ }
+ painter->drawRoundedRect(rect, secondLevelRoundingRadius, secondLevelRoundingRadius);
+ } else {
+ QRectF rect = btn->rect.marginsRemoved(QMargins(2,2,2,2));
+ painter->setPen(Qt::NoPen);
+ if (flags & (State_Sunken))
+ painter->setBrush(flags & State_On ? option->palette.accent().color().lighter(120) : WINUI3Colors[colorSchemeIndex][controlFillTertiary]);
+ else if (flags & State_MouseOver)
+ painter->setBrush(flags & State_On ? option->palette.accent().color().lighter(110) : WINUI3Colors[colorSchemeIndex][controlFillSecondary]);
+ else
+ painter->setBrush(flags & State_On ? option->palette.accent() : option->palette.button());
+ painter->drawRoundedRect(rect, secondLevelRoundingRadius, secondLevelRoundingRadius);
+
+ rect.adjust(0.5,0.5,-0.5,-0.5);
+ painter->setBrush(Qt::NoBrush);
+ painter->setPen(btn->features.testFlag(QStyleOptionButton::DefaultButton) ? QPen(option->palette.accent().color()) : QPen(WINUI3Colors[colorSchemeIndex][controlStrokePrimary]));
+ painter->drawRoundedRect(rect, secondLevelRoundingRadius, secondLevelRoundingRadius);
+
+ painter->setPen(btn->features.testFlag(QStyleOptionButton::DefaultButton) ? QPen(WINUI3Colors[colorSchemeIndex][controlStrokeOnAccentSecondary]) : QPen(WINUI3Colors[colorSchemeIndex][controlStrokeSecondary]));
+ if (flags & State_Raised)
+ painter->drawLine(rect.bottomLeft() + QPointF(4.0,0.0), rect.bottomRight() + QPointF(-4,0.0));
+ }
+ }
+ break;
+ case CE_MenuBarItem:
+ if (const auto *mbi = qstyleoption_cast<const QStyleOptionMenuItem *>(option)) {
+ constexpr int hPadding = 11;
+ constexpr int topPadding = 4;
+ constexpr int bottomPadding = 6;
+ bool active = mbi->state & State_Selected;
+ bool hasFocus = mbi->state & State_HasFocus;
+ bool down = mbi->state & State_Sunken;
+ bool enabled = mbi->state & State_Enabled;
+ QStyleOptionMenuItem newMbi = *mbi;
+ newMbi.font.setPointSize(10);
+ if (enabled && (active || hasFocus)) {
+ if (active && down)
+ painter->setBrushOrigin(painter->brushOrigin() + QPoint(1, 1));
+ if (active && hasFocus) {
+ painter->setBrush(WINUI3Colors[colorSchemeIndex][subtleHighlightColor]);
+ painter->setPen(Qt::NoPen);
+ QRect rect = mbi->rect.marginsRemoved(QMargins(5,0,5,0));
+ painter->drawRoundedRect(rect,secondLevelRoundingRadius,secondLevelRoundingRadius,Qt::AbsoluteSize);
+ }
+ }
+ newMbi.rect.adjust(hPadding,topPadding,-hPadding,-bottomPadding);
+ painter->setFont(newMbi.font);
+ QCommonStyle::drawControl(element, &newMbi, painter, widget);
+ }
+ break;
+
+#if QT_CONFIG(menu)
+ case CE_MenuEmptyArea:
+ break;
+
+ case CE_MenuItem:
+ if (const auto *menuitem = qstyleoption_cast<const QStyleOptionMenuItem *>(option)) {
+ int x, y, w, h;
+ menuitem->rect.getRect(&x, &y, &w, &h);
+ int tab = menuitem->reservedShortcutWidth;
+ bool dis = !(menuitem->state & State_Enabled);
+ bool checked = menuitem->checkType != QStyleOptionMenuItem::NotCheckable
+ ? menuitem->checked : false;
+ bool act = menuitem->state & State_Selected;
+
+ // windows always has a check column, regardless whether we have an icon or not
+ int checkcol = qMax<int>(menuitem->maxIconWidth, 32);
+
+ QBrush fill = (act == true && dis == false) ? QBrush(WINUI3Colors[colorSchemeIndex][subtleHighlightColor]) : menuitem->palette.brush(QPalette::Button);
+ painter->setBrush(fill);
+ painter->setPen(Qt::NoPen);
+ QRect rect = menuitem->rect;
+ rect = rect.marginsRemoved(QMargins(2,2,2,2));
+ if (act && dis == false)
+ painter->drawRoundedRect(rect,secondLevelRoundingRadius,secondLevelRoundingRadius,Qt::AbsoluteSize);
+
+ if (menuitem->menuItemType == QStyleOptionMenuItem::Separator){
+ int yoff = 4;
+ painter->setPen(highContrastTheme == true ? menuitem->palette.buttonText().color() : WINUI3Colors[colorSchemeIndex][frameColorLight]);
+ painter->drawLine(x, y + yoff, x + w, y + yoff );
+ break;
+ }
+
+ QRect vCheckRect = visualRect(option->direction, menuitem->rect, QRect(menuitem->rect.x(), menuitem->rect.y(), checkcol, menuitem->rect.height()));
+ if (!menuitem->icon.isNull() && checked) {
+ if (act) {
+ qDrawShadePanel(painter, vCheckRect,
+ menuitem->palette, true, 1,
+ &menuitem->palette.brush(QPalette::Button));
+ } else {
+ QBrush fill(menuitem->palette.light().color(), Qt::Dense4Pattern);
+ qDrawShadePanel(painter, vCheckRect, menuitem->palette, true, 1, &fill);
+ }
+ }
+ // On Windows Style, if we have a checkable item and an icon we
+ // draw the icon recessed to indicate an item is checked. If we
+ // have no icon, we draw a checkmark instead.
+ if (!menuitem->icon.isNull()) {
+ QIcon::Mode mode = dis ? QIcon::Disabled : QIcon::Normal;
+ if (act && !dis)
+ mode = QIcon::Active;
+ QPixmap pixmap;
+ if (checked)
+ 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);
+ QRect pmr(QPoint(0, 0), pixmap.deviceIndependentSize().toSize());
+ pmr.moveCenter(vCheckRect.center());
+ painter->setPen(menuitem->palette.text().color());
+ painter->drawPixmap(pmr.topLeft(), pixmap);
+ } else if (checked) {
+ QStyleOptionMenuItem newMi = *menuitem;
+ newMi.state = State_None;
+ if (!dis)
+ newMi.state |= State_Enabled;
+ if (act)
+ newMi.state |= State_On | State_Selected;
+ newMi.rect = visualRect(option->direction, menuitem->rect, QRect(menuitem->rect.x() + QWindowsStylePrivate::windowsItemFrame,
+ menuitem->rect.y() + QWindowsStylePrivate::windowsItemFrame,
+ checkcol - 2 * QWindowsStylePrivate::windowsItemFrame,
+ menuitem->rect.height() - 2 * QWindowsStylePrivate::windowsItemFrame));
+
+ QColor discol;
+ if (dis) {
+ discol = menuitem->palette.text().color();
+ painter->setPen(discol);
+ }
+ int xm = int(QWindowsStylePrivate::windowsItemFrame) + checkcol / 4 + int(QWindowsStylePrivate::windowsItemHMargin);
+ int xpos = menuitem->rect.x() + xm;
+ QRect textRect(xpos, y + QWindowsStylePrivate::windowsItemVMargin,
+ w - xm - QWindowsStylePrivate::windowsRightBorder - tab + 1, h - 2 * QWindowsStylePrivate::windowsItemVMargin);
+ QRect vTextRect = visualRect(option->direction, menuitem->rect, textRect);
+
+ painter->save();
+ painter->setFont(assetFont);
+ int text_flags = Qt::AlignVCenter | Qt::TextShowMnemonic | Qt::TextDontClip | Qt::TextSingleLine;
+ if (!proxy()->styleHint(SH_UnderlineShortcut, menuitem, widget))
+ text_flags |= Qt::TextHideMnemonic;
+ text_flags |= Qt::AlignLeft;
+
+ const QString textToDraw("\uE001");
+ painter->setPen(option->palette.text().color());
+ painter->drawText(vTextRect, text_flags, textToDraw);
+ painter->restore();
+ }
+ painter->setPen(act ? menuitem->palette.highlightedText().color() : menuitem->palette.buttonText().color());
+
+ QColor discol = menuitem->palette.text().color();
+ if (dis) {
+ discol = menuitem->palette.color(QPalette::Disabled, QPalette::WindowText);
+ painter->setPen(discol);
+ }
+
+ int xm = int(QWindowsStylePrivate::windowsItemFrame) + checkcol + int(QWindowsStylePrivate::windowsItemHMargin);
+ int xpos = menuitem->rect.x() + xm;
+ QRect textRect(xpos, y + QWindowsStylePrivate::windowsItemVMargin,
+ w - xm - QWindowsStylePrivate::windowsRightBorder - tab + 1, h - 2 * QWindowsStylePrivate::windowsItemVMargin);
+ QRect vTextRect = visualRect(option->direction, menuitem->rect, textRect);
+ QStringView s(menuitem->text);
+ if (!s.isEmpty()) { // draw text
+ painter->save();
+ qsizetype t = s.indexOf(u'\t');
+ int text_flags = Qt::AlignVCenter | Qt::TextShowMnemonic | Qt::TextDontClip | Qt::TextSingleLine;
+ if (!proxy()->styleHint(SH_UnderlineShortcut, menuitem, widget))
+ text_flags |= Qt::TextHideMnemonic;
+ text_flags |= Qt::AlignLeft;
+ if (t >= 0) {
+ QRect vShortcutRect = visualRect(option->direction, menuitem->rect,
+ QRect(textRect.topRight(), QPoint(menuitem->rect.right(), textRect.bottom())));
+ const QString textToDraw = s.mid(t + 1).toString();
+ if (dis && !act && proxy()->styleHint(SH_EtchDisabledText, option, widget)) {
+ painter->setPen(menuitem->palette.light().color());
+ painter->drawText(vShortcutRect.adjusted(1, 1, 1, 1), text_flags, textToDraw);
+ painter->setPen(discol);
+ }
+ painter->setPen(menuitem->palette.color(QPalette::Disabled, QPalette::Text));
+ painter->drawText(vShortcutRect, text_flags, textToDraw);
+ s = s.left(t);
+ }
+ QFont font = menuitem->font;
+ if (menuitem->menuItemType == QStyleOptionMenuItem::DefaultItem)
+ font.setBold(true);
+ painter->setFont(font);
+ const QString textToDraw = s.left(t).toString();
+ painter->setPen(discol);
+ painter->drawText(vTextRect, text_flags, textToDraw);
+ painter->restore();
+ }
+ if (menuitem->menuItemType == QStyleOptionMenuItem::SubMenu) {// draw sub menu arrow
+ int dim = (h - 2 * QWindowsStylePrivate::windowsItemFrame) / 2;
+ xpos = x + w - QWindowsStylePrivate::windowsArrowHMargin - QWindowsStylePrivate::windowsItemFrame - dim;
+ QRect vSubMenuRect = visualRect(option->direction, menuitem->rect, QRect(xpos, y + h / 2 - dim / 2, dim, dim));
+ QStyleOptionMenuItem newMI = *menuitem;
+ newMI.rect = vSubMenuRect;
+ newMI.state = dis ? State_None : State_Enabled;
+ if (act)
+ newMI.palette.setColor(QPalette::ButtonText,
+ newMI.palette.highlightedText().color());
+ painter->save();
+ painter->setFont(assetFont);
+ int text_flags = Qt::AlignVCenter | Qt::TextShowMnemonic | Qt::TextDontClip | Qt::TextSingleLine;
+ if (!proxy()->styleHint(SH_UnderlineShortcut, menuitem, widget))
+ text_flags |= Qt::TextHideMnemonic;
+ text_flags |= Qt::AlignLeft;
+ const QString textToDraw("\uE013");
+ painter->setPen(option->palette.text().color());
+ painter->drawText(vSubMenuRect, text_flags, textToDraw);
+ painter->restore();
+ }
+ }
+ break;
+#endif // QT_CONFIG(menu)
+ case CE_MenuBarEmptyArea: {
+ break;
+ }
+ case CE_HeaderEmptyArea:
+ break;
+ case CE_HeaderSection: {
+ if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(option)) {
+ painter->setPen(highContrastTheme == true ? header->palette.buttonText().color() : WINUI3Colors[colorSchemeIndex][frameColorLight]);
+ if (header->position == QStyleOptionHeader::OnlyOneSection) {
+ break;
+ }
+ else if (header->position == QStyleOptionHeader::Beginning) {
+ painter->drawLine(QPointF(option->rect.topRight()) + QPointF(0.5,0.0),
+ QPointF(option->rect.bottomRight()) + QPointF(0.5,0.0));
+ }
+ else if (header->position == QStyleOptionHeader::End) {
+ painter->drawLine(QPointF(option->rect.topLeft()) - QPointF(0.5,0.0),
+ QPointF(option->rect.bottomLeft()) - QPointF(0.5,0.0));
+ } else {
+ painter->drawLine(QPointF(option->rect.topRight()) + QPointF(0.5,0.0),
+ QPointF(option->rect.bottomRight()) + QPointF(0.5,0.0));
+ painter->drawLine(QPointF(option->rect.topLeft()) - QPointF(0.5,0.0),
+ QPointF(option->rect.bottomLeft()) - QPointF(0.5,0.0));
+ }
+ painter->drawLine(QPointF(option->rect.bottomLeft()) + QPointF(0.0,0.5),
+ QPointF(option->rect.bottomRight()) + QPointF(0.0,0.5));
+ }
+ break;
+ }
+ case QStyle::CE_ItemViewItem: {
+ if (const QStyleOptionViewItem *vopt = qstyleoption_cast<const QStyleOptionViewItem *>(option)) {
+ if (const QAbstractItemView *view = qobject_cast<const QAbstractItemView *>(widget)) {
+ QRect checkRect = proxy()->subElementRect(SE_ItemViewItemCheckIndicator, vopt, widget);
+ QRect iconRect = proxy()->subElementRect(SE_ItemViewItemDecoration, vopt, widget);
+ QRect textRect = proxy()->subElementRect(SE_ItemViewItemText, vopt, widget);
+
+ QRect rect = vopt->rect;
+
+ painter->setPen(highContrastTheme == true ? vopt->palette.buttonText().color() : WINUI3Colors[colorSchemeIndex][frameColorLight]);
+ if (vopt->viewItemPosition == QStyleOptionViewItem::OnlyOne || vopt->viewItemPosition == QStyleOptionViewItem::Invalid) {
+ } else if (vopt->viewItemPosition == QStyleOptionViewItem::Beginning) {
+ painter->drawLine(QPointF(option->rect.topRight()) + QPointF(0.5,0.0),
+ QPointF(option->rect.bottomRight()) + QPointF(0.5,0.0));
+ } else if (vopt->viewItemPosition == QStyleOptionViewItem::End) {
+ painter->drawLine(QPointF(option->rect.topLeft()) - QPointF(0.5,0.0),
+ QPointF(option->rect.bottomLeft()) - QPointF(0.5,0.0));
+ } else {
+ painter->drawLine(QPointF(option->rect.topRight()) + QPointF(0.5,0.0),
+ QPointF(option->rect.bottomRight()) + QPointF(0.5,0.0));
+ painter->drawLine(QPointF(option->rect.topLeft()) - QPointF(0.5,0.0),
+ QPointF(option->rect.bottomLeft()) - QPointF(0.5,0.0));
+ }
+ painter->setPen(QPen(option->palette.buttonText().color()));
+
+ bool isTreeView = widget && widget->inherits("QTreeView");
+
+ if ((vopt->state & State_Selected || vopt->state & State_MouseOver) && !(isTreeView && vopt->state & State_MouseOver) && vopt->showDecorationSelected) {
+ painter->setBrush(WINUI3Colors[colorSchemeIndex][subtleHighlightColor]);
+ QWidget *editorWidget = view->indexWidget(view->currentIndex());
+ if (editorWidget) {
+ QPalette pal = editorWidget->palette();
+ QColor editorBgColor = vopt->backgroundBrush == Qt::NoBrush ? vopt->palette.color(widget->backgroundRole()) : vopt->backgroundBrush.color();
+ editorBgColor.setAlpha(255);
+ pal.setColor(editorWidget->backgroundRole(),editorBgColor);
+ editorWidget->setPalette(pal);
+ }
+ } else {
+ painter->setBrush(vopt->backgroundBrush);
+ }
+ painter->setPen(Qt::NoPen);
+
+ if (vopt->viewItemPosition == QStyleOptionViewItem::OnlyOne || vopt->viewItemPosition == QStyleOptionViewItem::Invalid) {
+ painter->drawRoundedRect(vopt->rect.marginsRemoved(QMargins(2,2,2,2)),secondLevelRoundingRadius,secondLevelRoundingRadius);
+ } else if (vopt->viewItemPosition == QStyleOptionViewItem::Beginning) {
+ painter->drawRoundedRect(rect.marginsRemoved(QMargins(2,2,0,2)),secondLevelRoundingRadius,secondLevelRoundingRadius);
+ } else if (vopt->viewItemPosition == QStyleOptionViewItem::End) {
+ painter->drawRoundedRect(vopt->rect.marginsRemoved(QMargins(0,2,2,2)),secondLevelRoundingRadius,secondLevelRoundingRadius);
+ } else {
+ painter->drawRect(vopt->rect.marginsRemoved(QMargins(0,2,0,2)));
+ }
+
+ // draw the check mark
+ if (vopt->features & QStyleOptionViewItem::HasCheckIndicator) {
+ QStyleOptionViewItem option(*vopt);
+ option.rect = checkRect;
+ option.state = option.state & ~QStyle::State_HasFocus;
+
+ switch (vopt->checkState) {
+ case Qt::Unchecked:
+ option.state |= QStyle::State_Off;
+ break;
+ case Qt::PartiallyChecked:
+ option.state |= QStyle::State_NoChange;
+ break;
+ case Qt::Checked:
+ option.state |= QStyle::State_On;
+ break;
+ }
+ proxy()->drawPrimitive(QStyle::PE_IndicatorItemViewItemCheck, &option, painter, widget);
+ }
+
+ // draw the icon
+ QIcon::Mode mode = QIcon::Normal;
+ if (!(vopt->state & QStyle::State_Enabled))
+ mode = QIcon::Disabled;
+ else if (vopt->state & QStyle::State_Selected)
+ mode = QIcon::Selected;
+ QIcon::State state = vopt->state & QStyle::State_Open ? QIcon::On : QIcon::Off;
+ vopt->icon.paint(painter, iconRect, vopt->decorationAlignment, mode, state);
+
+ painter->setPen(QPen(option->palette.buttonText().color()));
+ if (!view->isPersistentEditorOpen(vopt->index))
+ d->viewItemDrawText(painter, vopt, textRect);
+ if (vopt->state & State_Selected && (vopt->viewItemPosition == QStyleOptionViewItem::Beginning || vopt->viewItemPosition == QStyleOptionViewItem::OnlyOne || vopt->viewItemPosition == QStyleOptionViewItem::Invalid)) {
+ if (widget && widget->inherits("QListView") && qobject_cast<const QListView*>(widget)->viewMode() != QListView::IconMode) {
+ painter->setPen(QPen(vopt->palette.accent().color()));
+ painter->drawLine(option->rect.x(),option->rect.y()+2,option->rect.x(),option->rect.y() + option->rect.height()-2);
+ painter->drawLine(option->rect.x()+1,option->rect.y()+2,option->rect.x()+1,option->rect.y() + option->rect.height()-2);
+ }
+ }
+ }
+ }
+ break;
+ }
+ default:
+ QWindowsVistaStyle::drawControl(element, option, painter, widget);
+ }
+ painter->restore();
+}
+
+int QWindows11Style::styleHint(StyleHint hint, const QStyleOption *opt,
+ const QWidget *widget, QStyleHintReturn *returnData) const {
+ switch (hint) {
+ case SH_GroupBox_TextLabelColor:
+ if (opt!=nullptr && widget!=nullptr)
+ return opt->palette.text().color().rgba();
+ return 0;
+ case QStyle::SH_ItemView_ShowDecorationSelected:
+ return 1;
+ default:
+ return QWindowsVistaStyle::styleHint(hint, opt, widget, returnData);
+ }
+}
+
+QRect QWindows11Style::subElementRect(QStyle::SubElement element, const QStyleOption *option,
+ const QWidget *widget) const
+{
+ QRect ret;
+ switch (element) {
+ case QStyle::SE_LineEditContents:
+ ret = option->rect.adjusted(8,0,-8,0);
+ break;
+ case QStyle::SE_ItemViewItemText:
+ if (const auto *item = qstyleoption_cast<const QStyleOptionViewItem *>(option)) {
+ const int decorationOffset = item->features.testFlag(QStyleOptionViewItem::HasDecoration) ? item->decorationSize.width() : 0;
+ if (widget && widget->parentWidget() &&
+ widget->parentWidget()->inherits("QComboBoxPrivateContainer")) {
+ ret = option->rect.adjusted(decorationOffset + 5, 0, -5, 0);
+ } else {
+ ret = QWindowsVistaStyle::subElementRect(element, option, widget);
+ }
+ } else {
+ ret = QWindowsVistaStyle::subElementRect(element, option, widget);
+ }
+ break;
+ default:
+ ret = QWindowsVistaStyle::subElementRect(element, option, widget);
+ }
+ return ret;
+}
+
+/*!
+ \internal
+ */
+QRect QWindows11Style::subControlRect(ComplexControl control, const QStyleOptionComplex *option,
+ SubControl subControl, const QWidget *widget) const
+{
+ QRect ret;
+
+ switch (control) {
+#if QT_CONFIG(spinbox)
+ case CC_SpinBox:
+ if (const QStyleOptionSpinBox *spinbox = qstyleoption_cast<const QStyleOptionSpinBox *>(option)) {
+ QSize bs;
+ int fw = spinbox->frame ? proxy()->pixelMetric(PM_SpinBoxFrameWidth, spinbox, widget) : 0;
+ bs.setHeight(qMax(8, spinbox->rect.height() - fw));
+ bs.setWidth(qMin(24.0, spinbox->rect.width()*(1.0/4.0)));
+ int y = fw + spinbox->rect.y();
+ int x, lx, rx;
+ x = spinbox->rect.x() + spinbox->rect.width() - fw - 2 * bs.width();
+ lx = fw;
+ rx = x - fw;
+ switch (subControl) {
+ case SC_SpinBoxUp:
+ if (spinbox->buttonSymbols == QAbstractSpinBox::NoButtons)
+ return QRect();
+ ret = QRect(x, y, bs.width(), bs.height());
+ break;
+ case SC_SpinBoxDown:
+ if (spinbox->buttonSymbols == QAbstractSpinBox::NoButtons)
+ return QRect();
+ ret = QRect(x + bs.width(), y, bs.width(), bs.height());
+ break;
+ case SC_SpinBoxEditField:
+ if (spinbox->buttonSymbols == QAbstractSpinBox::NoButtons) {
+ ret = QRect(lx, fw, spinbox->rect.width() - 2*fw, spinbox->rect.height() - 2*fw);
+ } else {
+ ret = QRect(lx, fw, rx, spinbox->rect.height() - 2*fw);
+ }
+ break;
+ case SC_SpinBoxFrame:
+ ret = spinbox->rect;
+ default:
+ break;
+ }
+ ret = visualRect(spinbox->direction, spinbox->rect, ret);
+ }
+ break;
+ case CC_TitleBar:
+ if (const QStyleOptionTitleBar *titlebar = qstyleoption_cast<const QStyleOptionTitleBar *>(option)) {
+ SubControl sc = subControl;
+ ret = QCommonStyle::subControlRect(control, option, subControl, widget);
+ static constexpr int indent = 3;
+ static constexpr int controlWidthMargin = 2;
+ const int controlHeight = titlebar->rect.height();
+ const int controlWidth = 46;
+ const int iconSize = proxy()->pixelMetric(QStyle::PM_TitleBarButtonIconSize, option, widget);
+ int offset = -(controlWidthMargin + indent);
+
+ bool isMinimized = titlebar->titleBarState & Qt::WindowMinimized;
+ bool isMaximized = titlebar->titleBarState & Qt::WindowMaximized;
+
+ switch (sc) {
+ case SC_TitleBarLabel:
+ if (titlebar->titleBarFlags & (Qt::WindowTitleHint | Qt::WindowSystemMenuHint)) {
+ ret = titlebar->rect;
+ if (titlebar->titleBarFlags & Qt::WindowSystemMenuHint)
+ ret.adjust(iconSize + controlWidthMargin + indent, 0, -controlWidth, 0);
+ if (titlebar->titleBarFlags & Qt::WindowMinimizeButtonHint)
+ ret.adjust(0, 0, -controlWidth, 0);
+ if (titlebar->titleBarFlags & Qt::WindowMaximizeButtonHint)
+ ret.adjust(0, 0, -controlWidth, 0);
+ if (titlebar->titleBarFlags & Qt::WindowShadeButtonHint)
+ ret.adjust(0, 0, -controlWidth, 0);
+ if (titlebar->titleBarFlags & Qt::WindowContextHelpButtonHint)
+ ret.adjust(0, 0, -controlWidth, 0);
+ }
+ break;
+ case SC_TitleBarContextHelpButton:
+ if (titlebar->titleBarFlags & Qt::WindowContextHelpButtonHint)
+ offset += controlWidth;
+ Q_FALLTHROUGH();
+ case SC_TitleBarMinButton:
+ if (!isMinimized && (titlebar->titleBarFlags & Qt::WindowMinimizeButtonHint))
+ offset += controlWidth;
+ else if (sc == SC_TitleBarMinButton)
+ break;
+ Q_FALLTHROUGH();
+ case SC_TitleBarNormalButton:
+ if (isMinimized && (titlebar->titleBarFlags & Qt::WindowMinimizeButtonHint))
+ offset += controlWidth;
+ else if (isMaximized && (titlebar->titleBarFlags & Qt::WindowMaximizeButtonHint))
+ offset += controlWidth;
+ else if (sc == SC_TitleBarNormalButton)
+ break;
+ Q_FALLTHROUGH();
+ case SC_TitleBarMaxButton:
+ if (!isMaximized && (titlebar->titleBarFlags & Qt::WindowMaximizeButtonHint))
+ offset += controlWidth;
+ else if (sc == SC_TitleBarMaxButton)
+ break;
+ Q_FALLTHROUGH();
+ case SC_TitleBarShadeButton:
+ if (!isMinimized && (titlebar->titleBarFlags & Qt::WindowShadeButtonHint))
+ offset += controlWidth;
+ else if (sc == SC_TitleBarShadeButton)
+ break;
+ Q_FALLTHROUGH();
+ case SC_TitleBarUnshadeButton:
+ if (isMinimized && (titlebar->titleBarFlags & Qt::WindowShadeButtonHint))
+ offset += controlWidth;
+ else if (sc == SC_TitleBarUnshadeButton)
+ break;
+ Q_FALLTHROUGH();
+ case SC_TitleBarCloseButton:
+ if (titlebar->titleBarFlags & Qt::WindowSystemMenuHint)
+ offset += controlWidth;
+ else if (sc == SC_TitleBarCloseButton)
+ break;
+ ret.setRect(titlebar->rect.right() - offset, titlebar->rect.top(),
+ controlWidth, controlHeight);
+ break;
+ case SC_TitleBarSysMenu:
+ if (titlebar->titleBarFlags & Qt::WindowSystemMenuHint) {
+ ret.setRect(titlebar->rect.left() + controlWidthMargin + indent, titlebar->rect.top() + iconSize/2,
+ iconSize, iconSize);
+ }
+ break;
+ default:
+ break;
+ }
+ if (widget && isMinimized && titlebar->rect.width() < offset)
+ const_cast<QWidget*>(widget)->resize(controlWidthMargin + indent + offset + iconSize + controlWidthMargin, controlWidth);
+ ret = visualRect(titlebar->direction, titlebar->rect, ret);
+ }
+ break;
+#endif // Qt_NO_SPINBOX
+ case CC_ScrollBar:
+ {
+ ret = QCommonStyle::subControlRect(control, option, subControl, widget);
+
+ switch (subControl) {
+ case QStyle::SC_ScrollBarAddLine:
+ if (const QStyleOptionSlider *scrollbar = qstyleoption_cast<const QStyleOptionSlider *>(option)) {
+ if (scrollbar->orientation == Qt::Vertical) {
+ ret = ret.adjusted(2,2,-2,-3);
+ } else {
+ ret = ret.adjusted(3,2,-2,-2);
+ }
+ }
+ break;
+ case QStyle::SC_ScrollBarSubLine:
+ if (const QStyleOptionSlider *scrollbar = qstyleoption_cast<const QStyleOptionSlider *>(option)) {
+ if (scrollbar->orientation == Qt::Vertical) {
+ ret = ret.adjusted(2,2,-2,-3);
+ } else {
+ ret = ret.adjusted(3,2,-2,-2);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+ default:
+ ret = QWindowsVistaStyle::subControlRect(control, option, subControl, widget);
+ }
+ return ret;
+}
+
+/*!
+ \internal
+ */
+QSize QWindows11Style::sizeFromContents(ContentsType type, const QStyleOption *option,
+ const QSize &size, const QWidget *widget) const
+{
+ QSize contentSize(size);
+
+ switch (type) {
+
+ case CT_Menu:
+ contentSize += QSize(10, 0);
+ break;
+
+#if QT_CONFIG(menubar)
+ case CT_MenuBarItem:
+ if (!contentSize.isEmpty()) {
+ constexpr int hMargin = 2 * 6;
+ constexpr int hPadding = 2 * 11;
+ constexpr int itemHeight = 32;
+ contentSize.setWidth(contentSize.width() + hMargin + hPadding);
+ contentSize.setHeight(itemHeight);
+ }
+ break;
+#endif
+
+ default:
+ contentSize = QWindowsVistaStyle::sizeFromContents(type, option, size, widget);
+ break;
+ }
+
+ return contentSize;
+}
+
+
+/*!
+ \internal
+ */
+int QWindows11Style::pixelMetric(PixelMetric metric, const QStyleOption *option, const QWidget *widget) const
+{
+ int res = 0;
+
+ switch (metric) {
+ case QStyle::PM_IndicatorWidth:
+ case QStyle::PM_IndicatorHeight:
+ case QStyle::PM_ExclusiveIndicatorWidth:
+ case QStyle::PM_ExclusiveIndicatorHeight:
+ res = 16;
+ break;
+ case QStyle::PM_SliderLength:
+ res = int(QStyleHelper::dpiScaled(16, option));
+ break;
+ case QStyle::PM_TitleBarButtonIconSize:
+ res = 16;
+ break;
+ case QStyle::PM_TitleBarButtonSize:
+ res = 32;
+ break;
+ case QStyle::PM_ScrollBarExtent:
+ res = 12;
+ break;
+ default:
+ res = QWindowsVistaStyle::pixelMetric(metric, option, widget);
+ }
+
+ return res;
+}
+
+void QWindows11Style::polish(QWidget* widget)
+{
+ QWindowsVistaStyle::polish(widget);
+ if (widget->inherits("QScrollBar") || widget->inherits("QComboBoxPrivateContainer") || widget->inherits("QMenu")) {
+ bool wasCreated = widget->testAttribute(Qt::WA_WState_Created);
+ bool layoutDirection = widget->testAttribute(Qt::WA_RightToLeft);
+ widget->setAttribute(Qt::WA_OpaquePaintEvent,false);
+ widget->setAttribute(Qt::WA_TranslucentBackground);
+ widget->setWindowFlag(Qt::FramelessWindowHint);
+ widget->setWindowFlag(Qt::NoDropShadowWindowHint);
+ widget->setAttribute(Qt::WA_RightToLeft, layoutDirection);
+ widget->setAttribute(Qt::WA_WState_Created, wasCreated);
+ auto pal = widget->palette();
+ pal.setColor(widget->backgroundRole(), Qt::transparent);
+ widget->setPalette(pal);
+ }
+ if (widget->inherits("QComboBoxPrivateContainer") || widget->inherits("QMenu")) {
+ QGraphicsDropShadowEffect* dropshadow = new QGraphicsDropShadowEffect(widget);
+ dropshadow->setBlurRadius(3);
+ dropshadow->setXOffset(3);
+ dropshadow->setYOffset(3);
+ widget->setGraphicsEffect(dropshadow);
+ }
+ if (widget->inherits("QComboBox")) {
+
+ QComboBox* cb = qobject_cast<QComboBox*>(widget);
+ if (cb->isEditable()) {
+ QLineEdit *le = cb->lineEdit();
+ le->setFrame(false);
+ }
+ }
+ if (widget->inherits("QGraphicsView") && !widget->inherits("QTextEdit")) {
+ QPalette pal = widget->palette();
+ pal.setColor(QPalette::Base, pal.window().color());
+ widget->setPalette(pal);
+ }
+ else if (widget->inherits("QAbstractScrollArea") && !widget->inherits("QMdiArea")) {
+ if (const auto *scrollarea = qobject_cast<QAbstractScrollArea *>(widget)) {
+ QPalette pal = widget->palette();
+ QColor backgroundColor = widget->palette().base().color();
+ backgroundColor.setAlpha(255);
+ pal.setColor(scrollarea->viewport()->backgroundRole(), backgroundColor);
+ scrollarea->viewport()->setPalette(pal);
+ }
+ }
+ if (widget->inherits("QCommandLinkButton")) {
+ widget->setProperty("_qt_usingVistaStyle",false);
+ QPalette pal = widget->palette();
+ pal.setColor(QPalette::ButtonText, pal.text().color());
+ pal.setColor(QPalette::BrightText, pal.text().color());
+ widget->setPalette(pal);
+ }
+}
+
+
+/*
+The colors for Windows 11 are taken from the official WinUI3 Figma style at
+https://www.figma.com/community/file/1159947337437047524
+*/
+static void populateLightSystemBasePalette(QPalette &result)
+{
+ static QString oldStyleSheet;
+ const bool styleSheetChanged = oldStyleSheet != qApp->styleSheet();
+
+ QPalette standardPalette = QApplication::palette();
+ const QColor textColor = QColor(0x00,0x00,0x00,0xE4);
+
+ const QColor btnFace = QColor(0xFF,0xFF,0xFF,0xB3);
+ const QColor btnHighlight = result.accent().color();
+ const QColor btnColor = result.button().color();
+
+ if (standardPalette.color(QPalette::Highlight) == result.color(QPalette::Highlight) || styleSheetChanged)
+ result.setColor(QPalette::Highlight, btnHighlight);
+ if (standardPalette.color(QPalette::WindowText) == result.color(QPalette::WindowText) || styleSheetChanged)
+ result.setColor(QPalette::WindowText, textColor);
+ if (standardPalette.color(QPalette::Button) == result.color(QPalette::Button) || styleSheetChanged)
+ result.setColor(QPalette::Button, btnFace);
+ if (standardPalette.color(QPalette::Light) == result.color(QPalette::Light) || styleSheetChanged)
+ result.setColor(QPalette::Light, btnColor.lighter(150));
+ if (standardPalette.color(QPalette::Dark) == result.color(QPalette::Dark) || styleSheetChanged)
+ result.setColor(QPalette::Dark, btnColor.darker(200));
+ if (standardPalette.color(QPalette::Mid) == result.color(QPalette::Mid) || styleSheetChanged)
+ result.setColor(QPalette::Mid, btnColor.darker(150));
+ if (standardPalette.color(QPalette::Text) == result.color(QPalette::Text) || styleSheetChanged)
+ result.setColor(QPalette::Text, textColor);
+ if (standardPalette.color(QPalette::BrightText) != result.color(QPalette::BrightText) || styleSheetChanged)
+ result.setColor(QPalette::BrightText, btnHighlight);
+ if (standardPalette.color(QPalette::Base) == result.color(QPalette::Base) || styleSheetChanged)
+ result.setColor(QPalette::Base, btnFace);
+ if (standardPalette.color(QPalette::Window) == result.color(QPalette::Window) || styleSheetChanged)
+ result.setColor(QPalette::Window, QColor(0xF3,0xF3,0xF3,0xFF));
+ if (standardPalette.color(QPalette::ButtonText) == result.color(QPalette::ButtonText) || styleSheetChanged)
+ result.setColor(QPalette::ButtonText, textColor);
+ if (standardPalette.color(QPalette::Midlight) == result.color(QPalette::Midlight) || styleSheetChanged)
+ result.setColor(QPalette::Midlight, btnColor.lighter(125));
+ if (standardPalette.color(QPalette::Shadow) == result.color(QPalette::Shadow) || styleSheetChanged)
+ result.setColor(QPalette::Shadow, Qt::black);
+ if (standardPalette.color(QPalette::ToolTipBase) == result.color(QPalette::ToolTipBase) || styleSheetChanged)
+ result.setColor(QPalette::ToolTipBase, result.window().color());
+ if (standardPalette.color(QPalette::ToolTipText) == result.color(QPalette::ToolTipText) || styleSheetChanged)
+ result.setColor(QPalette::ToolTipText, result.windowText().color());
+
+ if (result.midlight() == result.button())
+ result.setColor(QPalette::Midlight, btnColor.lighter(110));
+ oldStyleSheet = qApp->styleSheet();
+}
+
+/*!
+ \internal
+ */
+void QWindows11Style::polish(QPalette& pal)
+{
+ highContrastTheme = QGuiApplicationPrivate::colorScheme() == Qt::ColorScheme::Unknown;
+ colorSchemeIndex = QGuiApplicationPrivate::colorScheme() == Qt::ColorScheme::Light ? 0 : 1;
+
+ if (!highContrastTheme && colorSchemeIndex == 0)
+ populateLightSystemBasePalette(pal);
+
+ if (standardPalette().color(QPalette::Inactive, QPalette::Button) == pal.color(QPalette::Inactive, QPalette::Button))
+ pal.setColor(QPalette::Inactive, QPalette::Button, pal.button().color());
+ if (standardPalette().color(QPalette::Inactive, QPalette::Window) == pal.color(QPalette::Inactive, QPalette::Window))
+ pal.setColor(QPalette::Inactive, QPalette::Window, pal.window().color());
+ if (standardPalette().color(QPalette::Inactive, QPalette::Light) == pal.color(QPalette::Inactive, QPalette::Light))
+ pal.setColor(QPalette::Inactive, QPalette::Light, pal.light().color());
+ if (standardPalette().color(QPalette::Inactive, QPalette::Dark) == pal.color(QPalette::Inactive, QPalette::Dark))
+ pal.setColor(QPalette::Inactive, QPalette::Dark, pal.dark().color());
+ if (standardPalette().color(QPalette::Inactive, QPalette::Accent) == pal.color(QPalette::Inactive, QPalette::Accent))
+ pal.setColor(QPalette::Inactive, QPalette::Accent, pal.accent().color());
+ if (standardPalette().color(QPalette::Inactive, QPalette::Highlight) == pal.color(QPalette::Inactive, QPalette::Highlight))
+ pal.setColor(QPalette::Inactive, QPalette::Highlight, pal.highlight().color());
+ if (standardPalette().color(QPalette::Inactive, QPalette::HighlightedText) == pal.color(QPalette::Inactive, QPalette::HighlightedText))
+ pal.setColor(QPalette::Inactive, QPalette::HighlightedText, pal.highlightedText().color());
+ if (standardPalette().color(QPalette::Inactive, QPalette::Text) == pal.color(QPalette::Inactive, QPalette::Text))
+ pal.setColor(QPalette::Inactive, QPalette::Text, pal.text().color());
+ if (standardPalette().color(QPalette::Inactive, QPalette::WindowText) == pal.color(QPalette::Inactive, QPalette::WindowText))
+ pal.setColor(QPalette::Inactive, QPalette::WindowText, pal.windowText().color());
+
+ if (highContrastTheme)
+ pal.setColor(QPalette::Active, QPalette::HighlightedText, pal.windowText().color());
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/styles/modernwindows/qwindows11style_p.h b/src/plugins/styles/modernwindows/qwindows11style_p.h
new file mode 100644
index 0000000000..90e368f1ea
--- /dev/null
+++ b/src/plugins/styles/modernwindows/qwindows11style_p.h
@@ -0,0 +1,69 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QWINDOWS11STYLE_P_H
+#define QWINDOWS11STYLE_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 <QtWidgets/private/qtwidgetsglobal_p.h>
+#include <qwindowsvistastyle_p_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QWindows11StylePrivate;
+class QWindows11Style;
+
+class QWindows11Style : public QWindowsVistaStyle
+{
+ Q_OBJECT
+public:
+ QWindows11Style();
+ ~QWindows11Style() override;
+ void drawComplexControl(ComplexControl control, const QStyleOptionComplex *option,
+ QPainter *painter, const QWidget *widget) const override;
+ void drawPrimitive(PrimitiveElement element, const QStyleOption *option,
+ QPainter *painter, const QWidget *widget) const override;
+ QRect subElementRect(QStyle::SubElement element, const QStyleOption *option,
+ const QWidget *widget = nullptr) const override;
+ QRect subControlRect(ComplexControl control, const QStyleOptionComplex *option,
+ SubControl subControl, const QWidget *widget) const override;
+ void drawControl(ControlElement element, const QStyleOption *option,
+ QPainter *painter, const QWidget *widget) const override;
+ int styleHint(StyleHint hint, const QStyleOption *opt = nullptr,
+ const QWidget *widget = nullptr, QStyleHintReturn *returnData = nullptr) const override;
+ void polish(QWidget* widget) override;
+
+ QSize sizeFromContents(ContentsType type, const QStyleOption *option,
+ const QSize &size, const QWidget *widget) const override;
+ int pixelMetric(PixelMetric metric, const QStyleOption *option = nullptr,
+ const QWidget *widget = nullptr) const override;
+ void polish(QPalette &pal) override;
+protected:
+ QWindows11Style(QWindows11StylePrivate &dd);
+private:
+ Q_DISABLE_COPY_MOVE(QWindows11Style)
+ Q_DECLARE_PRIVATE(QWindows11Style)
+ friend class QStyleFactory;
+
+ bool highContrastTheme = false;
+ int colorSchemeIndex = 0;
+ const QFont assetFont = QFont("Segoe Fluent Icons"); //Font to load icons from
+};
+
+class QWindows11StylePrivate : public QWindowsVistaStylePrivate {
+ Q_DECLARE_PUBLIC(QWindows11Style)
+};
+
+QT_END_NAMESPACE
+
+#endif // QWINDOWS11STYLE_P_H
diff --git a/src/plugins/styles/modernwindows/qwindowsthemedata.cpp b/src/plugins/styles/modernwindows/qwindowsthemedata.cpp
new file mode 100644
index 0000000000..44569e054d
--- /dev/null
+++ b/src/plugins/styles/modernwindows/qwindowsthemedata.cpp
@@ -0,0 +1,59 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qwindowsthemedata_p.h"
+#include "qwindowsvistastyle_p_p.h"
+
+/* \internal
+ Returns \c true if the QWindowsThemeData is valid for use.
+*/
+bool QWindowsThemeData::isValid()
+{
+ return QWindowsVistaStylePrivate::useVista() && theme >= 0 && handle();
+}
+
+/* \internal
+ Returns the theme engine handle to the specific class.
+ If the handle hasn't been opened before, it opens the data, and
+ adds it to a static map, for caching.
+*/
+HTHEME QWindowsThemeData::handle()
+{
+ if (!QWindowsVistaStylePrivate::useVista())
+ return nullptr;
+
+ if (!htheme)
+ htheme = QWindowsVistaStylePrivate::createTheme(theme, QWindowsVistaStylePrivate::winId(widget));
+ return htheme;
+}
+
+/* \internal
+ Converts a QRect to the native RECT structure.
+*/
+RECT QWindowsThemeData::toRECT(const QRect &qr)
+{
+ RECT r;
+ r.left = qr.x();
+ r.right = qr.x() + qr.width();
+ r.top = qr.y();
+ r.bottom = qr.y() + qr.height();
+ return r;
+}
+
+/* \internal
+ Returns the native region of a part, if the part is considered
+ transparent. The region is scaled to the parts size (rect).
+*/
+HRGN QWindowsThemeData::mask(QWidget *widget)
+{
+ if (!IsThemeBackgroundPartiallyTransparent(handle(), partId, stateId))
+ return nullptr;
+
+ HRGN hrgn;
+ HDC dc = nullptr;
+ if (widget)
+ dc = QWindowsVistaStylePrivate::hdcForWidgetBackingStore(widget);
+ RECT nativeRect = toRECT(rect);
+ GetThemeBackgroundRegion(handle(), dc, partId, stateId, &nativeRect, &hrgn);
+ return hrgn;
+}
diff --git a/src/plugins/styles/modernwindows/qwindowsthemedata_p.h b/src/plugins/styles/modernwindows/qwindowsthemedata_p.h
new file mode 100644
index 0000000000..5de2bcbdea
--- /dev/null
+++ b/src/plugins/styles/modernwindows/qwindowsthemedata_p.h
@@ -0,0 +1,183 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QWINDOWSTHEMEDATA_P_H
+#define QWINDOWSTHEMEDATA_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 <qwidget.h>
+#include <qt_windows.h>
+#include <uxtheme.h>
+#include <vssym32.h>
+#include <limits.h>
+
+
+// TMT_TEXTSHADOWCOLOR is wrongly defined in mingw
+#if TMT_TEXTSHADOWCOLOR != 3818
+#undef TMT_TEXTSHADOWCOLOR
+#define TMT_TEXTSHADOWCOLOR 3818
+#endif
+#ifndef TST_NONE
+# define TST_NONE 0
+#endif
+
+// These defines are missing from the tmschema, but still exist as
+// states for their parts
+#ifndef MINBS_INACTIVE
+#define MINBS_INACTIVE 5
+#endif
+#ifndef MAXBS_INACTIVE
+#define MAXBS_INACTIVE 5
+#endif
+#ifndef RBS_INACTIVE
+#define RBS_INACTIVE 5
+#endif
+#ifndef HBS_INACTIVE
+#define HBS_INACTIVE 5
+#endif
+#ifndef CBS_INACTIVE
+#define CBS_INACTIVE 5
+#endif
+
+// Declarations -----------------------------------------------------------------------------------
+class QWindowsThemeData
+{
+public:
+ explicit QWindowsThemeData(const QWidget *w = nullptr, QPainter *p = nullptr, int themeIn = -1,
+ int part = 0, int state = 0, const QRect &r = QRect())
+ : widget(w), painter(p), theme(themeIn), partId(part), stateId(state),
+ mirrorHorizontally(false), mirrorVertically(false), noBorder(false),
+ noContent(false), invertPixels(false), rect(r)
+ {}
+
+ HRGN mask(QWidget *widget);
+ HTHEME handle();
+ bool isValid();
+ QSizeF size();
+
+ static QSizeF themeSize(const QWidget *w = nullptr, QPainter *p = nullptr,
+ int themeIn = -1, int part = 0, int state = 0);
+ static RECT toRECT(const QRect &qr);
+
+ QMarginsF margins(const QRect &rect, int propId = TMT_CONTENTMARGINS);
+ QMarginsF margins(int propId = TMT_CONTENTMARGINS);
+
+ const QWidget *widget;
+ QPainter *painter;
+
+ int theme;
+ HTHEME htheme = nullptr;
+ int partId;
+ int stateId;
+
+ uint mirrorHorizontally : 1;
+ uint mirrorVertically : 1;
+ uint noBorder : 1;
+ uint noContent : 1;
+ uint invertPixels : 1;
+ uint rotate = 0;
+ QRect rect;
+};
+
+struct ThemeMapKey {
+ int theme = 0;
+ int partId = -1;
+ int stateId = -1;
+ bool noBorder = false;
+ bool noContent = false;
+
+ ThemeMapKey() = default;
+ ThemeMapKey(const QWindowsThemeData &data)
+ : theme(data.theme), partId(data.partId), stateId(data.stateId),
+ noBorder(data.noBorder), noContent(data.noContent) {}
+
+};
+
+inline size_t qHash(const ThemeMapKey &key)
+{ return key.theme ^ key.partId ^ key.stateId; }
+
+inline bool operator==(const ThemeMapKey &k1, const ThemeMapKey &k2)
+{
+ return k1.theme == k2.theme
+ && k1.partId == k2.partId
+ && k1.stateId == k2.stateId;
+}
+
+enum AlphaChannelType {
+ UnknownAlpha = -1, // Alpha of part & state not yet known
+ NoAlpha, // Totally opaque, no need to touch alpha (RGB)
+ MaskAlpha, // Alpha channel must be fixed (ARGB)
+ RealAlpha // Proper alpha values from Windows (ARGB_Premultiplied)
+};
+
+struct ThemeMapData {
+ AlphaChannelType alphaType = UnknownAlpha; // Which type of alpha on part & state
+
+ bool dataValid : 1; // Only used to detect if hash value is ok
+ bool partIsTransparent : 1;
+ bool hasAlphaChannel : 1; // True = part & state has real Alpha
+ bool wasAlphaSwapped : 1; // True = alpha channel needs to be swapped
+ bool hadInvalidAlpha : 1; // True = alpha channel contained invalid alpha values
+
+ ThemeMapData() : dataValid(false), partIsTransparent(false),
+ hasAlphaChannel(false), wasAlphaSwapped(false), hadInvalidAlpha(false) {}
+};
+
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug d, const QWindowsThemeData &t);
+QDebug operator<<(QDebug d, const ThemeMapKey &k);
+QDebug operator<<(QDebug d, const ThemeMapData &td);
+#endif
+
+inline QSizeF QWindowsThemeData::size()
+{
+ QSizeF result(0, 0);
+ if (isValid()) {
+ SIZE size;
+ if (SUCCEEDED(GetThemePartSize(handle(), nullptr, partId, stateId, nullptr, TS_TRUE, &size)))
+ result = QSize(size.cx, size.cy);
+ }
+ return result;
+}
+
+inline QSizeF QWindowsThemeData::themeSize(const QWidget *w, QPainter *p, int themeIn, int part, int state)
+{
+ QWindowsThemeData theme(w, p, themeIn, part, state);
+ return theme.size();
+}
+
+inline QMarginsF QWindowsThemeData::margins(const QRect &qRect, int propId)
+{
+ QMarginsF result(0, 0, 0 ,0);
+ if (isValid()) {
+ MARGINS margins;
+ RECT rect = QWindowsThemeData::toRECT(qRect);
+ if (SUCCEEDED(GetThemeMargins(handle(), nullptr, partId, stateId, propId, &rect, &margins)))
+ result = QMargins(margins.cxLeftWidth, margins.cyTopHeight, margins.cxRightWidth, margins.cyBottomHeight);
+ }
+ return result;
+}
+
+inline QMarginsF QWindowsThemeData::margins(int propId)
+{
+ QMarginsF result(0, 0, 0 ,0);
+ if (isValid()) {
+ MARGINS margins;
+ if (SUCCEEDED(GetThemeMargins(handle(), nullptr, partId, stateId, propId, nullptr, &margins)))
+ result = QMargins(margins.cxLeftWidth, margins.cyTopHeight, margins.cxRightWidth, margins.cyBottomHeight);
+ }
+ return result;
+}
+
+#endif // QWINDOWSTHEMEDATA_P_H
diff --git a/src/plugins/styles/modernwindows/qwindowsvistaanimation.cpp b/src/plugins/styles/modernwindows/qwindowsvistaanimation.cpp
new file mode 100644
index 0000000000..ac9a5ad8c0
--- /dev/null
+++ b/src/plugins/styles/modernwindows/qwindowsvistaanimation.cpp
@@ -0,0 +1,15 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qwindowsvistaanimation_p.h"
+#include "qwindowsvistastyle_p_p.h"
+
+bool QWindowsVistaAnimation::isUpdateNeeded() const
+{
+ return QWindowsVistaStylePrivate::useVista();
+}
+
+void QWindowsVistaAnimation::paint(QPainter *painter, const QStyleOption *option)
+{
+ painter->drawImage(option->rect, currentImage());
+}
diff --git a/src/plugins/styles/modernwindows/qwindowsvistaanimation_p.h b/src/plugins/styles/modernwindows/qwindowsvistaanimation_p.h
new file mode 100644
index 0000000000..817fa5f4b5
--- /dev/null
+++ b/src/plugins/styles/modernwindows/qwindowsvistaanimation_p.h
@@ -0,0 +1,49 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QWINDOWSVISTAANIMATION_P_H
+#define QWINDOWSVISTAANIMATION_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 <private/qstyleanimation_p.h>
+#include <QtWidgets/private/qwindowsstyle_p.h>
+
+class QWindowsVistaAnimation : public QBlendStyleAnimation
+{
+ Q_OBJECT
+public:
+ QWindowsVistaAnimation(Type type, QObject *target) : QBlendStyleAnimation(type, target) { }
+
+ bool isUpdateNeeded() const override;
+ void paint(QPainter *painter, const QStyleOption *option);
+};
+
+
+// Handles state transition animations
+class QWindowsVistaTransition : public QWindowsVistaAnimation
+{
+ Q_OBJECT
+public:
+ QWindowsVistaTransition(QObject *target) : QWindowsVistaAnimation(Transition, target) {}
+};
+
+
+// Handles pulse animations (default buttons)
+class QWindowsVistaPulse: public QWindowsVistaAnimation
+{
+ Q_OBJECT
+public:
+ QWindowsVistaPulse(QObject *target) : QWindowsVistaAnimation(Pulse, target) {}
+};
+
+#endif // QWINDOWSVISTAANIMATION_P_H
diff --git a/src/plugins/styles/modernwindows/qwindowsvistastyle.cpp b/src/plugins/styles/modernwindows/qwindowsvistastyle.cpp
new file mode 100644
index 0000000000..1df134b629
--- /dev/null
+++ b/src/plugins/styles/modernwindows/qwindowsvistastyle.cpp
@@ -0,0 +1,5012 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qwindowsvistastyle_p.h"
+#include "qwindowsvistastyle_p_p.h"
+#include "qwindowsvistaanimation_p.h"
+#include <qoperatingsystemversion.h>
+#include <qscreen.h>
+#include <qstylehints.h>
+#include <qwindow.h>
+#include <private/qstyleanimation_p.h>
+#include <private/qstylehelper_p.h>
+#include <qpa/qplatformnativeinterface.h>
+#include <private/qapplication_p.h>
+#include <private/qsystemlibrary_p.h>
+#include <private/qwindowsthemecache_p.h>
+
+#include "qdrawutil.h" // for now
+#include <qbackingstore.h>
+
+
+QT_BEGIN_NAMESPACE
+
+using namespace Qt::StringLiterals;
+
+static const int windowsItemFrame = 2; // menu item frame width
+static const int windowsItemHMargin = 3; // menu item hor text margin
+static const int windowsItemVMargin = 4; // menu item ver text margin
+static const int windowsArrowHMargin = 6; // arrow horizontal margin
+static const int windowsRightBorder = 15; // right border on windows
+
+#ifndef TMT_CONTENTMARGINS
+# define TMT_CONTENTMARGINS 3602
+#endif
+#ifndef TMT_SIZINGMARGINS
+# define TMT_SIZINGMARGINS 3601
+#endif
+#ifndef LISS_NORMAL
+# define LISS_NORMAL 1
+# define LISS_HOT 2
+# define LISS_SELECTED 3
+# define LISS_DISABLED 4
+# define LISS_SELECTEDNOTFOCUS 5
+# define LISS_HOTSELECTED 6
+#endif
+#ifndef BP_COMMANDLINK
+# define BP_COMMANDLINK 6
+# define BP_COMMANDLINKGLYPH 7
+# define CMDLGS_NORMAL 1
+# define CMDLGS_HOT 2
+# define CMDLGS_PRESSED 3
+# define CMDLGS_DISABLED 4
+#endif
+
+// QWindowsVistaStylePrivate -------------------------------------------------------------------------
+// Static initializations
+HWND QWindowsVistaStylePrivate::m_vistaTreeViewHelper = nullptr;
+bool QWindowsVistaStylePrivate::useVistaTheme = false;
+Q_CONSTINIT QBasicAtomicInt QWindowsVistaStylePrivate::ref = Q_BASIC_ATOMIC_INITIALIZER(-1); // -1 based refcounting
+
+static void qt_add_rect(HRGN &winRegion, QRect r)
+{
+ HRGN rgn = CreateRectRgn(r.left(), r.top(), r.x() + r.width(), r.y() + r.height());
+ if (rgn) {
+ HRGN dest = CreateRectRgn(0,0,0,0);
+ int result = CombineRgn(dest, winRegion, rgn, RGN_OR);
+ if (result) {
+ DeleteObject(winRegion);
+ winRegion = dest;
+ }
+ DeleteObject(rgn);
+ }
+}
+
+static HRGN qt_hrgn_from_qregion(const QRegion &region)
+{
+ HRGN hRegion = CreateRectRgn(0,0,0,0);
+ if (region.rectCount() == 1) {
+ qt_add_rect(hRegion, region.boundingRect());
+ return hRegion;
+ }
+ for (const QRect &rect : region)
+ qt_add_rect(hRegion, rect);
+ return hRegion;
+}
+
+static inline Qt::Orientation progressBarOrientation(const QStyleOption *option = nullptr)
+{
+ if (const auto *pb = qstyleoption_cast<const QStyleOptionProgressBar *>(option))
+ return pb->state & QStyle::State_Horizontal ? Qt::Horizontal : Qt::Vertical;
+ return Qt::Horizontal;
+}
+
+/* In order to obtain the correct VistaTreeViewTheme (arrows for PE_IndicatorBranch),
+ * we need to set the windows "explorer" theme explicitly on a native
+ * window and open the "TREEVIEW" theme handle passing its window handle
+ * in order to get Vista-style item view themes (particularly drawBackground()
+ * for selected items needs this).
+ * We invoke a service of the native Windows interface to create
+ * a non-visible window handle, open the theme on it and insert it into
+ * the cache so that it is found by QWindowsThemeData::handle() first.
+ */
+static inline HWND createTreeViewHelperWindow()
+{
+ using QWindowsApplication = QNativeInterface::Private::QWindowsApplication;
+
+ HWND result = nullptr;
+ if (auto nativeWindowsApp = dynamic_cast<QWindowsApplication *>(QGuiApplicationPrivate::platformIntegration()))
+ result = nativeWindowsApp->createMessageWindow(QStringLiteral("QTreeViewThemeHelperWindowClass"),
+ QStringLiteral("QTreeViewThemeHelperWindow"));
+ return result;
+}
+
+enum TransformType { SimpleTransform, HighDpiScalingTransform, ComplexTransform };
+
+static inline TransformType transformType(const QTransform &transform, qreal devicePixelRatio)
+{
+ if (transform.type() <= QTransform::TxTranslate)
+ return SimpleTransform;
+ if (transform.type() > QTransform::TxScale)
+ return ComplexTransform;
+ return qFuzzyCompare(transform.m11(), devicePixelRatio)
+ && qFuzzyCompare(transform.m22(), devicePixelRatio)
+ ? HighDpiScalingTransform : ComplexTransform;
+}
+
+// QTBUG-60571: Exclude known fully opaque theme parts which produce values
+// invalid in ARGB32_Premultiplied (for example, 0x00ffffff).
+static inline bool isFullyOpaque(const QWindowsThemeData &themeData)
+{
+ return themeData.theme == QWindowsVistaStylePrivate::TaskDialogTheme && themeData.partId == TDLG_PRIMARYPANEL;
+}
+
+static inline QRectF scaleRect(const QRectF &r, qreal factor)
+{
+ return r.isValid() && factor > 1
+ ? QRectF(r.topLeft() * factor, r.size() * factor) : r;
+}
+
+static QRegion scaleRegion(const QRegion &region, qreal factor)
+{
+ if (region.isEmpty() || qFuzzyCompare(factor, qreal(1)))
+ return region;
+ QRegion result;
+ for (const QRect &rect : region)
+ result += QRectF(QPointF(rect.topLeft()) * factor, QSizeF(rect.size() * factor)).toRect();
+ return result;
+}
+
+
+/* \internal
+ Checks if the theme engine can/should be used, or if we should fall back
+ to Windows style. For Windows 10, this will still return false for the
+ High Contrast themes.
+*/
+bool QWindowsVistaStylePrivate::useVista(bool update)
+{
+ if (update)
+ useVistaTheme = IsThemeActive() && (IsAppThemed() || !QCoreApplication::instance());
+ return useVistaTheme;
+}
+
+/* \internal
+ Handles refcounting, and queries the theme engine for usage.
+*/
+void QWindowsVistaStylePrivate::init(bool force)
+{
+ if (ref.ref() && !force)
+ return;
+ if (!force) // -1 based atomic refcounting
+ ref.ref();
+
+ useVista(true);
+}
+
+/* \internal
+ Cleans up all static data.
+*/
+void QWindowsVistaStylePrivate::cleanup(bool force)
+{
+ if (bufferBitmap) {
+ if (bufferDC && nullBitmap)
+ SelectObject(bufferDC, nullBitmap);
+ DeleteObject(bufferBitmap);
+ bufferBitmap = nullptr;
+ }
+
+ if (bufferDC)
+ DeleteDC(bufferDC);
+ bufferDC = nullptr;
+
+ if (ref.deref() && !force)
+ return;
+ if (!force) // -1 based atomic refcounting
+ ref.deref();
+
+ useVistaTheme = false;
+ cleanupHandleMap();
+}
+
+bool QWindowsVistaStylePrivate::transitionsEnabled() const
+{
+ BOOL animEnabled = false;
+ if (SystemParametersInfo(SPI_GETCLIENTAREAANIMATION, 0, &animEnabled, 0))
+ {
+ if (animEnabled)
+ return true;
+ }
+ return false;
+}
+
+int QWindowsVistaStylePrivate::pixelMetricFromSystemDp(QStyle::PixelMetric pm, const QStyleOption *option, const QWidget *widget)
+{
+ switch (pm) {
+ case QStyle::PM_IndicatorWidth:
+ return QWindowsThemeData::themeSize(widget, nullptr, QWindowsVistaStylePrivate::ButtonTheme, BP_CHECKBOX, CBS_UNCHECKEDNORMAL).width();
+ case QStyle::PM_IndicatorHeight:
+ return QWindowsThemeData::themeSize(widget, nullptr, QWindowsVistaStylePrivate::ButtonTheme, BP_CHECKBOX, CBS_UNCHECKEDNORMAL).height();
+ case QStyle::PM_ExclusiveIndicatorWidth:
+ return QWindowsThemeData::themeSize(widget, nullptr, QWindowsVistaStylePrivate::ButtonTheme, BP_RADIOBUTTON, RBS_UNCHECKEDNORMAL).width();
+ case QStyle::PM_ExclusiveIndicatorHeight:
+ return QWindowsThemeData::themeSize(widget, nullptr, QWindowsVistaStylePrivate::ButtonTheme, BP_RADIOBUTTON, RBS_UNCHECKEDNORMAL).height();
+ case QStyle::PM_ProgressBarChunkWidth:
+ return progressBarOrientation(option) == Qt::Horizontal
+ ? QWindowsThemeData::themeSize(widget, nullptr, QWindowsVistaStylePrivate::ProgressTheme, PP_CHUNK).width()
+ : QWindowsThemeData::themeSize(widget, nullptr, QWindowsVistaStylePrivate::ProgressTheme, PP_CHUNKVERT).height();
+ case QStyle::PM_SliderThickness:
+ return QWindowsThemeData::themeSize(widget, nullptr, QWindowsVistaStylePrivate::TrackBarTheme, TKP_THUMB).height();
+ case QStyle::PM_TitleBarHeight:
+ return QWindowsStylePrivate::pixelMetricFromSystemDp(QStyle::PM_TitleBarHeight, option, widget);
+ case QStyle::PM_MdiSubWindowFrameWidth:
+ return QWindowsThemeData::themeSize(widget, nullptr, QWindowsVistaStylePrivate::WindowTheme, WP_FRAMELEFT, FS_ACTIVE).width();
+ case QStyle::PM_DockWidgetFrameWidth:
+ return QWindowsThemeData::themeSize(widget, nullptr, QWindowsVistaStylePrivate::WindowTheme, WP_SMALLFRAMERIGHT, FS_ACTIVE).width();
+ default:
+ break;
+ }
+ return QWindowsVistaStylePrivate::InvalidMetric;
+}
+
+int QWindowsVistaStylePrivate::fixedPixelMetric(QStyle::PixelMetric pm)
+{
+ switch (pm) {
+ case QStyle::PM_DockWidgetTitleBarButtonMargin:
+ return 5;
+ case QStyle::PM_ScrollBarSliderMin:
+ return 18;
+ case QStyle::PM_MenuHMargin:
+ case QStyle::PM_MenuVMargin:
+ return 0;
+ case QStyle::PM_MenuPanelWidth:
+ return 3;
+ default:
+ break;
+ }
+
+ return QWindowsVistaStylePrivate::InvalidMetric;
+}
+
+bool QWindowsVistaStylePrivate::initVistaTreeViewTheming()
+{
+ if (m_vistaTreeViewHelper)
+ return true;
+
+ m_vistaTreeViewHelper = createTreeViewHelperWindow();
+ if (!m_vistaTreeViewHelper) {
+ qWarning("Unable to create the treeview helper window.");
+ return false;
+ }
+ if (FAILED(SetWindowTheme(m_vistaTreeViewHelper, L"explorer", nullptr))) {
+ qErrnoWarning("SetWindowTheme() failed.");
+ cleanupVistaTreeViewTheming();
+ return false;
+ }
+ return true;
+}
+
+void QWindowsVistaStylePrivate::cleanupVistaTreeViewTheming()
+{
+ if (m_vistaTreeViewHelper) {
+ DestroyWindow(m_vistaTreeViewHelper);
+ m_vistaTreeViewHelper = nullptr;
+ }
+}
+
+/* \internal
+ Closes all open theme data handles to ensure that we don't leak
+ resources, and that we don't refer to old handles when for
+ example the user changes the theme style.
+*/
+void QWindowsVistaStylePrivate::cleanupHandleMap()
+{
+ QWindowsThemeCache::clearAllThemeCaches();
+ QWindowsVistaStylePrivate::cleanupVistaTreeViewTheming();
+}
+
+HTHEME QWindowsVistaStylePrivate::createTheme(int theme, HWND hwnd)
+{
+ if (theme == VistaTreeViewTheme && QWindowsVistaStylePrivate::initVistaTreeViewTheming())
+ hwnd = QWindowsVistaStylePrivate::m_vistaTreeViewHelper;
+ return QWindowsThemeCache::createTheme(theme, hwnd);
+}
+
+QBackingStore *QWindowsVistaStylePrivate::backingStoreForWidget(const QWidget *widget)
+{
+ if (QBackingStore *backingStore = widget->backingStore())
+ return backingStore;
+ if (const QWidget *topLevel = widget->nativeParentWidget())
+ if (QBackingStore *topLevelBackingStore = topLevel->backingStore())
+ return topLevelBackingStore;
+ return nullptr;
+}
+
+HDC QWindowsVistaStylePrivate::hdcForWidgetBackingStore(const QWidget *widget)
+{
+ if (QBackingStore *backingStore = backingStoreForWidget(widget)) {
+ QPlatformNativeInterface *nativeInterface = QGuiApplication::platformNativeInterface();
+ if (nativeInterface)
+ return static_cast<HDC>(nativeInterface->nativeResourceForBackingStore(QByteArrayLiteral("getDC"), backingStore));
+ }
+ return nullptr;
+}
+
+QString QWindowsVistaStylePrivate::themeName(int theme)
+{
+ return QWindowsThemeCache::themeName(theme);
+}
+
+bool QWindowsVistaStylePrivate::isItemViewDelegateLineEdit(const QWidget *widget)
+{
+ if (!widget)
+ return false;
+ const QWidget *parent1 = widget->parentWidget();
+ // Exclude dialogs or other toplevels parented on item views.
+ if (!parent1 || parent1->isWindow())
+ return false;
+ const QWidget *parent2 = parent1->parentWidget();
+ return parent2 && widget->inherits("QLineEdit")
+ && parent2->inherits("QAbstractItemView");
+}
+
+// Returns whether base color is set for this widget
+bool QWindowsVistaStylePrivate::isLineEditBaseColorSet(const QStyleOption *option, const QWidget *widget)
+{
+ uint resolveMask = option->palette.resolveMask();
+ if (widget) {
+ // Since spin box includes a line edit we need to resolve the palette mask also from
+ // the parent, as while the color is always correct on the palette supplied by panel,
+ // the mask can still be empty. If either mask specifies custom base color, use that.
+#if QT_CONFIG(spinbox)
+ if (const QAbstractSpinBox *spinbox = qobject_cast<QAbstractSpinBox*>(widget->parentWidget()))
+ resolveMask |= spinbox->palette().resolveMask();
+#endif // QT_CONFIG(spinbox)
+ }
+ return (resolveMask & (1 << QPalette::Base)) != 0;
+}
+
+/*! \internal
+ This function will always return a valid window handle, and might
+ create a limbo widget to do so.
+ We often need a window handle to for example open theme data, so
+ this function ensures that we get one.
+*/
+HWND QWindowsVistaStylePrivate::winId(const QWidget *widget)
+{
+ if (widget) {
+ if (const HWND hwnd = QApplicationPrivate::getHWNDForWidget(const_cast<QWidget *>(widget)))
+ return hwnd;
+ }
+
+ // Find top level with native window (there might be dialogs that do not have one).
+ const auto allWindows = QGuiApplication::allWindows();
+ for (const QWindow *window : allWindows) {
+ if (window->isTopLevel() && window->type() != Qt::Desktop && window->handle() != nullptr)
+ return reinterpret_cast<HWND>(window->winId());
+ }
+
+ return GetDesktopWindow();
+}
+
+/*! \internal
+ Returns a native buffer (DIB section) of at least the size of
+ ( \a x , \a y ). The buffer has a 32 bit depth, to not lose
+ the alpha values on proper alpha-pixmaps.
+*/
+HBITMAP QWindowsVistaStylePrivate::buffer(int w, int h)
+{
+ // If we already have a HBITMAP which is of adequate size, just return that
+ if (bufferBitmap) {
+ if (bufferW >= w && bufferH >= h)
+ return bufferBitmap;
+ // Not big enough, discard the old one
+ if (bufferDC && nullBitmap)
+ SelectObject(bufferDC, nullBitmap);
+ DeleteObject(bufferBitmap);
+ bufferBitmap = nullptr;
+ }
+
+ w = qMax(bufferW, w);
+ h = qMax(bufferH, h);
+
+ if (!bufferDC) {
+ HDC displayDC = GetDC(nullptr);
+ bufferDC = CreateCompatibleDC(displayDC);
+ ReleaseDC(nullptr, displayDC);
+ }
+
+ // Define the header
+ BITMAPINFO bmi;
+ memset(&bmi, 0, sizeof(bmi));
+ bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ bmi.bmiHeader.biWidth = w;
+ bmi.bmiHeader.biHeight = -h;
+ bmi.bmiHeader.biPlanes = 1;
+ bmi.bmiHeader.biBitCount = 32;
+ bmi.bmiHeader.biCompression = BI_RGB;
+
+ // Create the pixmap
+ bufferPixels = nullptr;
+ bufferBitmap = CreateDIBSection(bufferDC, &bmi, DIB_RGB_COLORS, reinterpret_cast<void **>(&bufferPixels), nullptr, 0);
+ GdiFlush();
+ nullBitmap = static_cast<HBITMAP>(SelectObject(bufferDC, bufferBitmap));
+
+ if (Q_UNLIKELY(!bufferBitmap)) {
+ qErrnoWarning("QWindowsVistaStylePrivate::buffer(%dx%d), CreateDIBSection() failed.", w, h);
+ bufferW = 0;
+ bufferH = 0;
+ return nullptr;
+ }
+ if (Q_UNLIKELY(!bufferPixels)) {
+ qErrnoWarning("QWindowsVistaStylePrivate::buffer(%dx%d), CreateDIBSection() did not allocate pixel data.", w, h);
+ bufferW = 0;
+ bufferH = 0;
+ return nullptr;
+ }
+ bufferW = w;
+ bufferH = h;
+#ifdef DEBUG_XP_STYLE
+ qDebug("Creating new dib section (%d, %d)", w, h);
+#endif
+ return bufferBitmap;
+}
+
+/*! \internal
+ Returns \c true if the part contains any transparency at all. This does
+ not indicate what kind of transparency we're dealing with. It can be
+ - Alpha transparency
+ - Masked transparency
+*/
+bool QWindowsVistaStylePrivate::isTransparent(QWindowsThemeData &themeData)
+{
+ return IsThemeBackgroundPartiallyTransparent(themeData.handle(), themeData.partId,
+ themeData.stateId);
+}
+
+
+/*! \internal
+ Returns a QRegion of the region of the part
+*/
+QRegion QWindowsVistaStylePrivate::region(QWindowsThemeData &themeData)
+{
+ HRGN hRgn = nullptr;
+ const qreal factor = QWindowsStylePrivate::nativeMetricScaleFactor(themeData.widget);
+ RECT rect = themeData.toRECT(QRect(themeData.rect.topLeft() / factor, themeData.rect.size() / factor));
+ if (!SUCCEEDED(GetThemeBackgroundRegion(themeData.handle(), bufferHDC(), themeData.partId,
+ themeData.stateId, &rect, &hRgn))) {
+ return QRegion();
+ }
+
+ HRGN dest = CreateRectRgn(0, 0, 0, 0);
+ const bool success = CombineRgn(dest, hRgn, nullptr, RGN_COPY) != ERROR;
+
+ QRegion region;
+
+ if (success) {
+ QVarLengthArray<char> buf(256);
+ RGNDATA *rd = reinterpret_cast<RGNDATA *>(buf.data());
+ if (GetRegionData(dest, buf.size(), rd) == 0) {
+ const auto numBytes = GetRegionData(dest, 0, nullptr);
+ if (numBytes > 0) {
+ buf.resize(numBytes);
+ rd = reinterpret_cast<RGNDATA *>(buf.data());
+ if (GetRegionData(dest, numBytes, rd) == 0)
+ rd = nullptr;
+ } else {
+ rd = nullptr;
+ }
+ }
+ if (rd) {
+ RECT *r = reinterpret_cast<RECT *>(rd->Buffer);
+ for (uint i = 0; i < rd->rdh.nCount; ++i) {
+ QRect rect;
+ rect.setCoords(int(r->left * factor), int(r->top * factor),
+ int((r->right - 1) * factor), int((r->bottom - 1) * factor));
+ ++r;
+ region |= rect;
+ }
+ }
+ }
+
+ DeleteObject(hRgn);
+ DeleteObject(dest);
+
+ return region;
+}
+
+/*! \internal
+ Returns \c true if the native doublebuffer contains pixels with
+ varying alpha value.
+*/
+bool QWindowsVistaStylePrivate::hasAlphaChannel(const QRect &rect)
+{
+ const int startX = rect.left();
+ const int startY = rect.top();
+ const int w = rect.width();
+ const int h = rect.height();
+
+ int firstAlpha = -1;
+ for (int y = startY; y < h/2; ++y) {
+ auto buffer = reinterpret_cast<const DWORD *>(bufferPixels) + (y * bufferW);
+ for (int x = startX; x < w; ++x, ++buffer) {
+ int alpha = (*buffer) >> 24;
+ if (firstAlpha == -1)
+ firstAlpha = alpha;
+ else if (alpha != firstAlpha)
+ return true;
+ }
+ }
+ return false;
+}
+
+/*! \internal
+ When the theme engine paints both a true alpha pixmap and a glyph
+ into our buffer, the glyph might not contain a proper alpha value.
+ The rule of thumb for premultiplied pixmaps is that the color
+ values of a pixel can never be higher than the alpha values, so
+ we use this to our advantage here, and fix all instances where
+ this occurs.
+*/
+bool QWindowsVistaStylePrivate::fixAlphaChannel(const QRect &rect)
+{
+ const int startX = rect.left();
+ const int startY = rect.top();
+ const int w = rect.width();
+ const int h = rect.height();
+ bool hasFixedAlphaValue = false;
+
+ for (int y = startY; y < h; ++y) {
+ auto buffer = reinterpret_cast<DWORD *>(bufferPixels) + (y * bufferW);
+ for (int x = startX; x < w; ++x, ++buffer) {
+ uint pixel = *buffer;
+ int alpha = qAlpha(pixel);
+ if (qRed(pixel) > alpha || qGreen(pixel) > alpha || qBlue(pixel) > alpha) {
+ *buffer |= 0xff000000;
+ hasFixedAlphaValue = true;
+ }
+ }
+ }
+ return hasFixedAlphaValue;
+}
+
+/*! \internal
+ Swaps the alpha values on certain pixels:
+ 0xFF?????? -> 0x00??????
+ 0x00?????? -> 0xFF??????
+ Used to determine the mask of a non-alpha transparent pixmap in
+ the native doublebuffer, and swap the alphas so we may paint
+ the image as a Premultiplied QImage with drawImage(), and obtain
+ the mask transparency.
+*/
+bool QWindowsVistaStylePrivate::swapAlphaChannel(const QRect &rect, bool allPixels)
+{
+ const int startX = rect.left();
+ const int startY = rect.top();
+ const int w = rect.width();
+ const int h = rect.height();
+ bool valueChange = false;
+
+ // Flip the alphas, so that 255-alpha pixels are 0, and 0-alpha are 255.
+ for (int y = startY; y < h; ++y) {
+ auto buffer = reinterpret_cast<DWORD *>(bufferPixels) + (y * bufferW);
+ for (int x = startX; x < w; ++x, ++buffer) {
+ if (allPixels) {
+ *buffer |= 0xFF000000;
+ continue;
+ }
+ unsigned int alphaValue = (*buffer) & 0xFF000000;
+ if (alphaValue == 0xFF000000) {
+ *buffer = 0;
+ valueChange = true;
+ } else if (alphaValue == 0) {
+ *buffer |= 0xFF000000;
+ valueChange = true;
+ }
+ }
+ }
+ return valueChange;
+}
+
+/*! \internal
+ Main theme drawing function.
+ Determines the correct lowlevel drawing method depending on several
+ factors.
+ Use drawBackgroundThruNativeBuffer() if:
+ - Painter does not have an HDC
+ - Theme part is flipped (mirrored horizontally)
+ else use drawBackgroundDirectly().
+ \note drawBackgroundThruNativeBuffer() can return false for large
+ sizes due to buffer()/CreateDIBSection() failing.
+*/
+bool QWindowsVistaStylePrivate::drawBackground(QWindowsThemeData &themeData, qreal correctionFactor)
+{
+ if (themeData.rect.isEmpty())
+ return true;
+
+ QPainter *painter = themeData.painter;
+ Q_ASSERT_X(painter != nullptr, "QWindowsVistaStylePrivate::drawBackground()", "Trying to draw a theme part without a painter");
+ if (!painter || !painter->isActive())
+ return false;
+
+ painter->save();
+
+ // Access paintDevice via engine since the painter may
+ // return the clip device which can still be a widget device in case of grabWidget().
+
+ bool translucentToplevel = false;
+ const QPaintDevice *paintDevice = painter->device();
+ const qreal aditionalDevicePixelRatio = themeData.widget ? themeData.widget->devicePixelRatio() : qreal(1);
+ if (paintDevice->devType() == QInternal::Widget) {
+ const QWidget *window = static_cast<const QWidget *>(paintDevice)->window();
+ translucentToplevel = window->testAttribute(Qt::WA_TranslucentBackground);
+ }
+
+ const TransformType tt = transformType(painter->deviceTransform(), aditionalDevicePixelRatio);
+
+ bool canDrawDirectly = false;
+ if (themeData.widget && painter->opacity() == 1.0 && !themeData.rotate
+ && !isFullyOpaque(themeData)
+ && tt != ComplexTransform && !themeData.mirrorVertically && !themeData.invertPixels
+ && !translucentToplevel) {
+ // Draw on backing store DC only for real widgets or backing store images.
+ const QPaintDevice *enginePaintDevice = painter->paintEngine()->paintDevice();
+ switch (enginePaintDevice->devType()) {
+ case QInternal::Widget:
+ canDrawDirectly = true;
+ break;
+ case QInternal::Image:
+ // Ensure the backing store has received as resize and is initialized.
+ if (QBackingStore *bs = backingStoreForWidget(themeData.widget)) {
+ if (bs->size().isValid() && bs->paintDevice() == enginePaintDevice)
+ canDrawDirectly = true;
+ }
+ break;
+ }
+ }
+
+ const HDC dc = canDrawDirectly ? hdcForWidgetBackingStore(themeData.widget) : nullptr;
+ const bool result = dc && qFuzzyCompare(correctionFactor, qreal(1))
+ ? drawBackgroundDirectly(dc, themeData, aditionalDevicePixelRatio)
+ : drawBackgroundThruNativeBuffer(themeData, aditionalDevicePixelRatio, correctionFactor);
+ painter->restore();
+ return result;
+}
+
+/*! \internal
+ This function draws the theme parts directly to the paintengines HDC.
+ Do not use this if you need to perform other transformations on the
+ resulting data.
+*/
+bool QWindowsVistaStylePrivate::drawBackgroundDirectly(HDC dc, QWindowsThemeData &themeData, qreal additionalDevicePixelRatio)
+{
+ QPainter *painter = themeData.painter;
+
+ const auto &deviceTransform = painter->deviceTransform();
+ const QPointF redirectionDelta(deviceTransform.dx(), deviceTransform.dy());
+ const QRect area = scaleRect(QRectF(themeData.rect), additionalDevicePixelRatio).translated(redirectionDelta).toRect();
+
+ QRegion sysRgn = painter->paintEngine()->systemClip();
+ if (sysRgn.isEmpty())
+ sysRgn = area;
+ else
+ sysRgn &= area;
+ if (painter->hasClipping())
+ sysRgn &= scaleRegion(painter->clipRegion(), additionalDevicePixelRatio).translated(redirectionDelta.toPoint());
+ HRGN hrgn = qt_hrgn_from_qregion(sysRgn);
+ SelectClipRgn(dc, hrgn);
+
+#ifdef DEBUG_XP_STYLE
+ printf("---[ DIRECT PAINTING ]------------------> Name(%-10s) Part(%d) State(%d)\n",
+ qPrintable(themeData.name), themeData.partId, themeData.stateId);
+ showProperties(themeData);
+#endif
+
+ RECT drawRECT = themeData.toRECT(area);
+ DTBGOPTS drawOptions;
+ memset(&drawOptions, 0, sizeof(drawOptions));
+ drawOptions.dwSize = sizeof(drawOptions);
+ drawOptions.rcClip = themeData.toRECT(sysRgn.boundingRect());
+ drawOptions.dwFlags = DTBG_CLIPRECT
+ | (themeData.noBorder ? DTBG_OMITBORDER : 0)
+ | (themeData.noContent ? DTBG_OMITCONTENT : 0)
+ | (themeData.mirrorHorizontally ? DTBG_MIRRORDC : 0);
+
+ const HRESULT result = DrawThemeBackgroundEx(themeData.handle(), dc, themeData.partId, themeData.stateId, &(drawRECT), &drawOptions);
+ SelectClipRgn(dc, nullptr);
+ DeleteObject(hrgn);
+ return SUCCEEDED(result);
+}
+
+/*! \internal
+ This function uses a secondary Native doublebuffer for painting parts.
+ It should only be used when the painteengine doesn't provide a proper
+ HDC for direct painting (e.g. when doing a grabWidget(), painting to
+ other pixmaps etc), or when special transformations are needed (e.g.
+ flips (horizontal mirroring only, vertical are handled by the theme
+ engine).
+
+ \a correctionFactor is an additional factor used to scale up controls
+ that are too small on High DPI screens, as has been observed for
+ WP_MDICLOSEBUTTON, WP_MDIRESTOREBUTTON, WP_MDIMINBUTTON (QTBUG-75927).
+*/
+bool QWindowsVistaStylePrivate::drawBackgroundThruNativeBuffer(QWindowsThemeData &themeData,
+ qreal additionalDevicePixelRatio,
+ qreal correctionFactor)
+{
+ QPainter *painter = themeData.painter;
+ QRectF rectF = scaleRect(QRectF(themeData.rect), additionalDevicePixelRatio);
+
+ if ((themeData.rotate + 90) % 180 == 0) { // Catch 90,270,etc.. degree flips.
+ rectF = QRectF(0, 0, rectF.height(), rectF.width());
+ }
+ rectF.moveTo(0, 0);
+
+ const bool hasCorrectionFactor = !qFuzzyCompare(correctionFactor, qreal(1));
+ QRect rect = rectF.toRect();
+ const QRect drawRect = hasCorrectionFactor
+ ? QRectF(rectF.topLeft() / correctionFactor, rectF.size() / correctionFactor).toRect()
+ : rect;
+ int partId = themeData.partId;
+ int stateId = themeData.stateId;
+ int w = rect.width();
+ int h = rect.height();
+
+ // Values initialized later, either from cached values, or from function calls
+ AlphaChannelType alphaType = UnknownAlpha;
+ bool stateHasData = true; // We assume so;
+ bool hasAlpha = false;
+ bool partIsTransparent;
+ bool potentialInvalidAlpha;
+
+ QString pixmapCacheKey = QStringLiteral("$qt_xp_");
+ pixmapCacheKey.append(themeName(themeData.theme));
+ pixmapCacheKey.append(QLatin1Char('p'));
+ pixmapCacheKey.append(QString::number(partId));
+ pixmapCacheKey.append(QLatin1Char('s'));
+ pixmapCacheKey.append(QString::number(stateId));
+ pixmapCacheKey.append(QLatin1Char('s'));
+ pixmapCacheKey.append(themeData.noBorder ? QLatin1Char('0') : QLatin1Char('1'));
+ pixmapCacheKey.append(QLatin1Char('b'));
+ pixmapCacheKey.append(themeData.noContent ? QLatin1Char('0') : QLatin1Char('1'));
+ pixmapCacheKey.append(QString::number(w));
+ pixmapCacheKey.append(QLatin1Char('w'));
+ pixmapCacheKey.append(QString::number(h));
+ pixmapCacheKey.append(QLatin1Char('h'));
+ pixmapCacheKey.append(QString::number(additionalDevicePixelRatio));
+ pixmapCacheKey.append(QLatin1Char('d'));
+ if (hasCorrectionFactor) {
+ pixmapCacheKey.append(QLatin1Char('c'));
+ pixmapCacheKey.append(QString::number(correctionFactor));
+ }
+
+ QPixmap cachedPixmap;
+ ThemeMapKey key(themeData);
+ ThemeMapData data = alphaCache.value(key);
+
+ bool haveCachedPixmap = false;
+ bool isCached = data.dataValid;
+ if (isCached) {
+ partIsTransparent = data.partIsTransparent;
+ hasAlpha = data.hasAlphaChannel;
+ alphaType = data.alphaType;
+ potentialInvalidAlpha = data.hadInvalidAlpha;
+
+ haveCachedPixmap = QPixmapCache::find(pixmapCacheKey, &cachedPixmap);
+
+#ifdef DEBUG_XP_STYLE
+ char buf[25];
+ ::sprintf(buf, "+ Pixmap(%3d, %3d) ]", w, h);
+ printf("---[ CACHED %s--------> Name(%-10s) Part(%d) State(%d)\n",
+ haveCachedPixmap ? buf : "]-------------------",
+ qPrintable(themeData.name), themeData.partId, themeData.stateId);
+#endif
+ } else {
+ // Not cached, so get values from Theme Engine
+ BOOL tmt_borderonly = false;
+ COLORREF tmt_transparentcolor = 0x0;
+ PROPERTYORIGIN proporigin = PO_NOTFOUND;
+ GetThemeBool(themeData.handle(), themeData.partId, themeData.stateId, TMT_BORDERONLY, &tmt_borderonly);
+ GetThemeColor(themeData.handle(), themeData.partId, themeData.stateId, TMT_TRANSPARENTCOLOR, &tmt_transparentcolor);
+ GetThemePropertyOrigin(themeData.handle(), themeData.partId, themeData.stateId, TMT_CAPTIONMARGINS, &proporigin);
+
+ partIsTransparent = isTransparent(themeData);
+
+ potentialInvalidAlpha = false;
+ GetThemePropertyOrigin(themeData.handle(), themeData.partId, themeData.stateId, TMT_GLYPHTYPE, &proporigin);
+ if (proporigin == PO_PART || proporigin == PO_STATE) {
+ int tmt_glyphtype = GT_NONE;
+ GetThemeEnumValue(themeData.handle(), themeData.partId, themeData.stateId, TMT_GLYPHTYPE, &tmt_glyphtype);
+ potentialInvalidAlpha = partIsTransparent && tmt_glyphtype == GT_IMAGEGLYPH;
+ }
+
+#ifdef DEBUG_XP_STYLE
+ printf("---[ NOT CACHED ]-----------------------> Name(%-10s) Part(%d) State(%d)\n",
+ qPrintable(themeData.name), themeData.partId, themeData.stateId);
+ printf("-->partIsTransparen = %d\n", partIsTransparent);
+ printf("-->potentialInvalidAlpha = %d\n", potentialInvalidAlpha);
+ showProperties(themeData);
+#endif
+ }
+ bool wasAlphaSwapped = false;
+ bool wasAlphaFixed = false;
+
+ // OLD PSDK Workaround ------------------------------------------------------------------------
+ // See if we need extra clipping for the older PSDK, which does
+ // not have a DrawThemeBackgroundEx function for DTGB_OMITBORDER
+ // and DTGB_OMITCONTENT
+ bool addBorderContentClipping = false;
+ QRegion extraClip;
+ QRect area = drawRect;
+ if (themeData.noBorder || themeData.noContent) {
+ extraClip = area;
+ // We are running on a system where the uxtheme.dll does not have
+ // the DrawThemeBackgroundEx function, so we need to clip away
+ // borders or contents manually.
+
+ int borderSize = 0;
+ PROPERTYORIGIN origin = PO_NOTFOUND;
+ GetThemePropertyOrigin(themeData.handle(), themeData.partId, themeData.stateId, TMT_BORDERSIZE, &origin);
+ GetThemeInt(themeData.handle(), themeData.partId, themeData.stateId, TMT_BORDERSIZE, &borderSize);
+ borderSize *= additionalDevicePixelRatio;
+
+ // Clip away border region
+ if ((origin == PO_CLASS || origin == PO_PART || origin == PO_STATE) && borderSize > 0) {
+ if (themeData.noBorder) {
+ extraClip &= area;
+ area = area.adjusted(-borderSize, -borderSize, borderSize, borderSize);
+ }
+
+ // Clip away content region
+ if (themeData.noContent) {
+ QRegion content = area.adjusted(borderSize, borderSize, -borderSize, -borderSize);
+ extraClip ^= content;
+ }
+ }
+ addBorderContentClipping = (themeData.noBorder | themeData.noContent);
+ }
+
+ QImage img;
+ if (!haveCachedPixmap) { // If the pixmap is not cached, generate it! -------------------------
+ if (!buffer(drawRect.width(), drawRect.height())) // Ensure a buffer of at least (w, h) in size
+ return false;
+ HDC dc = bufferHDC();
+
+ // Clear the buffer
+ if (alphaType != NoAlpha) {
+ // Consider have separate "memset" function for small chunks for more speedup
+ memset(bufferPixels, 0x00, bufferW * drawRect.height() * 4);
+ }
+
+ // Difference between area and rect
+ int dx = area.x() - drawRect.x();
+ int dy = area.y() - drawRect.y();
+
+ // Adjust so painting rect starts from Origo
+ rect.moveTo(0,0);
+ area.moveTo(dx,dy);
+ DTBGOPTS drawOptions;
+ drawOptions.dwSize = sizeof(drawOptions);
+ drawOptions.rcClip = themeData.toRECT(rect);
+ drawOptions.dwFlags = DTBG_CLIPRECT
+ | (themeData.noBorder ? DTBG_OMITBORDER : 0)
+ | (themeData.noContent ? DTBG_OMITCONTENT : 0);
+
+ // Drawing the part into the backing store
+ RECT wRect(themeData.toRECT(area));
+ DrawThemeBackgroundEx(themeData.handle(), dc, themeData.partId, themeData.stateId, &wRect, &drawOptions);
+
+ // If not cached, analyze the buffer data to figure
+ // out alpha type, and if it contains data
+ if (!isCached) {
+ // SHORTCUT: If the part's state has no data, cache it for NOOP later
+ if (!stateHasData) {
+ memset(static_cast<void *>(&data), 0, sizeof(data));
+ data.dataValid = true;
+ alphaCache.insert(key, data);
+ return true;
+ }
+ hasAlpha = hasAlphaChannel(rect);
+ if (!hasAlpha && partIsTransparent)
+ potentialInvalidAlpha = true;
+#if defined(DEBUG_XP_STYLE) && 1
+ dumpNativeDIB(drawRect.width(), drawRect.height());
+#endif
+ }
+
+ // Fix alpha values, if needed
+ if (potentialInvalidAlpha)
+ wasAlphaFixed = fixAlphaChannel(drawRect);
+
+ QImage::Format format;
+ if ((partIsTransparent && !wasAlphaSwapped) || (!partIsTransparent && hasAlpha)) {
+ format = QImage::Format_ARGB32_Premultiplied;
+ alphaType = RealAlpha;
+ } else if (wasAlphaSwapped) {
+ format = QImage::Format_ARGB32_Premultiplied;
+ alphaType = MaskAlpha;
+ } else {
+ format = QImage::Format_RGB32;
+ // The image data we got from the theme engine does not have any transparency,
+ // thus the alpha channel is set to 0.
+ // However, Format_RGB32 requires the alpha part to be set to 0xff, thus
+ // we must flip it from 0x00 to 0xff
+ swapAlphaChannel(rect, true);
+ alphaType = NoAlpha;
+ }
+#if defined(DEBUG_XP_STYLE) && 1
+ printf("Image format is: %s\n", alphaType == RealAlpha ? "Real Alpha" : alphaType == MaskAlpha ? "Masked Alpha" : "No Alpha");
+#endif
+ img = QImage(bufferPixels, bufferW, bufferH, format);
+ if (themeData.invertPixels)
+ img.invertPixels();
+
+ if (hasCorrectionFactor)
+ img = img.scaled(img.size() * correctionFactor, Qt::KeepAspectRatio, Qt::SmoothTransformation);
+ img.setDevicePixelRatio(additionalDevicePixelRatio);
+ }
+
+ // Blitting backing store
+ bool useRegion = partIsTransparent && !hasAlpha && !wasAlphaSwapped;
+
+ QRegion newRegion;
+ QRegion oldRegion;
+ if (useRegion) {
+ newRegion = region(themeData);
+ oldRegion = painter->clipRegion();
+ painter->setClipRegion(newRegion);
+#if defined(DEBUG_XP_STYLE) && 0
+ printf("Using region:\n");
+ for (const QRect &r : newRegion)
+ printf(" (%d, %d, %d, %d)\n", r.x(), r.y(), r.right(), r.bottom());
+#endif
+ }
+
+ if (addBorderContentClipping)
+ painter->setClipRegion(scaleRegion(extraClip, 1.0 / additionalDevicePixelRatio), Qt::IntersectClip);
+
+ if (!themeData.mirrorHorizontally && !themeData.mirrorVertically && !themeData.rotate) {
+ if (!haveCachedPixmap)
+ painter->drawImage(themeData.rect, img, rect);
+ else
+ painter->drawPixmap(themeData.rect, cachedPixmap);
+ } else {
+ // This is _slow_!
+ // Make a copy containing only the necessary data, and mirror
+ // on all wanted axes. Then draw the copy.
+ // If cached, the normal pixmap is cached, instead of caching
+ // all possible orientations for each part and state.
+ QImage imgCopy;
+ if (!haveCachedPixmap)
+ imgCopy = img.copy(rect);
+ else
+ imgCopy = cachedPixmap.toImage();
+
+ if (themeData.rotate) {
+ QTransform rotMatrix;
+ rotMatrix.rotate(themeData.rotate);
+ imgCopy = imgCopy.transformed(rotMatrix);
+ }
+ if (themeData.mirrorHorizontally || themeData.mirrorVertically)
+ imgCopy = imgCopy.mirrored(themeData.mirrorHorizontally, themeData.mirrorVertically);
+ painter->drawImage(themeData.rect, imgCopy);
+ }
+
+ if (useRegion || addBorderContentClipping) {
+ if (oldRegion.isEmpty())
+ painter->setClipping(false);
+ else
+ painter->setClipRegion(oldRegion);
+ }
+
+ // Cache the pixmap to avoid expensive swapAlphaChannel() calls
+ if (!haveCachedPixmap && w && h) {
+ QPixmap pix = QPixmap::fromImage(img).copy(rect);
+ QPixmapCache::insert(pixmapCacheKey, pix);
+#ifdef DEBUG_XP_STYLE
+ printf("+++Adding pixmap to cache, size(%d, %d), wasAlphaSwapped(%d), wasAlphaFixed(%d), name(%s)\n",
+ w, h, wasAlphaSwapped, wasAlphaFixed, qPrintable(pixmapCacheKey));
+#endif
+ }
+
+ // Add to theme part cache
+ if (!isCached) {
+ memset(static_cast<void *>(&data), 0, sizeof(data));
+ data.dataValid = true;
+ data.partIsTransparent = partIsTransparent;
+ data.alphaType = alphaType;
+ data.hasAlphaChannel = hasAlpha;
+ data.wasAlphaSwapped = wasAlphaSwapped;
+ data.hadInvalidAlpha = wasAlphaFixed;
+ alphaCache.insert(key, data);
+ }
+ return true;
+}
+
+/*!
+ \internal
+
+ Animations are started at a frame that is based on the current time,
+ which makes it impossible to run baseline tests with this style. Allow
+ overriding through a dynamic property.
+*/
+QTime QWindowsVistaStylePrivate::animationTime() const
+{
+ Q_Q(const QWindowsVistaStyle);
+ static bool animationTimeOverride = q->dynamicPropertyNames().contains("_qt_animation_time");
+ if (animationTimeOverride)
+ return q->property("_qt_animation_time").toTime();
+ return QTime::currentTime();
+}
+
+/* \internal
+ Checks and returns the style object
+*/
+inline QObject *styleObject(const QStyleOption *option) {
+ return option ? option->styleObject : nullptr;
+}
+
+/* \internal
+ Checks if we can animate on a style option
+*/
+bool canAnimate(const QStyleOption *option) {
+ return option
+ && option->styleObject
+ && !option->styleObject->property("_q_no_animation").toBool();
+}
+
+static inline QImage createAnimationBuffer(const QStyleOption *option, const QWidget *widget)
+{
+ const qreal devicePixelRatio = widget
+ ? widget->devicePixelRatioF() : qApp->devicePixelRatio();
+ QImage result(option->rect.size() * devicePixelRatio, QImage::Format_ARGB32_Premultiplied);
+ result.setDevicePixelRatio(devicePixelRatio);
+ result.fill(0);
+ return result;
+}
+
+/* \internal
+ Used by animations to clone a styleoption and shift its offset
+*/
+QStyleOption *clonedAnimationStyleOption(const QStyleOption*option) {
+ QStyleOption *styleOption = nullptr;
+ if (const QStyleOptionSlider *slider = qstyleoption_cast<const QStyleOptionSlider*>(option))
+ styleOption = new QStyleOptionSlider(*slider);
+ else if (const QStyleOptionSpinBox *spinbox = qstyleoption_cast<const QStyleOptionSpinBox*>(option))
+ styleOption = new QStyleOptionSpinBox(*spinbox);
+ else if (const QStyleOptionGroupBox *groupBox = qstyleoption_cast<const QStyleOptionGroupBox*>(option))
+ styleOption = new QStyleOptionGroupBox(*groupBox);
+ else if (const QStyleOptionComboBox *combo = qstyleoption_cast<const QStyleOptionComboBox*>(option))
+ styleOption = new QStyleOptionComboBox(*combo);
+ else if (const QStyleOptionButton *button = qstyleoption_cast<const QStyleOptionButton*>(option))
+ styleOption = new QStyleOptionButton(*button);
+ else
+ styleOption = new QStyleOption(*option);
+ styleOption->rect = QRect(QPoint(0,0), option->rect.size());
+ return styleOption;
+}
+
+/* \internal
+ Used by animations to delete cloned styleoption
+*/
+void deleteClonedAnimationStyleOption(const QStyleOption *option)
+{
+ if (const QStyleOptionSlider *slider = qstyleoption_cast<const QStyleOptionSlider*>(option))
+ delete slider;
+ else if (const QStyleOptionSpinBox *spinbox = qstyleoption_cast<const QStyleOptionSpinBox*>(option))
+ delete spinbox;
+ else if (const QStyleOptionGroupBox *groupBox = qstyleoption_cast<const QStyleOptionGroupBox*>(option))
+ delete groupBox;
+ else if (const QStyleOptionComboBox *combo = qstyleoption_cast<const QStyleOptionComboBox*>(option))
+ delete combo;
+ else if (const QStyleOptionButton *button = qstyleoption_cast<const QStyleOptionButton*>(option))
+ delete button;
+ else
+ delete option;
+}
+
+static void populateTitleBarButtonTheme(const QStyle *proxy, const QWidget *widget,
+ const QStyleOptionComplex *option,
+ QStyle::SubControl subControl,
+ bool isTitleBarActive, int part,
+ QWindowsThemeData *theme)
+{
+ theme->rect = proxy->subControlRect(QStyle::CC_TitleBar, option, subControl, widget);
+ theme->partId = part;
+ if (widget && !widget->isEnabled())
+ theme->stateId = RBS_DISABLED;
+ else if (option->activeSubControls == subControl && option->state.testFlag(QStyle::State_Sunken))
+ theme->stateId = RBS_PUSHED;
+ else if (option->activeSubControls == subControl && option->state.testFlag(QStyle::State_MouseOver))
+ theme->stateId = RBS_HOT;
+ else if (!isTitleBarActive)
+ theme->stateId = RBS_INACTIVE;
+ else
+ theme->stateId = RBS_NORMAL;
+}
+
+#if QT_CONFIG(mdiarea)
+// Helper for drawing MDI buttons into the corner widget of QMenuBar in case a
+// QMdiSubWindow is maximized.
+static void populateMdiButtonTheme(const QStyle *proxy, const QWidget *widget,
+ const QStyleOptionComplex *option,
+ QStyle::SubControl subControl, int part,
+ QWindowsThemeData *theme)
+{
+ theme->partId = part;
+ theme->rect = proxy->subControlRect(QStyle::CC_MdiControls, option, subControl, widget);
+ if (!option->state.testFlag(QStyle::State_Enabled))
+ theme->stateId = CBS_INACTIVE;
+ else if (option->state.testFlag(QStyle::State_Sunken) && option->activeSubControls.testFlag(subControl))
+ theme->stateId = CBS_PUSHED;
+ else if (option->state.testFlag(QStyle::State_MouseOver) && option->activeSubControls.testFlag(subControl))
+ theme->stateId = CBS_HOT;
+ else
+ theme->stateId = CBS_NORMAL;
+}
+
+// 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).
+static qreal mdiButtonCorrectionFactor(QWindowsThemeData &theme, const QPaintDevice *pd = nullptr)
+{
+ const auto dpr = pd ? pd->devicePixelRatio() : qApp->devicePixelRatio();
+ const QSizeF nativeSize = QSizeF(theme.size()) / dpr;
+ const QSizeF requestedSize(theme.rect.size());
+ const auto rawFactor = qMin(requestedSize.width() / nativeSize.width(),
+ requestedSize.height() / nativeSize.height());
+ const auto factor = rawFactor >= qreal(2) ? qreal(2) : qreal(1);
+ return factor;
+}
+#endif // QT_CONFIG(mdiarea)
+
+/*
+ This function is used by subControlRect to check if a button
+ should be drawn for the given subControl given a set of window flags.
+*/
+static bool buttonVisible(const QStyle::SubControl sc, const QStyleOptionTitleBar *tb){
+
+ bool isMinimized = tb->titleBarState & Qt::WindowMinimized;
+ bool isMaximized = tb->titleBarState & Qt::WindowMaximized;
+ const auto flags = tb->titleBarFlags;
+ bool retVal = false;
+ switch (sc) {
+ case QStyle::SC_TitleBarContextHelpButton:
+ if (flags & Qt::WindowContextHelpButtonHint)
+ retVal = true;
+ break;
+ case QStyle::SC_TitleBarMinButton:
+ if (!isMinimized && (flags & Qt::WindowMinimizeButtonHint))
+ retVal = true;
+ break;
+ case QStyle::SC_TitleBarNormalButton:
+ if (isMinimized && (flags & Qt::WindowMinimizeButtonHint))
+ retVal = true;
+ else if (isMaximized && (flags & Qt::WindowMaximizeButtonHint))
+ retVal = true;
+ break;
+ case QStyle::SC_TitleBarMaxButton:
+ if (!isMaximized && (flags & Qt::WindowMaximizeButtonHint))
+ retVal = true;
+ break;
+ case QStyle::SC_TitleBarShadeButton:
+ if (!isMinimized && flags & Qt::WindowShadeButtonHint)
+ retVal = true;
+ break;
+ case QStyle::SC_TitleBarUnshadeButton:
+ if (isMinimized && flags & Qt::WindowShadeButtonHint)
+ retVal = true;
+ break;
+ case QStyle::SC_TitleBarCloseButton:
+ if (flags & Qt::WindowSystemMenuHint)
+ retVal = true;
+ break;
+ case QStyle::SC_TitleBarSysMenu:
+ if (flags & Qt::WindowSystemMenuHint)
+ retVal = true;
+ break;
+ default :
+ retVal = true;
+ }
+ return retVal;
+}
+
+//convert Qt state flags to uxtheme button states
+static int buttonStateId(int flags, int partId)
+{
+ int stateId = 0;
+ if (partId == BP_RADIOBUTTON || partId == BP_CHECKBOX) {
+ if (!(flags & QStyle::State_Enabled))
+ stateId = RBS_UNCHECKEDDISABLED;
+ else if (flags & QStyle::State_Sunken)
+ stateId = RBS_UNCHECKEDPRESSED;
+ else if (flags & QStyle::State_MouseOver)
+ stateId = RBS_UNCHECKEDHOT;
+ else
+ stateId = RBS_UNCHECKEDNORMAL;
+
+ if (flags & QStyle::State_On)
+ stateId += RBS_CHECKEDNORMAL-1;
+
+ } else if (partId == BP_PUSHBUTTON) {
+ if (!(flags & QStyle::State_Enabled))
+ stateId = PBS_DISABLED;
+ else if (flags & (QStyle::State_Sunken | QStyle::State_On))
+ stateId = PBS_PRESSED;
+ else if (flags & QStyle::State_MouseOver)
+ stateId = PBS_HOT;
+ else
+ stateId = PBS_NORMAL;
+ } else {
+ Q_ASSERT(1);
+ }
+ return stateId;
+}
+
+static inline bool supportsStateTransition(QStyle::PrimitiveElement element,
+ const QStyleOption *option,
+ const QWidget *widget)
+{
+ bool result = false;
+ switch (element) {
+ case QStyle::PE_IndicatorRadioButton:
+ case QStyle::PE_IndicatorCheckBox:
+ result = true;
+ break;
+ // QTBUG-40634, do not animate when color is set in palette for PE_PanelLineEdit.
+ case QStyle::PE_FrameLineEdit:
+ result = !QWindowsVistaStylePrivate::isLineEditBaseColorSet(option, widget);
+ break;
+ default:
+ break;
+ }
+ return result;
+}
+
+/*!
+ \class QWindowsVistaStyle
+ \brief The QWindowsVistaStyle class provides a look and feel suitable for applications on Microsoft Windows Vista.
+ \since 4.3
+ \ingroup appearance
+ \inmodule QtWidgets
+ \internal
+
+ \warning This style is only available on the Windows Vista platform
+ because it makes use of Windows Vista's style engine.
+
+ \sa QMacStyle, QFusionStyle
+*/
+
+/*!
+ Constructs a QWindowsVistaStyle object.
+*/
+QWindowsVistaStyle::QWindowsVistaStyle() : QWindowsStyle(*new QWindowsVistaStylePrivate)
+{
+}
+
+/*!
+ \internal
+ Constructs a QWindowsStyle object.
+*/
+QWindowsVistaStyle::QWindowsVistaStyle(QWindowsVistaStylePrivate &dd) : QWindowsStyle(dd)
+{
+}
+
+/*!
+ Destructor.
+*/
+QWindowsVistaStyle::~QWindowsVistaStyle() = default;
+
+
+/*!
+ \internal
+
+ Animations are used for some state transitions on specific widgets.
+
+ Only one running animation can exist for a widget at any specific
+ time. Animations can be added through
+ QWindowsVistaStylePrivate::startAnimation(Animation *) and any
+ existing animation on a widget can be retrieved with
+ QWindowsVistaStylePrivate::widgetAnimation(Widget *).
+
+ Once an animation has been started,
+ QWindowsVistaStylePrivate::timerEvent(QTimerEvent *) will
+ continuously call update() on the widget until it is stopped,
+ meaning that drawPrimitive will be called many times until the
+ transition has completed. During this time, the result will be
+ retrieved by the Animation::paint(...) function and not by the style
+ itself.
+
+ To determine if a transition should occur, the style needs to know
+ the previous state of the widget as well as the current one. This is
+ solved by updating dynamic properties on the widget every time the
+ function is called.
+
+ Transitions interrupting existing transitions should always be
+ smooth, so whenever a hover-transition is started on a pulsating
+ button, it uses the current frame of the pulse-animation as the
+ starting image for the hover transition.
+
+ */
+void QWindowsVistaStyle::drawPrimitive(PrimitiveElement element, const QStyleOption *option,
+ QPainter *painter, const QWidget *widget) const
+{
+ if (!QWindowsVistaStylePrivate::useVista()) {
+ QWindowsStyle::drawPrimitive(element, option, painter, widget);
+ return;
+ }
+
+ QWindowsVistaStylePrivate *d = const_cast<QWindowsVistaStylePrivate*>(d_func());
+
+ int state = option->state;
+ QRect rect = option->rect;
+
+ if ((state & State_Enabled) && d->transitionsEnabled() && canAnimate(option)) {
+ if (supportsStateTransition(element, option, widget)) {
+ // Retrieve and update the dynamic properties tracking
+ // the previous state of the widget:
+ QObject *styleObject = option->styleObject;
+ styleObject->setProperty("_q_no_animation", true);
+ int oldState = styleObject->property("_q_stylestate").toInt();
+ QRect oldRect = styleObject->property("_q_stylerect").toRect();
+ QRect newRect = rect;
+ styleObject->setProperty("_q_stylestate", int(option->state));
+ styleObject->setProperty("_q_stylerect", option->rect);
+
+ bool doTransition = oldState &&
+ ((state & State_Sunken) != (oldState & State_Sunken) ||
+ (state & State_On) != (oldState & State_On) ||
+ (state & State_MouseOver) != (oldState & State_MouseOver));
+
+ if (oldRect != newRect ||
+ (state & State_Enabled) != (oldState & State_Enabled) ||
+ (state & State_Active) != (oldState & State_Active))
+ d->stopAnimation(styleObject);
+
+ if (state & State_ReadOnly && element == PE_FrameLineEdit) // Do not animate read only line edits
+ doTransition = false;
+
+ if (doTransition) {
+ QStyleOption *styleOption = clonedAnimationStyleOption(option);
+ styleOption->state = QStyle::State(oldState);
+
+ QWindowsVistaAnimation *animate = qobject_cast<QWindowsVistaAnimation *>(d->animation(styleObject));
+ QWindowsVistaTransition *transition = new QWindowsVistaTransition(styleObject);
+
+ // We create separate images for the initial and final transition states and store them in the
+ // Transition object.
+ QImage startImage = createAnimationBuffer(option, widget);
+ QPainter startPainter(&startImage);
+
+ QImage endImage = createAnimationBuffer(option, widget);
+ QPainter endPainter(&endImage);
+
+ // If we have a running animation on the widget already, we will use that to paint the initial
+ // state of the new transition, this ensures a smooth transition from a current animation such as a
+ // pulsating default button into the intended target state.
+ if (!animate)
+ proxy()->drawPrimitive(element, styleOption, &startPainter, widget);
+ else
+ animate->paint(&startPainter, styleOption);
+
+ transition->setStartImage(startImage);
+
+ // The end state of the transition is simply the result we would have painted
+ // if the style was not animated.
+ styleOption->styleObject = nullptr;
+ styleOption->state = option->state;
+ proxy()->drawPrimitive(element, styleOption, &endPainter, widget);
+
+ transition->setEndImage(endImage);
+
+ HTHEME theme;
+ int partId;
+ DWORD duration;
+ int fromState = 0;
+ int toState = 0;
+
+ //translate state flags to UXTHEME states :
+ if (element == PE_FrameLineEdit) {
+ theme = OpenThemeData(nullptr, L"Edit");
+ partId = EP_EDITBORDER_NOSCROLL;
+
+ if (oldState & State_HasFocus)
+ fromState = ETS_SELECTED;
+ else if (oldState & State_MouseOver)
+ fromState = ETS_HOT;
+ else
+ fromState = ETS_NORMAL;
+
+ if (state & State_HasFocus)
+ toState = ETS_SELECTED;
+ else if (state & State_MouseOver)
+ toState = ETS_HOT;
+ else
+ toState = ETS_NORMAL;
+
+ } else {
+ theme = OpenThemeData(nullptr, L"Button");
+ if (element == PE_IndicatorRadioButton)
+ partId = BP_RADIOBUTTON;
+ else if (element == PE_IndicatorCheckBox)
+ partId = BP_CHECKBOX;
+ else
+ partId = BP_PUSHBUTTON;
+
+ fromState = buttonStateId(oldState, partId);
+ toState = buttonStateId(option->state, partId);
+ }
+
+ // Retrieve the transition time between the states from the system.
+ if (theme
+ && SUCCEEDED(GetThemeTransitionDuration(theme, partId, fromState, toState,
+ TMT_TRANSITIONDURATIONS, &duration))) {
+ transition->setDuration(int(duration));
+ }
+ transition->setStartTime(d->animationTime());
+
+ deleteClonedAnimationStyleOption(styleOption);
+ d->startAnimation(transition);
+ }
+ styleObject->setProperty("_q_no_animation", false);
+ }
+ }
+
+ int themeNumber = -1;
+ int partId = 0;
+ int stateId = 0;
+ bool hMirrored = false;
+ bool vMirrored = false;
+ bool noBorder = false;
+ bool noContent = false;
+ int rotate = 0;
+
+ switch (element) {
+ case PE_PanelButtonCommand:
+ if (const auto *btn = qstyleoption_cast<const QStyleOptionButton *>(option)) {
+ QBrush fill;
+ if (!(state & State_Sunken) && (state & State_On))
+ fill = QBrush(option->palette.light().color(), Qt::Dense4Pattern);
+ else
+ fill = option->palette.brush(QPalette::Button);
+ if (btn->features & QStyleOptionButton::DefaultButton && state & State_Sunken) {
+ painter->setPen(option->palette.dark().color());
+ painter->setBrush(fill);
+ painter->drawRect(rect.adjusted(0, 0, -1, -1));
+ } else if (state & (State_Raised | State_On | State_Sunken)) {
+ qDrawWinButton(painter, rect, option->palette, state & (State_Sunken | State_On),
+ &fill);
+ } else {
+ painter->fillRect(rect, fill);
+ }
+ }
+ break;
+
+ case PE_PanelButtonTool:
+#if QT_CONFIG(dockwidget)
+ if (widget && widget->inherits("QDockWidgetTitleButton")) {
+ if (const QWidget *dw = widget->parentWidget())
+ if (dw->isWindow()) {
+ return;
+ }
+ }
+#endif // QT_CONFIG(dockwidget)
+ themeNumber = QWindowsVistaStylePrivate::ToolBarTheme;
+ partId = TP_BUTTON;
+ if (!(option->state & State_Enabled))
+ stateId = TS_DISABLED;
+ else if (option->state & State_Sunken)
+ stateId = TS_PRESSED;
+ else if (option->state & State_MouseOver)
+ stateId = option->state & State_On ? TS_HOTCHECKED : TS_HOT;
+ else if (option->state & State_On)
+ stateId = TS_CHECKED;
+ else if (!(option->state & State_AutoRaise))
+ stateId = TS_HOT;
+ else
+ stateId = TS_NORMAL;
+
+ break;
+
+ case PE_IndicatorHeaderArrow:
+ if (const auto *header = qstyleoption_cast<const QStyleOptionHeader *>(option)) {
+ int stateId = HSAS_SORTEDDOWN;
+ if (header->sortIndicator & QStyleOptionHeader::SortDown)
+ stateId = HSAS_SORTEDUP; //note that the uxtheme sort down indicator is the inverse of ours
+ QWindowsThemeData theme(widget, painter,
+ QWindowsVistaStylePrivate::HeaderTheme,
+ HP_HEADERSORTARROW, stateId, option->rect);
+ d->drawBackground(theme);
+ return;
+ }
+ break;
+
+ case PE_IndicatorCheckBox:
+ if (auto *animate =
+ qobject_cast<QWindowsVistaAnimation *>(d->animation(styleObject(option)))) {
+ animate->paint(painter, option);
+ return;
+ } else {
+ themeNumber = QWindowsVistaStylePrivate::ButtonTheme;
+ partId = BP_CHECKBOX;
+
+ if (!(option->state & State_Enabled))
+ stateId = CBS_UNCHECKEDDISABLED;
+ else if (option->state & State_Sunken)
+ stateId = CBS_UNCHECKEDPRESSED;
+ else if (option->state & State_MouseOver)
+ stateId = CBS_UNCHECKEDHOT;
+ else
+ stateId = CBS_UNCHECKEDNORMAL;
+
+ if (option->state & State_On)
+ stateId += CBS_CHECKEDNORMAL-1;
+ else if (option->state & State_NoChange)
+ stateId += CBS_MIXEDNORMAL-1;
+ }
+ break;
+
+ case PE_IndicatorItemViewItemCheck: {
+ QStyleOptionButton button;
+ button.QStyleOption::operator=(*option);
+ button.state &= ~State_MouseOver;
+ proxy()->drawPrimitive(PE_IndicatorCheckBox, &button, painter, widget);
+ return;
+ }
+
+ case PE_IndicatorBranch: {
+ QWindowsThemeData theme(widget, painter, QWindowsVistaStylePrivate::VistaTreeViewTheme);
+ static int decoration_size = 0;
+ if (!decoration_size && theme.isValid()) {
+ QWindowsThemeData themeSize = theme;
+ themeSize.partId = TVP_HOTGLYPH;
+ themeSize.stateId = GLPS_OPENED;
+ const QSizeF size = themeSize.size() * QWindowsStylePrivate::nativeMetricScaleFactor(widget);
+ decoration_size = qRound(qMax(size.width(), size.height()));
+ }
+ int mid_h = option->rect.x() + option->rect.width() / 2;
+ int mid_v = option->rect.y() + option->rect.height() / 2;
+ if (option->state & State_Children) {
+ int delta = decoration_size / 2;
+ theme.rect = QRect(mid_h - delta, mid_v - delta, decoration_size, decoration_size);
+ theme.partId = option->state & State_MouseOver ? TVP_HOTGLYPH : TVP_GLYPH;
+ theme.stateId = option->state & QStyle::State_Open ? GLPS_OPENED : GLPS_CLOSED;
+ if (option->direction == Qt::RightToLeft)
+ theme.mirrorHorizontally = true;
+ d->drawBackground(theme);
+ }
+ return;
+ }
+
+ case PE_PanelButtonBevel:
+ if (QWindowsVistaAnimation *animate =
+ qobject_cast<QWindowsVistaAnimation *>(d->animation(styleObject(option)))) {
+ animate->paint(painter, option);
+ return;
+ }
+
+ themeNumber = QWindowsVistaStylePrivate::ButtonTheme;
+ partId = BP_PUSHBUTTON;
+ if (!(option->state & State_Enabled))
+ stateId = PBS_DISABLED;
+ else if ((option->state & State_Sunken) || (option->state & State_On))
+ stateId = PBS_PRESSED;
+ else if (option->state & State_MouseOver)
+ stateId = PBS_HOT;
+ else
+ stateId = PBS_NORMAL;
+ break;
+
+ case PE_IndicatorRadioButton:
+ if (QWindowsVistaAnimation *animate =
+ qobject_cast<QWindowsVistaAnimation *>(d->animation(styleObject(option)))) {
+ animate->paint(painter, option);
+ return;
+ } else {
+ themeNumber = QWindowsVistaStylePrivate::ButtonTheme;
+ partId = BP_RADIOBUTTON;
+
+ if (!(option->state & State_Enabled))
+ stateId = RBS_UNCHECKEDDISABLED;
+ else if (option->state & State_Sunken)
+ stateId = RBS_UNCHECKEDPRESSED;
+ else if (option->state & State_MouseOver)
+ stateId = RBS_UNCHECKEDHOT;
+ else
+ stateId = RBS_UNCHECKEDNORMAL;
+
+ if (option->state & State_On)
+ stateId += RBS_CHECKEDNORMAL-1;
+ }
+ break;
+
+ case PE_Frame:
+#if QT_CONFIG(accessibility)
+ if (QStyleHelper::isInstanceOf(option->styleObject, QAccessible::EditableText)
+ || QStyleHelper::isInstanceOf(option->styleObject, QAccessible::StaticText) ||
+#else
+ if (
+#endif
+ (widget && widget->inherits("QTextEdit"))) {
+ painter->save();
+ int stateId = ETS_NORMAL;
+ if (!(state & State_Enabled))
+ stateId = ETS_DISABLED;
+ else if (state & State_ReadOnly)
+ stateId = ETS_READONLY;
+ else if (state & State_HasFocus)
+ stateId = ETS_SELECTED;
+ QWindowsThemeData theme(widget, painter,
+ QWindowsVistaStylePrivate::EditTheme,
+ EP_EDITBORDER_HVSCROLL, stateId, option->rect);
+ // Since EP_EDITBORDER_HVSCROLL does not us borderfill, theme.noContent cannot be used for clipping
+ int borderSize = 1;
+ GetThemeInt(theme.handle(), theme.partId, theme.stateId, TMT_BORDERSIZE, &borderSize);
+ QRegion clipRegion = option->rect;
+ QRegion content = option->rect.adjusted(borderSize, borderSize, -borderSize, -borderSize);
+ clipRegion ^= content;
+ painter->setClipRegion(clipRegion);
+ d->drawBackground(theme);
+ painter->restore();
+ return;
+ } else {
+ if (option->state & State_Raised)
+ return;
+
+ themeNumber = QWindowsVistaStylePrivate::ListViewTheme;
+ partId = LVP_LISTGROUP;
+ QWindowsThemeData theme(widget, nullptr, themeNumber, partId);
+
+ if (!(option->state & State_Enabled))
+ stateId = ETS_DISABLED;
+ else
+ stateId = ETS_NORMAL;
+
+ int fillType;
+
+ if (GetThemeEnumValue(theme.handle(), partId, stateId, TMT_BGTYPE, &fillType) == S_OK) {
+ if (fillType == BT_BORDERFILL) {
+ COLORREF bcRef;
+ GetThemeColor(theme.handle(), partId, stateId, TMT_BORDERCOLOR, &bcRef);
+ QColor bordercolor(qRgb(GetRValue(bcRef), GetGValue(bcRef), GetBValue(bcRef)));
+ QPen oldPen = painter->pen();
+
+ // Inner white border
+ painter->setPen(QPen(option->palette.base().color(), 0));
+ const qreal dpi = QStyleHelper::dpi(option);
+ const auto topLevelAdjustment = QStyleHelper::dpiScaled(0.5, dpi);
+ const auto bottomRightAdjustment = QStyleHelper::dpiScaled(-1, dpi);
+ painter->drawRect(QRectF(option->rect).adjusted(topLevelAdjustment, topLevelAdjustment,
+ bottomRightAdjustment, bottomRightAdjustment));
+ // Outer dark border
+ painter->setPen(QPen(bordercolor, 0));
+ painter->drawRect(QRectF(option->rect).adjusted(0, 0, -topLevelAdjustment, -topLevelAdjustment));
+ painter->setPen(oldPen);
+ }
+
+ if (fillType == BT_BORDERFILL || fillType == BT_NONE)
+ return;
+ }
+ }
+ break;
+
+ case PE_FrameMenu: {
+ int stateId = option->state & State_Active ? MB_ACTIVE : MB_INACTIVE;
+ QWindowsThemeData theme(widget, painter,
+ QWindowsVistaStylePrivate::MenuTheme,
+ MENU_POPUPBORDERS, stateId, option->rect);
+ d->drawBackground(theme);
+ return;
+ }
+
+ case PE_PanelMenuBar:
+ break;
+
+#if QT_CONFIG(dockwidget)
+ case PE_IndicatorDockWidgetResizeHandle:
+ return;
+
+ case PE_FrameDockWidget:
+ if (const auto *frm = qstyleoption_cast<const QStyleOptionFrame *>(option)) {
+ themeNumber = QWindowsVistaStylePrivate::WindowTheme;
+ if (option->state & State_Active)
+ stateId = FS_ACTIVE;
+ else
+ stateId = FS_INACTIVE;
+
+ int fwidth = proxy()->pixelMetric(PM_DockWidgetFrameWidth, frm, widget);
+
+ QWindowsThemeData theme(widget, painter, themeNumber, 0, stateId);
+
+ if (!theme.isValid())
+ break;
+
+ theme.rect = QRect(frm->rect.x(), frm->rect.y(), frm->rect.x()+fwidth, frm->rect.height()-fwidth);
+ theme.partId = WP_SMALLFRAMELEFT;
+ d->drawBackground(theme);
+ theme.rect = QRect(frm->rect.width()-fwidth, frm->rect.y(), fwidth, frm->rect.height()-fwidth);
+ theme.partId = WP_SMALLFRAMERIGHT;
+ d->drawBackground(theme);
+ theme.rect = QRect(frm->rect.x(), frm->rect.bottom()-fwidth+1, frm->rect.width(), fwidth);
+ theme.partId = WP_SMALLFRAMEBOTTOM;
+ d->drawBackground(theme);
+ return;
+ }
+ break;
+#endif // QT_CONFIG(dockwidget)
+
+ case PE_FrameTabWidget:
+ if (const auto *tab = qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(option)) {
+ themeNumber = QWindowsVistaStylePrivate::TabTheme;
+ partId = TABP_PANE;
+
+ if (widget) {
+ bool useGradient = true;
+ const int maxlength = 256;
+ wchar_t themeFileName[maxlength];
+ wchar_t themeColor[maxlength];
+ // Due to a a scaling issue with the XP Silver theme, tab gradients are not used with it
+ if (GetCurrentThemeName(themeFileName, maxlength, themeColor, maxlength, nullptr, 0) == S_OK) {
+ wchar_t *offset = nullptr;
+ if ((offset = wcsrchr(themeFileName, QChar(QLatin1Char('\\')).unicode())) != nullptr) {
+ offset++;
+ if (!lstrcmp(offset, L"Luna.msstyles") && !lstrcmp(offset, L"Metallic"))
+ useGradient = false;
+ }
+ }
+ // This should work, but currently there's an error in the ::drawBackgroundDirectly()
+ // code, when using the HDC directly..
+ if (useGradient) {
+ QStyleOptionTabWidgetFrame frameOpt = *tab;
+ frameOpt.rect = widget->rect();
+ QRect contentsRect = subElementRect(SE_TabWidgetTabContents, &frameOpt, widget);
+ QRegion reg = option->rect;
+ reg -= contentsRect;
+ painter->setClipRegion(reg);
+ QWindowsThemeData theme(widget, painter, themeNumber, partId, stateId, rect);
+ theme.mirrorHorizontally = hMirrored;
+ theme.mirrorVertically = vMirrored;
+ d->drawBackground(theme);
+ painter->setClipRect(contentsRect);
+ partId = TABP_BODY;
+ }
+ }
+ switch (tab->shape) {
+ case QTabBar::RoundedNorth:
+ case QTabBar::TriangularNorth:
+ break;
+ case QTabBar::RoundedSouth:
+ case QTabBar::TriangularSouth:
+ vMirrored = true;
+ break;
+ case QTabBar::RoundedEast:
+ case QTabBar::TriangularEast:
+ rotate = 90;
+ break;
+ case QTabBar::RoundedWest:
+ case QTabBar::TriangularWest:
+ rotate = 90;
+ hMirrored = true;
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+
+ case PE_FrameStatusBarItem:
+ themeNumber = QWindowsVistaStylePrivate::StatusTheme;
+ partId = SP_PANE;
+ break;
+
+ case PE_FrameWindow:
+ if (const auto *frm = qstyleoption_cast<const QStyleOptionFrame *>(option)) {
+ themeNumber = QWindowsVistaStylePrivate::WindowTheme;
+ if (option->state & State_Active)
+ stateId = FS_ACTIVE;
+ else
+ stateId = FS_INACTIVE;
+
+ int fwidth = int((frm->lineWidth + frm->midLineWidth) / QWindowsStylePrivate::nativeMetricScaleFactor(widget));
+
+ QWindowsThemeData theme(widget, painter, themeNumber, 0, stateId);
+ if (!theme.isValid())
+ break;
+
+ // May fail due to too-large buffers for large widgets, fall back to Windows style.
+ theme.rect = QRect(option->rect.x(), option->rect.y()+fwidth, option->rect.x()+fwidth, option->rect.height()-fwidth);
+ theme.partId = WP_FRAMELEFT;
+ if (!d->drawBackground(theme)) {
+ QWindowsStyle::drawPrimitive(element, option, painter, widget);
+ return;
+ }
+ theme.rect = QRect(option->rect.width()-fwidth, option->rect.y()+fwidth, fwidth, option->rect.height()-fwidth);
+ theme.partId = WP_FRAMERIGHT;
+ if (!d->drawBackground(theme)) {
+ QWindowsStyle::drawPrimitive(element, option, painter, widget);
+ return;
+ }
+ theme.rect = QRect(option->rect.x(), option->rect.height()-fwidth, option->rect.width(), fwidth);
+ theme.partId = WP_FRAMEBOTTOM;
+ if (!d->drawBackground(theme)) {
+ QWindowsStyle::drawPrimitive(element, option, painter, widget);
+ return;
+ }
+ theme.rect = QRect(option->rect.x(), option->rect.y(), option->rect.width(), option->rect.y()+fwidth);
+ theme.partId = WP_CAPTION;
+ if (!d->drawBackground(theme))
+ QWindowsStyle::drawPrimitive(element, option, painter, widget);
+ return;
+ }
+ break;
+
+ case PE_PanelLineEdit:
+ if (const auto *panel = qstyleoption_cast<const QStyleOptionFrame *>(option)) {
+ bool isEnabled = state & State_Enabled;
+ if (QWindowsVistaStylePrivate::isLineEditBaseColorSet(option, widget)) {
+ painter->fillRect(panel->rect, panel->palette.brush(QPalette::Base));
+ } else {
+ int partId = EP_BACKGROUND;
+ int stateId = EBS_NORMAL;
+ if (!isEnabled)
+ stateId = EBS_DISABLED;
+ else if (option->state & State_ReadOnly)
+ stateId = EBS_READONLY;
+ else if (option->state & State_MouseOver)
+ stateId = EBS_HOT;
+
+ QWindowsThemeData theme(nullptr, painter, QWindowsVistaStylePrivate::EditTheme,
+ partId, stateId, rect);
+ if (!theme.isValid()) {
+ QWindowsStyle::drawPrimitive(element, option, painter, widget);
+ return;
+ }
+ int bgType;
+ GetThemeEnumValue(theme.handle(), partId, stateId, TMT_BGTYPE, &bgType);
+ if (bgType == BT_IMAGEFILE) {
+ d->drawBackground(theme);
+ } else {
+ QBrush fillColor = option->palette.brush(QPalette::Base);
+ if (!isEnabled) {
+ PROPERTYORIGIN origin = PO_NOTFOUND;
+ GetThemePropertyOrigin(theme.handle(), theme.partId, theme.stateId, TMT_FILLCOLOR, &origin);
+ // Use only if the fill property comes from our part
+ if ((origin == PO_PART || origin == PO_STATE)) {
+ COLORREF bgRef;
+ GetThemeColor(theme.handle(), partId, stateId, TMT_FILLCOLOR, &bgRef);
+ fillColor = QBrush(qRgb(GetRValue(bgRef), GetGValue(bgRef), GetBValue(bgRef)));
+ }
+ }
+ painter->fillRect(option->rect, fillColor);
+ }
+ }
+ if (panel->lineWidth > 0)
+ proxy()->drawPrimitive(PE_FrameLineEdit, panel, painter, widget);
+ }
+ return;
+
+ case PE_IndicatorButtonDropDown:
+ themeNumber = QWindowsVistaStylePrivate::ToolBarTheme;
+ partId = TP_SPLITBUTTONDROPDOWN;
+ if (!(option->state & State_Enabled))
+ stateId = TS_DISABLED;
+ else if (option->state & State_Sunken)
+ stateId = TS_PRESSED;
+ else if (option->state & State_MouseOver)
+ stateId = option->state & State_On ? TS_HOTCHECKED : TS_HOT;
+ else if (option->state & State_On)
+ stateId = TS_CHECKED;
+ else if (!(option->state & State_AutoRaise))
+ stateId = TS_HOT;
+ else
+ stateId = TS_NORMAL;
+ if (option->direction == Qt::RightToLeft)
+ hMirrored = true;
+ break;
+
+ case PE_FrameLineEdit:
+ if (QWindowsVistaAnimation *animate = qobject_cast<QWindowsVistaAnimation *>(d->animation(styleObject(option)))) {
+ animate->paint(painter, option);
+ } else {
+ if (QWindowsVistaStylePrivate::isItemViewDelegateLineEdit(widget)) {
+ // we try to check if this lineedit is a delegate on a QAbstractItemView-derived class.
+ QPen oldPen = painter->pen();
+ // Inner white border
+ painter->setPen(QPen(option->palette.base().color(), 1));
+ painter->drawRect(option->rect.adjusted(1, 1, -2, -2));
+ // Outer dark border
+ painter->setPen(QPen(option->palette.shadow().color(), 1));
+ painter->drawRect(option->rect.adjusted(0, 0, -1, -1));
+ painter->setPen(oldPen);
+ return;
+ }
+ int stateId = ETS_NORMAL;
+ if (!(state & State_Enabled))
+ stateId = ETS_DISABLED;
+ else if (state & State_ReadOnly)
+ stateId = ETS_READONLY;
+ else if (state & State_HasFocus)
+ stateId = ETS_SELECTED;
+ else if (state & State_MouseOver)
+ stateId = ETS_HOT;
+ QWindowsThemeData theme(widget, painter,
+ QWindowsVistaStylePrivate::EditTheme,
+ EP_EDITBORDER_NOSCROLL, stateId, option->rect);
+ theme.noContent = true;
+ painter->save();
+ QRegion clipRegion = option->rect;
+ clipRegion -= option->rect.adjusted(2, 2, -2, -2);
+ painter->setClipRegion(clipRegion);
+ d->drawBackground(theme);
+ painter->restore();
+ }
+ return;
+
+ case PE_FrameGroupBox:
+ themeNumber = QWindowsVistaStylePrivate::ButtonTheme;
+ partId = BP_GROUPBOX;
+ if (!(option->state & State_Enabled))
+ stateId = GBS_DISABLED;
+ else
+ stateId = GBS_NORMAL;
+ if (const auto *frame = qstyleoption_cast<const QStyleOptionFrame *>(option)) {
+ if (frame->features & QStyleOptionFrame::Flat) {
+ // Windows XP does not have a theme part for a flat GroupBox, paint it with the windows style
+ QRect fr = frame->rect;
+ QPoint p1(fr.x(), fr.y() + 1);
+ QPoint p2(fr.x() + fr.width(), p1.y() + 1);
+ rect = QRect(p1, p2);
+ themeNumber = -1;
+ }
+ }
+ break;
+
+ case PE_IndicatorToolBarHandle: {
+ QWindowsThemeData theme;
+ QRect rect;
+ if (option->state & State_Horizontal) {
+ theme = QWindowsThemeData(widget, painter,
+ QWindowsVistaStylePrivate::RebarTheme,
+ RP_GRIPPER, ETS_NORMAL, option->rect.adjusted(0, 1, -2, -2));
+ rect = option->rect.adjusted(0, 1, 0, -2);
+ rect.setWidth(4);
+ } else {
+ theme = QWindowsThemeData(widget, painter, QWindowsVistaStylePrivate::RebarTheme,
+ RP_GRIPPERVERT, ETS_NORMAL, option->rect.adjusted(0, 1, -2, -2));
+ rect = option->rect.adjusted(1, 0, -1, 0);
+ rect.setHeight(4);
+ }
+ theme.rect = rect;
+ d->drawBackground(theme);
+ return;
+ }
+
+ case PE_IndicatorToolBarSeparator: {
+ QPen pen = painter->pen();
+ int margin = 3;
+ painter->setPen(option->palette.window().color().darker(114));
+ if (option->state & State_Horizontal) {
+ int x1 = option->rect.center().x();
+ painter->drawLine(QPoint(x1, option->rect.top() + margin), QPoint(x1, option->rect.bottom() - margin));
+ } else {
+ int y1 = option->rect.center().y();
+ painter->drawLine(QPoint(option->rect.left() + margin, y1), QPoint(option->rect.right() - margin, y1));
+ }
+ painter->setPen(pen);
+ return;
+ }
+
+ case PE_PanelTipLabel: {
+ QWindowsThemeData theme(widget, painter,
+ QWindowsVistaStylePrivate::ToolTipTheme,
+ TTP_STANDARD, TTSS_NORMAL, option->rect);
+ d->drawBackground(theme);
+ return;
+ }
+
+ case PE_FrameTabBarBase:
+ if (const auto *tbb = qstyleoption_cast<const QStyleOptionTabBarBase *>(option)) {
+ painter->save();
+ switch (tbb->shape) {
+ case QTabBar::RoundedNorth:
+ painter->setPen(QPen(tbb->palette.dark(), 0));
+ painter->drawLine(tbb->rect.topLeft(), tbb->rect.topRight());
+ break;
+ case QTabBar::RoundedWest:
+ painter->setPen(QPen(tbb->palette.dark(), 0));
+ painter->drawLine(tbb->rect.left(), tbb->rect.top(), tbb->rect.left(), tbb->rect.bottom());
+ break;
+ case QTabBar::RoundedSouth:
+ painter->setPen(QPen(tbb->palette.dark(), 0));
+ painter->drawLine(tbb->rect.left(), tbb->rect.top(),
+ tbb->rect.right(), tbb->rect.top());
+ break;
+ case QTabBar::RoundedEast:
+ painter->setPen(QPen(tbb->palette.dark(), 0));
+ painter->drawLine(tbb->rect.topLeft(), tbb->rect.bottomLeft());
+ break;
+ case QTabBar::TriangularNorth:
+ case QTabBar::TriangularEast:
+ case QTabBar::TriangularWest:
+ case QTabBar::TriangularSouth:
+ painter->restore();
+ QWindowsStyle::drawPrimitive(element, option, painter, widget);
+ return;
+ }
+ painter->restore();
+ }
+ return;
+
+ case PE_Widget: {
+#if QT_CONFIG(dialogbuttonbox)
+ const QDialogButtonBox *buttonBox = nullptr;
+ if (qobject_cast<const QMessageBox *> (widget))
+ buttonBox = widget->findChild<const QDialogButtonBox *>(QLatin1String("qt_msgbox_buttonbox"));
+#if QT_CONFIG(inputdialog)
+ else if (qobject_cast<const QInputDialog *> (widget))
+ buttonBox = widget->findChild<const QDialogButtonBox *>(QLatin1String("qt_inputdlg_buttonbox"));
+#endif // QT_CONFIG(inputdialog)
+ if (buttonBox) {
+ //draw white panel part
+ QWindowsThemeData theme(widget, painter,
+ QWindowsVistaStylePrivate::TaskDialogTheme,
+ TDLG_PRIMARYPANEL, 0, option->rect);
+ QRect toprect = option->rect;
+ toprect.setBottom(buttonBox->geometry().top());
+ theme.rect = toprect;
+ d->drawBackground(theme);
+
+ //draw bottom panel part
+ QRect buttonRect = option->rect;
+ buttonRect.setTop(buttonBox->geometry().top());
+ theme.rect = buttonRect;
+ theme.partId = TDLG_SECONDARYPANEL;
+ d->drawBackground(theme);
+ }
+#endif
+ return;
+ }
+
+ case PE_PanelItemViewItem: {
+ const QStyleOptionViewItem *vopt;
+ bool newStyle = true;
+ QAbstractItemView::SelectionBehavior selectionBehavior = QAbstractItemView::SelectRows;
+ QAbstractItemView::SelectionMode selectionMode = QAbstractItemView::NoSelection;
+ if (const QAbstractItemView *view = qobject_cast<const QAbstractItemView *>(widget)) {
+ newStyle = !qobject_cast<const QTableView*>(view);
+ selectionBehavior = view->selectionBehavior();
+ selectionMode = view->selectionMode();
+#if QT_CONFIG(accessibility)
+ } else if (!widget) {
+ newStyle = !QStyleHelper::hasAncestor(option->styleObject, QAccessible::MenuItem) ;
+#endif
+ }
+
+ if (newStyle && (vopt = qstyleoption_cast<const QStyleOptionViewItem *>(option))) {
+ bool selected = vopt->state & QStyle::State_Selected;
+ const bool hover = selectionMode != QAbstractItemView::NoSelection && (vopt->state & QStyle::State_MouseOver);
+ bool active = vopt->state & QStyle::State_Active;
+
+ if (vopt->features & QStyleOptionViewItem::Alternate)
+ painter->fillRect(vopt->rect, vopt->palette.alternateBase());
+
+ QPalette::ColorGroup cg = vopt->state & QStyle::State_Enabled
+ ? QPalette::Normal : QPalette::Disabled;
+ if (cg == QPalette::Normal && !(vopt->state & QStyle::State_Active))
+ cg = QPalette::Inactive;
+
+ QRect itemRect = subElementRect(QStyle::SE_ItemViewItemFocusRect, option, widget).adjusted(-1, 0, 1, 0);
+ itemRect.setTop(vopt->rect.top());
+ itemRect.setBottom(vopt->rect.bottom());
+
+ QSize sectionSize = itemRect.size();
+ if (vopt->showDecorationSelected)
+ sectionSize = vopt->rect.size();
+
+ if (selectionBehavior == QAbstractItemView::SelectRows)
+ sectionSize.setWidth(vopt->rect.width());
+ QPixmap pixmap;
+
+ if (vopt->backgroundBrush.style() != Qt::NoBrush) {
+ const QPointF oldBrushOrigin = painter->brushOrigin();
+ painter->setBrushOrigin(vopt->rect.topLeft());
+ painter->fillRect(vopt->rect, vopt->backgroundBrush);
+ painter->setBrushOrigin(oldBrushOrigin);
+ }
+
+ if (hover || selected) {
+ if (sectionSize.width() > 0 && sectionSize.height() > 0) {
+ QString key = QString::fromLatin1("qvdelegate-%1-%2-%3-%4-%5").arg(sectionSize.width())
+ .arg(sectionSize.height()).arg(selected).arg(active).arg(hover);
+ if (!QPixmapCache::find(key, &pixmap)) {
+ pixmap = QPixmap(sectionSize);
+ pixmap.fill(Qt::transparent);
+
+ int state;
+ if (selected && hover)
+ state = LISS_HOTSELECTED;
+ else if (selected && !active)
+ state = LISS_SELECTEDNOTFOCUS;
+ else if (selected)
+ state = LISS_SELECTED;
+ else
+ state = LISS_HOT;
+
+ QPainter pixmapPainter(&pixmap);
+
+ QWindowsThemeData theme(widget, &pixmapPainter,
+ QWindowsVistaStylePrivate::VistaTreeViewTheme,
+ LVP_LISTITEM, state, QRect(0, 0, sectionSize.width(), sectionSize.height()));
+
+ if (!theme.isValid())
+ break;
+
+ d->drawBackground(theme);
+ QPixmapCache::insert(key, pixmap);
+ }
+ }
+
+ if (vopt->showDecorationSelected) {
+ const int frame = 2; //Assumes a 2 pixel pixmap border
+ QRect srcRect = QRect(0, 0, sectionSize.width(), sectionSize.height());
+ QRect pixmapRect = vopt->rect;
+ bool reverse = vopt->direction == Qt::RightToLeft;
+ bool leftSection = vopt->viewItemPosition == QStyleOptionViewItem::Beginning;
+ bool rightSection = vopt->viewItemPosition == QStyleOptionViewItem::End;
+ if (vopt->viewItemPosition == QStyleOptionViewItem::OnlyOne
+ || vopt->viewItemPosition == QStyleOptionViewItem::Invalid)
+ painter->drawPixmap(pixmapRect.topLeft(), pixmap);
+ else if (reverse ? rightSection : leftSection){
+ painter->drawPixmap(QRect(pixmapRect.topLeft(),
+ QSize(frame, pixmapRect.height())), pixmap,
+ QRect(QPoint(0, 0), QSize(frame, pixmapRect.height())));
+ painter->drawPixmap(pixmapRect.adjusted(frame, 0, 0, 0),
+ pixmap, srcRect.adjusted(frame, 0, -frame, 0));
+ } else if (reverse ? leftSection : rightSection) {
+ painter->drawPixmap(QRect(pixmapRect.topRight() - QPoint(frame - 1, 0),
+ QSize(frame, pixmapRect.height())), pixmap,
+ QRect(QPoint(pixmapRect.width() - frame, 0),
+ QSize(frame, pixmapRect.height())));
+ painter->drawPixmap(pixmapRect.adjusted(0, 0, -frame, 0),
+ pixmap, srcRect.adjusted(frame, 0, -frame, 0));
+ } else if (vopt->viewItemPosition == QStyleOptionViewItem::Middle)
+ painter->drawPixmap(pixmapRect, pixmap,
+ srcRect.adjusted(frame, 0, -frame, 0));
+ } else {
+ if (vopt->text.isEmpty() && vopt->icon.isNull())
+ break;
+ painter->drawPixmap(itemRect.topLeft(), pixmap);
+ }
+ }
+ return;
+ }
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ QWindowsThemeData theme(widget, painter, themeNumber, partId, stateId, rect);
+
+ if (!theme.isValid()) {
+ QWindowsStyle::drawPrimitive(element, option, painter, widget);
+ return;
+ }
+
+ theme.mirrorHorizontally = hMirrored;
+ theme.mirrorVertically = vMirrored;
+ theme.noBorder = noBorder;
+ theme.noContent = noContent;
+ theme.rotate = rotate;
+
+ d->drawBackground(theme);
+}
+
+/*! \internal */
+int QWindowsVistaStyle::styleHint(StyleHint hint, const QStyleOption *option, const QWidget *widget,
+ QStyleHintReturn *returnData) const
+{
+ QWindowsVistaStylePrivate *d = const_cast<QWindowsVistaStylePrivate*>(d_func());
+
+ int ret = 0;
+ switch (hint) {
+ case SH_EtchDisabledText:
+ ret = (qobject_cast<const QLabel*>(widget) != 0);
+ break;
+
+ case SH_SpinControls_DisableOnBounds:
+ ret = 0;
+ break;
+
+ case SH_TitleBar_AutoRaise:
+ case SH_TitleBar_NoBorder:
+ ret = 1;
+ break;
+
+ case SH_GroupBox_TextLabelColor:
+ if (!widget || widget->isEnabled())
+ ret = d->groupBoxTextColor;
+ else
+ ret = d->groupBoxTextColorDisabled;
+ break;
+
+ case SH_WindowFrame_Mask: {
+ ret = 1;
+ auto *mask = qstyleoption_cast<QStyleHintReturnMask *>(returnData);
+ const auto *titlebar = qstyleoption_cast<const QStyleOptionTitleBar *>(option);
+ if (mask && titlebar) {
+ // Note certain themes will not return the whole window frame but only the titlebar part when
+ // queried This function needs to return the entire window mask, hence we will only fetch the mask for the
+ // titlebar itself and add the remaining part of the window rect at the bottom.
+ int tbHeight = proxy()->pixelMetric(PM_TitleBarHeight, option, widget);
+ QRect titleBarRect = option->rect;
+ titleBarRect.setHeight(tbHeight);
+ QWindowsThemeData themeData;
+ if (titlebar->titleBarState & Qt::WindowMinimized) {
+ themeData = QWindowsThemeData(widget, nullptr,
+ QWindowsVistaStylePrivate::WindowTheme,
+ WP_MINCAPTION, CS_ACTIVE, titleBarRect);
+ } else
+ themeData = QWindowsThemeData(widget, nullptr,
+ QWindowsVistaStylePrivate::WindowTheme,
+ WP_CAPTION, CS_ACTIVE, titleBarRect);
+ mask->region = d->region(themeData) +
+ QRect(0, tbHeight, option->rect.width(), option->rect.height() - tbHeight);
+ }
+ break;
+ }
+
+#if QT_CONFIG(rubberband)
+ case SH_RubberBand_Mask:
+ if (qstyleoption_cast<const QStyleOptionRubberBand *>(option))
+ ret = 0;
+ break;
+#endif // QT_CONFIG(rubberband)
+
+ case SH_MessageBox_CenterButtons:
+ ret = false;
+ break;
+
+ case SH_ToolTip_Mask:
+ if (option) {
+ if (QStyleHintReturnMask *mask = qstyleoption_cast<QStyleHintReturnMask*>(returnData)) {
+ ret = true;
+ QWindowsThemeData themeData(widget, nullptr,
+ QWindowsVistaStylePrivate::ToolTipTheme,
+ TTP_STANDARD, TTSS_NORMAL, option->rect);
+ mask->region = d->region(themeData);
+ }
+ }
+ break;
+
+ case SH_Table_GridLineColor:
+ if (option)
+ ret = int(option->palette.color(QPalette::Base).darker(118).rgba());
+ else
+ ret = -1;
+ break;
+
+ case SH_Header_ArrowAlignment:
+ ret = Qt::AlignTop | Qt::AlignHCenter;
+ break;
+
+ case SH_ItemView_DrawDelegateFrame:
+ ret = 1;
+ break;
+
+ default:
+ ret = QWindowsStyle::styleHint(hint, option, widget, returnData);
+ break;
+ }
+
+ return ret;
+}
+
+
+/*!
+ \internal
+
+ see drawPrimitive for comments on the animation support
+ */
+void QWindowsVistaStyle::drawControl(ControlElement element, const QStyleOption *option,
+ QPainter *painter, const QWidget *widget) const
+{
+ if (!QWindowsVistaStylePrivate::useVista()) {
+ QWindowsStyle::drawControl(element, option, painter, widget);
+ return;
+ }
+
+ QWindowsVistaStylePrivate *d = const_cast<QWindowsVistaStylePrivate*>(d_func());
+
+ bool selected = option->state & State_Selected;
+ bool pressed = option->state & State_Sunken;
+ bool disabled = !(option->state & State_Enabled);
+
+ int state = option->state;
+ int themeNumber = -1;
+
+ QRect rect(option->rect);
+ State flags = option->state;
+ int partId = 0;
+ int stateId = 0;
+
+ if (d->transitionsEnabled() && canAnimate(option)) {
+ if (element == CE_PushButtonBevel) {
+ QRect oldRect;
+ QRect newRect;
+
+ QObject *styleObject = option->styleObject;
+
+ int oldState = styleObject->property("_q_stylestate").toInt();
+ oldRect = styleObject->property("_q_stylerect").toRect();
+ newRect = option->rect;
+ styleObject->setProperty("_q_stylestate", int(option->state));
+ styleObject->setProperty("_q_stylerect", option->rect);
+
+ bool wasDefault = false;
+ bool isDefault = false;
+ if (const QStyleOptionButton *button = qstyleoption_cast<const QStyleOptionButton *>(option)) {
+ wasDefault = styleObject->property("_q_isdefault").toBool();
+ isDefault = button->features & QStyleOptionButton::DefaultButton;
+ styleObject->setProperty("_q_isdefault", isDefault);
+ }
+
+ bool doTransition = ((state & State_Sunken) != (oldState & State_Sunken) ||
+ (state & State_On) != (oldState & State_On) ||
+ (state & State_MouseOver) != (oldState & State_MouseOver));
+
+ if (oldRect != newRect || (wasDefault && !isDefault)) {
+ doTransition = false;
+ d->stopAnimation(styleObject);
+ }
+
+ if (doTransition) {
+ styleObject->setProperty("_q_no_animation", true);
+
+ QWindowsVistaTransition *t = new QWindowsVistaTransition(styleObject);
+ QWindowsVistaAnimation *anim = qobject_cast<QWindowsVistaAnimation *>(d->animation(styleObject));
+ QStyleOption *styleOption = clonedAnimationStyleOption(option);
+ styleOption->state = QStyle::State(oldState);
+
+ QImage startImage = createAnimationBuffer(option, widget);
+ QPainter startPainter(&startImage);
+
+ // Use current state of existing animation if already one is running
+ if (!anim) {
+ proxy()->drawControl(element, styleOption, &startPainter, widget);
+ } else {
+ anim->paint(&startPainter, styleOption);
+ d->stopAnimation(styleObject);
+ }
+
+ t->setStartImage(startImage);
+ QImage endImage = createAnimationBuffer(option, widget);
+ QPainter endPainter(&endImage);
+ styleOption->state = option->state;
+ proxy()->drawControl(element, styleOption, &endPainter, widget);
+ t->setEndImage(endImage);
+
+
+ DWORD duration = 0;
+ const HTHEME theme = OpenThemeData(nullptr, L"Button");
+
+ int fromState = buttonStateId(oldState, BP_PUSHBUTTON);
+ int toState = buttonStateId(option->state, BP_PUSHBUTTON);
+ if (GetThemeTransitionDuration(theme, BP_PUSHBUTTON, fromState, toState, TMT_TRANSITIONDURATIONS, &duration) == S_OK)
+ t->setDuration(int(duration));
+ else
+ t->setDuration(0);
+ t->setStartTime(d->animationTime());
+ styleObject->setProperty("_q_no_animation", false);
+
+ deleteClonedAnimationStyleOption(styleOption);
+ d->startAnimation(t);
+ }
+
+ QWindowsVistaAnimation *anim = qobject_cast<QWindowsVistaAnimation *>(d->animation(styleObject));
+ if (anim) {
+ anim->paint(painter, option);
+ return;
+ }
+
+ }
+ }
+
+ bool hMirrored = false;
+ bool vMirrored = false;
+ int rotate = 0;
+
+ switch (element) {
+ case CE_PushButtonBevel:
+ if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(option)) {
+ themeNumber = QWindowsVistaStylePrivate::ButtonTheme;
+ partId = BP_PUSHBUTTON;
+ if (btn->features & QStyleOptionButton::CommandLinkButton)
+ partId = BP_COMMANDLINK;
+ bool justFlat = (btn->features & QStyleOptionButton::Flat) && !(flags & (State_On|State_Sunken));
+ if (!(flags & State_Enabled) && !(btn->features & QStyleOptionButton::Flat))
+ stateId = PBS_DISABLED;
+ else if (justFlat)
+ ;
+ else if (flags & (State_Sunken | State_On))
+ stateId = PBS_PRESSED;
+ else if (flags & State_MouseOver)
+ stateId = PBS_HOT;
+ else if (btn->features & QStyleOptionButton::DefaultButton && (state & State_Active))
+ stateId = PBS_DEFAULTED;
+ else
+ stateId = PBS_NORMAL;
+
+ if (!justFlat) {
+
+ if (d->transitionsEnabled() && (btn->features & QStyleOptionButton::DefaultButton) &&
+ !(state & (State_Sunken | State_On)) && !(state & State_MouseOver) &&
+ (state & State_Enabled) && (state & State_Active))
+ {
+ QWindowsVistaAnimation *anim = qobject_cast<QWindowsVistaAnimation *>(d->animation(styleObject(option)));
+
+ if (!anim) {
+ QImage startImage = createAnimationBuffer(option, widget);
+ QImage alternateImage = createAnimationBuffer(option, widget);
+
+ QWindowsVistaPulse *pulse = new QWindowsVistaPulse(styleObject(option));
+
+ QPainter startPainter(&startImage);
+ stateId = PBS_DEFAULTED;
+ QWindowsThemeData theme(widget, &startPainter, themeNumber, partId, stateId, rect);
+ d->drawBackground(theme);
+
+ QPainter alternatePainter(&alternateImage);
+ theme.stateId = PBS_DEFAULTED_ANIMATING;
+ theme.painter = &alternatePainter;
+ d->drawBackground(theme);
+
+ pulse->setStartImage(startImage);
+ pulse->setEndImage(alternateImage);
+ pulse->setStartTime(d->animationTime());
+ pulse->setDuration(2000);
+ d->startAnimation(pulse);
+ anim = pulse;
+ }
+
+ if (anim)
+ anim->paint(painter, option);
+ else {
+ QWindowsThemeData theme(widget, painter, themeNumber, partId, stateId, rect);
+ d->drawBackground(theme);
+ }
+ }
+ else {
+ QWindowsThemeData theme(widget, painter, themeNumber, partId, stateId, rect);
+ d->drawBackground(theme);
+ }
+ }
+
+ if (btn->features & QStyleOptionButton::HasMenu) {
+ int mbiw = 0, mbih = 0;
+ QWindowsThemeData theme(widget, nullptr, QWindowsVistaStylePrivate::ToolBarTheme,
+ TP_DROPDOWNBUTTON);
+ if (theme.isValid()) {
+ const QSizeF size = theme.size() * QStyleHelper::dpiScaled(1, option);
+ if (!size.isEmpty()) {
+ mbiw = qRound(size.width());
+ mbih = qRound(size.height());
+ }
+ }
+ QRect ir = subElementRect(SE_PushButtonContents, option, nullptr);
+ QStyleOptionButton newBtn = *btn;
+ newBtn.rect = QStyle::visualRect(option->direction, option->rect,
+ QRect(ir.right() - mbiw - 2,
+ option->rect.top() + (option->rect.height()/2) - (mbih/2),
+ mbiw + 1, mbih + 1));
+ proxy()->drawPrimitive(PE_IndicatorArrowDown, &newBtn, painter, widget);
+ }
+ }
+ return;
+
+ case CE_SizeGrip: {
+ themeNumber = QWindowsVistaStylePrivate::StatusTheme;
+ partId = SP_GRIPPER;
+ QWindowsThemeData theme(nullptr, painter, themeNumber, partId);
+ QSize size = (theme.size() * QWindowsStylePrivate::nativeMetricScaleFactor(widget)).toSize();
+ size.rheight()--;
+ if (const auto *sg = qstyleoption_cast<const QStyleOptionSizeGrip *>(option)) {
+ switch (sg->corner) {
+ case Qt::BottomRightCorner:
+ rect = QRect(QPoint(rect.right() - size.width(), rect.bottom() - size.height()), size);
+ break;
+ case Qt::BottomLeftCorner:
+ rect = QRect(QPoint(rect.left() + 1, rect.bottom() - size.height()), size);
+ hMirrored = true;
+ break;
+ case Qt::TopRightCorner:
+ rect = QRect(QPoint(rect.right() - size.width(), rect.top() + 1), size);
+ vMirrored = true;
+ break;
+ case Qt::TopLeftCorner:
+ rect = QRect(rect.topLeft() + QPoint(1, 1), size);
+ hMirrored = vMirrored = true;
+ }
+ }
+ break;
+ }
+
+ case CE_Splitter:
+ painter->eraseRect(option->rect);
+ return;
+
+ case CE_TabBarTab:
+ if (const auto *tab = qstyleoption_cast<const QStyleOptionTab *>(option))
+ stateId = tab->state & State_Enabled ? TIS_NORMAL : TIS_DISABLED;
+ break;
+
+ case CE_TabBarTabShape:
+ if (const auto *tab = qstyleoption_cast<const QStyleOptionTab *>(option)) {
+ themeNumber = QWindowsVistaStylePrivate::TabTheme;
+ const bool isDisabled = !(tab->state & State_Enabled);
+ const bool hasFocus = tab->state & State_HasFocus;
+ const bool isHot = tab->state & State_MouseOver;
+ const bool selected = tab->state & State_Selected;
+ bool lastTab = tab->position == QStyleOptionTab::End;
+ bool firstTab = tab->position == QStyleOptionTab::Beginning;
+ const bool onlyOne = tab->position == QStyleOptionTab::OnlyOneTab;
+ const bool leftAligned = proxy()->styleHint(SH_TabBar_Alignment, tab, widget) == Qt::AlignLeft;
+ const bool centerAligned = proxy()->styleHint(SH_TabBar_Alignment, tab, widget) == Qt::AlignCenter;
+ const int borderThickness = proxy()->pixelMetric(PM_DefaultFrameWidth, option, widget);
+ const int tabOverlap = proxy()->pixelMetric(PM_TabBarTabOverlap, option, widget);
+
+ if (isDisabled)
+ stateId = TIS_DISABLED;
+ else if (selected)
+ stateId = TIS_SELECTED;
+ else if (hasFocus)
+ stateId = TIS_FOCUSED;
+ else if (isHot)
+ stateId = TIS_HOT;
+ else
+ stateId = TIS_NORMAL;
+
+ // Selecting proper part depending on position
+ if (firstTab || onlyOne) {
+ if (leftAligned)
+ partId = TABP_TABITEMLEFTEDGE;
+ else if (centerAligned)
+ partId = TABP_TABITEM;
+ else // rightAligned
+ partId = TABP_TABITEMRIGHTEDGE;
+ } else {
+ partId = TABP_TABITEM;
+ }
+
+ if (tab->direction == Qt::RightToLeft
+ && (tab->shape == QTabBar::RoundedNorth || tab->shape == QTabBar::RoundedSouth)) {
+ bool temp = firstTab;
+ firstTab = lastTab;
+ lastTab = temp;
+ }
+
+ const bool begin = firstTab || onlyOne;
+ const bool end = lastTab || onlyOne;
+
+ switch (tab->shape) {
+ case QTabBar::RoundedNorth:
+ if (selected)
+ rect.adjust(begin ? 0 : -tabOverlap, 0, end ? 0 : tabOverlap, borderThickness);
+ else
+ rect.adjust(begin? tabOverlap : 0, tabOverlap, end ? -tabOverlap : 0, 0);
+ break;
+ case QTabBar::RoundedSouth:
+ //vMirrored = true;
+ rotate = 180; // Not 100% correct, but works
+ if (selected)
+ rect.adjust(begin ? 0 : -tabOverlap , -borderThickness, end ? 0 : tabOverlap, 0);
+ else
+ rect.adjust(begin ? tabOverlap : 0, 0, end ? -tabOverlap : 0 , -tabOverlap);
+ break;
+ case QTabBar::RoundedEast:
+ rotate = 90;
+ if (selected)
+ rect.adjust(-borderThickness, begin ? 0 : -tabOverlap, 0, end ? 0 : tabOverlap);
+ else
+ rect.adjust(0, begin ? tabOverlap : 0, -tabOverlap, end ? -tabOverlap : 0);
+ break;
+ case QTabBar::RoundedWest:
+ hMirrored = true;
+ rotate = 90;
+ if (selected)
+ rect.adjust(0, begin ? 0 : -tabOverlap, borderThickness, end ? 0 : tabOverlap);
+ else
+ rect.adjust(tabOverlap, begin ? tabOverlap : 0, 0, end ? -tabOverlap : 0);
+ break;
+ default:
+ themeNumber = -1; // Do our own painting for triangular
+ break;
+ }
+
+ if (!selected) {
+ switch (tab->shape) {
+ case QTabBar::RoundedNorth:
+ rect.adjust(0,0, 0,-1);
+ break;
+ case QTabBar::RoundedSouth:
+ rect.adjust(0,1, 0,0);
+ break;
+ case QTabBar::RoundedEast:
+ rect.adjust( 1,0, 0,0);
+ break;
+ case QTabBar::RoundedWest:
+ rect.adjust(0,0, -1,0);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ break;
+
+ case CE_ProgressBarGroove: {
+ Qt::Orientation orient = Qt::Horizontal;
+ if (const auto *pb = qstyleoption_cast<const QStyleOptionProgressBar *>(option))
+ if (!(pb->state & QStyle::State_Horizontal))
+ orient = Qt::Vertical;
+
+ partId = (orient == Qt::Horizontal) ? PP_BAR : PP_BARVERT;
+ themeNumber = QWindowsVistaStylePrivate::ProgressTheme;
+ stateId = 1;
+ break;
+ }
+
+ case CE_ProgressBarContents:
+ if (const auto *bar = qstyleoption_cast<const QStyleOptionProgressBar *>(option)) {
+ bool isIndeterminate = (bar->minimum == 0 && bar->maximum == 0);
+ const bool vertical = !(bar->state & QStyle::State_Horizontal);
+ const bool inverted = bar->invertedAppearance;
+
+ if (isIndeterminate || (bar->progress > 0 && (bar->progress < bar->maximum) && d->transitionsEnabled())) {
+ if (!d->animation(styleObject(option)))
+ d->startAnimation(new QProgressStyleAnimation(d->animationFps, styleObject(option)));
+ } else {
+ d->stopAnimation(styleObject(option));
+ }
+
+ QWindowsThemeData theme(widget, painter,
+ QWindowsVistaStylePrivate::ProgressTheme,
+ vertical ? PP_FILLVERT : PP_FILL);
+ theme.rect = option->rect;
+ bool reverse = (bar->direction == Qt::LeftToRight && inverted) || (bar->direction == Qt::RightToLeft && !inverted);
+ QTime current = d->animationTime();
+
+ if (isIndeterminate) {
+ if (auto *progressAnimation = qobject_cast<QProgressStyleAnimation *>(d->animation(styleObject(option)))) {
+ int glowSize = 120;
+ int animationWidth = glowSize * 2 + (vertical ? theme.rect.height() : theme.rect.width());
+ int animOffset = progressAnimation->startTime().msecsTo(current) / 4;
+ if (animOffset > animationWidth)
+ progressAnimation->setStartTime(d->animationTime());
+ painter->save();
+ painter->setClipRect(theme.rect);
+ QRect animRect;
+ QSize pixmapSize(14, 14);
+ if (vertical) {
+ animRect = QRect(theme.rect.left(),
+ inverted ? rect.top() - glowSize + animOffset :
+ rect.bottom() + glowSize - animOffset,
+ rect.width(), glowSize);
+ pixmapSize.setHeight(animRect.height());
+ } else {
+ animRect = QRect(rect.left() - glowSize + animOffset,
+ rect.top(), glowSize, rect.height());
+ animRect = QStyle::visualRect(reverse ? Qt::RightToLeft : Qt::LeftToRight,
+ option->rect, animRect);
+ pixmapSize.setWidth(animRect.width());
+ }
+ QString name = QString::fromLatin1("qiprogress-%1-%2").arg(pixmapSize.width()).arg(pixmapSize.height());
+ QPixmap pixmap;
+ if (!QPixmapCache::find(name, &pixmap)) {
+ QImage image(pixmapSize, QImage::Format_ARGB32);
+ image.fill(Qt::transparent);
+ QPainter imagePainter(&image);
+ theme.painter = &imagePainter;
+ theme.partId = vertical ? PP_FILLVERT : PP_FILL;
+ theme.rect = QRect(QPoint(0,0), animRect.size());
+ QLinearGradient alphaGradient(0, 0, vertical ? 0 : image.width(),
+ vertical ? image.height() : 0);
+ alphaGradient.setColorAt(0, QColor(0, 0, 0, 0));
+ alphaGradient.setColorAt(0.5, QColor(0, 0, 0, 220));
+ alphaGradient.setColorAt(1, QColor(0, 0, 0, 0));
+ imagePainter.fillRect(image.rect(), alphaGradient);
+ imagePainter.setCompositionMode(QPainter::CompositionMode_SourceIn);
+ d->drawBackground(theme);
+ imagePainter.end();
+ pixmap = QPixmap::fromImage(image);
+ QPixmapCache::insert(name, pixmap);
+ }
+ painter->drawPixmap(animRect, pixmap);
+ painter->restore();
+ }
+ } else {
+ qint64 progress = qMax<qint64>(bar->progress, bar->minimum); // workaround for bug in QProgressBar
+
+ if (vertical) {
+ int maxHeight = option->rect.height();
+ int minHeight = 0;
+ double vc6_workaround = ((progress - qint64(bar->minimum)) / qMax(double(1.0), double(qint64(bar->maximum) - qint64(bar->minimum))) * maxHeight);
+ int height = isIndeterminate ? maxHeight: qMax(int(vc6_workaround), minHeight);
+ theme.rect.setHeight(height);
+ if (!inverted)
+ theme.rect.moveTop(rect.height() - theme.rect.height());
+ } else {
+ int maxWidth = option->rect.width();
+ int minWidth = 0;
+ double vc6_workaround = ((progress - qint64(bar->minimum)) / qMax(double(1.0), double(qint64(bar->maximum) - qint64(bar->minimum))) * maxWidth);
+ int width = isIndeterminate ? maxWidth : qMax(int(vc6_workaround), minWidth);
+ theme.rect.setWidth(width);
+ theme.rect = QStyle::visualRect(reverse ? Qt::RightToLeft : Qt::LeftToRight,
+ option->rect, theme.rect);
+ }
+ d->drawBackground(theme);
+
+ if (QProgressStyleAnimation *a = qobject_cast<QProgressStyleAnimation *>(d->animation(styleObject(option)))) {
+ int glowSize = 140;
+ int animationWidth = glowSize * 2 + (vertical ? theme.rect.height() : theme.rect.width());
+ int animOffset = a->startTime().msecsTo(current) / 4;
+ theme.partId = vertical ? PP_MOVEOVERLAYVERT : PP_MOVEOVERLAY;
+ if (animOffset > animationWidth) {
+ if (bar->progress < bar->maximum)
+ a->setStartTime(d->animationTime());
+ else
+ d->stopAnimation(styleObject(option)); //we stop the glow motion only after it has
+ //moved out of view
+ }
+ painter->save();
+ painter->setClipRect(theme.rect);
+ if (vertical) {
+ theme.rect = QRect(theme.rect.left(),
+ inverted ? rect.top() - glowSize + animOffset :
+ rect.bottom() + glowSize - animOffset,
+ rect.width(), glowSize);
+ } else {
+ theme.rect = QRect(rect.left() - glowSize + animOffset,rect.top(), glowSize, rect.height());
+ theme.rect = QStyle::visualRect(reverse ? Qt::RightToLeft : Qt::LeftToRight, option->rect, theme.rect);
+ }
+ d->drawBackground(theme);
+ painter->restore();
+ }
+ }
+ }
+ return;
+
+ case CE_MenuBarItem:
+ if (const auto *mbi = qstyleoption_cast<const QStyleOptionMenuItem *>(option)) {
+ if (mbi->menuItemType == QStyleOptionMenuItem::DefaultItem)
+ break;
+
+ QPalette::ColorRole textRole = disabled ? QPalette::Text : QPalette::ButtonText;
+ QPixmap pix = mbi->icon.pixmap(proxy()->pixelMetric(PM_SmallIconSize, option, widget), QIcon::Normal);
+
+ int alignment = Qt::AlignCenter | Qt::TextShowMnemonic | Qt::TextDontClip | Qt::TextSingleLine;
+ if (!proxy()->styleHint(SH_UnderlineShortcut, mbi, widget))
+ alignment |= Qt::TextHideMnemonic;
+
+ if (widget && mbi->palette.color(QPalette::Window) != Qt::transparent) { // Not needed for QtQuick Controls
+ //The rect adjustment is a workaround for the menu not really filling its background.
+ QWindowsThemeData theme(widget, painter,
+ QWindowsVistaStylePrivate::MenuTheme,
+ MENU_BARBACKGROUND, 0, option->rect.adjusted(-1, 0, 2, 1));
+ d->drawBackground(theme);
+
+ int stateId = MBI_NORMAL;
+ if (disabled)
+ stateId = MBI_DISABLED;
+ else if (pressed)
+ stateId = MBI_PUSHED;
+ else if (selected)
+ stateId = MBI_HOT;
+
+ QWindowsThemeData theme2(widget, painter,
+ QWindowsVistaStylePrivate::MenuTheme,
+ MENU_BARITEM, stateId, option->rect);
+ d->drawBackground(theme2);
+ }
+
+ if (!pix.isNull())
+ drawItemPixmap(painter, mbi->rect, alignment, pix);
+ else
+ drawItemText(painter, mbi->rect, alignment, mbi->palette, mbi->state & State_Enabled, mbi->text, textRole);
+ }
+ return;
+
+#if QT_CONFIG(menu)
+ case CE_MenuEmptyArea:
+ if (const auto *menuitem = qstyleoption_cast<const QStyleOptionMenuItem *>(option)) {
+ QBrush fill = menuitem->palette.brush((menuitem->state & State_Selected) ?
+ QPalette::Highlight : QPalette::Button);
+ painter->fillRect(rect, fill);
+ break;
+ }
+ return;
+
+ case CE_MenuItem:
+ if (const auto *menuitem = qstyleoption_cast<const QStyleOptionMenuItem *>(option)) {
+ // windows always has a check column, regardless whether we have an icon or not
+ const qreal factor = QWindowsVistaStylePrivate::nativeMetricScaleFactor(widget);
+ int checkcol = qRound(qreal(25) * factor);
+ const int gutterWidth = qRound(qreal(3) * factor);
+ {
+ QWindowsThemeData theme(widget, nullptr, QWindowsVistaStylePrivate::MenuTheme,
+ MENU_POPUPCHECKBACKGROUND, MBI_HOT);
+ QWindowsThemeData themeSize = theme;
+ themeSize.partId = MENU_POPUPCHECK;
+ themeSize.stateId = 0;
+ const QSizeF size = themeSize.size() * QWindowsStylePrivate::nativeMetricScaleFactor(widget);
+ const QMarginsF margins = themeSize.margins() * QWindowsStylePrivate::nativeMetricScaleFactor(widget);
+ checkcol = qMax(menuitem->maxIconWidth, qRound(gutterWidth + size.width() + margins.left() + margins.right()));
+ }
+ QRect rect = option->rect;
+
+ //draw vertical menu line
+ if (option->direction == Qt::LeftToRight)
+ checkcol += rect.x();
+ QPoint p1 = QStyle::visualPos(option->direction, menuitem->rect, QPoint(checkcol, rect.top()));
+ QPoint p2 = QStyle::visualPos(option->direction, menuitem->rect, QPoint(checkcol, rect.bottom()));
+ QRect gutterRect(p1.x(), p1.y(), gutterWidth, p2.y() - p1.y() + 1);
+ QWindowsThemeData theme2(widget, painter, QWindowsVistaStylePrivate::MenuTheme,
+ MENU_POPUPGUTTER, stateId, gutterRect);
+ d->drawBackground(theme2);
+
+ int x, y, w, h;
+ menuitem->rect.getRect(&x, &y, &w, &h);
+ int tab = menuitem->reservedShortcutWidth;
+ bool dis = !(menuitem->state & State_Enabled);
+ bool checked = menuitem->checkType != QStyleOptionMenuItem::NotCheckable
+ ? menuitem->checked : false;
+ bool act = menuitem->state & State_Selected;
+
+ if (menuitem->menuItemType == QStyleOptionMenuItem::Separator) {
+ int yoff = y-2 + h / 2;
+ const int separatorSize = qRound(qreal(6) * QWindowsStylePrivate::nativeMetricScaleFactor(widget));
+ QPoint p1 = QPoint(x + checkcol, yoff);
+ QPoint p2 = QPoint(x + w + separatorSize, yoff);
+ stateId = MBI_HOT;
+ QRect subRect(p1.x() + (gutterWidth - menuitem->rect.x()), p1.y(),
+ p2.x() - p1.x(), separatorSize);
+ subRect = QStyle::visualRect(option->direction, option->rect, subRect );
+ QWindowsThemeData theme2(widget, painter,
+ QWindowsVistaStylePrivate::MenuTheme,
+ MENU_POPUPSEPARATOR, stateId, subRect);
+ d->drawBackground(theme2);
+ return;
+ }
+
+ QRect vCheckRect = visualRect(option->direction, menuitem->rect, QRect(menuitem->rect.x(),
+ menuitem->rect.y(), checkcol - (gutterWidth + menuitem->rect.x()), menuitem->rect.height()));
+
+ if (act) {
+ stateId = dis ? MBI_DISABLED : MBI_HOT;
+ QWindowsThemeData theme2(widget, painter,
+ QWindowsVistaStylePrivate::MenuTheme,
+ MENU_POPUPITEM, stateId, option->rect);
+ d->drawBackground(theme2);
+ }
+
+ if (checked) {
+ QWindowsThemeData theme(widget, painter,
+ QWindowsVistaStylePrivate::MenuTheme,
+ MENU_POPUPCHECKBACKGROUND,
+ menuitem->icon.isNull() ? MBI_HOT : MBI_PUSHED, vCheckRect);
+ QWindowsThemeData themeSize = theme;
+ themeSize.partId = MENU_POPUPCHECK;
+ themeSize.stateId = 0;
+ const QSizeF size = themeSize.size() * QWindowsStylePrivate::nativeMetricScaleFactor(widget);
+ const QMarginsF margins = themeSize.margins() * QWindowsStylePrivate::nativeMetricScaleFactor(widget);
+ QRect checkRect(0, 0, qRound(size.width() + margins.left() + margins.right()),
+ qRound(size.height() + margins.bottom() + margins.top()));
+ checkRect.moveCenter(vCheckRect.center());
+ theme.rect = checkRect;
+
+ d->drawBackground(theme);
+
+ if (menuitem->icon.isNull()) {
+ checkRect = QRect(QPoint(0, 0), size.toSize());
+ checkRect.moveCenter(theme.rect.center());
+ theme.rect = checkRect;
+
+ theme.partId = MENU_POPUPCHECK;
+ bool bullet = menuitem->checkType & QStyleOptionMenuItem::Exclusive;
+ if (dis)
+ theme.stateId = bullet ? MC_BULLETDISABLED: MC_CHECKMARKDISABLED;
+ else
+ theme.stateId = bullet ? MC_BULLETNORMAL: MC_CHECKMARKNORMAL;
+ d->drawBackground(theme);
+ }
+ }
+
+ if (!menuitem->icon.isNull()) {
+ QIcon::Mode mode = dis ? QIcon::Disabled : QIcon::Normal;
+ if (act && !dis)
+ mode = QIcon::Active;
+ const auto size = proxy()->pixelMetric(PM_SmallIconSize, option, widget);
+ const auto dpr = painter->device()->devicePixelRatio();
+ const auto pixmap = menuitem->icon.pixmap({size, size}, dpr, mode,
+ checked ? QIcon::On : QIcon::Off);
+ QRect pmr(QPoint(0, 0), pixmap.deviceIndependentSize().toSize());
+ pmr.moveCenter(vCheckRect.center());
+ painter->setPen(menuitem->palette.text().color());
+ painter->drawPixmap(pmr.topLeft(), pixmap);
+ }
+
+ painter->setPen(menuitem->palette.buttonText().color());
+
+ const QColor textColor = menuitem->palette.text().color();
+ if (dis)
+ painter->setPen(textColor);
+
+ int xm = windowsItemFrame + checkcol + windowsItemHMargin + (gutterWidth - menuitem->rect.x()) - 1;
+ int xpos = menuitem->rect.x() + xm;
+ QRect textRect(xpos, y + windowsItemVMargin, w - xm - windowsRightBorder - tab + 1, h - 2 * windowsItemVMargin);
+ QRect vTextRect = visualRect(option->direction, menuitem->rect, textRect);
+ QString s = menuitem->text;
+ if (!s.isEmpty()) { // draw text
+ painter->save();
+ int t = s.indexOf(QLatin1Char('\t'));
+ int text_flags = Qt::AlignVCenter | Qt::TextShowMnemonic | Qt::TextDontClip | Qt::TextSingleLine;
+ if (!proxy()->styleHint(SH_UnderlineShortcut, menuitem, widget))
+ text_flags |= Qt::TextHideMnemonic;
+ text_flags |= Qt::AlignLeft;
+ if (t >= 0) {
+ QRect vShortcutRect = visualRect(option->direction, menuitem->rect,
+ QRect(textRect.topRight(), QPoint(menuitem->rect.right(), textRect.bottom())));
+ painter->drawText(vShortcutRect, text_flags, s.mid(t + 1));
+ s = s.left(t);
+ }
+ QFont font = menuitem->font;
+ if (menuitem->menuItemType == QStyleOptionMenuItem::DefaultItem)
+ font.setBold(true);
+ painter->setFont(font);
+ painter->setPen(textColor);
+ painter->drawText(vTextRect, text_flags, s.left(t));
+ painter->restore();
+ }
+ if (menuitem->menuItemType == QStyleOptionMenuItem::SubMenu) {// draw sub menu arrow
+ int dim = (h - 2 * windowsItemFrame) / 2;
+ PrimitiveElement arrow;
+ arrow = (option->direction == Qt::RightToLeft) ? PE_IndicatorArrowLeft : PE_IndicatorArrowRight;
+ xpos = x + w - windowsArrowHMargin - windowsItemFrame - dim;
+ QRect vSubMenuRect = visualRect(option->direction, menuitem->rect, QRect(xpos, y + h / 2 - dim / 2, dim, dim));
+ QStyleOptionMenuItem newMI = *menuitem;
+ newMI.rect = vSubMenuRect;
+ newMI.state = dis ? State_None : State_Enabled;
+ proxy()->drawPrimitive(arrow, &newMI, painter, widget);
+ }
+ }
+ return;
+#endif // QT_CONFIG(menu)
+
+ case CE_HeaderSection:
+ if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(option)) {
+ partId = HP_HEADERITEM;
+ if (flags & State_Sunken)
+ stateId = HIS_PRESSED;
+ else if (flags & State_MouseOver)
+ stateId = HIS_HOT;
+ else
+ stateId = HIS_NORMAL;
+
+ if (header->sortIndicator != QStyleOptionHeader::None)
+ stateId += 3;
+
+ QWindowsThemeData theme(widget, painter,
+ QWindowsVistaStylePrivate::HeaderTheme,
+ partId, stateId, option->rect);
+ d->drawBackground(theme);
+ }
+ return;
+
+ case CE_MenuBarEmptyArea: {
+ stateId = MBI_NORMAL;
+ if (!(state & State_Enabled))
+ stateId = MBI_DISABLED;
+ QWindowsThemeData theme(widget, painter, QWindowsVistaStylePrivate::MenuTheme,
+ MENU_BARBACKGROUND, stateId, option->rect);
+ d->drawBackground(theme);
+ return;
+ }
+
+ case CE_ToolBar:
+ if (const auto *toolbar = qstyleoption_cast<const QStyleOptionToolBar *>(option)) {
+ QPalette pal = option->palette;
+ pal.setColor(QPalette::Dark, option->palette.window().color().darker(130));
+ QStyleOptionToolBar copyOpt = *toolbar;
+ copyOpt.palette = pal;
+ QWindowsStyle::drawControl(element, &copyOpt, painter, widget);
+ }
+ return;
+
+#if QT_CONFIG(dockwidget)
+ case CE_DockWidgetTitle:
+ if (const auto *dwOpt = qstyleoption_cast<const QStyleOptionDockWidget *>(option)) {
+ QRect rect = option->rect;
+ const QDockWidget *dw = qobject_cast<const QDockWidget *>(widget);
+ bool isFloating = dw && dw->isFloating();
+ int buttonMargin = 4;
+ int mw = proxy()->pixelMetric(QStyle::PM_DockWidgetTitleMargin, dwOpt, widget);
+ int fw = proxy()->pixelMetric(PM_DockWidgetFrameWidth, dwOpt, widget);
+
+ const bool verticalTitleBar = dwOpt->verticalTitleBar;
+
+ if (verticalTitleBar) {
+ rect = rect.transposed();
+
+ painter->translate(rect.left() - 1, rect.top() + rect.width());
+ painter->rotate(-90);
+ painter->translate(-rect.left() + 1, -rect.top());
+ }
+
+ QRect r = option->rect.adjusted(0, 2, -1, -3);
+ QRect titleRect = r;
+
+ if (dwOpt->closable) {
+ QSize sz = proxy()->standardIcon(QStyle::SP_TitleBarCloseButton, dwOpt, widget).actualSize(QSize(10, 10));
+ titleRect.adjust(0, 0, -sz.width() - mw - buttonMargin, 0);
+ }
+
+ if (dwOpt->floatable) {
+ QSize sz = proxy()->standardIcon(QStyle::SP_TitleBarMaxButton, dwOpt, widget).actualSize(QSize(10, 10));
+ titleRect.adjust(0, 0, -sz.width() - mw - buttonMargin, 0);
+ }
+
+ if (isFloating) {
+ titleRect.adjust(0, -fw, 0, 0);
+ if (widget && widget->windowIcon().cacheKey() != QApplication::windowIcon().cacheKey())
+ titleRect.adjust(titleRect.height() + mw, 0, 0, 0);
+ } else {
+ titleRect.adjust(mw, 0, 0, 0);
+ if (!dwOpt->floatable && !dwOpt->closable)
+ titleRect.adjust(0, 0, -mw, 0);
+ }
+
+ if (!verticalTitleBar)
+ titleRect = visualRect(dwOpt->direction, r, titleRect);
+
+ if (isFloating) {
+ const bool isActive = dwOpt->state & State_Active;
+ themeNumber = QWindowsVistaStylePrivate::WindowTheme;
+ if (isActive)
+ stateId = CS_ACTIVE;
+ else
+ stateId = CS_INACTIVE;
+
+ int titleHeight = rect.height() - 2;
+ rect = rect.adjusted(-fw, -fw, fw, 0);
+
+ QWindowsThemeData theme(widget, painter, themeNumber, 0, stateId);
+ if (!theme.isValid())
+ break;
+
+ // Draw small type title bar
+ theme.rect = rect;
+ theme.partId = WP_SMALLCAPTION;
+ d->drawBackground(theme);
+
+ // Figure out maximal button space on title bar
+
+ QIcon ico = widget->windowIcon();
+ bool hasIcon = (ico.cacheKey() != QApplication::windowIcon().cacheKey());
+ if (hasIcon) {
+ QPixmap pxIco = ico.pixmap(titleHeight);
+ if (!verticalTitleBar && dwOpt->direction == Qt::RightToLeft)
+ painter->drawPixmap(rect.width() - titleHeight - pxIco.width(), rect.bottom() - titleHeight - 2, pxIco);
+ else
+ painter->drawPixmap(fw, rect.bottom() - titleHeight - 2, pxIco);
+ }
+ if (!dwOpt->title.isEmpty()) {
+ QPen oldPen = painter->pen();
+ QFont oldFont = painter->font();
+ QFont titleFont = oldFont;
+ titleFont.setBold(true);
+ painter->setFont(titleFont);
+ QString titleText
+ = painter->fontMetrics().elidedText(dwOpt->title, Qt::ElideRight, titleRect.width());
+
+ int result = TST_NONE;
+ GetThemeEnumValue(theme.handle(), WP_SMALLCAPTION, isActive ? CS_ACTIVE : CS_INACTIVE, TMT_TEXTSHADOWTYPE, &result);
+ if (result != TST_NONE) {
+ COLORREF textShadowRef;
+ GetThemeColor(theme.handle(), WP_SMALLCAPTION, isActive ? CS_ACTIVE : CS_INACTIVE, TMT_TEXTSHADOWCOLOR, &textShadowRef);
+ QColor textShadow = qRgb(GetRValue(textShadowRef), GetGValue(textShadowRef), GetBValue(textShadowRef));
+ painter->setPen(textShadow);
+ drawItemText(painter, titleRect.adjusted(1, 1, 1, 1),
+ Qt::AlignLeft | Qt::AlignBottom | Qt::TextHideMnemonic, dwOpt->palette,
+ dwOpt->state & State_Enabled, titleText);
+ }
+
+ COLORREF captionText = GetSysColor(isActive ? COLOR_CAPTIONTEXT : COLOR_INACTIVECAPTIONTEXT);
+ QColor textColor = qRgb(GetRValue(captionText), GetGValue(captionText), GetBValue(captionText));
+ painter->setPen(textColor);
+ drawItemText(painter, titleRect,
+ Qt::AlignLeft | Qt::AlignBottom | Qt::TextHideMnemonic, dwOpt->palette,
+ dwOpt->state & State_Enabled, titleText);
+ painter->setFont(oldFont);
+ painter->setPen(oldPen);
+ }
+ } else {
+ painter->setBrush(option->palette.window().color().darker(110));
+ painter->setPen(option->palette.window().color().darker(130));
+ painter->drawRect(rect.adjusted(0, 1, -1, -3));
+
+ if (!dwOpt->title.isEmpty()) {
+ QString titleText = painter->fontMetrics().elidedText(dwOpt->title, Qt::ElideRight,
+ verticalTitleBar ? titleRect.height() : titleRect.width());
+ const int indent = 4;
+ drawItemText(painter, rect.adjusted(indent + 1, 1, -indent - 1, -1),
+ Qt::AlignLeft | Qt::AlignVCenter | Qt::TextHideMnemonic,
+ dwOpt->palette,
+ dwOpt->state & State_Enabled, titleText,
+ QPalette::WindowText);
+ }
+ }
+ }
+ return;
+#endif // QT_CONFIG(dockwidget)
+
+#if QT_CONFIG(rubberband)
+ case CE_RubberBand:
+ if (qstyleoption_cast<const QStyleOptionRubberBand *>(option)) {
+ QColor highlight = option->palette.color(QPalette::Active, QPalette::Highlight);
+ painter->save();
+ painter->setPen(highlight.darker(120));
+ QColor dimHighlight(qMin(highlight.red()/2 + 110, 255),
+ qMin(highlight.green()/2 + 110, 255),
+ qMin(highlight.blue()/2 + 110, 255),
+ (widget && widget->isWindow())? 255 : 127);
+ painter->setBrush(dimHighlight);
+ painter->drawRect(option->rect.adjusted(0, 0, -1, -1));
+ painter->restore();
+ return;
+ }
+ break;
+#endif // QT_CONFIG(rubberband)
+
+ case CE_HeaderEmptyArea:
+ if (option->state & State_Horizontal) {
+ themeNumber = QWindowsVistaStylePrivate::HeaderTheme;
+ stateId = HIS_NORMAL;
+ } else {
+ QWindowsStyle::drawControl(CE_HeaderEmptyArea, option, painter, widget);
+ return;
+ }
+ break;
+
+#if QT_CONFIG(itemviews)
+ case CE_ItemViewItem: {
+ const QStyleOptionViewItem *vopt;
+ const QAbstractItemView *view = qobject_cast<const QAbstractItemView *>(widget);
+ bool newStyle = true;
+
+ if (qobject_cast<const QTableView*>(widget))
+ newStyle = false;
+
+ QWindowsThemeData theme(widget, painter, themeNumber, partId, stateId, rect);
+
+ if (newStyle && view && (vopt = qstyleoption_cast<const QStyleOptionViewItem *>(option))) {
+ /*
+ // We cannot currently get the correct selection color for "explorer style" views
+ COLORREF cref = 0;
+ QWindowsThemeData theme(d->treeViewHelper(), 0, QLatin1String("LISTVIEW"), 0, 0);
+ unsigned int res = GetThemeColor(theme.handle(), LVP_LISTITEM, LISS_SELECTED, TMT_TEXTCOLOR, &cref);
+ QColor textColor(GetRValue(cref), GetGValue(cref), GetBValue(cref));
+ */
+ QPalette palette = vopt->palette;
+ palette.setColor(QPalette::All, QPalette::HighlightedText, palette.color(QPalette::Active, QPalette::Text));
+ // Note that setting a saturated color here results in ugly XOR colors in the focus rect
+ palette.setColor(QPalette::All, QPalette::Highlight, palette.base().color().darker(108));
+ QStyleOptionViewItem adjustedOption = *vopt;
+ adjustedOption.palette = palette;
+ // We hide the focusrect in singleselection as it is not required
+ if ((view->selectionMode() == QAbstractItemView::SingleSelection)
+ && !(vopt->state & State_KeyboardFocusChange))
+ adjustedOption.state &= ~State_HasFocus;
+ if (!theme.isValid()) {
+ QWindowsStyle::drawControl(element, &adjustedOption, painter, widget);
+ return;
+ }
+ } else {
+ if (!theme.isValid()) {
+ QWindowsStyle::drawControl(element, option, painter, widget);
+ return;
+ }
+ }
+
+ theme.rotate = rotate;
+ theme.mirrorHorizontally = hMirrored;
+ theme.mirrorVertically = vMirrored;
+ d->drawBackground(theme);
+ return;
+ }
+#endif // QT_CONFIG(itemviews)
+
+#if QT_CONFIG(combobox)
+ case CE_ComboBoxLabel:
+ QCommonStyle::drawControl(element, option, painter, widget);
+ return;
+#endif // QT_CONFIG(combobox)
+
+ default:
+ break;
+ }
+
+ QWindowsThemeData theme(widget, painter, themeNumber, partId, stateId, rect);
+
+ if (!theme.isValid()) {
+ QWindowsStyle::drawControl(element, option, painter, widget);
+ return;
+ }
+
+ theme.rotate = rotate;
+ theme.mirrorHorizontally = hMirrored;
+ theme.mirrorVertically = vMirrored;
+
+ d->drawBackground(theme);
+}
+
+/*!
+ \internal
+ see drawPrimitive for comments on the animation support
+
+ */
+void QWindowsVistaStyle::drawComplexControl(ComplexControl control, const QStyleOptionComplex *option,
+ QPainter *painter, const QWidget *widget) const
+{
+ QWindowsVistaStylePrivate *d = const_cast<QWindowsVistaStylePrivate*>(d_func());
+
+ if (!QWindowsVistaStylePrivate::useVista()) {
+ QWindowsStyle::drawComplexControl(control, option, painter, widget);
+ return;
+ }
+
+ State state = option->state;
+ SubControls sub = option->subControls;
+ QRect r = option->rect;
+
+ int partId = 0;
+ int stateId = 0;
+
+ State flags = option->state;
+ if (widget && widget->testAttribute(Qt::WA_UnderMouse) && widget->isActiveWindow())
+ flags |= State_MouseOver;
+
+ if (d->transitionsEnabled() && canAnimate(option))
+ {
+ if (control == CC_ScrollBar || control == CC_SpinBox || control == CC_ComboBox) {
+ QObject *styleObject = option->styleObject; // Can be widget or qquickitem
+
+ int oldState = styleObject->property("_q_stylestate").toInt();
+ int oldActiveControls = styleObject->property("_q_stylecontrols").toInt();
+
+ QRect oldRect = styleObject->property("_q_stylerect").toRect();
+ styleObject->setProperty("_q_stylestate", int(option->state));
+ styleObject->setProperty("_q_stylecontrols", int(option->activeSubControls));
+ styleObject->setProperty("_q_stylerect", option->rect);
+
+ bool doTransition = ((state & State_Sunken) != (oldState & State_Sunken)
+ || (state & State_On) != (oldState & State_On)
+ || (state & State_MouseOver) != (oldState & State_MouseOver)
+ || oldActiveControls != int(option->activeSubControls));
+
+ if (qstyleoption_cast<const QStyleOptionSlider *>(option)) {
+ QRect oldSliderPos = styleObject->property("_q_stylesliderpos").toRect();
+ QRect currentPos = proxy()->subControlRect(CC_ScrollBar, option, SC_ScrollBarSlider, widget);
+ styleObject->setProperty("_q_stylesliderpos", currentPos);
+ if (oldSliderPos != currentPos) {
+ doTransition = false;
+ d->stopAnimation(styleObject);
+ }
+ } else if (control == CC_SpinBox) {
+ //spinboxes have a transition when focus changes
+ if (!doTransition)
+ doTransition = (state & State_HasFocus) != (oldState & State_HasFocus);
+ }
+
+ if (oldRect != option->rect) {
+ doTransition = false;
+ d->stopAnimation(styleObject);
+ }
+
+ if (doTransition) {
+ QImage startImage = createAnimationBuffer(option, widget);
+ QPainter startPainter(&startImage);
+
+ QImage endImage = createAnimationBuffer(option, widget);
+ QPainter endPainter(&endImage);
+
+ QWindowsVistaAnimation *anim = qobject_cast<QWindowsVistaAnimation *>(d->animation(styleObject));
+ QWindowsVistaTransition *t = new QWindowsVistaTransition(styleObject);
+
+ // Draw the image that ends the animation by using the current styleoption
+ QStyleOptionComplex *styleOption = qstyleoption_cast<QStyleOptionComplex*>(clonedAnimationStyleOption(option));
+
+ styleObject->setProperty("_q_no_animation", true);
+
+ // Draw transition source
+ if (!anim) {
+ styleOption->state = QStyle::State(oldState);
+ styleOption->activeSubControls = QStyle::SubControl(oldActiveControls);
+ proxy()->drawComplexControl(control, styleOption, &startPainter, widget);
+ } else {
+ anim->paint(&startPainter, option);
+ }
+ t->setStartImage(startImage);
+
+ // Draw transition target
+ styleOption->state = option->state;
+ styleOption->activeSubControls = option->activeSubControls;
+ proxy()->drawComplexControl(control, styleOption, &endPainter, widget);
+
+ styleObject->setProperty("_q_no_animation", false);
+
+ t->setEndImage(endImage);
+ t->setStartTime(d->animationTime());
+
+ if (option->state & State_MouseOver || option->state & State_Sunken)
+ t->setDuration(150);
+ else
+ t->setDuration(500);
+
+ deleteClonedAnimationStyleOption(styleOption);
+ d->startAnimation(t);
+ }
+ if (QWindowsVistaAnimation *anim = qobject_cast<QWindowsVistaAnimation *>(d->animation(styleObject))) {
+ anim->paint(painter, option);
+ return;
+ }
+ }
+ }
+
+ switch (control) {
+
+#if QT_CONFIG(slider)
+ case CC_Slider:
+ if (const auto *slider = qstyleoption_cast<const QStyleOptionSlider *>(option)) {
+ QWindowsThemeData theme(widget, painter, QWindowsVistaStylePrivate::TrackBarTheme);
+ QRect slrect = slider->rect;
+ QRegion tickreg = slrect;
+ if (sub & SC_SliderGroove) {
+ theme.rect = proxy()->subControlRect(CC_Slider, option, SC_SliderGroove, widget);
+ if (slider->orientation == Qt::Horizontal) {
+ partId = TKP_TRACK;
+ stateId = TRS_NORMAL;
+ theme.rect = QRect(slrect.left(), theme.rect.center().y() - 2, slrect.width(), 4);
+ } else {
+ partId = TKP_TRACKVERT;
+ stateId = TRVS_NORMAL;
+ theme.rect = QRect(theme.rect.center().x() - 2, slrect.top(), 4, slrect.height());
+ }
+ theme.partId = partId;
+ theme.stateId = stateId;
+ d->drawBackground(theme);
+ tickreg -= theme.rect;
+ }
+ if (sub & SC_SliderTickmarks) {
+ int tickOffset = proxy()->pixelMetric(PM_SliderTickmarkOffset, slider, widget);
+ int ticks = slider->tickPosition;
+ int thickness = proxy()->pixelMetric(PM_SliderControlThickness, slider, widget);
+ int len = proxy()->pixelMetric(PM_SliderLength, slider, widget);
+ int available = proxy()->pixelMetric(PM_SliderSpaceAvailable, slider, widget);
+ int interval = slider->tickInterval;
+ if (interval <= 0) {
+ interval = slider->singleStep;
+ if (QStyle::sliderPositionFromValue(slider->minimum, slider->maximum, interval,
+ available)
+ - QStyle::sliderPositionFromValue(slider->minimum, slider->maximum,
+ 0, available) < 3)
+ interval = slider->pageStep;
+ }
+ if (!interval)
+ interval = 1;
+ int fudge = len / 2;
+ int pos;
+ int bothOffset = (ticks & QSlider::TicksAbove && ticks & QSlider::TicksBelow) ? 1 : 0;
+ painter->setPen(d->sliderTickColor);
+ QVarLengthArray<QLine, 32> lines;
+ int v = slider->minimum;
+ while (v <= slider->maximum + 1) {
+ if (v == slider->maximum + 1 && interval == 1)
+ break;
+ const int v_ = qMin(v, slider->maximum);
+ int tickLength = (v_ == slider->minimum || v_ >= slider->maximum) ? 4 : 3;
+ pos = QStyle::sliderPositionFromValue(slider->minimum, slider->maximum,
+ v_, available) + fudge;
+ if (slider->orientation == Qt::Horizontal) {
+ if (ticks & QSlider::TicksAbove) {
+ lines.append(QLine(pos, tickOffset - 1 - bothOffset,
+ pos, tickOffset - 1 - bothOffset - tickLength));
+ }
+
+ if (ticks & QSlider::TicksBelow) {
+ lines.append(QLine(pos, tickOffset + thickness + bothOffset,
+ pos, tickOffset + thickness + bothOffset + tickLength));
+ }
+ } else {
+ if (ticks & QSlider::TicksAbove) {
+ lines.append(QLine(tickOffset - 1 - bothOffset, pos,
+ tickOffset - 1 - bothOffset - tickLength, pos));
+ }
+
+ if (ticks & QSlider::TicksBelow) {
+ lines.append(QLine(tickOffset + thickness + bothOffset, pos,
+ tickOffset + thickness + bothOffset + tickLength, pos));
+ }
+ }
+ // in the case where maximum is max int
+ int nextInterval = v + interval;
+ if (nextInterval < v)
+ break;
+ v = nextInterval;
+ }
+ if (!lines.isEmpty()) {
+ painter->save();
+ painter->translate(slrect.topLeft());
+ painter->drawLines(lines.constData(), lines.size());
+ painter->restore();
+ }
+ }
+ if (sub & SC_SliderHandle) {
+ theme.rect = proxy()->subControlRect(CC_Slider, option, SC_SliderHandle, widget);
+ if (slider->orientation == Qt::Horizontal) {
+ if (slider->tickPosition == QSlider::TicksAbove)
+ partId = TKP_THUMBTOP;
+ else if (slider->tickPosition == QSlider::TicksBelow)
+ partId = TKP_THUMBBOTTOM;
+ else
+ partId = TKP_THUMB;
+
+ if (!(slider->state & State_Enabled))
+ stateId = TUS_DISABLED;
+ else if (slider->activeSubControls & SC_SliderHandle && (slider->state & State_Sunken))
+ stateId = TUS_PRESSED;
+ else if (slider->activeSubControls & SC_SliderHandle && (slider->state & State_MouseOver))
+ stateId = TUS_HOT;
+ else if (flags & State_HasFocus)
+ stateId = TUS_FOCUSED;
+ else
+ stateId = TUS_NORMAL;
+ } else {
+ if (slider->tickPosition == QSlider::TicksLeft)
+ partId = TKP_THUMBLEFT;
+ else if (slider->tickPosition == QSlider::TicksRight)
+ partId = TKP_THUMBRIGHT;
+ else
+ partId = TKP_THUMBVERT;
+
+ if (!(slider->state & State_Enabled))
+ stateId = TUVS_DISABLED;
+ else if (slider->activeSubControls & SC_SliderHandle && (slider->state & State_Sunken))
+ stateId = TUVS_PRESSED;
+ else if (slider->activeSubControls & SC_SliderHandle && (slider->state & State_MouseOver))
+ stateId = TUVS_HOT;
+ else if (flags & State_HasFocus)
+ stateId = TUVS_FOCUSED;
+ else
+ stateId = TUVS_NORMAL;
+ }
+ theme.partId = partId;
+ theme.stateId = stateId;
+ d->drawBackground(theme);
+ }
+ if (slider->state & State_HasFocus) {
+ QStyleOptionFocusRect fropt;
+ fropt.QStyleOption::operator=(*slider);
+ fropt.rect = subElementRect(SE_SliderFocusRect, slider, widget);
+ proxy()->drawPrimitive(PE_FrameFocusRect, &fropt, painter, widget);
+ }
+ }
+ break;
+#endif
+
+#if QT_CONFIG(toolbutton)
+ case CC_ToolButton:
+ if (const auto *toolbutton = qstyleoption_cast<const QStyleOptionToolButton *>(option)) {
+ QRect button, menuarea;
+ button = proxy()->subControlRect(control, toolbutton, SC_ToolButton, widget);
+ menuarea = proxy()->subControlRect(control, toolbutton, SC_ToolButtonMenu, widget);
+
+ State bflags = toolbutton->state & ~State_Sunken;
+ State mflags = bflags;
+ bool autoRaise = flags & State_AutoRaise;
+ if (autoRaise) {
+ if (!(bflags & State_MouseOver) || !(bflags & State_Enabled))
+ bflags &= ~State_Raised;
+ }
+
+ if (toolbutton->state & State_Sunken) {
+ if (toolbutton->activeSubControls & SC_ToolButton) {
+ bflags |= State_Sunken;
+ mflags |= State_MouseOver | State_Sunken;
+ } else if (toolbutton->activeSubControls & SC_ToolButtonMenu) {
+ mflags |= State_Sunken;
+ bflags |= State_MouseOver;
+ }
+ }
+
+ QStyleOption tool = *toolbutton;
+ if (toolbutton->subControls & SC_ToolButton) {
+ if (flags & (State_Sunken | State_On | State_Raised) || !autoRaise) {
+ if (toolbutton->features & QStyleOptionToolButton::MenuButtonPopup && autoRaise) {
+ QWindowsThemeData theme(widget, painter, QWindowsVistaStylePrivate::ToolBarTheme);
+ theme.partId = TP_SPLITBUTTON;
+ theme.rect = button;
+ if (!(bflags & State_Enabled))
+ stateId = TS_DISABLED;
+ else if (bflags & State_Sunken)
+ stateId = TS_PRESSED;
+ else if (bflags & State_MouseOver || !(flags & State_AutoRaise))
+ stateId = flags & State_On ? TS_HOTCHECKED : TS_HOT;
+ else if (bflags & State_On)
+ stateId = TS_CHECKED;
+ else
+ stateId = TS_NORMAL;
+ if (option->direction == Qt::RightToLeft)
+ theme.mirrorHorizontally = true;
+ theme.stateId = stateId;
+ d->drawBackground(theme);
+ } else {
+ tool.rect = option->rect;
+ tool.state = bflags;
+ if (autoRaise) // for tool bars
+ proxy()->drawPrimitive(PE_PanelButtonTool, &tool, painter, widget);
+ else
+ proxy()->drawPrimitive(PE_PanelButtonBevel, &tool, painter, widget);
+ }
+ }
+ }
+
+ if (toolbutton->state & State_HasFocus) {
+ QStyleOptionFocusRect fr;
+ fr.QStyleOption::operator=(*toolbutton);
+ fr.rect.adjust(3, 3, -3, -3);
+ if (toolbutton->features & QStyleOptionToolButton::MenuButtonPopup)
+ fr.rect.adjust(0, 0, -proxy()->pixelMetric(QStyle::PM_MenuButtonIndicator,
+ toolbutton, widget), 0);
+ proxy()->drawPrimitive(PE_FrameFocusRect, &fr, painter, widget);
+ }
+ QStyleOptionToolButton label = *toolbutton;
+ label.state = bflags;
+ int fw = 2;
+ if (!autoRaise)
+ label.state &= ~State_Sunken;
+ label.rect = button.adjusted(fw, fw, -fw, -fw);
+ proxy()->drawControl(CE_ToolButtonLabel, &label, painter, widget);
+
+ if (toolbutton->subControls & SC_ToolButtonMenu) {
+ tool.rect = menuarea;
+ tool.state = mflags;
+ if (autoRaise) {
+ proxy()->drawPrimitive(PE_IndicatorButtonDropDown, &tool, painter, widget);
+ } else {
+ tool.state = mflags;
+ menuarea.adjust(-2, 0, 0, 0);
+ // Draw menu button
+ if ((bflags & State_Sunken) != (mflags & State_Sunken)){
+ painter->save();
+ painter->setClipRect(menuarea);
+ tool.rect = option->rect;
+ proxy()->drawPrimitive(PE_PanelButtonBevel, &tool, painter, nullptr);
+ painter->restore();
+ }
+ // Draw arrow
+ painter->save();
+ painter->setPen(option->palette.dark().color());
+ painter->drawLine(menuarea.left(), menuarea.top() + 3,
+ menuarea.left(), menuarea.bottom() - 3);
+ painter->setPen(option->palette.light().color());
+ painter->drawLine(menuarea.left() - 1, menuarea.top() + 3,
+ menuarea.left() - 1, menuarea.bottom() - 3);
+
+ tool.rect = menuarea.adjusted(2, 3, -2, -1);
+ proxy()->drawPrimitive(PE_IndicatorArrowDown, &tool, painter, widget);
+ painter->restore();
+ }
+ } else if (toolbutton->features & QStyleOptionToolButton::HasMenu) {
+ int mbi = proxy()->pixelMetric(PM_MenuButtonIndicator, toolbutton, widget);
+ QRect ir = toolbutton->rect;
+ QStyleOptionToolButton newBtn = *toolbutton;
+ newBtn.rect = QRect(ir.right() + 4 - mbi, ir.height() - mbi + 4, mbi - 5, mbi - 5);
+ proxy()->drawPrimitive(PE_IndicatorArrowDown, &newBtn, painter, widget);
+ }
+ }
+ break;
+#endif // QT_CONFIG(toolbutton)
+
+ case CC_TitleBar:
+ if (const auto *tb = qstyleoption_cast<const QStyleOptionTitleBar *>(option)) {
+ const qreal factor = QWindowsStylePrivate::nativeMetricScaleFactor(widget);
+ bool isActive = tb->titleBarState & QStyle::State_Active;
+ QWindowsThemeData theme(widget, painter, QWindowsVistaStylePrivate::WindowTheme);
+ if (sub & SC_TitleBarLabel) {
+ partId = (tb->titleBarState & Qt::WindowMinimized) ? WP_MINCAPTION : WP_CAPTION;
+ theme.rect = option->rect;
+ if (widget && !widget->isEnabled())
+ stateId = CS_DISABLED;
+ else if (isActive)
+ stateId = CS_ACTIVE;
+ else
+ stateId = CS_INACTIVE;
+
+ theme.partId = partId;
+ theme.stateId = stateId;
+ d->drawBackground(theme);
+
+ QRect ir = proxy()->subControlRect(CC_TitleBar, tb, SC_TitleBarLabel, widget);
+
+ int result = TST_NONE;
+ GetThemeEnumValue(theme.handle(), WP_CAPTION, isActive ? CS_ACTIVE : CS_INACTIVE, TMT_TEXTSHADOWTYPE, &result);
+ if (result != TST_NONE) {
+ COLORREF textShadowRef;
+ GetThemeColor(theme.handle(), WP_CAPTION, isActive ? CS_ACTIVE : CS_INACTIVE, TMT_TEXTSHADOWCOLOR, &textShadowRef);
+ QColor textShadow = qRgb(GetRValue(textShadowRef), GetGValue(textShadowRef), GetBValue(textShadowRef));
+ painter->setPen(textShadow);
+ painter->drawText(int(ir.x() + 3 * factor), int(ir.y() + 2 * factor),
+ int(ir.width() - 1 * factor), ir.height(),
+ Qt::AlignLeft | Qt::AlignVCenter | Qt::TextSingleLine, tb->text);
+ }
+ COLORREF captionText = GetSysColor(isActive ? COLOR_CAPTIONTEXT : COLOR_INACTIVECAPTIONTEXT);
+ QColor textColor = qRgb(GetRValue(captionText), GetGValue(captionText), GetBValue(captionText));
+ painter->setPen(textColor);
+ painter->drawText(int(ir.x() + 2 * factor), int(ir.y() + 1 * factor),
+ int(ir.width() - 2 * factor), ir.height(),
+ Qt::AlignLeft | Qt::AlignVCenter | Qt::TextSingleLine, tb->text);
+ }
+ if (sub & SC_TitleBarSysMenu && tb->titleBarFlags & Qt::WindowSystemMenuHint) {
+ theme.rect = proxy()->subControlRect(CC_TitleBar, option, SC_TitleBarSysMenu, widget);
+ partId = WP_SYSBUTTON;
+ if ((widget && !widget->isEnabled()) || !isActive)
+ stateId = SBS_DISABLED;
+ else if (option->activeSubControls == SC_TitleBarSysMenu && (option->state & State_Sunken))
+ stateId = SBS_PUSHED;
+ else if (option->activeSubControls == SC_TitleBarSysMenu && (option->state & State_MouseOver))
+ stateId = SBS_HOT;
+ else
+ stateId = SBS_NORMAL;
+ if (!tb->icon.isNull()) {
+ tb->icon.paint(painter, theme.rect);
+ } else {
+ theme.partId = partId;
+ theme.stateId = stateId;
+ if (theme.size().isEmpty()) {
+ int iconSize = proxy()->pixelMetric(PM_SmallIconSize, tb, widget);
+ QPixmap pm = proxy()->standardIcon(SP_TitleBarMenuButton, tb, widget).pixmap(iconSize, iconSize);
+ painter->save();
+ drawItemPixmap(painter, theme.rect, Qt::AlignCenter, pm);
+ painter->restore();
+ } else {
+ d->drawBackground(theme);
+ }
+ }
+ }
+
+ if (sub & SC_TitleBarMinButton && tb->titleBarFlags & Qt::WindowMinimizeButtonHint
+ && !(tb->titleBarState & Qt::WindowMinimized)) {
+ populateTitleBarButtonTheme(proxy(), widget, option, SC_TitleBarMinButton, isActive, WP_MINBUTTON, &theme);
+ d->drawBackground(theme);
+ }
+ if (sub & SC_TitleBarMaxButton && tb->titleBarFlags & Qt::WindowMaximizeButtonHint
+ && !(tb->titleBarState & Qt::WindowMaximized)) {
+ populateTitleBarButtonTheme(proxy(), widget, option, SC_TitleBarMaxButton, isActive, WP_MAXBUTTON, &theme);
+ d->drawBackground(theme);
+ }
+ if (sub & SC_TitleBarContextHelpButton
+ && tb->titleBarFlags & Qt::WindowContextHelpButtonHint) {
+ populateTitleBarButtonTheme(proxy(), widget, option, SC_TitleBarContextHelpButton, isActive, WP_HELPBUTTON, &theme);
+ d->drawBackground(theme);
+ }
+ bool drawNormalButton = (sub & SC_TitleBarNormalButton)
+ && (((tb->titleBarFlags & Qt::WindowMinimizeButtonHint)
+ && (tb->titleBarState & Qt::WindowMinimized))
+ || ((tb->titleBarFlags & Qt::WindowMaximizeButtonHint)
+ && (tb->titleBarState & Qt::WindowMaximized)));
+ if (drawNormalButton) {
+ populateTitleBarButtonTheme(proxy(), widget, option, SC_TitleBarNormalButton, isActive, WP_RESTOREBUTTON, &theme);
+ d->drawBackground(theme);
+ }
+ if (sub & SC_TitleBarShadeButton && tb->titleBarFlags & Qt::WindowShadeButtonHint
+ && !(tb->titleBarState & Qt::WindowMinimized)) {
+ populateTitleBarButtonTheme(proxy(), widget, option, SC_TitleBarShadeButton, isActive, WP_MINBUTTON, &theme);
+ d->drawBackground(theme);
+ }
+ if (sub & SC_TitleBarUnshadeButton && tb->titleBarFlags & Qt::WindowShadeButtonHint
+ && tb->titleBarState & Qt::WindowMinimized) {
+ populateTitleBarButtonTheme(proxy(), widget, option, SC_TitleBarUnshadeButton, isActive, WP_RESTOREBUTTON, &theme);
+ d->drawBackground(theme);
+ }
+ if (sub & SC_TitleBarCloseButton && tb->titleBarFlags & Qt::WindowSystemMenuHint) {
+ populateTitleBarButtonTheme(proxy(), widget, option, SC_TitleBarCloseButton, isActive, WP_CLOSEBUTTON, &theme);
+ d->drawBackground(theme);
+ }
+ }
+ break;
+
+#if QT_CONFIG(mdiarea)
+ case CC_MdiControls: {
+ QWindowsThemeData theme(widget, painter, QWindowsVistaStylePrivate::WindowTheme, WP_MDICLOSEBUTTON, CBS_NORMAL);
+ if (Q_UNLIKELY(!theme.isValid()))
+ return;
+
+ if (option->subControls.testFlag(SC_MdiCloseButton)) {
+ populateMdiButtonTheme(proxy(), widget, option, SC_MdiCloseButton, WP_MDICLOSEBUTTON, &theme);
+ d->drawBackground(theme, mdiButtonCorrectionFactor(theme, widget));
+ }
+ if (option->subControls.testFlag(SC_MdiNormalButton)) {
+ populateMdiButtonTheme(proxy(), widget, option, SC_MdiNormalButton, WP_MDIRESTOREBUTTON, &theme);
+ d->drawBackground(theme, mdiButtonCorrectionFactor(theme, widget));
+ }
+ if (option->subControls.testFlag(QStyle::SC_MdiMinButton)) {
+ populateMdiButtonTheme(proxy(), widget, option, SC_MdiMinButton, WP_MDIMINBUTTON, &theme);
+ d->drawBackground(theme, mdiButtonCorrectionFactor(theme, widget));
+ }
+ break;
+ }
+#endif // QT_CONFIG(mdiarea)
+
+#if QT_CONFIG(dial)
+ case CC_Dial:
+ if (const auto *dial = qstyleoption_cast<const QStyleOptionSlider *>(option))
+ QStyleHelper::drawDial(dial, painter);
+ break;
+#endif // QT_CONFIG(dial)
+
+ case CC_ComboBox:
+ if (const QStyleOptionComboBox *cmb = qstyleoption_cast<const QStyleOptionComboBox *>(option)) {
+ if (cmb->editable) {
+ if (sub & SC_ComboBoxEditField) {
+ partId = EP_EDITBORDER_NOSCROLL;
+ if (!(flags & State_Enabled))
+ stateId = ETS_DISABLED;
+ else if (flags & State_MouseOver)
+ stateId = ETS_HOT;
+ else if (flags & State_HasFocus)
+ stateId = ETS_FOCUSED;
+ else
+ stateId = ETS_NORMAL;
+
+ QWindowsThemeData theme(widget, painter,
+ QWindowsVistaStylePrivate::EditTheme,
+ partId, stateId, r);
+
+ d->drawBackground(theme);
+ }
+ if (sub & SC_ComboBoxArrow) {
+ QRect subRect = proxy()->subControlRect(CC_ComboBox, option, SC_ComboBoxArrow, widget);
+ QWindowsThemeData theme(widget, painter, QWindowsVistaStylePrivate::ComboboxTheme);
+ theme.rect = subRect;
+ partId = option->direction == Qt::RightToLeft ? CP_DROPDOWNBUTTONLEFT : CP_DROPDOWNBUTTONRIGHT;
+
+ if (!(cmb->state & State_Enabled))
+ stateId = CBXS_DISABLED;
+ else if (cmb->state & State_Sunken || cmb->state & State_On)
+ stateId = CBXS_PRESSED;
+ else if (cmb->state & State_MouseOver && option->activeSubControls & SC_ComboBoxArrow)
+ stateId = CBXS_HOT;
+ else
+ stateId = CBXS_NORMAL;
+
+ theme.partId = partId;
+ theme.stateId = stateId;
+ d->drawBackground(theme);
+ }
+
+ } else {
+ if (sub & SC_ComboBoxFrame) {
+ QWindowsThemeData theme(widget, painter, QWindowsVistaStylePrivate::ComboboxTheme);
+ theme.rect = option->rect;
+ theme.partId = CP_READONLY;
+ if (!(cmb->state & State_Enabled))
+ theme.stateId = CBXS_DISABLED;
+ else if (cmb->state & State_Sunken || cmb->state & State_On)
+ theme.stateId = CBXS_PRESSED;
+ else if (cmb->state & State_MouseOver)
+ theme.stateId = CBXS_HOT;
+ else
+ theme.stateId = CBXS_NORMAL;
+ d->drawBackground(theme);
+ }
+ if (sub & SC_ComboBoxArrow) {
+ QWindowsThemeData theme(widget, painter, QWindowsVistaStylePrivate::ComboboxTheme);
+ theme.rect = proxy()->subControlRect(CC_ComboBox, option, SC_ComboBoxArrow, widget);
+ theme.partId = option->direction == Qt::RightToLeft ? CP_DROPDOWNBUTTONLEFT : CP_DROPDOWNBUTTONRIGHT;
+ if (!(cmb->state & State_Enabled))
+ theme.stateId = CBXS_DISABLED;
+ else
+ theme.stateId = CBXS_NORMAL;
+ d->drawBackground(theme);
+ }
+ if ((sub & SC_ComboBoxEditField) && (flags & State_HasFocus)) {
+ QStyleOptionFocusRect fropt;
+ fropt.QStyleOption::operator=(*cmb);
+ fropt.rect = proxy()->subControlRect(CC_ComboBox, option, SC_ComboBoxEditField, widget);
+ proxy()->drawPrimitive(PE_FrameFocusRect, &fropt, painter, widget);
+ }
+ }
+ }
+ break;
+
+ case CC_ScrollBar:
+ if (const QStyleOptionSlider *scrollbar = qstyleoption_cast<const QStyleOptionSlider *>(option)) {
+ QWindowsThemeData theme(widget, painter, QWindowsVistaStylePrivate::ScrollBarTheme);
+ bool maxedOut = (scrollbar->maximum == scrollbar->minimum);
+ if (maxedOut)
+ flags &= ~State_Enabled;
+
+ bool isHorz = flags & State_Horizontal;
+ bool isRTL = option->direction == Qt::RightToLeft;
+ if (sub & SC_ScrollBarAddLine) {
+ theme.rect = proxy()->subControlRect(CC_ScrollBar, option, SC_ScrollBarAddLine, widget);
+ partId = SBP_ARROWBTN;
+ if (!(flags & State_Enabled))
+ stateId = (isHorz ? (isRTL ? ABS_LEFTDISABLED : ABS_RIGHTDISABLED) : ABS_DOWNDISABLED);
+ else if (scrollbar->activeSubControls & SC_ScrollBarAddLine && (scrollbar->state & State_Sunken))
+ stateId = (isHorz ? (isRTL ? ABS_LEFTPRESSED : ABS_RIGHTPRESSED) : ABS_DOWNPRESSED);
+ else if (scrollbar->activeSubControls & SC_ScrollBarAddLine && (scrollbar->state & State_MouseOver))
+ stateId = (isHorz ? (isRTL ? ABS_LEFTHOT : ABS_RIGHTHOT) : ABS_DOWNHOT);
+ else if (scrollbar->state & State_MouseOver)
+ stateId = (isHorz ? (isRTL ? ABS_LEFTHOVER : ABS_RIGHTHOVER) : ABS_DOWNHOVER);
+ else
+ stateId = (isHorz ? (isRTL ? ABS_LEFTNORMAL : ABS_RIGHTNORMAL) : ABS_DOWNNORMAL);
+ theme.partId = partId;
+ theme.stateId = stateId;
+ d->drawBackground(theme);
+ }
+ if (sub & SC_ScrollBarSubLine) {
+ theme.rect = proxy()->subControlRect(CC_ScrollBar, option, SC_ScrollBarSubLine, widget);
+ partId = SBP_ARROWBTN;
+ if (!(flags & State_Enabled))
+ stateId = (isHorz ? (isRTL ? ABS_RIGHTDISABLED : ABS_LEFTDISABLED) : ABS_UPDISABLED);
+ else if (scrollbar->activeSubControls & SC_ScrollBarSubLine && (scrollbar->state & State_Sunken))
+ stateId = (isHorz ? (isRTL ? ABS_RIGHTPRESSED : ABS_LEFTPRESSED) : ABS_UPPRESSED);
+ else if (scrollbar->activeSubControls & SC_ScrollBarSubLine && (scrollbar->state & State_MouseOver))
+ stateId = (isHorz ? (isRTL ? ABS_RIGHTHOT : ABS_LEFTHOT) : ABS_UPHOT);
+ else if (scrollbar->state & State_MouseOver)
+ stateId = (isHorz ? (isRTL ? ABS_RIGHTHOVER : ABS_LEFTHOVER) : ABS_UPHOVER);
+ else
+ stateId = (isHorz ? (isRTL ? ABS_RIGHTNORMAL : ABS_LEFTNORMAL) : ABS_UPNORMAL);
+ theme.partId = partId;
+ theme.stateId = stateId;
+ d->drawBackground(theme);
+ }
+ if (maxedOut) {
+ theme.rect = proxy()->subControlRect(CC_ScrollBar, option, SC_ScrollBarSlider, widget);
+ theme.rect = theme.rect.united(proxy()->subControlRect(CC_ScrollBar, option, SC_ScrollBarSubPage, widget));
+ theme.rect = theme.rect.united(proxy()->subControlRect(CC_ScrollBar, option, SC_ScrollBarAddPage, widget));
+ partId = flags & State_Horizontal ? SBP_LOWERTRACKHORZ : SBP_LOWERTRACKVERT;
+ stateId = SCRBS_DISABLED;
+ theme.partId = partId;
+ theme.stateId = stateId;
+ d->drawBackground(theme);
+ } else {
+ if (sub & SC_ScrollBarSubPage) {
+ theme.rect = proxy()->subControlRect(CC_ScrollBar, option, SC_ScrollBarSubPage, widget);
+ partId = flags & State_Horizontal ? SBP_UPPERTRACKHORZ : SBP_UPPERTRACKVERT;
+ if (!(flags & State_Enabled))
+ stateId = SCRBS_DISABLED;
+ else if (scrollbar->activeSubControls & SC_ScrollBarSubPage && (scrollbar->state & State_Sunken))
+ stateId = SCRBS_PRESSED;
+ else if (scrollbar->activeSubControls & SC_ScrollBarSubPage && (scrollbar->state & State_MouseOver))
+ stateId = SCRBS_HOT;
+ else
+ stateId = SCRBS_NORMAL;
+ theme.partId = partId;
+ theme.stateId = stateId;
+ d->drawBackground(theme);
+ }
+ if (sub & SC_ScrollBarAddPage) {
+ theme.rect = proxy()->subControlRect(CC_ScrollBar, option, SC_ScrollBarAddPage, widget);
+ partId = flags & State_Horizontal ? SBP_LOWERTRACKHORZ : SBP_LOWERTRACKVERT;
+ if (!(flags & State_Enabled))
+ stateId = SCRBS_DISABLED;
+ else if (scrollbar->activeSubControls & SC_ScrollBarAddPage && (scrollbar->state & State_Sunken))
+ stateId = SCRBS_PRESSED;
+ else if (scrollbar->activeSubControls & SC_ScrollBarAddPage && (scrollbar->state & State_MouseOver))
+ stateId = SCRBS_HOT;
+ else
+ stateId = SCRBS_NORMAL;
+ theme.partId = partId;
+ theme.stateId = stateId;
+ d->drawBackground(theme);
+ }
+ if (sub & SC_ScrollBarSlider) {
+ theme.rect = proxy()->subControlRect(CC_ScrollBar, option, SC_ScrollBarSlider, widget);
+ if (!(flags & State_Enabled))
+ stateId = SCRBS_DISABLED;
+ else if (scrollbar->activeSubControls & SC_ScrollBarSlider && (scrollbar->state & State_Sunken))
+ stateId = SCRBS_PRESSED;
+ else if (scrollbar->activeSubControls & SC_ScrollBarSlider && (scrollbar->state & State_MouseOver))
+ stateId = SCRBS_HOT;
+ else if (option->state & State_MouseOver)
+ stateId = SCRBS_HOVER;
+ else
+ stateId = SCRBS_NORMAL;
+
+ // Draw handle
+ theme.partId = flags & State_Horizontal ? SBP_THUMBBTNHORZ : SBP_THUMBBTNVERT;
+ theme.stateId = stateId;
+ d->drawBackground(theme);
+ }
+ }
+ }
+ break;
+
+#if QT_CONFIG(spinbox)
+ case CC_SpinBox:
+ if (const QStyleOptionSpinBox *sb = qstyleoption_cast<const QStyleOptionSpinBox *>(option)) {
+ QWindowsThemeData theme(widget, painter, QWindowsVistaStylePrivate::SpinTheme);
+ if (sb->frame && (sub & SC_SpinBoxFrame)) {
+ partId = EP_EDITBORDER_NOSCROLL;
+ if (!(flags & State_Enabled))
+ stateId = ETS_DISABLED;
+ else if (flags & State_MouseOver)
+ stateId = ETS_HOT;
+ else if (flags & State_HasFocus)
+ stateId = ETS_SELECTED;
+ else
+ stateId = ETS_NORMAL;
+
+ QWindowsThemeData ftheme(widget, painter,
+ QWindowsVistaStylePrivate::EditTheme,
+ partId, stateId, r);
+ // The spinbox in Windows QStyle is drawn with frameless QLineEdit inside it
+ // That however breaks with QtQuickControls where this results in transparent
+ // spinbox background, so if there's no "widget" passed (QtQuickControls case),
+ // let ftheme.noContent be false, which fixes the spinbox rendering in QQC
+ ftheme.noContent = (widget != nullptr);
+ d->drawBackground(ftheme);
+ }
+ if (sub & SC_SpinBoxUp) {
+ theme.rect = proxy()->subControlRect(CC_SpinBox, option, SC_SpinBoxUp, widget).adjusted(0, 0, 0, 1);
+ partId = SPNP_UP;
+ if (!(sb->stepEnabled & QAbstractSpinBox::StepUpEnabled) || !(flags & State_Enabled))
+ stateId = UPS_DISABLED;
+ else if (sb->activeSubControls == SC_SpinBoxUp && (sb->state & State_Sunken))
+ stateId = UPS_PRESSED;
+ else if (sb->activeSubControls == SC_SpinBoxUp && (sb->state & State_MouseOver))
+ stateId = UPS_HOT;
+ else
+ stateId = UPS_NORMAL;
+ theme.partId = partId;
+ theme.stateId = stateId;
+ d->drawBackground(theme);
+ }
+ if (sub & SC_SpinBoxDown) {
+ theme.rect = proxy()->subControlRect(CC_SpinBox, option, SC_SpinBoxDown, widget);
+ partId = SPNP_DOWN;
+ if (!(sb->stepEnabled & QAbstractSpinBox::StepDownEnabled) || !(flags & State_Enabled))
+ stateId = DNS_DISABLED;
+ else if (sb->activeSubControls == SC_SpinBoxDown && (sb->state & State_Sunken))
+ stateId = DNS_PRESSED;
+ else if (sb->activeSubControls == SC_SpinBoxDown && (sb->state & State_MouseOver))
+ stateId = DNS_HOT;
+ else
+ stateId = DNS_NORMAL;
+ theme.partId = partId;
+ theme.stateId = stateId;
+ d->drawBackground(theme);
+ }
+ }
+ break;
+#endif // QT_CONFIG(spinbox)
+
+ default:
+ QWindowsStyle::drawComplexControl(control, option, painter, widget);
+ break;
+ }
+}
+
+/*!
+ \internal
+ */
+QSize QWindowsVistaStyle::sizeFromContents(ContentsType type, const QStyleOption *option,
+ const QSize &size, const QWidget *widget) const
+{
+ if (!QWindowsVistaStylePrivate::useVista())
+ return QWindowsStyle::sizeFromContents(type, option, size, widget);
+
+ QSize contentSize(size);
+
+ switch (type) {
+ case CT_LineEdit:
+ case CT_ComboBox: {
+ QWindowsThemeData buttontheme(widget, nullptr, QWindowsVistaStylePrivate::ButtonTheme, BP_PUSHBUTTON, PBS_NORMAL);
+ if (buttontheme.isValid()) {
+ const qreal factor = QWindowsStylePrivate::nativeMetricScaleFactor(widget);
+ const QMarginsF borderSize = buttontheme.margins() * factor;
+ if (!borderSize.isNull()) {
+ const qreal margin = qreal(2) * factor;
+ contentSize.rwidth() += qRound(borderSize.left() + borderSize.right() - margin);
+ contentSize.rheight() += int(borderSize.bottom() + borderSize.top() - margin
+ + qreal(1) / factor - 1);
+ }
+ const int textMargins = 2*(proxy()->pixelMetric(PM_FocusFrameHMargin, option) + 1);
+ contentSize += QSize(qMax(pixelMetric(QStyle::PM_ScrollBarExtent, option, widget)
+ + textMargins, 23), 0); //arrow button
+ }
+ break;
+ }
+
+ case CT_TabWidget:
+ contentSize += QSize(6, 6);
+ break;
+
+ case CT_Menu:
+ contentSize += QSize(1, 0);
+ break;
+
+#if QT_CONFIG(menubar)
+ case CT_MenuBarItem:
+ if (!contentSize.isEmpty())
+ contentSize += QSize(windowsItemHMargin * 5 + 1, 5);
+ break;
+#endif
+
+ case CT_MenuItem: {
+ contentSize = QWindowsStyle::sizeFromContents(type, option, size, widget);
+ QWindowsThemeData theme(widget, nullptr,
+ QWindowsVistaStylePrivate::MenuTheme,
+ MENU_POPUPCHECKBACKGROUND, MBI_HOT);
+ QWindowsThemeData themeSize = theme;
+ themeSize.partId = MENU_POPUPCHECK;
+ themeSize.stateId = 0;
+ const QSizeF size = themeSize.size() * QWindowsStylePrivate::nativeMetricScaleFactor(widget);
+ const QMarginsF margins = themeSize.margins() * QWindowsStylePrivate::nativeMetricScaleFactor(widget);
+ int minimumHeight = qMax(qRound(size.height() + margins.bottom() + margins.top()), contentSize.height());
+ contentSize.rwidth() += qRound(size.width() + margins.left() + margins.right());
+ if (const QStyleOptionMenuItem *menuitem = qstyleoption_cast<const QStyleOptionMenuItem *>(option)) {
+ if (menuitem->menuItemType != QStyleOptionMenuItem::Separator)
+ contentSize.setHeight(minimumHeight);
+ }
+ break;
+ }
+
+ case CT_MdiControls: {
+ contentSize.setHeight(int(QStyleHelper::dpiScaled(19, option)));
+ int width = 54;
+ if (const auto *styleOpt = qstyleoption_cast<const QStyleOptionComplex *>(option)) {
+ width = 0;
+ if (styleOpt->subControls & SC_MdiMinButton)
+ width += 17 + 1;
+ if (styleOpt->subControls & SC_MdiNormalButton)
+ width += 17 + 1;
+ if (styleOpt->subControls & SC_MdiCloseButton)
+ width += 17 + 1;
+ }
+ contentSize.setWidth(int(QStyleHelper::dpiScaled(width, option)));
+ break;
+ }
+
+ case CT_ItemViewItem:
+ contentSize = QWindowsStyle::sizeFromContents(type, option, size, widget);
+ contentSize.rheight() += 2;
+ break;
+
+ case CT_SpinBox: {
+ //Spinbox adds frame twice
+ contentSize = QWindowsStyle::sizeFromContents(type, option, size, widget);
+ int border = proxy()->pixelMetric(PM_SpinBoxFrameWidth, option, widget);
+ contentSize -= QSize(2*border, 2*border);
+ break;
+ }
+
+ case CT_HeaderSection:
+ // When there is a sort indicator it adds to the width but it is shown
+ // above the text natively and not on the side
+ if (QStyleOptionHeader *hdr = qstyleoption_cast<QStyleOptionHeader *>(const_cast<QStyleOption *>(option))) {
+ QStyleOptionHeader::SortIndicator sortInd = hdr->sortIndicator;
+ hdr->sortIndicator = QStyleOptionHeader::None;
+ contentSize = QWindowsStyle::sizeFromContents(type, hdr, size, widget);
+ hdr->sortIndicator = sortInd;
+ }
+ break;
+
+ default:
+ contentSize = QWindowsStyle::sizeFromContents(type, option, size, widget);
+ break;
+ }
+
+ return contentSize;
+}
+
+/*!
+ \internal
+ */
+QRect QWindowsVistaStyle::subElementRect(SubElement element, const QStyleOption *option, const QWidget *widget) const
+{
+ if (!QWindowsVistaStylePrivate::useVista())
+ return QWindowsStyle::subElementRect(element, option, widget);
+
+ QRect rect(option->rect);
+
+ switch (element) {
+ case SE_PushButtonContents:
+ if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(option)) {
+ MARGINS borderSize;
+ const HTHEME theme = OpenThemeData(widget ? QWindowsVistaStylePrivate::winId(widget) : nullptr, L"Button");
+ if (theme) {
+ int stateId = PBS_NORMAL;
+ if (!(option->state & State_Enabled))
+ stateId = PBS_DISABLED;
+ else if (option->state & State_Sunken)
+ stateId = PBS_PRESSED;
+ else if (option->state & State_MouseOver)
+ stateId = PBS_HOT;
+ else if (btn->features & QStyleOptionButton::DefaultButton)
+ stateId = PBS_DEFAULTED;
+
+ int border = proxy()->pixelMetric(PM_DefaultFrameWidth, btn, widget);
+ rect = option->rect.adjusted(border, border, -border, -border);
+
+ if (SUCCEEDED(GetThemeMargins(theme, nullptr, BP_PUSHBUTTON, stateId, TMT_CONTENTMARGINS, nullptr, &borderSize))) {
+ rect.adjust(borderSize.cxLeftWidth, borderSize.cyTopHeight,
+ -borderSize.cxRightWidth, -borderSize.cyBottomHeight);
+ rect = visualRect(option->direction, option->rect, rect);
+ }
+ }
+ }
+ break;
+
+ case SE_DockWidgetCloseButton:
+ case SE_DockWidgetFloatButton:
+ rect = QWindowsStyle::subElementRect(element, option, widget);
+ return rect.translated(0, 1);
+
+ case SE_TabWidgetTabContents:
+ rect = QWindowsStyle::subElementRect(element, option, widget);
+ if (qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(option)) {
+ rect = QWindowsStyle::subElementRect(element, option, widget);
+ if (const QTabWidget *tabWidget = qobject_cast<const QTabWidget *>(widget)) {
+ if (tabWidget->documentMode())
+ break;
+ rect.adjust(0, 0, -2, -2);
+ }
+ }
+ break;
+
+ case SE_TabWidgetTabBar: {
+ rect = QWindowsStyle::subElementRect(element, option, widget);
+ const auto *twfOption = qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(option);
+ if (twfOption && twfOption->direction == Qt::RightToLeft
+ && (twfOption->shape == QTabBar::RoundedNorth
+ || twfOption->shape == QTabBar::RoundedSouth))
+ {
+ QStyleOptionTab otherOption;
+ otherOption.shape = (twfOption->shape == QTabBar::RoundedNorth
+ ? QTabBar::RoundedEast : QTabBar::RoundedSouth);
+ int overlap = proxy()->pixelMetric(PM_TabBarBaseOverlap, &otherOption, widget);
+ int borderThickness = proxy()->pixelMetric(PM_DefaultFrameWidth, option, widget);
+ rect.adjust(-overlap + borderThickness, 0, -overlap + borderThickness, 0);
+ }
+ break;
+ }
+
+ case SE_HeaderArrow: {
+ rect = QWindowsStyle::subElementRect(element, option, widget);
+ QRect r = rect;
+ int h = option->rect.height();
+ int w = option->rect.width();
+ int x = option->rect.x();
+ int y = option->rect.y();
+ int margin = proxy()->pixelMetric(QStyle::PM_HeaderMargin, option, widget);
+
+ QWindowsThemeData theme(widget, nullptr,
+ QWindowsVistaStylePrivate::HeaderTheme,
+ HP_HEADERSORTARROW, HSAS_SORTEDDOWN, option->rect);
+
+ int arrowWidth = 13;
+ int arrowHeight = 5;
+ if (theme.isValid()) {
+ const QSizeF size = theme.size() * QWindowsStylePrivate::nativeMetricScaleFactor(widget);
+ if (!size.isEmpty()) {
+ arrowWidth = qRound(size.width());
+ arrowHeight = qRound(size.height());
+ }
+ }
+ if (option->state & State_Horizontal) {
+ r.setRect(x + w/2 - arrowWidth/2, y , arrowWidth, arrowHeight);
+ } else {
+ int vert_size = w / 2;
+ r.setRect(x + 5, y + h - margin * 2 - vert_size,
+ w - margin * 2 - 5, vert_size);
+ }
+ rect = visualRect(option->direction, option->rect, r);
+ break;
+ }
+
+ case SE_HeaderLabel: {
+ rect = QWindowsStyle::subElementRect(element, option, widget);
+ int margin = proxy()->pixelMetric(QStyle::PM_HeaderMargin, option, widget);
+ QRect r = option->rect;
+ r.setRect(option->rect.x() + margin, option->rect.y() + margin,
+ option->rect.width() - margin * 2, option->rect.height() - margin * 2);
+ if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(option)) {
+ // Subtract width needed for arrow, if there is one
+ if (header->sortIndicator != QStyleOptionHeader::None) {
+ if (!(option->state & State_Horizontal)) //horizontal arrows are positioned on top
+ r.setHeight(r.height() - (option->rect.width() / 2) - (margin * 2));
+ }
+ }
+ rect = visualRect(option->direction, option->rect, r);
+ break;
+ }
+
+ case SE_ProgressBarContents:
+ rect = QCommonStyle::subElementRect(SE_ProgressBarGroove, option, widget);
+ break;
+
+ case SE_ItemViewItemDecoration:
+ rect = QWindowsStyle::subElementRect(element, option, widget);
+ if (qstyleoption_cast<const QStyleOptionViewItem *>(option))
+ rect.adjust(-2, 0, 2, 0);
+ break;
+
+ case SE_ItemViewItemFocusRect:
+ rect = QWindowsStyle::subElementRect(element, option, widget);
+ if (const QStyleOptionViewItem *vopt = qstyleoption_cast<const QStyleOptionViewItem *>(option)) {
+ QRect textRect = subElementRect(QStyle::SE_ItemViewItemText, option, widget);
+ QRect displayRect = subElementRect(QStyle::SE_ItemViewItemDecoration, option, widget);
+ if (!vopt->icon.isNull())
+ rect = textRect.united(displayRect);
+ else
+ rect = textRect;
+ rect = rect.adjusted(1, 0, -1, 0);
+ }
+ break;
+
+ default:
+ rect = QWindowsStyle::subElementRect(element, option, widget);
+ break;
+ }
+
+ return rect;
+}
+
+/*!
+ \internal
+ */
+QRect QWindowsVistaStyle::subControlRect(ComplexControl control, const QStyleOptionComplex *option,
+ SubControl subControl, const QWidget *widget) const
+{
+ if (!QWindowsVistaStylePrivate::useVista())
+ return QWindowsStyle::subControlRect(control, option, subControl, widget);
+
+ QRect rect;
+
+ switch (control) {
+#if QT_CONFIG(combobox)
+ case CC_ComboBox:
+ if (const auto *cb = qstyleoption_cast<const QStyleOptionComboBox *>(option)) {
+ const int x = cb->rect.x(), y = cb->rect.y(), wi = cb->rect.width(), he = cb->rect.height();
+ const int margin = cb->frame ? 3 : 0;
+ const int bmarg = cb->frame ? 2 : 0;
+ const int arrowWidth = qRound(QStyleHelper::dpiScaled(16, option));
+ const int arrowButtonWidth = bmarg + arrowWidth;
+ const int xpos = x + wi - arrowButtonWidth;
+
+ switch (subControl) {
+ case SC_ComboBoxFrame:
+ case SC_ComboBoxListBoxPopup:
+ rect = cb->rect;
+ break;
+
+ case SC_ComboBoxArrow: {
+ rect.setRect(xpos, y , arrowButtonWidth, he);
+ }
+ break;
+
+ case SC_ComboBoxEditField: {
+ rect.setRect(x + margin, y + margin, wi - 2 * margin - arrowWidth, he - 2 * margin);
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ break;
+#endif // QT_CONFIG(combobox)
+
+ case CC_TitleBar:
+ if (const QStyleOptionTitleBar *tb = qstyleoption_cast<const QStyleOptionTitleBar *>(option)) {
+ if (!buttonVisible(subControl, tb))
+ return rect;
+ const qreal factor = QWindowsStylePrivate::nativeMetricScaleFactor(widget);
+ const bool isToolTitle = false;
+ const int height = tb->rect.height();
+ const int width = tb->rect.width();
+
+ const int buttonMargin = int(QStyleHelper::dpiScaled(4, option));
+ int buttonHeight = qRound(qreal(GetSystemMetrics(SM_CYSIZE)) * factor)
+ - buttonMargin;
+ const int buttonWidth =
+ qRound(qreal(GetSystemMetrics(SM_CXSIZE)) * factor - QStyleHelper::dpiScaled(4, option));
+
+ const int frameWidth = proxy()->pixelMetric(PM_MdiSubWindowFrameWidth, option, widget);
+ const bool sysmenuHint = (tb->titleBarFlags & Qt::WindowSystemMenuHint) != 0;
+ const bool minimizeHint = (tb->titleBarFlags & Qt::WindowMinimizeButtonHint) != 0;
+ const bool maximizeHint = (tb->titleBarFlags & Qt::WindowMaximizeButtonHint) != 0;
+ const bool contextHint = (tb->titleBarFlags & Qt::WindowContextHelpButtonHint) != 0;
+ const bool shadeHint = (tb->titleBarFlags & Qt::WindowShadeButtonHint) != 0;
+
+ bool isMinimized = tb->titleBarState & Qt::WindowMinimized;
+ bool isMaximized = tb->titleBarState & Qt::WindowMaximized;
+ int offset = 0;
+ const int delta = buttonWidth + 2;
+ int controlTop = option->rect.bottom() - buttonHeight - 2;
+
+ switch (subControl) {
+ case SC_TitleBarLabel: {
+ rect = QRect(frameWidth, 0, width - (buttonWidth + frameWidth + 10), height);
+ if (isToolTitle) {
+ if (sysmenuHint) {
+ rect.adjust(0, 0, int(-buttonWidth - 3 * factor), 0);
+ }
+ if (minimizeHint || maximizeHint)
+ rect.adjust(0, 0, int(-buttonWidth - 2 * factor), 0);
+ } else {
+ if (sysmenuHint) {
+ const int leftOffset = int(height - 8 * factor);
+ rect.adjust(leftOffset, 0, 0, int(4 * factor));
+ }
+ if (minimizeHint)
+ rect.adjust(0, 0, int(-buttonWidth - 2 * factor), 0);
+ if (maximizeHint)
+ rect.adjust(0, 0, int(-buttonWidth - 2 * factor), 0);
+ if (contextHint)
+ rect.adjust(0, 0, int(-buttonWidth - 2 * factor), 0);
+ if (shadeHint)
+ rect.adjust(0, 0, int(-buttonWidth - 2 * factor), 0);
+ }
+ rect.translate(0, int(2 * factor));
+ }
+ break;
+
+ case SC_TitleBarContextHelpButton:
+ if (tb->titleBarFlags & Qt::WindowContextHelpButtonHint)
+ offset += delta;
+ Q_FALLTHROUGH();
+ case SC_TitleBarMinButton:
+ if (!isMinimized && (tb->titleBarFlags & Qt::WindowMinimizeButtonHint))
+ offset += delta;
+ else if (subControl == SC_TitleBarMinButton)
+ break;
+ Q_FALLTHROUGH();
+ case SC_TitleBarNormalButton:
+ if (isMinimized && (tb->titleBarFlags & Qt::WindowMinimizeButtonHint))
+ offset += delta;
+ else if (isMaximized && (tb->titleBarFlags & Qt::WindowMaximizeButtonHint))
+ offset += delta;
+ else if (subControl == SC_TitleBarNormalButton)
+ break;
+ Q_FALLTHROUGH();
+ case SC_TitleBarMaxButton:
+ if (!isMaximized && (tb->titleBarFlags & Qt::WindowMaximizeButtonHint))
+ offset += delta;
+ else if (subControl == SC_TitleBarMaxButton)
+ break;
+ Q_FALLTHROUGH();
+ case SC_TitleBarShadeButton:
+ if (!isMinimized && (tb->titleBarFlags & Qt::WindowShadeButtonHint))
+ offset += delta;
+ else if (subControl == SC_TitleBarShadeButton)
+ break;
+ Q_FALLTHROUGH();
+ case SC_TitleBarUnshadeButton:
+ if (isMinimized && (tb->titleBarFlags & Qt::WindowShadeButtonHint))
+ offset += delta;
+ else if (subControl == SC_TitleBarUnshadeButton)
+ break;
+ Q_FALLTHROUGH();
+ case SC_TitleBarCloseButton:
+ if (tb->titleBarFlags & Qt::WindowSystemMenuHint)
+ offset += delta;
+ else if (subControl == SC_TitleBarCloseButton)
+ break;
+
+ rect.setRect(width - offset - controlTop + 1, controlTop,
+ buttonWidth, buttonHeight);
+ break;
+
+ case SC_TitleBarSysMenu: {
+ const int controlTop = int(6 * factor);
+ const int controlHeight = int(height - controlTop - 3 * factor);
+ int iconExtent = proxy()->pixelMetric(PM_SmallIconSize, option);
+ QSize iconSize = tb->icon.actualSize(QSize(iconExtent, iconExtent));
+ if (tb->icon.isNull())
+ iconSize = QSize(controlHeight, controlHeight);
+ int hPad = (controlHeight - iconSize.height())/2;
+ int vPad = (controlHeight - iconSize.width())/2;
+ rect = QRect(frameWidth + hPad, controlTop + vPad, iconSize.width(), iconSize.height());
+ rect.translate(0, int(3 * factor));
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ break;
+
+#if QT_CONFIG(mdiarea)
+ case CC_MdiControls: {
+ int numSubControls = 0;
+ if (option->subControls & SC_MdiCloseButton)
+ ++numSubControls;
+ if (option->subControls & SC_MdiMinButton)
+ ++numSubControls;
+ if (option->subControls & SC_MdiNormalButton)
+ ++numSubControls;
+ if (numSubControls == 0)
+ break;
+
+ int buttonWidth = option->rect.width() / numSubControls;
+ int offset = 0;
+
+ switch (subControl) {
+ case SC_MdiCloseButton:
+ // Only one sub control, no offset needed.
+ if (numSubControls == 1)
+ break;
+ offset += buttonWidth;
+ Q_FALLTHROUGH();
+ case SC_MdiNormalButton:
+ // No offset needed if
+ // 1) There's only one sub control
+ // 2) We have a close button and a normal button (offset already added in SC_MdiClose)
+ if (numSubControls == 1 || (numSubControls == 2 && !(option->subControls & SC_MdiMinButton)))
+ break;
+ if (option->subControls & SC_MdiNormalButton)
+ offset += buttonWidth;
+ break;
+ default:
+ break;
+ }
+
+ rect = QRect(offset, 0, buttonWidth, option->rect.height());
+ break;
+ }
+#endif // QT_CONFIG(mdiarea)
+
+ default:
+ return QWindowsStyle::subControlRect(control, option, subControl, widget);
+ }
+
+ return visualRect(option->direction, option->rect, rect);
+}
+
+/*!
+ \internal
+ */
+QStyle::SubControl QWindowsVistaStyle::hitTestComplexControl(ComplexControl control, const QStyleOptionComplex *option,
+ const QPoint &pos, const QWidget *widget) const
+{
+ return QWindowsStyle::hitTestComplexControl(control, option, pos, widget);
+}
+
+/*!
+ \internal
+ */
+int QWindowsVistaStyle::pixelMetric(PixelMetric metric, const QStyleOption *option, const QWidget *widget) const
+{
+ if (!QWindowsVistaStylePrivate::useVista())
+ return QWindowsStyle::pixelMetric(metric, option, widget);
+
+ int ret = QWindowsVistaStylePrivate::fixedPixelMetric(metric);
+ if (ret != QWindowsStylePrivate::InvalidMetric)
+ return int(QStyleHelper::dpiScaled(ret, option));
+
+ int res = QWindowsVistaStylePrivate::pixelMetricFromSystemDp(metric, option, widget);
+ if (res != QWindowsStylePrivate::InvalidMetric)
+ return qRound(qreal(res) * QWindowsStylePrivate::nativeMetricScaleFactor(widget));
+
+ res = 0;
+
+ switch (metric) {
+ case PM_MenuBarPanelWidth:
+ case PM_ButtonDefaultIndicator:
+ res = 0;
+ break;
+
+ case PM_DefaultFrameWidth:
+ res = qobject_cast<const QListView*>(widget) ? 2 : 1;
+ break;
+ case PM_MenuPanelWidth:
+ case PM_SpinBoxFrameWidth:
+ res = 1;
+ break;
+
+ case PM_TabBarTabOverlap:
+ case PM_MenuHMargin:
+ case PM_MenuVMargin:
+ res = 2;
+ break;
+
+ case PM_TabBarBaseOverlap:
+ if (const auto *tab = qstyleoption_cast<const QStyleOptionTab *>(option)) {
+ switch (tab->shape) {
+ case QTabBar::RoundedNorth:
+ case QTabBar::TriangularNorth:
+ case QTabBar::RoundedWest:
+ case QTabBar::TriangularWest:
+ res = 1;
+ break;
+ case QTabBar::RoundedSouth:
+ case QTabBar::TriangularSouth:
+ res = 2;
+ break;
+ case QTabBar::RoundedEast:
+ case QTabBar::TriangularEast:
+ res = 3;
+ break;
+ }
+ }
+ break;
+
+ case PM_SplitterWidth:
+ res = QStyleHelper::dpiScaled(5., option);
+ break;
+
+ case PM_MdiSubWindowMinimizedWidth:
+ res = 160;
+ break;
+
+#if QT_CONFIG(toolbar)
+ case PM_ToolBarHandleExtent:
+ res = int(QStyleHelper::dpiScaled(8., option));
+ break;
+
+#endif // QT_CONFIG(toolbar)
+ case PM_DockWidgetSeparatorExtent:
+ case PM_DockWidgetTitleMargin:
+ res = int(QStyleHelper::dpiScaled(4., option));
+ break;
+
+ case PM_ButtonShiftHorizontal:
+ case PM_ButtonShiftVertical:
+ res = qstyleoption_cast<const QStyleOptionToolButton *>(option) ? 1 : 0;
+ break;
+
+ default:
+ res = QWindowsStyle::pixelMetric(metric, option, widget);
+ }
+
+ return res;
+}
+
+/*!
+ \internal
+ */
+void QWindowsVistaStyle::polish(QWidget *widget)
+{
+ QWindowsStyle::polish(widget);
+ if (!QWindowsVistaStylePrivate::useVista())
+ return;
+
+ if (false
+#if QT_CONFIG(abstractbutton)
+ || qobject_cast<QAbstractButton*>(widget)
+#endif // QT_CONFIG(abstractbutton)
+ || qobject_cast<QToolButton*>(widget)
+ || qobject_cast<QTabBar*>(widget)
+#if QT_CONFIG(combobox)
+ || qobject_cast<QComboBox*>(widget)
+#endif // QT_CONFIG(combobox)
+ || qobject_cast<QScrollBar*>(widget)
+ || qobject_cast<QSlider*>(widget)
+ || qobject_cast<QHeaderView*>(widget)
+#if QT_CONFIG(spinbox)
+ || qobject_cast<QAbstractSpinBox*>(widget)
+ || qobject_cast<QSpinBox*>(widget)
+#endif // QT_CONFIG(spinbox)
+ ) {
+ widget->setAttribute(Qt::WA_Hover);
+ }
+
+#if QT_CONFIG(rubberband)
+ if (qobject_cast<QRubberBand*>(widget))
+ widget->setWindowOpacity(0.6);
+#endif
+
+#if QT_CONFIG(lineedit)
+ if (qobject_cast<QLineEdit*>(widget))
+ widget->setAttribute(Qt::WA_Hover);
+ else
+#endif // QT_CONFIG(lineedit)
+ if (qobject_cast<QGroupBox*>(widget))
+ widget->setAttribute(Qt::WA_Hover);
+#if QT_CONFIG(commandlinkbutton)
+ else if (qobject_cast<QCommandLinkButton*>(widget)) {
+ widget->setProperty("_qt_usingVistaStyle", true);
+ QFont buttonFont = widget->font();
+ buttonFont.setFamilies(QStringList{QLatin1String("Segoe UI")});
+ widget->setFont(buttonFont);
+ QPalette pal = widget->palette();
+ pal.setColor(QPalette::Active, QPalette::ButtonText, QColor(21, 28, 85));
+ pal.setColor(QPalette::Active, QPalette::BrightText, QColor(7, 64, 229));
+ widget->setPalette(pal);
+ }
+#endif // QT_CONFIG(commandlinkbutton)
+ else if (widget->inherits("QTipLabel")) {
+ //note that since tooltips are not reused
+ //we do not have to care about unpolishing
+ widget->setContentsMargins(3, 0, 4, 0);
+ COLORREF bgRef;
+ HTHEME theme = OpenThemeData(widget ? QWindowsVistaStylePrivate::winId(widget) : nullptr, L"TOOLTIP");
+ if (theme && SUCCEEDED(GetThemeColor(theme, TTP_STANDARD, TTSS_NORMAL, TMT_TEXTCOLOR, &bgRef))) {
+ QColor textColor = QColor::fromRgb(bgRef);
+ QPalette pal;
+ pal.setColor(QPalette::All, QPalette::ToolTipText, textColor);
+ pal.setResolveMask(0);
+ widget->setPalette(pal);
+ }
+ } else if (qobject_cast<QMessageBox *> (widget)) {
+ widget->setAttribute(Qt::WA_StyledBackground);
+#if QT_CONFIG(dialogbuttonbox)
+ QDialogButtonBox *buttonBox = widget->findChild<QDialogButtonBox *>(QLatin1String("qt_msgbox_buttonbox"));
+ if (buttonBox)
+ buttonBox->setContentsMargins(0, 9, 0, 0);
+#endif
+ }
+#if QT_CONFIG(inputdialog)
+ else if (qobject_cast<QInputDialog *> (widget)) {
+ widget->setAttribute(Qt::WA_StyledBackground);
+#if QT_CONFIG(dialogbuttonbox)
+ QDialogButtonBox *buttonBox = widget->findChild<QDialogButtonBox *>(QLatin1String("qt_inputdlg_buttonbox"));
+ if (buttonBox)
+ buttonBox->setContentsMargins(0, 9, 0, 0);
+#endif
+ }
+#endif // QT_CONFIG(inputdialog)
+ else if (QTreeView *tree = qobject_cast<QTreeView *> (widget)) {
+ tree->viewport()->setAttribute(Qt::WA_Hover);
+ }
+ else if (QListView *list = qobject_cast<QListView *> (widget)) {
+ list->viewport()->setAttribute(Qt::WA_Hover);
+ }
+}
+
+/*!
+ \internal
+ */
+void QWindowsVistaStyle::unpolish(QWidget *widget)
+{
+ Q_D(QWindowsVistaStyle);
+
+#if QT_CONFIG(rubberband)
+ if (qobject_cast<QRubberBand*>(widget))
+ widget->setWindowOpacity(1.0);
+#endif
+
+ // Unpolish of widgets is the first thing that
+ // happens when a theme changes, or the theme
+ // engine is turned off. So we detect it here.
+ bool oldState = QWindowsVistaStylePrivate::useVista();
+ bool newState = QWindowsVistaStylePrivate::useVista(true);
+ if ((oldState != newState) && newState) {
+ d->cleanup(true);
+ d->init(true);
+ } else {
+ // Cleanup handle map, if just changing style,
+ // or turning it on. In both cases the values
+ // already in the map might be old (other style).
+ d->cleanupHandleMap();
+ }
+ if (false
+ #if QT_CONFIG(abstractbutton)
+ || qobject_cast<QAbstractButton*>(widget)
+ #endif
+ || qobject_cast<QToolButton*>(widget)
+ || qobject_cast<QTabBar*>(widget)
+ #if QT_CONFIG(combobox)
+ || qobject_cast<QComboBox*>(widget)
+ #endif // QT_CONFIG(combobox)
+ || qobject_cast<QScrollBar*>(widget)
+ || qobject_cast<QSlider*>(widget)
+ || qobject_cast<QHeaderView*>(widget)
+ #if QT_CONFIG(spinbox)
+ || qobject_cast<QAbstractSpinBox*>(widget)
+ || qobject_cast<QSpinBox*>(widget)
+ #endif // QT_CONFIG(spinbox)
+ ) {
+ widget->setAttribute(Qt::WA_Hover, false);
+ }
+
+ QWindowsStyle::unpolish(widget);
+
+ d->stopAnimation(widget);
+
+#if QT_CONFIG(lineedit)
+ if (qobject_cast<QLineEdit*>(widget))
+ widget->setAttribute(Qt::WA_Hover, false);
+ else {
+#endif // QT_CONFIG(lineedit)
+ if (qobject_cast<QGroupBox*>(widget))
+ widget->setAttribute(Qt::WA_Hover, false);
+ else if (qobject_cast<QMessageBox *> (widget)) {
+ widget->setAttribute(Qt::WA_StyledBackground, false);
+#if QT_CONFIG(dialogbuttonbox)
+ QDialogButtonBox *buttonBox = widget->findChild<QDialogButtonBox *>(QLatin1String("qt_msgbox_buttonbox"));
+ if (buttonBox)
+ buttonBox->setContentsMargins(0, 0, 0, 0);
+#endif
+ }
+#if QT_CONFIG(inputdialog)
+ else if (qobject_cast<QInputDialog *> (widget)) {
+ widget->setAttribute(Qt::WA_StyledBackground, false);
+#if QT_CONFIG(dialogbuttonbox)
+ QDialogButtonBox *buttonBox = widget->findChild<QDialogButtonBox *>(QLatin1String("qt_inputdlg_buttonbox"));
+ if (buttonBox)
+ buttonBox->setContentsMargins(0, 0, 0, 0);
+#endif
+ }
+#endif // QT_CONFIG(inputdialog)
+ else if (QTreeView *tree = qobject_cast<QTreeView *> (widget)) {
+ tree->viewport()->setAttribute(Qt::WA_Hover, false);
+ }
+#if QT_CONFIG(commandlinkbutton)
+ else if (qobject_cast<QCommandLinkButton*>(widget)) {
+ QFont font = QApplication::font("QCommandLinkButton");
+ QFont widgetFont = widget->font();
+ widgetFont.setFamilies(font.families()); //Only family set by polish
+ widget->setFont(widgetFont);
+ }
+#endif // QT_CONFIG(commandlinkbutton)
+ }
+}
+
+/*!
+ \internal
+ */
+void QWindowsVistaStyle::polish(QPalette &pal)
+{
+ Q_D(QWindowsVistaStyle);
+
+ if (QGuiApplicationPrivate::colorScheme() == Qt::ColorScheme::Dark) {
+ // System runs in dark mode, but the Vista style cannot use a dark palette.
+ // Overwrite with the light system palette.
+ using QWindowsApplication = QNativeInterface::Private::QWindowsApplication;
+ if (auto nativeWindowsApp = dynamic_cast<QWindowsApplication *>(QGuiApplicationPrivate::platformIntegration()))
+ nativeWindowsApp->populateLightSystemPalette(pal);
+ }
+
+ QPixmapCache::clear();
+ d->alphaCache.clear();
+ d->hasInitColors = false;
+
+ if (!d->hasInitColors) {
+ // Get text color for group box labels
+ QWindowsThemeData theme(nullptr, nullptr, QWindowsVistaStylePrivate::ButtonTheme, 0, 0);
+ COLORREF cref;
+ GetThemeColor(theme.handle(), BP_GROUPBOX, GBS_NORMAL, TMT_TEXTCOLOR, &cref);
+ d->groupBoxTextColor = qRgb(GetRValue(cref), GetGValue(cref), GetBValue(cref));
+ GetThemeColor(theme.handle(), BP_GROUPBOX, GBS_DISABLED, TMT_TEXTCOLOR, &cref);
+ d->groupBoxTextColorDisabled = qRgb(GetRValue(cref), GetGValue(cref), GetBValue(cref));
+ // Where does this color come from?
+ //GetThemeColor(theme.handle(), TKP_TICS, TSS_NORMAL, TMT_COLOR, &cref);
+ d->sliderTickColor = qRgb(165, 162, 148);
+ d->hasInitColors = true;
+ }
+
+ QWindowsStyle::polish(pal);
+ pal.setBrush(QPalette::AlternateBase, pal.base().color().darker(104));
+}
+
+/*!
+ \internal
+ */
+void QWindowsVistaStyle::polish(QApplication *app)
+{
+ // Override windows theme palettes to light
+ if (qApp->styleHints()->colorScheme() == Qt::ColorScheme::Dark) {
+ static const char* themedWidgets[] = {
+ "QToolButton",
+ "QAbstractButton",
+ "QCheckBox",
+ "QRadioButton",
+ "QHeaderView",
+ "QAbstractItemView",
+ "QMessageBoxLabel",
+ "QTabBar",
+ "QLabel",
+ "QGroupBox",
+ "QMenu",
+ "QMenuBar",
+ "QTextEdit",
+ "QTextControl",
+ "QLineEdit"
+ };
+ for (const auto& themedWidget : std::as_const(themedWidgets)) {
+ auto defaultResolveMask = QApplication::palette().resolveMask();
+ auto widgetResolveMask = QApplication::palette(themedWidget).resolveMask();
+ if (widgetResolveMask != defaultResolveMask)
+ QApplication::setPalette(QApplication::palette(), themedWidget);
+ }
+ }
+
+ QWindowsStyle::polish(app);
+}
+
+/*!
+ \internal
+ */
+QPixmap QWindowsVistaStyle::standardPixmap(StandardPixmap standardPixmap, const QStyleOption *option,
+ const QWidget *widget) const
+{
+ if (!QWindowsVistaStylePrivate::useVista()) {
+ return QWindowsStyle::standardPixmap(standardPixmap, option, widget);
+ }
+
+ switch (standardPixmap) {
+ case SP_TitleBarMaxButton:
+ case SP_TitleBarCloseButton:
+ if (qstyleoption_cast<const QStyleOptionDockWidget *>(option)) {
+ if (widget && widget->isWindow()) {
+ QWindowsThemeData theme(widget, nullptr, QWindowsVistaStylePrivate::WindowTheme, WP_SMALLCLOSEBUTTON, CBS_NORMAL);
+ if (theme.isValid()) {
+ const QSize size = (theme.size() * QWindowsStylePrivate::nativeMetricScaleFactor(widget)).toSize();
+ return QIcon(QWindowsStyle::standardPixmap(standardPixmap, option, widget)).pixmap(size);
+ }
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return QWindowsStyle::standardPixmap(standardPixmap, option, widget);
+}
+
+/*!
+\reimp
+*/
+QIcon QWindowsVistaStyle::standardIcon(StandardPixmap standardIcon,
+ const QStyleOption *option,
+ const QWidget *widget) const
+{
+ if (!QWindowsVistaStylePrivate::useVista()) {
+ return QWindowsStyle::standardIcon(standardIcon, option, widget);
+ }
+
+ auto *d = const_cast<QWindowsVistaStylePrivate*>(d_func());
+
+ switch (standardIcon) {
+ case SP_TitleBarMaxButton:
+ if (qstyleoption_cast<const QStyleOptionDockWidget *>(option)) {
+ if (d->dockFloat.isNull()) {
+ QWindowsThemeData themeSize(nullptr, nullptr, QWindowsVistaStylePrivate::WindowTheme,
+ WP_SMALLCLOSEBUTTON, CBS_NORMAL);
+ QWindowsThemeData theme(nullptr, nullptr, QWindowsVistaStylePrivate::WindowTheme,
+ WP_MAXBUTTON, MAXBS_NORMAL);
+ if (theme.isValid()) {
+ const QSize size = (themeSize.size() * QWindowsStylePrivate::nativeMetricScaleFactor(widget)).toSize();
+ QPixmap pm(size);
+ pm.fill(Qt::transparent);
+ QPainter p(&pm);
+ theme.painter = &p;
+ theme.rect = QRect(QPoint(0, 0), size);
+ d->drawBackground(theme);
+ d->dockFloat.addPixmap(pm, QIcon::Normal, QIcon::Off); // Normal
+ pm.fill(Qt::transparent);
+ theme.stateId = MAXBS_PUSHED;
+ d->drawBackground(theme);
+ d->dockFloat.addPixmap(pm, QIcon::Normal, QIcon::On); // Pressed
+ pm.fill(Qt::transparent);
+ theme.stateId = MAXBS_HOT;
+ d->drawBackground(theme);
+ d->dockFloat.addPixmap(pm, QIcon::Active, QIcon::Off); // Hover
+ pm.fill(Qt::transparent);
+ theme.stateId = MAXBS_INACTIVE;
+ d->drawBackground(theme);
+ d->dockFloat.addPixmap(pm, QIcon::Disabled, QIcon::Off); // Disabled
+ }
+ }
+ if (widget && widget->isWindow())
+ return d->dockFloat;
+ }
+ break;
+
+ case SP_TitleBarCloseButton:
+ if (qstyleoption_cast<const QStyleOptionDockWidget *>(option)) {
+ if (d->dockClose.isNull()) {
+ QWindowsThemeData theme(nullptr, nullptr, QWindowsVistaStylePrivate::WindowTheme,
+ WP_SMALLCLOSEBUTTON, CBS_NORMAL);
+ if (theme.isValid()) {
+ const QSize size = (theme.size() * QWindowsStylePrivate::nativeMetricScaleFactor(widget)).toSize();
+ QPixmap pm(size);
+ pm.fill(Qt::transparent);
+ QPainter p(&pm);
+ theme.painter = &p;
+ theme.partId = WP_CLOSEBUTTON; // ####
+ theme.rect = QRect(QPoint(0, 0), size);
+ d->drawBackground(theme);
+ d->dockClose.addPixmap(pm, QIcon::Normal, QIcon::Off); // Normal
+ pm.fill(Qt::transparent);
+ theme.stateId = CBS_PUSHED;
+ d->drawBackground(theme);
+ d->dockClose.addPixmap(pm, QIcon::Normal, QIcon::On); // Pressed
+ pm.fill(Qt::transparent);
+ theme.stateId = CBS_HOT;
+ d->drawBackground(theme);
+ d->dockClose.addPixmap(pm, QIcon::Active, QIcon::Off); // Hover
+ pm.fill(Qt::transparent);
+ theme.stateId = CBS_INACTIVE;
+ d->drawBackground(theme);
+ d->dockClose.addPixmap(pm, QIcon::Disabled, QIcon::Off); // Disabled
+ }
+ }
+ if (widget && widget->isWindow())
+ return d->dockClose;
+ }
+ break;
+
+ case SP_TitleBarNormalButton:
+ if (qstyleoption_cast<const QStyleOptionDockWidget *>(option)) {
+ if (d->dockFloat.isNull()) {
+ QWindowsThemeData themeSize(nullptr, nullptr, QWindowsVistaStylePrivate::WindowTheme,
+ WP_SMALLCLOSEBUTTON, CBS_NORMAL);
+ QWindowsThemeData theme(nullptr, nullptr, QWindowsVistaStylePrivate::WindowTheme,
+ WP_RESTOREBUTTON, RBS_NORMAL);
+ if (theme.isValid()) {
+ const QSize size = (themeSize.size() * QWindowsStylePrivate::nativeMetricScaleFactor(widget)).toSize();
+ QPixmap pm(size);
+ pm.fill(Qt::transparent);
+ QPainter p(&pm);
+ theme.painter = &p;
+ theme.rect = QRect(QPoint(0, 0), size);
+ d->drawBackground(theme);
+ d->dockFloat.addPixmap(pm, QIcon::Normal, QIcon::Off); // Normal
+ pm.fill(Qt::transparent);
+ theme.stateId = RBS_PUSHED;
+ d->drawBackground(theme);
+ d->dockFloat.addPixmap(pm, QIcon::Normal, QIcon::On); // Pressed
+ pm.fill(Qt::transparent);
+ theme.stateId = RBS_HOT;
+ d->drawBackground(theme);
+ d->dockFloat.addPixmap(pm, QIcon::Active, QIcon::Off); // Hover
+ pm.fill(Qt::transparent);
+ theme.stateId = RBS_INACTIVE;
+ d->drawBackground(theme);
+ d->dockFloat.addPixmap(pm, QIcon::Disabled, QIcon::Off); // Disabled
+ }
+ }
+ if (widget && widget->isWindow())
+ return d->dockFloat;
+ }
+ break;
+
+ case SP_CommandLink: {
+ QWindowsThemeData theme(nullptr, nullptr, QWindowsVistaStylePrivate::ButtonTheme,
+ BP_COMMANDLINKGLYPH, CMDLGS_NORMAL);
+ if (theme.isValid()) {
+ const QSize size = theme.size().toSize();
+ QIcon linkGlyph;
+ QPixmap pm(size);
+ pm.fill(Qt::transparent);
+ QPainter p(&pm);
+ theme.painter = &p;
+ theme.rect = QRect(QPoint(0, 0), size);
+ d->drawBackground(theme);
+ linkGlyph.addPixmap(pm, QIcon::Normal, QIcon::Off); // Normal
+ pm.fill(Qt::transparent);
+
+ theme.stateId = CMDLGS_PRESSED;
+ d->drawBackground(theme);
+ linkGlyph.addPixmap(pm, QIcon::Normal, QIcon::On); // Pressed
+ pm.fill(Qt::transparent);
+
+ theme.stateId = CMDLGS_HOT;
+ d->drawBackground(theme);
+ linkGlyph.addPixmap(pm, QIcon::Active, QIcon::Off); // Hover
+ pm.fill(Qt::transparent);
+
+ theme.stateId = CMDLGS_DISABLED;
+ d->drawBackground(theme);
+ linkGlyph.addPixmap(pm, QIcon::Disabled, QIcon::Off); // Disabled
+ return linkGlyph;
+ }
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ return QWindowsStyle::standardIcon(standardIcon, option, widget);
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/styles/windowsvista/qwindowsvistastyle_p.h b/src/plugins/styles/modernwindows/qwindowsvistastyle_p.h
index 43a2a670f8..ff5300beca 100644
--- a/src/plugins/styles/windowsvista/qwindowsvistastyle_p.h
+++ b/src/plugins/styles/modernwindows/qwindowsvistastyle_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtWidgets module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QWINDOWSVISTASTYLE_P_H
#define QWINDOWSVISTASTYLE_P_H
@@ -52,12 +16,12 @@
//
#include <QtWidgets/private/qtwidgetsglobal_p.h>
-#include "qwindowsxpstyle_p.h"
+#include <QtWidgets/private/qwindowsstyle_p.h>
QT_BEGIN_NAMESPACE
class QWindowsVistaStylePrivate;
-class QWindowsVistaStyle : public QWindowsXPStyle
+class QWindowsVistaStyle : public QWindowsStyle
{
Q_OBJECT
public:
@@ -95,9 +59,8 @@ public:
void unpolish(QWidget *widget) override;
void polish(QPalette &pal) override;
void polish(QApplication *app) override;
- void unpolish(QApplication *app) override;
- QPalette standardPalette() const override;
-
+protected:
+ QWindowsVistaStyle(QWindowsVistaStylePrivate &dd);
private:
Q_DISABLE_COPY_MOVE(QWindowsVistaStyle)
Q_DECLARE_PRIVATE(QWindowsVistaStyle)
diff --git a/src/plugins/styles/modernwindows/qwindowsvistastyle_p_p.h b/src/plugins/styles/modernwindows/qwindowsvistastyle_p_p.h
new file mode 100644
index 0000000000..053e98b68d
--- /dev/null
+++ b/src/plugins/styles/modernwindows/qwindowsvistastyle_p_p.h
@@ -0,0 +1,176 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QWINDOWSVISTASTYLE_P_P_H
+#define QWINDOWSVISTASTYLE_P_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of qapplication_*.cpp, qwidget*.cpp and qfiledialog.cpp. This header
+// file may change from version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtWidgets/private/qtwidgetsglobal_p.h>
+#include "qwindowsvistastyle_p.h"
+#include "qwindowsthemedata_p.h"
+#include <private/qpaintengine_raster_p.h>
+#include <qpaintengine.h>
+#include <qwidget.h>
+#include <qapplication.h>
+#include <qpixmapcache.h>
+#include <qstyleoption.h>
+#include <QtWidgets/private/qwindowsstyle_p_p.h>
+#include <qmap.h>
+
+#if QT_CONFIG(pushbutton)
+#include <qpushbutton.h>
+#endif
+#include <qradiobutton.h>
+#if QT_CONFIG(lineedit)
+#include <qlineedit.h>
+#endif
+#include <qgroupbox.h>
+#if QT_CONFIG(toolbutton)
+#include <qtoolbutton.h>
+#endif
+#if QT_CONFIG(spinbox)
+#include <qspinbox.h>
+#endif
+#if QT_CONFIG(toolbar)
+#include <qtoolbar.h>
+#endif
+#if QT_CONFIG(combobox)
+#include <qcombobox.h>
+#endif
+#if QT_CONFIG(scrollbar)
+#include <qscrollbar.h>
+#endif
+#if QT_CONFIG(progressbar)
+#include <qprogressbar.h>
+#endif
+#if QT_CONFIG(dockwidget)
+#include <qdockwidget.h>
+#endif
+#if QT_CONFIG(listview)
+#include <qlistview.h>
+#endif
+#if QT_CONFIG(treeview)
+#include <qtreeview.h>
+#endif
+#include <qtextedit.h>
+#include <qmessagebox.h>
+#if QT_CONFIG(dialogbuttonbox)
+#include <qdialogbuttonbox.h>
+#endif
+#include <qinputdialog.h>
+#if QT_CONFIG(tableview)
+#include <qtableview.h>
+#endif
+#include <qdatetime.h>
+#if QT_CONFIG(commandlinkbutton)
+#include <qcommandlinkbutton.h>
+#endif
+#include <qlabel.h>
+#include <qheaderview.h>
+#include <uxtheme.h>
+
+QT_BEGIN_NAMESPACE
+
+class QWindowsVistaStylePrivate : public QWindowsStylePrivate
+{
+ Q_DECLARE_PUBLIC(QWindowsVistaStyle)
+
+public:
+ enum Theme {
+ ButtonTheme,
+ ComboboxTheme,
+ EditTheme,
+ HeaderTheme,
+ ListViewTheme,
+ MenuTheme,
+ ProgressTheme,
+ RebarTheme,
+ ScrollBarTheme,
+ SpinTheme,
+ TabTheme,
+ TaskDialogTheme,
+ ToolBarTheme,
+ ToolTipTheme,
+ TrackBarTheme,
+ WindowTheme,
+ StatusTheme,
+ VistaTreeViewTheme, // arrow shape treeview indicators (Vista) obtained from "explorer" theme.
+ NThemes
+ };
+
+ QWindowsVistaStylePrivate()
+ { init(); }
+
+ ~QWindowsVistaStylePrivate()
+ { cleanup(); }
+
+ static HTHEME createTheme(int theme, HWND hwnd);
+ static QString themeName(int theme);
+ static bool isItemViewDelegateLineEdit(const QWidget *widget);
+ static int pixelMetricFromSystemDp(QStyle::PixelMetric pm, const QStyleOption *option = nullptr, const QWidget *widget = nullptr);
+ static int fixedPixelMetric(QStyle::PixelMetric pm);
+ static bool isLineEditBaseColorSet(const QStyleOption *option, const QWidget *widget);
+ static HWND winId(const QWidget *widget);
+ static bool useVista(bool update = false);
+ static QBackingStore *backingStoreForWidget(const QWidget *widget);
+ static HDC hdcForWidgetBackingStore(const QWidget *widget);
+
+ void init(bool force = false);
+ void cleanup(bool force = false);
+ void cleanupHandleMap();
+
+ HBITMAP buffer(int w = 0, int h = 0);
+ HDC bufferHDC()
+ { return bufferDC; }
+
+ bool isTransparent(QWindowsThemeData &QWindowsThemeData);
+ QRegion region(QWindowsThemeData &QWindowsThemeData);
+
+ bool drawBackground(QWindowsThemeData &QWindowsThemeData, qreal correctionFactor = 1);
+ bool drawBackgroundThruNativeBuffer(QWindowsThemeData &QWindowsThemeData, qreal aditionalDevicePixelRatio, qreal correctionFactor);
+ bool drawBackgroundDirectly(HDC dc, QWindowsThemeData &QWindowsThemeData, qreal aditionalDevicePixelRatio);
+
+ bool hasAlphaChannel(const QRect &rect);
+ bool fixAlphaChannel(const QRect &rect);
+ bool swapAlphaChannel(const QRect &rect, bool allPixels = false);
+
+ QRgb groupBoxTextColor = 0;
+ QRgb groupBoxTextColorDisabled = 0;
+ QRgb sliderTickColor = 0;
+ bool hasInitColors = false;
+ QIcon dockFloat, dockClose;
+
+ QTime animationTime() const;
+ bool transitionsEnabled() const;
+
+private:
+ static bool initVistaTreeViewTheming();
+ static void cleanupVistaTreeViewTheming();
+
+ static QBasicAtomicInt ref;
+ static bool useVistaTheme;
+
+ QHash<ThemeMapKey, ThemeMapData> alphaCache;
+ HDC bufferDC = nullptr;
+ HBITMAP bufferBitmap = nullptr;
+ HBITMAP nullBitmap = nullptr;
+ uchar *bufferPixels = nullptr;
+ int bufferW = 0;
+ int bufferH = 0;
+
+ static HWND m_vistaTreeViewHelper;
+};
+
+QT_END_NAMESPACE
+
+#endif // QWINDOWSVISTASTYLE_P_P_H
diff --git a/src/plugins/styles/styles.pro b/src/plugins/styles/styles.pro
deleted file mode 100644
index 542ad1329a..0000000000
--- a/src/plugins/styles/styles.pro
+++ /dev/null
@@ -1,8 +0,0 @@
-TEMPLATE = subdirs
-QT_FOR_CONFIG += widgets-private
-
-qtConfig(style-android): SUBDIRS += android
-
-qtConfig(style-mac): SUBDIRS += mac
-
-qtConfig(style-windowsvista): SUBDIRS += windowsvista
diff --git a/src/plugins/styles/windowsvista/main.cpp b/src/plugins/styles/windowsvista/main.cpp
deleted file mode 100644
index 5e7bcf5e6e..0000000000
--- a/src/plugins/styles/windowsvista/main.cpp
+++ /dev/null
@@ -1,64 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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 <QtWidgets/private/qtwidgetsglobal_p.h>
-#include <QtWidgets/qstyleplugin.h>
-#include "qwindowsvistastyle_p.h"
-
-QT_BEGIN_NAMESPACE
-
-class QWindowsVistaStylePlugin : public QStylePlugin
-{
- Q_OBJECT
- Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QStyleFactoryInterface" FILE "windowsvistastyle.json")
-public:
- QStyle *create(const QString &key) override;
-};
-
-QStyle *QWindowsVistaStylePlugin::create(const QString &key)
-{
- if (key.compare(QLatin1String("windowsvista"), Qt::CaseInsensitive) == 0)
- return new QWindowsVistaStyle();
-
- return nullptr;
-}
-
-QT_END_NAMESPACE
-
-#include "main.moc"
diff --git a/src/plugins/styles/windowsvista/qwindowsvistastyle.cpp b/src/plugins/styles/windowsvista/qwindowsvistastyle.cpp
deleted file mode 100644
index e8d74180cd..0000000000
--- a/src/plugins/styles/windowsvista/qwindowsvistastyle.cpp
+++ /dev/null
@@ -1,2509 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtWidgets module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and 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 "qwindowsvistastyle_p.h"
-#include "qwindowsvistastyle_p_p.h"
-#include <qoperatingsystemversion.h>
-#include <qscreen.h>
-#include <qwindow.h>
-#include <private/qstyleanimation_p.h>
-#include <private/qstylehelper_p.h>
-#include <qpa/qplatformnativeinterface.h>
-
-QT_BEGIN_NAMESPACE
-
-static const int windowsItemFrame = 2; // menu item frame width
-static const int windowsItemHMargin = 3; // menu item hor text margin
-static const int windowsItemVMargin = 4; // menu item ver text margin
-static const int windowsArrowHMargin = 6; // arrow horizontal margin
-static const int windowsRightBorder = 15; // right border on windows
-
-#ifndef TMT_CONTENTMARGINS
-# define TMT_CONTENTMARGINS 3602
-#endif
-#ifndef TMT_SIZINGMARGINS
-# define TMT_SIZINGMARGINS 3601
-#endif
-#ifndef LISS_NORMAL
-# define LISS_NORMAL 1
-# define LISS_HOT 2
-# define LISS_SELECTED 3
-# define LISS_DISABLED 4
-# define LISS_SELECTEDNOTFOCUS 5
-# define LISS_HOTSELECTED 6
-#endif
-#ifndef BP_COMMANDLINK
-# define BP_COMMANDLINK 6
-# define BP_COMMANDLINKGLYPH 7
-# define CMDLGS_NORMAL 1
-# define CMDLGS_HOT 2
-# define CMDLGS_PRESSED 3
-# define CMDLGS_DISABLED 4
-#endif
-
-/* \internal
- Checks if we should use Vista style , or if we should
- fall back to Windows style.
-*/
-bool QWindowsVistaStylePrivate::useVista()
-{
- return QWindowsVistaStylePrivate::useXP();
-}
-
-/* \internal
- Checks and returns the style object
-*/
-inline QObject *styleObject(const QStyleOption *option) {
- return option ? option->styleObject : nullptr;
-}
-
-/* \internal
- Checks if we can animate on a style option
-*/
-bool canAnimate(const QStyleOption *option) {
- return option
- && option->styleObject
- && !option->styleObject->property("_q_no_animation").toBool();
-}
-
-static inline QImage createAnimationBuffer(const QStyleOption *option, const QWidget *widget)
-{
- const int devicePixelRatio = widget ? widget->devicePixelRatio() : 1;
- QImage result(option->rect.size() * devicePixelRatio, QImage::Format_ARGB32_Premultiplied);
- result.setDevicePixelRatio(devicePixelRatio);
- result.fill(0);
- return result;
-}
-
-/* \internal
- Used by animations to clone a styleoption and shift its offset
-*/
-QStyleOption *clonedAnimationStyleOption(const QStyleOption*option) {
- QStyleOption *styleOption = nullptr;
- if (const QStyleOptionSlider *slider = qstyleoption_cast<const QStyleOptionSlider*>(option))
- styleOption = new QStyleOptionSlider(*slider);
- else if (const QStyleOptionSpinBox *spinbox = qstyleoption_cast<const QStyleOptionSpinBox*>(option))
- styleOption = new QStyleOptionSpinBox(*spinbox);
- else if (const QStyleOptionGroupBox *groupBox = qstyleoption_cast<const QStyleOptionGroupBox*>(option))
- styleOption = new QStyleOptionGroupBox(*groupBox);
- else if (const QStyleOptionComboBox *combo = qstyleoption_cast<const QStyleOptionComboBox*>(option))
- styleOption = new QStyleOptionComboBox(*combo);
- else if (const QStyleOptionButton *button = qstyleoption_cast<const QStyleOptionButton*>(option))
- styleOption = new QStyleOptionButton(*button);
- else
- styleOption = new QStyleOption(*option);
- styleOption->rect = QRect(QPoint(0,0), option->rect.size());
- return styleOption;
-}
-
-/* \internal
- Used by animations to delete cloned styleoption
-*/
-void deleteClonedAnimationStyleOption(const QStyleOption *option)
-{
- if (const QStyleOptionSlider *slider = qstyleoption_cast<const QStyleOptionSlider*>(option))
- delete slider;
- else if (const QStyleOptionSpinBox *spinbox = qstyleoption_cast<const QStyleOptionSpinBox*>(option))
- delete spinbox;
- else if (const QStyleOptionGroupBox *groupBox = qstyleoption_cast<const QStyleOptionGroupBox*>(option))
- delete groupBox;
- else if (const QStyleOptionComboBox *combo = qstyleoption_cast<const QStyleOptionComboBox*>(option))
- delete combo;
- else if (const QStyleOptionButton *button = qstyleoption_cast<const QStyleOptionButton*>(option))
- delete button;
- else
- delete option;
-}
-
-/*!
- \class QWindowsVistaStyle
- \brief The QWindowsVistaStyle class provides a look and feel suitable for applications on Microsoft Windows Vista.
- \since 4.3
- \ingroup appearance
- \inmodule QtWidgets
- \internal
-
- \warning This style is only available on the Windows Vista platform
- because it makes use of Windows Vista's style engine.
-
- \sa QMacStyle, QWindowsXPStyle, QFusionStyle
-*/
-
-/*!
- Constructs a QWindowsVistaStyle object.
-*/
-QWindowsVistaStyle::QWindowsVistaStyle()
- : QWindowsXPStyle(*new QWindowsVistaStylePrivate)
-{
-}
-
-/*!
- Destructor.
-*/
-QWindowsVistaStyle::~QWindowsVistaStyle() = default;
-
-//convert Qt state flags to uxtheme button states
-static int buttonStateId(int flags, int partId)
-{
- int stateId = 0;
- if (partId == BP_RADIOBUTTON || partId == BP_CHECKBOX) {
- if (!(flags & QStyle::State_Enabled))
- stateId = RBS_UNCHECKEDDISABLED;
- else if (flags & QStyle::State_Sunken)
- stateId = RBS_UNCHECKEDPRESSED;
- else if (flags & QStyle::State_MouseOver)
- stateId = RBS_UNCHECKEDHOT;
- else
- stateId = RBS_UNCHECKEDNORMAL;
-
- if (flags & QStyle::State_On)
- stateId += RBS_CHECKEDNORMAL-1;
-
- } else if (partId == BP_PUSHBUTTON) {
- if (!(flags & QStyle::State_Enabled))
- stateId = PBS_DISABLED;
- else if (flags & (QStyle::State_Sunken | QStyle::State_On))
- stateId = PBS_PRESSED;
- else if (flags & QStyle::State_MouseOver)
- stateId = PBS_HOT;
- else
- stateId = PBS_NORMAL;
- } else {
- Q_ASSERT(1);
- }
- return stateId;
-}
-
-bool QWindowsVistaAnimation::isUpdateNeeded() const
-{
- return QWindowsVistaStylePrivate::useVista();
-}
-
-void QWindowsVistaAnimation::paint(QPainter *painter, const QStyleOption *option)
-{
- painter->drawImage(option->rect, currentImage());
-}
-
-static inline bool supportsStateTransition(QStyle::PrimitiveElement element,
- const QStyleOption *option,
- const QWidget *widget)
-{
- bool result = false;
- switch (element) {
- case QStyle::PE_IndicatorRadioButton:
- case QStyle::PE_IndicatorCheckBox:
- result = true;
- break;
- // QTBUG-40634, do not animate when color is set in palette for PE_PanelLineEdit.
- case QStyle::PE_FrameLineEdit:
- result = !QWindowsXPStylePrivate::isLineEditBaseColorSet(option, widget);
- break;
- default:
- break;
- }
- return result;
-}
-
-/*!
- \internal
-
- Animations are used for some state transitions on specific widgets.
-
- Only one running animation can exist for a widget at any specific
- time. Animations can be added through
- QWindowsVistaStylePrivate::startAnimation(Animation *) and any
- existing animation on a widget can be retrieved with
- QWindowsVistaStylePrivate::widgetAnimation(Widget *).
-
- Once an animation has been started,
- QWindowsVistaStylePrivate::timerEvent(QTimerEvent *) will
- continuously call update() on the widget until it is stopped,
- meaning that drawPrimitive will be called many times until the
- transition has completed. During this time, the result will be
- retrieved by the Animation::paint(...) function and not by the style
- itself.
-
- To determine if a transition should occur, the style needs to know
- the previous state of the widget as well as the current one. This is
- solved by updating dynamic properties on the widget every time the
- function is called.
-
- Transitions interrupting existing transitions should always be
- smooth, so whenever a hover-transition is started on a pulsating
- button, it uses the current frame of the pulse-animation as the
- starting image for the hover transition.
-
- */
-
-void QWindowsVistaStyle::drawPrimitive(PrimitiveElement element, const QStyleOption *option,
- QPainter *painter, const QWidget *widget) const
-{
- QWindowsVistaStylePrivate *d = const_cast<QWindowsVistaStylePrivate*>(d_func());
-
- int state = option->state;
- if (!QWindowsVistaStylePrivate::useVista()) {
- QWindowsStyle::drawPrimitive(element, option, painter, widget);
- return;
- }
-
- if ((option->state & State_Enabled) && d->transitionsEnabled() && canAnimate(option)) {
- {
- QRect oldRect;
- QRect newRect;
-
- if (supportsStateTransition(element, option, widget)) {
- // Retrieve and update the dynamic properties tracking
- // the previous state of the widget:
- QObject *styleObject = option->styleObject;
- styleObject->setProperty("_q_no_animation", true);
-
- int oldState = styleObject->property("_q_stylestate").toInt();
- oldRect = styleObject->property("_q_stylerect").toRect();
- newRect = option->rect;
- styleObject->setProperty("_q_stylestate", int(option->state));
- styleObject->setProperty("_q_stylerect", option->rect);
-
- bool doTransition = oldState &&
- ((state & State_Sunken) != (oldState & State_Sunken) ||
- (state & State_On) != (oldState & State_On) ||
- (state & State_MouseOver) != (oldState & State_MouseOver));
-
- if (oldRect != newRect ||
- (state & State_Enabled) != (oldState & State_Enabled) ||
- (state & State_Active) != (oldState & State_Active))
- d->stopAnimation(styleObject);
-
- if (option->state & State_ReadOnly && element == PE_FrameLineEdit) // Do not animate read only line edits
- doTransition = false;
-
- if (doTransition) {
- QStyleOption *styleOption = clonedAnimationStyleOption(option);
- styleOption->state = QStyle::State(oldState);
-
- QWindowsVistaAnimation *anim = qobject_cast<QWindowsVistaAnimation *>(d->animation(styleObject));
- QWindowsVistaTransition *t = new QWindowsVistaTransition(styleObject);
-
- // We create separate images for the initial and final transition states and store them in the
- // Transition object.
- QImage startImage = createAnimationBuffer(option, widget);
- QPainter startPainter(&startImage);
-
- QImage endImage = createAnimationBuffer(option, widget);
- QPainter endPainter(&endImage);
-
- // If we have a running animation on the widget already, we will use that to paint the initial
- // state of the new transition, this ensures a smooth transition from a current animation such as a
- // pulsating default button into the intended target state.
- if (!anim)
- proxy()->drawPrimitive(element, styleOption, &startPainter, widget);
- else
- anim->paint(&startPainter, styleOption);
-
- t->setStartImage(startImage);
-
- // The end state of the transition is simply the result we would have painted
- // if the style was not animated.
- styleOption->styleObject = nullptr;
- styleOption->state = option->state;
- proxy()->drawPrimitive(element, styleOption, &endPainter, widget);
-
-
- t->setEndImage(endImage);
-
- HTHEME theme;
- int partId;
- DWORD duration;
- int fromState = 0;
- int toState = 0;
-
- //translate state flags to UXTHEME states :
- if (element == PE_FrameLineEdit) {
- theme = OpenThemeData(nullptr, L"Edit");
- partId = EP_EDITBORDER_NOSCROLL;
-
- if (oldState & State_MouseOver)
- fromState = ETS_HOT;
- else if (oldState & State_HasFocus)
- fromState = ETS_FOCUSED;
- else
- fromState = ETS_NORMAL;
-
- if (state & State_MouseOver)
- toState = ETS_HOT;
- else if (state & State_HasFocus)
- toState = ETS_FOCUSED;
- else
- toState = ETS_NORMAL;
-
- } else {
- theme = OpenThemeData(nullptr, L"Button");
- if (element == PE_IndicatorRadioButton)
- partId = BP_RADIOBUTTON;
- else if (element == PE_IndicatorCheckBox)
- partId = BP_CHECKBOX;
- else
- partId = BP_PUSHBUTTON;
-
- fromState = buttonStateId(oldState, partId);
- toState = buttonStateId(option->state, partId);
- }
-
- // Retrieve the transition time between the states from the system.
- if (theme
- && SUCCEEDED(GetThemeTransitionDuration(theme, partId, fromState, toState,
- TMT_TRANSITIONDURATIONS, &duration))) {
- t->setDuration(int(duration));
- }
- t->setStartTime(QTime::currentTime());
-
- deleteClonedAnimationStyleOption(styleOption);
- d->startAnimation(t);
- }
- styleObject->setProperty("_q_no_animation", false);
- }
-
- } // End of animation part
- }
-
- QRect rect = option->rect;
-
- switch (element) {
- case PE_IndicatorHeaderArrow:
- if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(option)) {
- int stateId = HSAS_SORTEDDOWN;
- if (header->sortIndicator & QStyleOptionHeader::SortDown)
- stateId = HSAS_SORTEDUP; //note that the uxtheme sort down indicator is the inverse of ours
- XPThemeData theme(widget, painter,
- QWindowsXPStylePrivate::HeaderTheme,
- HP_HEADERSORTARROW, stateId, option->rect);
- d->drawBackground(theme);
- }
- break;
-
- case PE_IndicatorBranch:
- {
- XPThemeData theme(widget, painter, QWindowsXPStylePrivate::VistaTreeViewTheme);
- static int decoration_size = 0;
- if (!decoration_size && theme.isValid()) {
- XPThemeData themeSize = theme;
- themeSize.partId = TVP_HOTGLYPH;
- themeSize.stateId = GLPS_OPENED;
- const QSizeF size = themeSize.size() * QWindowsStylePrivate::nativeMetricScaleFactor(widget);
- decoration_size = qRound(qMax(size.width(), size.height()));
- }
- int mid_h = option->rect.x() + option->rect.width() / 2;
- int mid_v = option->rect.y() + option->rect.height() / 2;
- int bef_h = mid_h;
- int bef_v = mid_v;
- int aft_h = mid_h;
- int aft_v = mid_v;
- if (option->state & State_Children) {
- int delta = decoration_size / 2;
- theme.rect = QRect(bef_h - delta, bef_v - delta, decoration_size, decoration_size);
- theme.partId = option->state & State_MouseOver ? TVP_HOTGLYPH : TVP_GLYPH;
- theme.stateId = option->state & QStyle::State_Open ? GLPS_OPENED : GLPS_CLOSED;
- if (option->direction == Qt::RightToLeft)
- theme.mirrorHorizontally = true;
- d->drawBackground(theme);
- bef_h -= delta + 2;
- bef_v -= delta + 2;
- aft_h += delta - 2;
- aft_v += delta - 2;
- }
-#if 0
- QBrush brush(option->palette.dark().color(), Qt::Dense4Pattern);
- if (option->state & State_Item) {
- if (option->direction == Qt::RightToLeft)
- painter->fillRect(option->rect.left(), mid_v, bef_h - option->rect.left(), 1, brush);
- else
- painter->fillRect(aft_h, mid_v, option->rect.right() - aft_h + 1, 1, brush);
- }
- if (option->state & State_Sibling && option->rect.bottom() > aft_v)
- painter->fillRect(mid_h, aft_v, 1, option->rect.bottom() - aft_v + 1, brush);
- if (option->state & (State_Open | State_Children | State_Item | State_Sibling) && (bef_v > option->rect.y()))
- painter->fillRect(mid_h, option->rect.y(), 1, bef_v - option->rect.y(), brush);
-#endif
- }
- break;
-
- case PE_PanelButtonBevel:
- case PE_IndicatorCheckBox:
- case PE_IndicatorRadioButton:
- {
- if (QWindowsVistaAnimation *a =
- qobject_cast<QWindowsVistaAnimation *>(d->animation(styleObject(option)))){
- a->paint(painter, option);
- } else {
- QWindowsXPStyle::drawPrimitive(element, option, painter, widget);
- }
- }
- break;
-
- case PE_FrameMenu:
- {
- int stateId = option->state & State_Active ? MB_ACTIVE : MB_INACTIVE;
- XPThemeData theme(widget, painter,
- QWindowsXPStylePrivate::MenuTheme,
- MENU_POPUPBORDERS, stateId, option->rect);
- d->drawBackground(theme);
- }
- break;
- case PE_Frame: {
-#ifndef QT_NO_ACCESSIBILITY
- if (QStyleHelper::isInstanceOf(option->styleObject, QAccessible::EditableText)
- || QStyleHelper::isInstanceOf(option->styleObject, QAccessible::StaticText) ||
-#else
- if (
-#endif
- (widget && widget->inherits("QTextEdit"))) {
- painter->save();
- int stateId = ETS_NORMAL;
- if (!(state & State_Enabled))
- stateId = ETS_DISABLED;
- else if (state & State_ReadOnly)
- stateId = ETS_READONLY;
- else if (state & State_HasFocus)
- stateId = ETS_SELECTED;
- XPThemeData theme(widget, painter,
- QWindowsXPStylePrivate::EditTheme,
- EP_EDITBORDER_HVSCROLL, stateId, option->rect);
- // Since EP_EDITBORDER_HVSCROLL does not us borderfill, theme.noContent cannot be used for clipping
- int borderSize = 1;
- GetThemeInt(theme.handle(), theme.partId, theme.stateId, TMT_BORDERSIZE, &borderSize);
- QRegion clipRegion = option->rect;
- QRegion content = option->rect.adjusted(borderSize, borderSize, -borderSize, -borderSize);
- clipRegion ^= content;
- painter->setClipRegion(clipRegion);
- d->drawBackground(theme);
- painter->restore();
- } else {
- QWindowsXPStyle::drawPrimitive(element, option, painter, widget);
- }
- }
- break;
-
- case PE_PanelLineEdit:
- if (const QStyleOptionFrame *panel = qstyleoption_cast<const QStyleOptionFrame *>(option)) {
- bool isEnabled = option->state & State_Enabled;
- if (QWindowsXPStylePrivate::isLineEditBaseColorSet(option, widget)) {
- painter->fillRect(panel->rect, panel->palette.brush(QPalette::Base));
- } else {
- int partId = EP_BACKGROUND;
- int stateId = EBS_NORMAL;
- if (!isEnabled)
- stateId = EBS_DISABLED;
- else if (state & State_ReadOnly)
- stateId = EBS_READONLY;
- else if (state & State_MouseOver)
- stateId = EBS_HOT;
-
- XPThemeData theme(nullptr, painter, QWindowsXPStylePrivate::EditTheme,
- partId, stateId, rect);
- if (!theme.isValid()) {
- QWindowsStyle::drawPrimitive(element, option, painter, widget);
- return;
- }
- int bgType;
- GetThemeEnumValue(theme.handle(), partId, stateId, TMT_BGTYPE, &bgType);
- if( bgType == BT_IMAGEFILE ) {
- d->drawBackground(theme);
- } else {
- QBrush fillColor = option->palette.brush(QPalette::Base);
- if (!isEnabled) {
- PROPERTYORIGIN origin = PO_NOTFOUND;
- GetThemePropertyOrigin(theme.handle(), theme.partId, theme.stateId, TMT_FILLCOLOR, &origin);
- // Use only if the fill property comes from our part
- if ((origin == PO_PART || origin == PO_STATE)) {
- COLORREF bgRef;
- GetThemeColor(theme.handle(), partId, stateId, TMT_FILLCOLOR, &bgRef);
- fillColor = QBrush(qRgb(GetRValue(bgRef), GetGValue(bgRef), GetBValue(bgRef)));
- }
- }
- painter->fillRect(option->rect, fillColor);
- }
- }
- if (panel->lineWidth > 0)
- proxy()->drawPrimitive(PE_FrameLineEdit, panel, painter, widget);
- return;
- }
- break;
-
- case PE_FrameLineEdit:
- if (QWindowsVistaAnimation *anim = qobject_cast<QWindowsVistaAnimation *>(d->animation(styleObject(option)))) {
- anim->paint(painter, option);
- } else {
- QPainter *p = painter;
- if (QWindowsXPStylePrivate::isItemViewDelegateLineEdit(widget)) {
- // we try to check if this lineedit is a delegate on a QAbstractItemView-derived class.
- QPen oldPen = p->pen();
- // Inner white border
- p->setPen(QPen(option->palette.base().color(), 1));
- p->drawRect(option->rect.adjusted(1, 1, -2, -2));
- // Outer dark border
- p->setPen(QPen(option->palette.shadow().color(), 1));
- p->drawRect(option->rect.adjusted(0, 0, -1, -1));
- p->setPen(oldPen);
- return;
- }
- int stateId = ETS_NORMAL;
- if (!(state & State_Enabled))
- stateId = ETS_DISABLED;
- else if (state & State_ReadOnly)
- stateId = ETS_READONLY;
- else if (state & State_MouseOver)
- stateId = ETS_HOT;
- else if (state & State_HasFocus)
- stateId = ETS_SELECTED;
- XPThemeData theme(widget, painter,
- QWindowsXPStylePrivate::EditTheme,
- EP_EDITBORDER_NOSCROLL, stateId, option->rect);
- theme.noContent = true;
- painter->save();
- QRegion clipRegion = option->rect;
- clipRegion -= option->rect.adjusted(2, 2, -2, -2);
- painter->setClipRegion(clipRegion);
- d->drawBackground(theme);
- painter->restore();
- }
- break;
-
- case PE_IndicatorToolBarHandle:
- {
- XPThemeData theme;
- QRect rect;
- if (option->state & State_Horizontal) {
- theme = XPThemeData(widget, painter,
- QWindowsXPStylePrivate::RebarTheme,
- RP_GRIPPER, ETS_NORMAL, option->rect.adjusted(0, 1, -2, -2));
- rect = option->rect.adjusted(0, 1, 0, -2);
- rect.setWidth(4);
- } else {
- theme = XPThemeData(widget, painter, QWindowsXPStylePrivate::RebarTheme,
- RP_GRIPPERVERT, ETS_NORMAL, option->rect.adjusted(0, 1, -2, -2));
- rect = option->rect.adjusted(1, 0, -1, 0);
- rect.setHeight(4);
- }
- theme.rect = rect;
- d->drawBackground(theme);
- }
- break;
-
- case PE_IndicatorToolBarSeparator:
- {
- QPen pen = painter->pen();
- int margin = 3;
- painter->setPen(option->palette.window().color().darker(114));
- if (option->state & State_Horizontal) {
- int x1 = option->rect.center().x();
- painter->drawLine(QPoint(x1, option->rect.top() + margin), QPoint(x1, option->rect.bottom() - margin));
- } else {
- int y1 = option->rect.center().y();
- painter->drawLine(QPoint(option->rect.left() + margin, y1), QPoint(option->rect.right() - margin, y1));
- }
- painter->setPen(pen);
- }
- break;
-
- case PE_PanelTipLabel: {
- XPThemeData theme(widget, painter,
- QWindowsXPStylePrivate::ToolTipTheme,
- TTP_STANDARD, TTSS_NORMAL, option->rect);
- d->drawBackground(theme);
- break;
- }
-
- case PE_PanelItemViewItem:
- {
- const QStyleOptionViewItem *vopt;
- bool newStyle = true;
- QAbstractItemView::SelectionBehavior selectionBehavior = QAbstractItemView::SelectRows;
- QAbstractItemView::SelectionMode selectionMode = QAbstractItemView::NoSelection;
- if (const QAbstractItemView *view = qobject_cast<const QAbstractItemView *>(widget)) {
- newStyle = !qobject_cast<const QTableView*>(view);
- selectionBehavior = view->selectionBehavior();
- selectionMode = view->selectionMode();
-#ifndef QT_NO_ACCESSIBILITY
- } else if (!widget) {
- newStyle = !QStyleHelper::hasAncestor(option->styleObject, QAccessible::MenuItem) ;
-#endif
- }
-
- if (newStyle && (vopt = qstyleoption_cast<const QStyleOptionViewItem *>(option))) {
- bool selected = vopt->state & QStyle::State_Selected;
- const bool hover = selectionMode != QAbstractItemView::NoSelection && (vopt->state & QStyle::State_MouseOver);
- bool active = vopt->state & QStyle::State_Active;
-
- if (vopt->features & QStyleOptionViewItem::Alternate)
- painter->fillRect(vopt->rect, vopt->palette.alternateBase());
-
- QPalette::ColorGroup cg = vopt->state & QStyle::State_Enabled
- ? QPalette::Normal : QPalette::Disabled;
- if (cg == QPalette::Normal && !(vopt->state & QStyle::State_Active))
- cg = QPalette::Inactive;
-
- QRect itemRect = subElementRect(QStyle::SE_ItemViewItemFocusRect, option, widget).adjusted(-1, 0, 1, 0);
- itemRect.setTop(vopt->rect.top());
- itemRect.setBottom(vopt->rect.bottom());
-
- QSize sectionSize = itemRect.size();
- if (vopt->showDecorationSelected)
- sectionSize = vopt->rect.size();
-
- if (selectionBehavior == QAbstractItemView::SelectRows)
- sectionSize.setWidth(vopt->rect.width());
- QPixmap pixmap;
-
- if (vopt->backgroundBrush.style() != Qt::NoBrush) {
- const QPointF oldBrushOrigin = painter->brushOrigin();
- painter->setBrushOrigin(vopt->rect.topLeft());
- painter->fillRect(vopt->rect, vopt->backgroundBrush);
- painter->setBrushOrigin(oldBrushOrigin);
- }
-
- if (hover || selected) {
- if (sectionSize.width() > 0 && sectionSize.height() > 0) {
- QString key = QString::fromLatin1("qvdelegate-%1-%2-%3-%4-%5").arg(sectionSize.width())
- .arg(sectionSize.height()).arg(selected).arg(active).arg(hover);
- if (!QPixmapCache::find(key, &pixmap)) {
- pixmap = QPixmap(sectionSize);
- pixmap.fill(Qt::transparent);
-
- int state;
- if (selected && hover)
- state = LISS_HOTSELECTED;
- else if (selected && !active)
- state = LISS_SELECTEDNOTFOCUS;
- else if (selected)
- state = LISS_SELECTED;
- else
- state = LISS_HOT;
-
- QPainter pixmapPainter(&pixmap);
- XPThemeData theme(widget, &pixmapPainter,
- QWindowsXPStylePrivate::VistaTreeViewTheme,
- LVP_LISTITEM, state, QRect(0, 0, sectionSize.width(), sectionSize.height()));
- if (theme.isValid()) {
- d->drawBackground(theme);
- } else {
- QWindowsXPStyle::drawPrimitive(PE_PanelItemViewItem, option, painter, widget);
- break;
- }
- QPixmapCache::insert(key, pixmap);
- }
- }
-
- if (vopt->showDecorationSelected) {
- const int frame = 2; //Assumes a 2 pixel pixmap border
- QRect srcRect = QRect(0, 0, sectionSize.width(), sectionSize.height());
- QRect pixmapRect = vopt->rect;
- bool reverse = vopt->direction == Qt::RightToLeft;
- bool leftSection = vopt->viewItemPosition == QStyleOptionViewItem::Beginning;
- bool rightSection = vopt->viewItemPosition == QStyleOptionViewItem::End;
- if (vopt->viewItemPosition == QStyleOptionViewItem::OnlyOne
- || vopt->viewItemPosition == QStyleOptionViewItem::Invalid)
- painter->drawPixmap(pixmapRect.topLeft(), pixmap);
- else if (reverse ? rightSection : leftSection){
- painter->drawPixmap(QRect(pixmapRect.topLeft(),
- QSize(frame, pixmapRect.height())), pixmap,
- QRect(QPoint(0, 0), QSize(frame, pixmapRect.height())));
- painter->drawPixmap(pixmapRect.adjusted(frame, 0, 0, 0),
- pixmap, srcRect.adjusted(frame, 0, -frame, 0));
- } else if (reverse ? leftSection : rightSection) {
- painter->drawPixmap(QRect(pixmapRect.topRight() - QPoint(frame - 1, 0),
- QSize(frame, pixmapRect.height())), pixmap,
- QRect(QPoint(pixmapRect.width() - frame, 0),
- QSize(frame, pixmapRect.height())));
- painter->drawPixmap(pixmapRect.adjusted(0, 0, -frame, 0),
- pixmap, srcRect.adjusted(frame, 0, -frame, 0));
- } else if (vopt->viewItemPosition == QStyleOptionViewItem::Middle)
- painter->drawPixmap(pixmapRect, pixmap,
- srcRect.adjusted(frame, 0, -frame, 0));
- } else {
- if (vopt->text.isEmpty() && vopt->icon.isNull())
- break;
- painter->drawPixmap(itemRect.topLeft(), pixmap);
- }
- }
- } else {
- QWindowsXPStyle::drawPrimitive(element, option, painter, widget);
- }
- break;
- }
- case PE_Widget:
- {
-#if QT_CONFIG(dialogbuttonbox)
- const QDialogButtonBox *buttonBox = nullptr;
-
- if (qobject_cast<const QMessageBox *> (widget))
- buttonBox = widget->findChild<const QDialogButtonBox *>(QLatin1String("qt_msgbox_buttonbox"));
-#if QT_CONFIG(inputdialog)
- else if (qobject_cast<const QInputDialog *> (widget))
- buttonBox = widget->findChild<const QDialogButtonBox *>(QLatin1String("qt_inputdlg_buttonbox"));
-#endif // QT_CONFIG(inputdialog)
-
- if (buttonBox) {
- //draw white panel part
- XPThemeData theme(widget, painter,
- QWindowsXPStylePrivate::TaskDialogTheme,
- TDLG_PRIMARYPANEL, 0, option->rect);
- QRect toprect = option->rect;
- toprect.setBottom(buttonBox->geometry().top());
- theme.rect = toprect;
- d->drawBackground(theme);
-
- //draw bottom panel part
- QRect buttonRect = option->rect;
- buttonRect.setTop(buttonBox->geometry().top());
- theme.rect = buttonRect;
- theme.partId = TDLG_SECONDARYPANEL;
- d->drawBackground(theme);
- }
-#endif
- }
- break;
- default:
- QWindowsXPStyle::drawPrimitive(element, option, painter, widget);
- break;
- }
-}
-
-
-/*!
- \internal
-
- see drawPrimitive for comments on the animation support
- */
-void QWindowsVistaStyle::drawControl(ControlElement element, const QStyleOption *option,
- QPainter *painter, const QWidget *widget) const
-{
- QWindowsVistaStylePrivate *d = const_cast<QWindowsVistaStylePrivate*>(d_func());
-
- if (!QWindowsVistaStylePrivate::useVista()) {
- QWindowsStyle::drawControl(element, option, painter, widget);
- return;
- }
-
- bool selected = option->state & State_Selected;
- bool pressed = option->state & State_Sunken;
- bool disabled = !(option->state & State_Enabled);
-
- int state = option->state;
- int themeNumber = -1;
-
- QRect rect(option->rect);
- State flags = option->state;
- int partId = 0;
- int stateId = 0;
-
- if (d->transitionsEnabled() && canAnimate(option))
- {
- if (element == CE_PushButtonBevel) {
- QRect oldRect;
- QRect newRect;
-
- QObject *styleObject = option->styleObject;
-
- int oldState = styleObject->property("_q_stylestate").toInt();
- oldRect = styleObject->property("_q_stylerect").toRect();
- newRect = option->rect;
- styleObject->setProperty("_q_stylestate", int(option->state));
- styleObject->setProperty("_q_stylerect", option->rect);
-
- bool wasDefault = false;
- bool isDefault = false;
- if (const QStyleOptionButton *button = qstyleoption_cast<const QStyleOptionButton *>(option)) {
- wasDefault = styleObject->property("_q_isdefault").toBool();
- isDefault = button->features & QStyleOptionButton::DefaultButton;
- styleObject->setProperty("_q_isdefault", isDefault);
- }
-
- bool doTransition = ((state & State_Sunken) != (oldState & State_Sunken) ||
- (state & State_On) != (oldState & State_On) ||
- (state & State_MouseOver) != (oldState & State_MouseOver));
-
- if (oldRect != newRect || (wasDefault && !isDefault)) {
- doTransition = false;
- d->stopAnimation(styleObject);
- }
-
- if (doTransition) {
- styleObject->setProperty("_q_no_animation", true);
-
- QWindowsVistaTransition *t = new QWindowsVistaTransition(styleObject);
- QWindowsVistaAnimation *anim = qobject_cast<QWindowsVistaAnimation *>(d->animation(styleObject));
- QStyleOption *styleOption = clonedAnimationStyleOption(option);
- styleOption->state = QStyle::State(oldState);
-
- QImage startImage = createAnimationBuffer(option, widget);
- QPainter startPainter(&startImage);
-
- // Use current state of existing animation if already one is running
- if (!anim) {
- proxy()->drawControl(element, styleOption, &startPainter, widget);
- } else {
- anim->paint(&startPainter, styleOption);
- d->stopAnimation(styleObject);
- }
-
- t->setStartImage(startImage);
- QImage endImage = createAnimationBuffer(option, widget);
- QPainter endPainter(&endImage);
- styleOption->state = option->state;
- proxy()->drawControl(element, styleOption, &endPainter, widget);
- t->setEndImage(endImage);
-
-
- DWORD duration = 0;
- const HTHEME theme = OpenThemeData(nullptr, L"Button");
-
- int fromState = buttonStateId(oldState, BP_PUSHBUTTON);
- int toState = buttonStateId(option->state, BP_PUSHBUTTON);
- if (GetThemeTransitionDuration(theme, BP_PUSHBUTTON, fromState, toState, TMT_TRANSITIONDURATIONS, &duration) == S_OK)
- t->setDuration(int(duration));
- else
- t->setDuration(0);
- t->setStartTime(QTime::currentTime());
- styleObject->setProperty("_q_no_animation", false);
-
- deleteClonedAnimationStyleOption(styleOption);
- d->startAnimation(t);
- }
-
- QWindowsVistaAnimation *anim = qobject_cast<QWindowsVistaAnimation *>(d->animation(styleObject));
- if (anim) {
- anim->paint(painter, option);
- return;
- }
-
- }
- }
- switch (element) {
- case CE_PushButtonBevel:
- if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(option))
- {
- themeNumber = QWindowsXPStylePrivate::ButtonTheme;
- partId = BP_PUSHBUTTON;
- if (btn->features & QStyleOptionButton::CommandLinkButton)
- partId = BP_COMMANDLINK;
- bool justFlat = (btn->features & QStyleOptionButton::Flat) && !(flags & (State_On|State_Sunken));
- if (!(flags & State_Enabled) && !(btn->features & QStyleOptionButton::Flat))
- stateId = PBS_DISABLED;
- else if (justFlat)
- ;
- else if (flags & (State_Sunken | State_On))
- stateId = PBS_PRESSED;
- else if (flags & State_MouseOver)
- stateId = PBS_HOT;
- else if (btn->features & QStyleOptionButton::DefaultButton && (state & State_Active))
- stateId = PBS_DEFAULTED;
- else
- stateId = PBS_NORMAL;
-
- if (!justFlat) {
-
- if (d->transitionsEnabled() && (btn->features & QStyleOptionButton::DefaultButton) &&
- !(state & (State_Sunken | State_On)) && !(state & State_MouseOver) &&
- (state & State_Enabled) && (state & State_Active))
- {
- QWindowsVistaAnimation *anim = qobject_cast<QWindowsVistaAnimation *>(d->animation(styleObject(option)));
-
- if (!anim) {
- QImage startImage = createAnimationBuffer(option, widget);
- QImage alternateImage = createAnimationBuffer(option, widget);
-
- QWindowsVistaPulse *pulse = new QWindowsVistaPulse(styleObject(option));
-
- QPainter startPainter(&startImage);
- stateId = PBS_DEFAULTED;
- XPThemeData theme(widget, &startPainter, themeNumber, partId, stateId, rect);
- d->drawBackground(theme);
-
- QPainter alternatePainter(&alternateImage);
- theme.stateId = PBS_DEFAULTED_ANIMATING;
- theme.painter = &alternatePainter;
- d->drawBackground(theme);
- pulse->setStartImage(startImage);
- pulse->setEndImage(alternateImage);
- pulse->setStartTime(QTime::currentTime());
- pulse->setDuration(2000);
- d->startAnimation(pulse);
- anim = pulse;
- }
-
- if (anim)
- anim->paint(painter, option);
- else {
- XPThemeData theme(widget, painter, themeNumber, partId, stateId, rect);
- d->drawBackground(theme);
- }
- }
- else {
- XPThemeData theme(widget, painter, themeNumber, partId, stateId, rect);
- d->drawBackground(theme);
- }
- }
-
- if (btn->features & QStyleOptionButton::HasMenu) {
- int mbiw = 0, mbih = 0;
- XPThemeData theme(widget, nullptr, QWindowsXPStylePrivate::ToolBarTheme,
- TP_DROPDOWNBUTTON);
- if (theme.isValid()) {
- const QSizeF size = theme.size() * QStyleHelper::dpiScaled(1, option);
- if (!size.isEmpty()) {
- mbiw = qRound(size.width());
- mbih = qRound(size.height());
- }
- }
- QRect ir = subElementRect(SE_PushButtonContents, option, nullptr);
- QStyleOptionButton newBtn = *btn;
- newBtn.rect = QStyle::visualRect(option->direction, option->rect,
- QRect(ir.right() - mbiw - 2,
- option->rect.top() + (option->rect.height()/2) - (mbih/2),
- mbiw + 1, mbih + 1));
- proxy()->drawPrimitive(PE_IndicatorArrowDown, &newBtn, painter, widget);
- }
- return;
- }
- break;
-
- case CE_ProgressBarContents:
- if (const QStyleOptionProgressBar *bar
- = qstyleoption_cast<const QStyleOptionProgressBar *>(option)) {
- bool isIndeterminate = (bar->minimum == 0 && bar->maximum == 0);
- const bool vertical = bar->orientation == Qt::Vertical;
- const bool inverted = bar->invertedAppearance;
-
- if (isIndeterminate || (bar->progress > 0 && (bar->progress < bar->maximum) && d->transitionsEnabled())) {
- if (!d->animation(styleObject(option)))
- d->startAnimation(new QProgressStyleAnimation(d->animationFps, styleObject(option)));
- } else {
- d->stopAnimation(styleObject(option));
- }
-
- XPThemeData theme(widget, painter,
- QWindowsXPStylePrivate::ProgressTheme,
- vertical ? PP_FILLVERT : PP_FILL);
- theme.rect = option->rect;
- bool reverse = (bar->direction == Qt::LeftToRight && inverted) || (bar->direction == Qt::RightToLeft && !inverted);
- QTime current = QTime::currentTime();
-
- if (isIndeterminate) {
- if (QProgressStyleAnimation *a = qobject_cast<QProgressStyleAnimation *>(d->animation(styleObject(option)))) {
- int glowSize = 120;
- int animationWidth = glowSize * 2 + (vertical ? theme.rect.height() : theme.rect.width());
- int animOffset = a->startTime().msecsTo(current) / 4;
- if (animOffset > animationWidth)
- a->setStartTime(QTime::currentTime());
- painter->save();
- painter->setClipRect(theme.rect);
- QRect animRect;
- QSize pixmapSize(14, 14);
- if (vertical) {
- animRect = QRect(theme.rect.left(),
- inverted ? rect.top() - glowSize + animOffset :
- rect.bottom() + glowSize - animOffset,
- rect.width(), glowSize);
- pixmapSize.setHeight(animRect.height());
- } else {
- animRect = QRect(rect.left() - glowSize + animOffset,
- rect.top(), glowSize, rect.height());
- animRect = QStyle::visualRect(reverse ? Qt::RightToLeft : Qt::LeftToRight,
- option->rect, animRect);
- pixmapSize.setWidth(animRect.width());
- }
- QString name = QString::fromLatin1("qiprogress-%1-%2").arg(pixmapSize.width()).arg(pixmapSize.height());
- QPixmap pixmap;
- if (!QPixmapCache::find(name, &pixmap)) {
- QImage image(pixmapSize, QImage::Format_ARGB32);
- image.fill(Qt::transparent);
- QPainter imagePainter(&image);
- theme.painter = &imagePainter;
- theme.partId = vertical ? PP_FILLVERT : PP_FILL;
- theme.rect = QRect(QPoint(0,0), animRect.size());
- QLinearGradient alphaGradient(0, 0, vertical ? 0 : image.width(),
- vertical ? image.height() : 0);
- alphaGradient.setColorAt(0, QColor(0, 0, 0, 0));
- alphaGradient.setColorAt(0.5, QColor(0, 0, 0, 220));
- alphaGradient.setColorAt(1, QColor(0, 0, 0, 0));
- imagePainter.fillRect(image.rect(), alphaGradient);
- imagePainter.setCompositionMode(QPainter::CompositionMode_SourceIn);
- d->drawBackground(theme);
- imagePainter.end();
- pixmap = QPixmap::fromImage(image);
- QPixmapCache::insert(name, pixmap);
- }
- painter->drawPixmap(animRect, pixmap);
- painter->restore();
- }
- }
- else {
- qint64 progress = qMax<qint64>(bar->progress, bar->minimum); // workaround for bug in QProgressBar
-
- if (vertical) {
- int maxHeight = option->rect.height();
- int minHeight = 0;
- double vc6_workaround = ((progress - qint64(bar->minimum)) / qMax(double(1.0), double(qint64(bar->maximum) - qint64(bar->minimum))) * maxHeight);
- int height = isIndeterminate ? maxHeight: qMax(int(vc6_workaround), minHeight);
- theme.rect.setHeight(height);
- if (!inverted)
- theme.rect.moveTop(rect.height() - theme.rect.height());
- } else {
- int maxWidth = option->rect.width();
- int minWidth = 0;
- double vc6_workaround = ((progress - qint64(bar->minimum)) / qMax(double(1.0), double(qint64(bar->maximum) - qint64(bar->minimum))) * maxWidth);
- int width = isIndeterminate ? maxWidth : qMax(int(vc6_workaround), minWidth);
- theme.rect.setWidth(width);
- theme.rect = QStyle::visualRect(reverse ? Qt::RightToLeft : Qt::LeftToRight,
- option->rect, theme.rect);
- }
- d->drawBackground(theme);
-
- if (QProgressStyleAnimation *a = qobject_cast<QProgressStyleAnimation *>(d->animation(styleObject(option)))) {
- int glowSize = 140;
- int animationWidth = glowSize * 2 + (vertical ? theme.rect.height() : theme.rect.width());
- int animOffset = a->startTime().msecsTo(current) / 4;
- theme.partId = vertical ? PP_MOVEOVERLAYVERT : PP_MOVEOVERLAY;
- if (animOffset > animationWidth) {
- if (bar->progress < bar->maximum)
- a->setStartTime(QTime::currentTime());
- else
- d->stopAnimation(styleObject(option)); //we stop the glow motion only after it has
- //moved out of view
- }
- painter->save();
- painter->setClipRect(theme.rect);
- if (vertical) {
- theme.rect = QRect(theme.rect.left(),
- inverted ? rect.top() - glowSize + animOffset :
- rect.bottom() + glowSize - animOffset,
- rect.width(), glowSize);
- } else {
- theme.rect = QRect(rect.left() - glowSize + animOffset,rect.top(), glowSize, rect.height());
- theme.rect = QStyle::visualRect(reverse ? Qt::RightToLeft : Qt::LeftToRight, option->rect, theme.rect);
- }
- d->drawBackground(theme);
- painter->restore();
- }
- }
- }
- break;
-
- case CE_MenuBarItem:
- {
-
- if (const QStyleOptionMenuItem *mbi = qstyleoption_cast<const QStyleOptionMenuItem *>(option))
- {
- if (mbi->menuItemType == QStyleOptionMenuItem::DefaultItem)
- break;
-
- QPalette::ColorRole textRole = disabled ? QPalette::Text : QPalette::ButtonText;
- QPixmap pix = mbi->icon.pixmap(proxy()->pixelMetric(PM_SmallIconSize, option, widget), QIcon::Normal);
-
- int alignment = Qt::AlignCenter | Qt::TextShowMnemonic | Qt::TextDontClip | Qt::TextSingleLine;
- if (!proxy()->styleHint(SH_UnderlineShortcut, mbi, widget))
- alignment |= Qt::TextHideMnemonic;
-
- if (widget && mbi->palette.color(QPalette::Window) != Qt::transparent) { // Not needed for QtQuick Controls
- //The rect adjustment is a workaround for the menu not really filling its background.
- XPThemeData theme(widget, painter,
- QWindowsXPStylePrivate::MenuTheme,
- MENU_BARBACKGROUND, 0, option->rect.adjusted(-1, 0, 2, 1));
- d->drawBackground(theme);
- }
-
- int stateId = MBI_NORMAL;
- if (disabled)
- stateId = MBI_DISABLED;
- else if (pressed)
- stateId = MBI_PUSHED;
- else if (selected)
- stateId = MBI_HOT;
-
- XPThemeData theme2(widget, painter,
- QWindowsXPStylePrivate::MenuTheme,
- MENU_BARITEM, stateId, option->rect);
- d->drawBackground(theme2);
-
- if (!pix.isNull())
- drawItemPixmap(painter, mbi->rect, alignment, pix);
- else
- drawItemText(painter, mbi->rect, alignment, mbi->palette, mbi->state & State_Enabled, mbi->text, textRole);
- }
- }
- break;
-#if QT_CONFIG(menu)
- case CE_MenuItem:
- if (const QStyleOptionMenuItem *menuitem = qstyleoption_cast<const QStyleOptionMenuItem *>(option)) {
- // windows always has a check column, regardless whether we have an icon or not
- const qreal factor = QWindowsXPStylePrivate::nativeMetricScaleFactor(widget);
- int checkcol = qRound(qreal(25) * factor);
- const int gutterWidth = qRound(qreal(3) * factor);
- {
- XPThemeData theme(widget, nullptr, QWindowsXPStylePrivate::MenuTheme,
- MENU_POPUPCHECKBACKGROUND, MBI_HOT);
- XPThemeData themeSize = theme;
- themeSize.partId = MENU_POPUPCHECK;
- themeSize.stateId = 0;
- const QSizeF size = themeSize.size() * QWindowsStylePrivate::nativeMetricScaleFactor(widget);
- const QMarginsF margins = themeSize.margins() * QWindowsStylePrivate::nativeMetricScaleFactor(widget);
- checkcol = qMax(menuitem->maxIconWidth, qRound(gutterWidth + size.width() + margins.left() + margins.right()));
- }
- QRect rect = option->rect;
-
- //draw vertical menu line
- if (option->direction == Qt::LeftToRight)
- checkcol += rect.x();
- QPoint p1 = QStyle::visualPos(option->direction, menuitem->rect, QPoint(checkcol, rect.top()));
- QPoint p2 = QStyle::visualPos(option->direction, menuitem->rect, QPoint(checkcol, rect.bottom()));
- QRect gutterRect(p1.x(), p1.y(), gutterWidth, p2.y() - p1.y() + 1);
- XPThemeData theme2(widget, painter, QWindowsXPStylePrivate::MenuTheme,
- MENU_POPUPGUTTER, stateId, gutterRect);
- d->drawBackground(theme2);
-
- int x, y, w, h;
- menuitem->rect.getRect(&x, &y, &w, &h);
- int tab = menuitem->tabWidth;
- bool dis = !(menuitem->state & State_Enabled);
- bool checked = menuitem->checkType != QStyleOptionMenuItem::NotCheckable
- ? menuitem->checked : false;
- bool act = menuitem->state & State_Selected;
-
- if (menuitem->menuItemType == QStyleOptionMenuItem::Separator) {
- int yoff = y-2 + h / 2;
- const int separatorSize = qRound(qreal(6) * QWindowsStylePrivate::nativeMetricScaleFactor(widget));
- QPoint p1 = QPoint(x + checkcol, yoff);
- QPoint p2 = QPoint(x + w + separatorSize, yoff);
- stateId = MBI_HOT;
- QRect subRect(p1.x() + (gutterWidth - menuitem->rect.x()), p1.y(),
- p2.x() - p1.x(), separatorSize);
- subRect = QStyle::visualRect(option->direction, option->rect, subRect );
- XPThemeData theme2(widget, painter,
- QWindowsXPStylePrivate::MenuTheme,
- MENU_POPUPSEPARATOR, stateId, subRect);
- d->drawBackground(theme2);
- return;
- }
-
- QRect vCheckRect = visualRect(option->direction, menuitem->rect, QRect(menuitem->rect.x(),
- menuitem->rect.y(), checkcol - (gutterWidth + menuitem->rect.x()), menuitem->rect.height()));
-
- if (act) {
- stateId = dis ? MBI_DISABLED : MBI_HOT;
- XPThemeData theme2(widget, painter,
- QWindowsXPStylePrivate::MenuTheme,
- MENU_POPUPITEM, stateId, option->rect);
- d->drawBackground(theme2);
- }
-
- if (checked) {
- XPThemeData theme(widget, painter,
- QWindowsXPStylePrivate::MenuTheme,
- MENU_POPUPCHECKBACKGROUND,
- menuitem->icon.isNull() ? MBI_HOT : MBI_PUSHED, vCheckRect);
- XPThemeData themeSize = theme;
- themeSize.partId = MENU_POPUPCHECK;
- themeSize.stateId = 0;
- const QSizeF size = themeSize.size() * QWindowsStylePrivate::nativeMetricScaleFactor(widget);
- const QMarginsF margins = themeSize.margins() * QWindowsStylePrivate::nativeMetricScaleFactor(widget);
- QRect checkRect(0, 0, qRound(size.width() + margins.left() + margins.right()),
- qRound(size.height() + margins.bottom() + margins.top()));
- checkRect.moveCenter(vCheckRect.center());
- theme.rect = checkRect;
-
- d->drawBackground(theme);
-
- if (menuitem->icon.isNull()) {
- checkRect = QRect(QPoint(0, 0), size.toSize());
- checkRect.moveCenter(theme.rect.center());
- theme.rect = checkRect;
-
- theme.partId = MENU_POPUPCHECK;
- bool bullet = menuitem->checkType & QStyleOptionMenuItem::Exclusive;
- if (dis)
- theme.stateId = bullet ? MC_BULLETDISABLED: MC_CHECKMARKDISABLED;
- else
- theme.stateId = bullet ? MC_BULLETNORMAL: MC_CHECKMARKNORMAL;
- d->drawBackground(theme);
- }
- }
-
- if (!menuitem->icon.isNull()) {
- QIcon::Mode mode = dis ? QIcon::Disabled : QIcon::Normal;
- if (act && !dis)
- mode = QIcon::Active;
- QPixmap pixmap;
- if (checked)
- 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);
- pmr.moveCenter(vCheckRect.center());
- painter->setPen(menuitem->palette.text().color());
- painter->drawPixmap(pmr.topLeft(), pixmap);
- }
-
- painter->setPen(menuitem->palette.buttonText().color());
-
- const QColor textColor = menuitem->palette.text().color();
- if (dis)
- painter->setPen(textColor);
-
- int xm = windowsItemFrame + checkcol + windowsItemHMargin + (gutterWidth - menuitem->rect.x()) - 1;
- int xpos = menuitem->rect.x() + xm;
- QRect textRect(xpos, y + windowsItemVMargin, w - xm - windowsRightBorder - tab + 1, h - 2 * windowsItemVMargin);
- QRect vTextRect = visualRect(option->direction, menuitem->rect, textRect);
- QString s = menuitem->text;
- if (!s.isEmpty()) { // draw text
- painter->save();
- int t = s.indexOf(QLatin1Char('\t'));
- int text_flags = Qt::AlignVCenter | Qt::TextShowMnemonic | Qt::TextDontClip | Qt::TextSingleLine;
- if (!proxy()->styleHint(SH_UnderlineShortcut, menuitem, widget))
- text_flags |= Qt::TextHideMnemonic;
- text_flags |= Qt::AlignLeft;
- if (t >= 0) {
- QRect vShortcutRect = visualRect(option->direction, menuitem->rect,
- QRect(textRect.topRight(), QPoint(menuitem->rect.right(), textRect.bottom())));
- painter->drawText(vShortcutRect, text_flags, s.mid(t + 1));
- s = s.left(t);
- }
- QFont font = menuitem->font;
- if (menuitem->menuItemType == QStyleOptionMenuItem::DefaultItem)
- font.setBold(true);
- painter->setFont(font);
- painter->setPen(textColor);
- painter->drawText(vTextRect, text_flags, s.left(t));
- painter->restore();
- }
- if (menuitem->menuItemType == QStyleOptionMenuItem::SubMenu) {// draw sub menu arrow
- int dim = (h - 2 * windowsItemFrame) / 2;
- PrimitiveElement arrow;
- arrow = (option->direction == Qt::RightToLeft) ? PE_IndicatorArrowLeft : PE_IndicatorArrowRight;
- xpos = x + w - windowsArrowHMargin - windowsItemFrame - dim;
- QRect vSubMenuRect = visualRect(option->direction, menuitem->rect, QRect(xpos, y + h / 2 - dim / 2, dim, dim));
- QStyleOptionMenuItem newMI = *menuitem;
- newMI.rect = vSubMenuRect;
- newMI.state = dis ? State_None : State_Enabled;
- proxy()->drawPrimitive(arrow, &newMI, painter, widget);
- }
- }
- break;
-#endif // QT_CONFIG(menu)
- case CE_HeaderSection:
- if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(option)) {
- partId = HP_HEADERITEM;
- if (flags & State_Sunken)
- stateId = HIS_PRESSED;
- else if (flags & State_MouseOver)
- stateId = HIS_HOT;
- else
- stateId = HIS_NORMAL;
-
- if (header->sortIndicator != QStyleOptionHeader::None)
- stateId += 3;
-
- XPThemeData theme(widget, painter,
- QWindowsXPStylePrivate::HeaderTheme,
- partId, stateId, option->rect);
- d->drawBackground(theme);
- }
- break;
- case CE_MenuBarEmptyArea:
- {
- stateId = MBI_NORMAL;
- if (!(state & State_Enabled))
- stateId = MBI_DISABLED;
- XPThemeData theme(widget, painter,
- QWindowsXPStylePrivate::MenuTheme,
- MENU_BARBACKGROUND, stateId, option->rect);
- d->drawBackground(theme);
- }
- break;
- case CE_ToolBar:
- if (const QStyleOptionToolBar *toolbar = qstyleoption_cast<const QStyleOptionToolBar *>(option)) {
- QPalette pal = option->palette;
- pal.setColor(QPalette::Dark, option->palette.window().color().darker(130));
- QStyleOptionToolBar copyOpt = *toolbar;
- copyOpt.palette = pal;
- QWindowsStyle::drawControl(element, &copyOpt, painter, widget);
- }
- break;
-#if QT_CONFIG(dockwidget)
- case CE_DockWidgetTitle:
- if (const QStyleOptionDockWidget *dwOpt = qstyleoption_cast<const QStyleOptionDockWidget *>(option)) {
- const QDockWidget *dockWidget = qobject_cast<const QDockWidget *>(widget);
- QRect rect = option->rect;
- if (dockWidget && dockWidget->isFloating()) {
- QWindowsXPStyle::drawControl(element, option, painter, widget);
- break; //otherwise fall through
- }
-
- const bool verticalTitleBar = dwOpt->verticalTitleBar;
-
- if (verticalTitleBar) {
- rect = rect.transposed();
-
- painter->translate(rect.left() - 1, rect.top() + rect.width());
- painter->rotate(-90);
- painter->translate(-rect.left() + 1, -rect.top());
- }
-
- painter->setBrush(option->palette.window().color().darker(110));
- painter->setPen(option->palette.window().color().darker(130));
- painter->drawRect(rect.adjusted(0, 1, -1, -3));
-
- int buttonMargin = 4;
- int mw = proxy()->pixelMetric(QStyle::PM_DockWidgetTitleMargin, dwOpt, widget);
- int fw = proxy()->pixelMetric(PM_DockWidgetFrameWidth, dwOpt, widget);
- const QDockWidget *dw = qobject_cast<const QDockWidget *>(widget);
- bool isFloating = dw && dw->isFloating();
-
- QRect r = option->rect.adjusted(0, 2, -1, -3);
- QRect titleRect = r;
-
- if (dwOpt->closable) {
- QSize sz = proxy()->standardIcon(QStyle::SP_TitleBarCloseButton, dwOpt, widget).actualSize(QSize(10, 10));
- titleRect.adjust(0, 0, -sz.width() - mw - buttonMargin, 0);
- }
-
- if (dwOpt->floatable) {
- QSize sz = proxy()->standardIcon(QStyle::SP_TitleBarMaxButton, dwOpt, widget).actualSize(QSize(10, 10));
- titleRect.adjust(0, 0, -sz.width() - mw - buttonMargin, 0);
- }
-
- if (isFloating) {
- titleRect.adjust(0, -fw, 0, 0);
- if (widget && widget->windowIcon().cacheKey() != QApplication::windowIcon().cacheKey())
- titleRect.adjust(titleRect.height() + mw, 0, 0, 0);
- } else {
- titleRect.adjust(mw, 0, 0, 0);
- if (!dwOpt->floatable && !dwOpt->closable)
- titleRect.adjust(0, 0, -mw, 0);
- }
- if (!verticalTitleBar)
- titleRect = visualRect(dwOpt->direction, r, titleRect);
-
- if (!dwOpt->title.isEmpty()) {
- QString titleText = painter->fontMetrics().elidedText(dwOpt->title, Qt::ElideRight,
- verticalTitleBar ? titleRect.height() : titleRect.width());
- const int indent = 4;
- drawItemText(painter, rect.adjusted(indent + 1, 1, -indent - 1, -1),
- Qt::AlignLeft | Qt::AlignVCenter | Qt::TextShowMnemonic,
- dwOpt->palette,
- dwOpt->state & State_Enabled, titleText,
- QPalette::WindowText);
- }
- }
- break;
-#endif // QT_CONFIG(dockwidget)
-#if QT_CONFIG(itemviews)
- case CE_ItemViewItem:
- {
- const QStyleOptionViewItem *vopt;
-
- const QAbstractItemView *view = qobject_cast<const QAbstractItemView *>(widget);
- bool newStyle = true;
-
- if (qobject_cast<const QTableView*>(widget))
- newStyle = false;
-
- if (newStyle && view && (vopt = qstyleoption_cast<const QStyleOptionViewItem *>(option))) {
- /*
- // We cannot currently get the correct selection color for "explorer style" views
- COLORREF cref = 0;
- XPThemeData theme(d->treeViewHelper(), 0, QLatin1String("LISTVIEW"), 0, 0);
- unsigned int res = GetThemeColor(theme.handle(), LVP_LISTITEM, LISS_SELECTED, TMT_TEXTCOLOR, &cref);
- QColor textColor(GetRValue(cref), GetGValue(cref), GetBValue(cref));
- */
- QPalette palette = vopt->palette;
- palette.setColor(QPalette::All, QPalette::HighlightedText, palette.color(QPalette::Active, QPalette::Text));
- // Note that setting a saturated color here results in ugly XOR colors in the focus rect
- palette.setColor(QPalette::All, QPalette::Highlight, palette.base().color().darker(108));
- QStyleOptionViewItem adjustedOption = *vopt;
- adjustedOption.palette = palette;
- // We hide the focusrect in singleselection as it is not required
- if ((view->selectionMode() == QAbstractItemView::SingleSelection)
- && !(vopt->state & State_KeyboardFocusChange))
- adjustedOption.state &= ~State_HasFocus;
- QWindowsXPStyle::drawControl(element, &adjustedOption, painter, widget);
- } else {
- QWindowsXPStyle::drawControl(element, option, painter, widget);
- }
- break;
- }
-#endif // QT_CONFIG(itemviews)
-#if QT_CONFIG(combobox)
- case CE_ComboBoxLabel:
- QCommonStyle::drawControl(element, option, painter, widget);
- break;
-#endif // QT_CONFIG(combobox)
- default:
- QWindowsXPStyle::drawControl(element, option, painter, widget);
- break;
- }
-}
-
-/*!
- \internal
-
- see drawPrimitive for comments on the animation support
-
- */
-void QWindowsVistaStyle::drawComplexControl(ComplexControl control, const QStyleOptionComplex *option,
- QPainter *painter, const QWidget *widget) const
-{
- QWindowsVistaStylePrivate *d = const_cast<QWindowsVistaStylePrivate*>(d_func());
- if (!QWindowsVistaStylePrivate::useVista()) {
- QWindowsStyle::drawComplexControl(control, option, painter, widget);
- return;
- }
-
- State state = option->state;
- SubControls sub = option->subControls;
- QRect r = option->rect;
-
- int partId = 0;
- int stateId = 0;
-
- State flags = option->state;
- if (widget && widget->testAttribute(Qt::WA_UnderMouse) && widget->isActiveWindow())
- flags |= State_MouseOver;
-
- if (d->transitionsEnabled() && canAnimate(option))
- {
-
- if (control == CC_ScrollBar || control == CC_SpinBox || control == CC_ComboBox) {
-
- QObject *styleObject = option->styleObject; // Can be widget or qquickitem
-
- int oldState = styleObject->property("_q_stylestate").toInt();
- int oldActiveControls = styleObject->property("_q_stylecontrols").toInt();
-
- QRect oldRect = styleObject->property("_q_stylerect").toRect();
- styleObject->setProperty("_q_stylestate", int(option->state));
- styleObject->setProperty("_q_stylecontrols", int(option->activeSubControls));
- styleObject->setProperty("_q_stylerect", option->rect);
-
- bool doTransition = ((state & State_Sunken) != (oldState & State_Sunken) ||
- (state & State_On) != (oldState & State_On) ||
- (state & State_MouseOver) != (oldState & State_MouseOver) ||
- oldActiveControls != int(option->activeSubControls));
-
- if (qstyleoption_cast<const QStyleOptionSlider *>(option)) {
- QRect oldSliderPos = styleObject->property("_q_stylesliderpos").toRect();
- QRect currentPos = proxy()->subControlRect(CC_ScrollBar, option, SC_ScrollBarSlider, widget);
- styleObject->setProperty("_q_stylesliderpos", currentPos);
- if (oldSliderPos != currentPos) {
- doTransition = false;
- d->stopAnimation(styleObject);
- }
- } else if (control == CC_SpinBox) {
- //spinboxes have a transition when focus changes
- if (!doTransition)
- doTransition = (state & State_HasFocus) != (oldState & State_HasFocus);
- }
-
- if (oldRect != option->rect) {
- doTransition = false;
- d->stopAnimation(styleObject);
- }
-
- if (doTransition) {
- QImage startImage = createAnimationBuffer(option, widget);
- QPainter startPainter(&startImage);
-
- QImage endImage = createAnimationBuffer(option, widget);
- QPainter endPainter(&endImage);
-
- QWindowsVistaAnimation *anim = qobject_cast<QWindowsVistaAnimation *>(d->animation(styleObject));
- QWindowsVistaTransition *t = new QWindowsVistaTransition(styleObject);
-
- // Draw the image that ends the animation by using the current styleoption
- QStyleOptionComplex *styleOption = qstyleoption_cast<QStyleOptionComplex*>(clonedAnimationStyleOption(option));
-
- styleObject->setProperty("_q_no_animation", true);
-
- // Draw transition source
- if (!anim) {
- styleOption->state = QStyle::State(oldState);
- styleOption->activeSubControls = QStyle::SubControl(oldActiveControls);
- proxy()->drawComplexControl(control, styleOption, &startPainter, widget);
- } else {
- anim->paint(&startPainter, option);
- }
- t->setStartImage(startImage);
-
- // Draw transition target
- styleOption->state = option->state;
- styleOption->activeSubControls = option->activeSubControls;
- proxy()->drawComplexControl(control, styleOption, &endPainter, widget);
-
- styleObject->setProperty("_q_no_animation", false);
-
- t->setEndImage(endImage);
- t->setStartTime(QTime::currentTime());
-
- if (option->state & State_MouseOver || option->state & State_Sunken)
- t->setDuration(150);
- else
- t->setDuration(500);
-
- deleteClonedAnimationStyleOption(styleOption);
- d->startAnimation(t);
- }
- if (QWindowsVistaAnimation *anim = qobject_cast<QWindowsVistaAnimation *>(d->animation(styleObject))) {
- anim->paint(painter, option);
- return;
- }
- }
- }
-
- switch (control) {
- case CC_ComboBox:
- if (const QStyleOptionComboBox *cmb = qstyleoption_cast<const QStyleOptionComboBox *>(option))
- {
- if (cmb->editable) {
- if (sub & SC_ComboBoxEditField) {
- partId = EP_EDITBORDER_NOSCROLL;
- if (!(flags & State_Enabled))
- stateId = ETS_DISABLED;
- else if (flags & State_MouseOver)
- stateId = ETS_HOT;
- else if (flags & State_HasFocus)
- stateId = ETS_FOCUSED;
- else
- stateId = ETS_NORMAL;
-
- XPThemeData theme(widget, painter,
- QWindowsXPStylePrivate::EditTheme,
- partId, stateId, r);
-
- d->drawBackground(theme);
- }
- if (sub & SC_ComboBoxArrow) {
- QRect subRect = proxy()->subControlRect(CC_ComboBox, option, SC_ComboBoxArrow, widget);
- XPThemeData theme(widget, painter, QWindowsXPStylePrivate::ComboboxTheme);
- theme.rect = subRect;
- partId = option->direction == Qt::RightToLeft ? CP_DROPDOWNBUTTONLEFT : CP_DROPDOWNBUTTONRIGHT;
-
- if (!(cmb->state & State_Enabled))
- stateId = CBXS_DISABLED;
- else if (cmb->state & State_Sunken || cmb->state & State_On)
- stateId = CBXS_PRESSED;
- else if (cmb->state & State_MouseOver && option->activeSubControls & SC_ComboBoxArrow)
- stateId = CBXS_HOT;
- else
- stateId = CBXS_NORMAL;
-
- theme.partId = partId;
- theme.stateId = stateId;
- d->drawBackground(theme);
- }
-
- } else {
- if (sub & SC_ComboBoxFrame) {
- XPThemeData theme(widget, painter, QWindowsXPStylePrivate::ComboboxTheme);
- theme.rect = option->rect;
- theme.partId = CP_READONLY;
- if (!(cmb->state & State_Enabled))
- theme.stateId = CBXS_DISABLED;
- else if (cmb->state & State_Sunken || cmb->state & State_On)
- theme.stateId = CBXS_PRESSED;
- else if (cmb->state & State_MouseOver)
- theme.stateId = CBXS_HOT;
- else
- theme.stateId = CBXS_NORMAL;
- d->drawBackground(theme);
- }
- if (sub & SC_ComboBoxArrow) {
- XPThemeData theme(widget, painter, QWindowsXPStylePrivate::ComboboxTheme);
- theme.rect = proxy()->subControlRect(CC_ComboBox, option, SC_ComboBoxArrow, widget);
- theme.partId = option->direction == Qt::RightToLeft ? CP_DROPDOWNBUTTONLEFT : CP_DROPDOWNBUTTONRIGHT;
- if (!(cmb->state & State_Enabled))
- theme.stateId = CBXS_DISABLED;
- else
- theme.stateId = CBXS_NORMAL;
- d->drawBackground(theme);
- }
- if ((sub & SC_ComboBoxEditField) && (flags & State_HasFocus)) {
- QStyleOptionFocusRect fropt;
- fropt.QStyleOption::operator=(*cmb);
- fropt.rect = proxy()->subControlRect(CC_ComboBox, option, SC_ComboBoxEditField, widget);
- proxy()->drawPrimitive(PE_FrameFocusRect, &fropt, painter, widget);
- }
- }
- }
- break;
- case CC_ScrollBar:
- if (const QStyleOptionSlider *scrollbar = qstyleoption_cast<const QStyleOptionSlider *>(option))
- {
- XPThemeData theme(widget, painter, QWindowsXPStylePrivate::ScrollBarTheme);
- bool maxedOut = (scrollbar->maximum == scrollbar->minimum);
- if (maxedOut)
- flags &= ~State_Enabled;
-
- bool isHorz = flags & State_Horizontal;
- bool isRTL = option->direction == Qt::RightToLeft;
- if (sub & SC_ScrollBarAddLine) {
- theme.rect = proxy()->subControlRect(CC_ScrollBar, option, SC_ScrollBarAddLine, widget);
- partId = SBP_ARROWBTN;
- if (!(flags & State_Enabled))
- stateId = (isHorz ? (isRTL ? ABS_LEFTDISABLED : ABS_RIGHTDISABLED) : ABS_DOWNDISABLED);
- else if (scrollbar->activeSubControls & SC_ScrollBarAddLine && (scrollbar->state & State_Sunken))
- stateId = (isHorz ? (isRTL ? ABS_LEFTPRESSED : ABS_RIGHTPRESSED) : ABS_DOWNPRESSED);
- else if (scrollbar->activeSubControls & SC_ScrollBarAddLine && (scrollbar->state & State_MouseOver))
- stateId = (isHorz ? (isRTL ? ABS_LEFTHOT : ABS_RIGHTHOT) : ABS_DOWNHOT);
- else if (scrollbar->state & State_MouseOver)
- stateId = (isHorz ? (isRTL ? ABS_LEFTHOVER : ABS_RIGHTHOVER) : ABS_DOWNHOVER);
- else
- stateId = (isHorz ? (isRTL ? ABS_LEFTNORMAL : ABS_RIGHTNORMAL) : ABS_DOWNNORMAL);
- theme.partId = partId;
- theme.stateId = stateId;
- d->drawBackground(theme);
- }
- if (sub & SC_ScrollBarSubLine) {
- theme.rect = proxy()->subControlRect(CC_ScrollBar, option, SC_ScrollBarSubLine, widget);
- partId = SBP_ARROWBTN;
- if (!(flags & State_Enabled))
- stateId = (isHorz ? (isRTL ? ABS_RIGHTDISABLED : ABS_LEFTDISABLED) : ABS_UPDISABLED);
- else if (scrollbar->activeSubControls & SC_ScrollBarSubLine && (scrollbar->state & State_Sunken))
- stateId = (isHorz ? (isRTL ? ABS_RIGHTPRESSED : ABS_LEFTPRESSED) : ABS_UPPRESSED);
- else if (scrollbar->activeSubControls & SC_ScrollBarSubLine && (scrollbar->state & State_MouseOver))
- stateId = (isHorz ? (isRTL ? ABS_RIGHTHOT : ABS_LEFTHOT) : ABS_UPHOT);
- else if (scrollbar->state & State_MouseOver)
- stateId = (isHorz ? (isRTL ? ABS_RIGHTHOVER : ABS_LEFTHOVER) : ABS_UPHOVER);
- else
- stateId = (isHorz ? (isRTL ? ABS_RIGHTNORMAL : ABS_LEFTNORMAL) : ABS_UPNORMAL);
- theme.partId = partId;
- theme.stateId = stateId;
- d->drawBackground(theme);
- }
- if (maxedOut) {
- theme.rect = proxy()->subControlRect(CC_ScrollBar, option, SC_ScrollBarSlider, widget);
- theme.rect = theme.rect.united(proxy()->subControlRect(CC_ScrollBar, option, SC_ScrollBarSubPage, widget));
- theme.rect = theme.rect.united(proxy()->subControlRect(CC_ScrollBar, option, SC_ScrollBarAddPage, widget));
- partId = flags & State_Horizontal ? SBP_LOWERTRACKHORZ : SBP_LOWERTRACKVERT;
- stateId = SCRBS_DISABLED;
- theme.partId = partId;
- theme.stateId = stateId;
- d->drawBackground(theme);
- } else {
- if (sub & SC_ScrollBarSubPage) {
- theme.rect = proxy()->subControlRect(CC_ScrollBar, option, SC_ScrollBarSubPage, widget);
- partId = flags & State_Horizontal ? SBP_UPPERTRACKHORZ : SBP_UPPERTRACKVERT;
- if (!(flags & State_Enabled))
- stateId = SCRBS_DISABLED;
- else if (scrollbar->activeSubControls & SC_ScrollBarSubPage && (scrollbar->state & State_Sunken))
- stateId = SCRBS_PRESSED;
- else if (scrollbar->activeSubControls & SC_ScrollBarSubPage && (scrollbar->state & State_MouseOver))
- stateId = SCRBS_HOT;
- else
- stateId = SCRBS_NORMAL;
- theme.partId = partId;
- theme.stateId = stateId;
- d->drawBackground(theme);
- }
- if (sub & SC_ScrollBarAddPage) {
- theme.rect = proxy()->subControlRect(CC_ScrollBar, option, SC_ScrollBarAddPage, widget);
- partId = flags & State_Horizontal ? SBP_LOWERTRACKHORZ : SBP_LOWERTRACKVERT;
- if (!(flags & State_Enabled))
- stateId = SCRBS_DISABLED;
- else if (scrollbar->activeSubControls & SC_ScrollBarAddPage && (scrollbar->state & State_Sunken))
- stateId = SCRBS_PRESSED;
- else if (scrollbar->activeSubControls & SC_ScrollBarAddPage && (scrollbar->state & State_MouseOver))
- stateId = SCRBS_HOT;
- else
- stateId = SCRBS_NORMAL;
- theme.partId = partId;
- theme.stateId = stateId;
- d->drawBackground(theme);
- }
- if (sub & SC_ScrollBarSlider) {
- theme.rect = proxy()->subControlRect(CC_ScrollBar, option, SC_ScrollBarSlider, widget);
- if (!(flags & State_Enabled))
- stateId = SCRBS_DISABLED;
- else if (scrollbar->activeSubControls & SC_ScrollBarSlider && (scrollbar->state & State_Sunken))
- stateId = SCRBS_PRESSED;
- else if (scrollbar->activeSubControls & SC_ScrollBarSlider && (scrollbar->state & State_MouseOver))
- stateId = SCRBS_HOT;
- else if (option->state & State_MouseOver)
- stateId = SCRBS_HOVER;
- else
- stateId = SCRBS_NORMAL;
-
- // Draw handle
- 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();
- }
- }
- }
- }
- }
- break;
-#if QT_CONFIG(spinbox)
- case CC_SpinBox:
- if (const QStyleOptionSpinBox *sb = qstyleoption_cast<const QStyleOptionSpinBox *>(option))
- {
- XPThemeData theme(widget, painter, QWindowsXPStylePrivate::SpinTheme);
- if (sb->frame && (sub & SC_SpinBoxFrame)) {
- partId = EP_EDITBORDER_NOSCROLL;
- if (!(flags & State_Enabled))
- stateId = ETS_DISABLED;
- else if (flags & State_MouseOver)
- stateId = ETS_HOT;
- else if (flags & State_HasFocus)
- stateId = ETS_SELECTED;
- else
- stateId = ETS_NORMAL;
-
- XPThemeData ftheme(widget, painter,
- QWindowsXPStylePrivate::EditTheme,
- partId, stateId, r);
- // The spinbox in Windows QStyle is drawn with frameless QLineEdit inside it
- // That however breaks with QtQuickControls where this results in transparent
- // spinbox background, so if there's no "widget" passed (QtQuickControls case),
- // let ftheme.noContent be false, which fixes the spinbox rendering in QQC
- ftheme.noContent = (widget != nullptr);
- d->drawBackground(ftheme);
- }
- if (sub & SC_SpinBoxUp) {
- theme.rect = proxy()->subControlRect(CC_SpinBox, option, SC_SpinBoxUp, widget).adjusted(0, 0, 0, 1);
- partId = SPNP_UP;
- if (!(sb->stepEnabled & QAbstractSpinBox::StepUpEnabled) || !(flags & State_Enabled))
- stateId = UPS_DISABLED;
- else if (sb->activeSubControls == SC_SpinBoxUp && (sb->state & State_Sunken))
- stateId = UPS_PRESSED;
- else if (sb->activeSubControls == SC_SpinBoxUp && (sb->state & State_MouseOver))
- stateId = UPS_HOT;
- else
- stateId = UPS_NORMAL;
- theme.partId = partId;
- theme.stateId = stateId;
- d->drawBackground(theme);
- }
- if (sub & SC_SpinBoxDown) {
- theme.rect = proxy()->subControlRect(CC_SpinBox, option, SC_SpinBoxDown, widget);
- partId = SPNP_DOWN;
- if (!(sb->stepEnabled & QAbstractSpinBox::StepDownEnabled) || !(flags & State_Enabled))
- stateId = DNS_DISABLED;
- else if (sb->activeSubControls == SC_SpinBoxDown && (sb->state & State_Sunken))
- stateId = DNS_PRESSED;
- else if (sb->activeSubControls == SC_SpinBoxDown && (sb->state & State_MouseOver))
- stateId = DNS_HOT;
- else
- stateId = DNS_NORMAL;
- theme.partId = partId;
- theme.stateId = stateId;
- d->drawBackground(theme);
- }
- }
- break;
-#endif // QT_CONFIG(spinbox)
- default:
- QWindowsXPStyle::drawComplexControl(control, option, painter, widget);
- break;
- }
-}
-
-/*!
- \internal
- */
-QSize QWindowsVistaStyle::sizeFromContents(ContentsType type, const QStyleOption *option,
- const QSize &size, const QWidget *widget) const
-{
- if (!QWindowsVistaStylePrivate::useVista())
- return QWindowsStyle::sizeFromContents(type, option, size, widget);
-
- QSize sz(size);
- switch (type) {
- case CT_MenuItem:
- sz = QWindowsXPStyle::sizeFromContents(type, option, size, widget);
- int minimumHeight;
- {
- XPThemeData theme(widget, nullptr,
- QWindowsXPStylePrivate::MenuTheme,
- MENU_POPUPCHECKBACKGROUND, MBI_HOT);
- XPThemeData themeSize = theme;
- themeSize.partId = MENU_POPUPCHECK;
- themeSize.stateId = 0;
- const QSizeF size = themeSize.size() * QWindowsStylePrivate::nativeMetricScaleFactor(widget);
- const QMarginsF margins = themeSize.margins() * QWindowsStylePrivate::nativeMetricScaleFactor(widget);
- minimumHeight = qMax(qRound(size.height() + margins.bottom() + margins.top()), sz.height());
- sz.rwidth() += qRound(size.width() + margins.left() + margins.right());
- }
-
- if (const QStyleOptionMenuItem *menuitem = qstyleoption_cast<const QStyleOptionMenuItem *>(option)) {
- if (menuitem->menuItemType != QStyleOptionMenuItem::Separator)
- sz.setHeight(minimumHeight);
- }
- return sz;
-#if QT_CONFIG(menubar)
- case CT_MenuBarItem:
- if (!sz.isEmpty())
- sz += QSize(windowsItemHMargin * 5 + 1, 5);
- return sz;
-#endif
- case CT_ItemViewItem:
- sz = QWindowsXPStyle::sizeFromContents(type, option, size, widget);
- sz.rheight() += 2;
- return sz;
- case CT_SpinBox:
- {
- //Spinbox adds frame twice
- sz = QWindowsStyle::sizeFromContents(type, option, size, widget);
- int border = proxy()->pixelMetric(PM_SpinBoxFrameWidth, option, widget);
- sz -= QSize(2*border, 2*border);
- }
- return sz;
- case CT_HeaderSection:
- {
- // When there is a sort indicator it adds to the width but it is shown
- // above the text natively and not on the side
- if (QStyleOptionHeader *hdr = qstyleoption_cast<QStyleOptionHeader *>(const_cast<QStyleOption *>(option))) {
- QStyleOptionHeader::SortIndicator sortInd = hdr->sortIndicator;
- hdr->sortIndicator = QStyleOptionHeader::None;
- sz = QWindowsXPStyle::sizeFromContents(type, hdr, size, widget);
- hdr->sortIndicator = sortInd;
- return sz;
- }
- break;
- }
- default:
- break;
- }
- return QWindowsXPStyle::sizeFromContents(type, option, size, widget);
-}
-
-/*!
- \internal
- */
-QRect QWindowsVistaStyle::subElementRect(SubElement element, const QStyleOption *option, const QWidget *widget) const
-{
- if (!QWindowsVistaStylePrivate::useVista())
- return QWindowsStyle::subElementRect(element, option, widget);
-
- QRect rect = QWindowsXPStyle::subElementRect(element, option, widget);
- switch (element) {
-
- case SE_PushButtonContents:
- if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(option)) {
- MARGINS borderSize;
- const HTHEME theme = OpenThemeData(widget ? QWindowsVistaStylePrivate::winId(widget) : nullptr, L"Button");
- if (theme) {
- int stateId = PBS_NORMAL;
- if (!(option->state & State_Enabled))
- stateId = PBS_DISABLED;
- else if (option->state & State_Sunken)
- stateId = PBS_PRESSED;
- else if (option->state & State_MouseOver)
- stateId = PBS_HOT;
- else if (btn->features & QStyleOptionButton::DefaultButton)
- stateId = PBS_DEFAULTED;
-
- int border = proxy()->pixelMetric(PM_DefaultFrameWidth, btn, widget);
- rect = option->rect.adjusted(border, border, -border, -border);
-
- if (SUCCEEDED(GetThemeMargins(theme, nullptr, BP_PUSHBUTTON, stateId, TMT_CONTENTMARGINS, nullptr, &borderSize))) {
- rect.adjust(borderSize.cxLeftWidth, borderSize.cyTopHeight,
- -borderSize.cxRightWidth, -borderSize.cyBottomHeight);
- rect = visualRect(option->direction, option->rect, rect);
- }
- }
- }
- break;
-
- case SE_HeaderArrow:
- {
- QRect r = rect;
- int h = option->rect.height();
- int w = option->rect.width();
- int x = option->rect.x();
- int y = option->rect.y();
- int margin = proxy()->pixelMetric(QStyle::PM_HeaderMargin, option, widget);
-
- XPThemeData theme(widget, nullptr,
- QWindowsXPStylePrivate::HeaderTheme,
- HP_HEADERSORTARROW, HSAS_SORTEDDOWN, option->rect);
-
- int arrowWidth = 13;
- int arrowHeight = 5;
- if (theme.isValid()) {
- const QSizeF size = theme.size() * QWindowsStylePrivate::nativeMetricScaleFactor(widget);
- if (!size.isEmpty()) {
- arrowWidth = qRound(size.width());
- arrowHeight = qRound(size.height());
- }
- }
- if (option->state & State_Horizontal) {
- r.setRect(x + w/2 - arrowWidth/2, y , arrowWidth, arrowHeight);
- } else {
- int vert_size = w / 2;
- r.setRect(x + 5, y + h - margin * 2 - vert_size,
- w - margin * 2 - 5, vert_size);
- }
- rect = visualRect(option->direction, option->rect, r);
- }
- break;
-
- case SE_HeaderLabel:
- {
- int margin = proxy()->pixelMetric(QStyle::PM_HeaderMargin, option, widget);
- QRect r = option->rect;
- r.setRect(option->rect.x() + margin, option->rect.y() + margin,
- option->rect.width() - margin * 2, option->rect.height() - margin * 2);
- if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(option)) {
- // Subtract width needed for arrow, if there is one
- if (header->sortIndicator != QStyleOptionHeader::None) {
- if (!(option->state & State_Horizontal)) //horizontal arrows are positioned on top
- r.setHeight(r.height() - (option->rect.width() / 2) - (margin * 2));
- }
- }
- rect = visualRect(option->direction, option->rect, r);
- }
- break;
- case SE_ProgressBarContents:
- rect = QCommonStyle::subElementRect(SE_ProgressBarGroove, option, widget);
- break;
- case SE_ItemViewItemDecoration:
- if (qstyleoption_cast<const QStyleOptionViewItem *>(option))
- rect.adjust(-2, 0, 2, 0);
- break;
- case SE_ItemViewItemFocusRect:
- if (const QStyleOptionViewItem *vopt = qstyleoption_cast<const QStyleOptionViewItem *>(option)) {
- QRect textRect = subElementRect(QStyle::SE_ItemViewItemText, option, widget);
- QRect displayRect = subElementRect(QStyle::SE_ItemViewItemDecoration, option, widget);
- if (!vopt->icon.isNull())
- rect = textRect.united(displayRect);
- else
- rect = textRect;
- rect = rect.adjusted(1, 0, -1, 0);
- }
- break;
- default:
- break;
- }
- return rect;
-}
-
-
-/*
- This function is used by subControlRect to check if a button
- should be drawn for the given subControl given a set of window flags.
-*/
-static bool buttonVisible(const QStyle::SubControl sc, const QStyleOptionTitleBar *tb){
-
- bool isMinimized = tb->titleBarState & Qt::WindowMinimized;
- bool isMaximized = tb->titleBarState & Qt::WindowMaximized;
- const auto flags = tb->titleBarFlags;
- bool retVal = false;
- switch (sc) {
- case QStyle::SC_TitleBarContextHelpButton:
- if (flags & Qt::WindowContextHelpButtonHint)
- retVal = true;
- break;
- case QStyle::SC_TitleBarMinButton:
- if (!isMinimized && (flags & Qt::WindowMinimizeButtonHint))
- retVal = true;
- break;
- case QStyle::SC_TitleBarNormalButton:
- if (isMinimized && (flags & Qt::WindowMinimizeButtonHint))
- retVal = true;
- else if (isMaximized && (flags & Qt::WindowMaximizeButtonHint))
- retVal = true;
- break;
- case QStyle::SC_TitleBarMaxButton:
- if (!isMaximized && (flags & Qt::WindowMaximizeButtonHint))
- retVal = true;
- break;
- case QStyle::SC_TitleBarShadeButton:
- if (!isMinimized && flags & Qt::WindowShadeButtonHint)
- retVal = true;
- break;
- case QStyle::SC_TitleBarUnshadeButton:
- if (isMinimized && flags & Qt::WindowShadeButtonHint)
- retVal = true;
- break;
- case QStyle::SC_TitleBarCloseButton:
- if (flags & Qt::WindowSystemMenuHint)
- retVal = true;
- break;
- case QStyle::SC_TitleBarSysMenu:
- if (flags & Qt::WindowSystemMenuHint)
- retVal = true;
- break;
- default :
- retVal = true;
- }
- return retVal;
-}
-
-
-/*! \internal */
-int QWindowsVistaStyle::styleHint(StyleHint hint, const QStyleOption *option, const QWidget *widget,
- QStyleHintReturn *returnData) const
-{
- QWindowsVistaStylePrivate *d = const_cast<QWindowsVistaStylePrivate*>(d_func());
- int ret = 0;
- switch (hint) {
- case SH_MessageBox_CenterButtons:
- ret = false;
- break;
- case SH_ToolTip_Mask:
- if (option) {
- if (QStyleHintReturnMask *mask = qstyleoption_cast<QStyleHintReturnMask*>(returnData)) {
- ret = true;
- XPThemeData themeData(widget, nullptr,
- QWindowsXPStylePrivate::ToolTipTheme,
- TTP_STANDARD, TTSS_NORMAL, option->rect);
- mask->region = d->region(themeData);
- }
- }
- break;
- case SH_Table_GridLineColor:
- if (option)
- ret = int(option->palette.color(QPalette::Base).darker(118).rgba());
- else
- ret = -1;
- break;
- case SH_Header_ArrowAlignment:
- ret = Qt::AlignTop | Qt::AlignHCenter;
- break;
- default:
- ret = QWindowsXPStyle::styleHint(hint, option, widget, returnData);
- break;
- }
- return ret;
-}
-
-
-/*!
- \internal
- */
-QRect QWindowsVistaStyle::subControlRect(ComplexControl control, const QStyleOptionComplex *option,
- SubControl subControl, const QWidget *widget) const
-{
- if (!QWindowsVistaStylePrivate::useVista())
- return QWindowsStyle::subControlRect(control, option, subControl, widget);
-
- QRect rect = QWindowsXPStyle::subControlRect(control, option, subControl, widget);
- switch (control) {
-#if QT_CONFIG(combobox)
- case CC_ComboBox:
- if (const QStyleOptionComboBox *cb = qstyleoption_cast<const QStyleOptionComboBox *>(option)) {
- const int x = cb->rect.x(), y = cb->rect.y(), wi = cb->rect.width(), he = cb->rect.height();
- const int margin = cb->frame ? 3 : 0;
- const int bmarg = cb->frame ? 2 : 0;
- const int arrowWidth = qRound(QStyleHelper::dpiScaled(16, option));
- const int arrowButtonWidth = bmarg + arrowWidth;
- const int xpos = x + wi - arrowButtonWidth;
-
- switch (subControl) {
- case SC_ComboBoxFrame:
- rect = cb->rect;
- break;
- case SC_ComboBoxArrow:
- rect.setRect(xpos, y , arrowButtonWidth, he);
- break;
- case SC_ComboBoxEditField:
- rect.setRect(x + margin, y + margin, wi - 2 * margin - arrowWidth, he - 2 * margin);
- break;
- case SC_ComboBoxListBoxPopup:
- rect = cb->rect;
- break;
- default:
- break;
- }
- rect = visualRect(cb->direction, cb->rect, rect);
- return rect;
- }
- break;
-#endif // QT_CONFIG(combobox)
- case CC_TitleBar:
- if (const QStyleOptionTitleBar *tb = qstyleoption_cast<const QStyleOptionTitleBar *>(option)) {
- if (!buttonVisible(subControl, tb))
- return rect;
- const qreal factor = QWindowsStylePrivate::nativeMetricScaleFactor(widget);
- const bool isToolTitle = false;
- const int height = tb->rect.height();
- const int width = tb->rect.width();
- const int buttonWidth =
- qRound(qreal(GetSystemMetrics(SM_CXSIZE)) * factor - QStyleHelper::dpiScaled(4, option));
-
- const int frameWidth = proxy()->pixelMetric(PM_MdiSubWindowFrameWidth, option, widget);
- const bool sysmenuHint = (tb->titleBarFlags & Qt::WindowSystemMenuHint) != 0;
- const bool minimizeHint = (tb->titleBarFlags & Qt::WindowMinimizeButtonHint) != 0;
- const bool maximizeHint = (tb->titleBarFlags & Qt::WindowMaximizeButtonHint) != 0;
- const bool contextHint = (tb->titleBarFlags & Qt::WindowContextHelpButtonHint) != 0;
- const bool shadeHint = (tb->titleBarFlags & Qt::WindowShadeButtonHint) != 0;
-
- switch (subControl) {
- case SC_TitleBarLabel:
- rect = QRect(frameWidth, 0, width - (buttonWidth + frameWidth + 10), height);
- if (isToolTitle) {
- if (sysmenuHint) {
- rect.adjust(0, 0, int(-buttonWidth - 3 * factor), 0);
- }
- if (minimizeHint || maximizeHint)
- rect.adjust(0, 0, int(-buttonWidth - 2 * factor), 0);
- } else {
- if (sysmenuHint) {
- const int leftOffset = int(height - 8 * factor);
- rect.adjust(leftOffset, 0, 0, int(4 * factor));
- }
- if (minimizeHint)
- rect.adjust(0, 0, int(-buttonWidth - 2 * factor), 0);
- if (maximizeHint)
- rect.adjust(0, 0, int(-buttonWidth - 2 * factor), 0);
- if (contextHint)
- rect.adjust(0, 0, int(-buttonWidth - 2 * factor), 0);
- if (shadeHint)
- rect.adjust(0, 0, int(-buttonWidth - 2 * factor), 0);
- }
- rect.translate(0, int(2 * factor));
- rect = visualRect(option->direction, option->rect, rect);
- break;
- case SC_TitleBarSysMenu:
- {
- const int controlTop = int(6 * factor);
- const int controlHeight = int(height - controlTop - 3 * factor);
- int iconExtent = proxy()->pixelMetric(PM_SmallIconSize);
- QSize iconSize = tb->icon.actualSize(QSize(iconExtent, iconExtent));
- if (tb->icon.isNull())
- iconSize = QSize(controlHeight, controlHeight);
- int hPad = (controlHeight - iconSize.height())/2;
- int vPad = (controlHeight - iconSize.width())/2;
- rect = QRect(frameWidth + hPad, controlTop + vPad, iconSize.width(), iconSize.height());
- rect.translate(0, int(3 * factor));
- rect = visualRect(option->direction, option->rect, rect);
- }
- break;
- default:
- break;
- }
- }
- break;
- default:
- break;
- }
- return rect;
-}
-
-/*!
- \internal
- */
-QStyle::SubControl QWindowsVistaStyle::hitTestComplexControl(ComplexControl control, const QStyleOptionComplex *option,
- const QPoint &pos, const QWidget *widget) const
-{
- if (!QWindowsVistaStylePrivate::useVista()) {
- return QWindowsStyle::hitTestComplexControl(control, option, pos, widget);
- }
- return QWindowsXPStyle::hitTestComplexControl(control, option, pos, widget);
-}
-
-int QWindowsVistaStylePrivate::fixedPixelMetric(QStyle::PixelMetric pm)
-{
- switch (pm) {
- case QStyle::PM_DockWidgetTitleBarButtonMargin:
- return 5;
- case QStyle::PM_ScrollBarSliderMin:
- return 18;
- case QStyle::PM_MenuHMargin:
- case QStyle::PM_MenuVMargin:
- return 0;
- case QStyle::PM_MenuPanelWidth:
- return 3;
- default:
- break;
- }
- return QWindowsVistaStylePrivate::InvalidMetric;
-}
-
-/*!
- \internal
- */
-int QWindowsVistaStyle::pixelMetric(PixelMetric metric, const QStyleOption *option, const QWidget *widget) const
-{
- if (!QWindowsVistaStylePrivate::useVista())
- return QWindowsStyle::pixelMetric(metric, option, widget);
-
- int ret = QWindowsVistaStylePrivate::fixedPixelMetric(metric);
- if (ret != QWindowsStylePrivate::InvalidMetric)
- return int(QStyleHelper::dpiScaled(ret, option));
-
- return QWindowsXPStyle::pixelMetric(metric, option, widget);
-}
-
-/*!
- \internal
- */
-QPalette QWindowsVistaStyle::standardPalette() const
-{
- return QWindowsXPStyle::standardPalette();
-}
-
-/*!
- \internal
- */
-void QWindowsVistaStyle::polish(QApplication *app)
-{
- QWindowsXPStyle::polish(app);
-}
-
-/*!
- \internal
- */
-void QWindowsVistaStyle::polish(QWidget *widget)
-{
- QWindowsXPStyle::polish(widget);
-#if QT_CONFIG(lineedit)
- if (qobject_cast<QLineEdit*>(widget))
- widget->setAttribute(Qt::WA_Hover);
- else
-#endif // QT_CONFIG(lineedit)
- if (qobject_cast<QGroupBox*>(widget))
- widget->setAttribute(Qt::WA_Hover);
-#if QT_CONFIG(commandlinkbutton)
- else if (qobject_cast<QCommandLinkButton*>(widget)) {
- QFont buttonFont = widget->font();
- buttonFont.setFamily(QLatin1String("Segoe UI"));
- widget->setFont(buttonFont);
- }
-#endif // QT_CONFIG(commandlinkbutton)
- else if (widget->inherits("QTipLabel")){
- //note that since tooltips are not reused
- //we do not have to care about unpolishing
- widget->setContentsMargins(3, 0, 4, 0);
- COLORREF bgRef;
- HTHEME theme = OpenThemeData(widget ? QWindowsVistaStylePrivate::winId(widget) : nullptr, L"TOOLTIP");
- if (theme && SUCCEEDED(GetThemeColor(theme, TTP_STANDARD, TTSS_NORMAL, TMT_TEXTCOLOR, &bgRef))) {
- QColor textColor = QColor::fromRgb(bgRef);
- QPalette pal;
- pal.setColor(QPalette::All, QPalette::ToolTipText, textColor);
- widget->setPalette(pal);
- }
- } else if (qobject_cast<QMessageBox *> (widget)) {
- widget->setAttribute(Qt::WA_StyledBackground);
-#if QT_CONFIG(dialogbuttonbox)
- QDialogButtonBox *buttonBox = widget->findChild<QDialogButtonBox *>(QLatin1String("qt_msgbox_buttonbox"));
- if (buttonBox)
- buttonBox->setContentsMargins(0, 9, 0, 0);
-#endif
- }
-#if QT_CONFIG(inputdialog)
- else if (qobject_cast<QInputDialog *> (widget)) {
- widget->setAttribute(Qt::WA_StyledBackground);
-#if QT_CONFIG(dialogbuttonbox)
- QDialogButtonBox *buttonBox = widget->findChild<QDialogButtonBox *>(QLatin1String("qt_inputdlg_buttonbox"));
- if (buttonBox)
- buttonBox->setContentsMargins(0, 9, 0, 0);
-#endif
- }
-#endif // QT_CONFIG(inputdialog)
- else if (QTreeView *tree = qobject_cast<QTreeView *> (widget)) {
- tree->viewport()->setAttribute(Qt::WA_Hover);
- }
- else if (QListView *list = qobject_cast<QListView *> (widget)) {
- list->viewport()->setAttribute(Qt::WA_Hover);
- }
-}
-
-/*!
- \internal
- */
-void QWindowsVistaStyle::unpolish(QWidget *widget)
-{
- QWindowsXPStyle::unpolish(widget);
-
- QWindowsVistaStylePrivate *d = d_func();
-
- d->stopAnimation(widget);
-
-#if QT_CONFIG(lineedit)
- if (qobject_cast<QLineEdit*>(widget))
- widget->setAttribute(Qt::WA_Hover, false);
- else
-#endif // QT_CONFIG(lineedit)
- if (qobject_cast<QGroupBox*>(widget))
- widget->setAttribute(Qt::WA_Hover, false);
- else if (qobject_cast<QMessageBox *> (widget)) {
- widget->setAttribute(Qt::WA_StyledBackground, false);
-#if QT_CONFIG(dialogbuttonbox)
- QDialogButtonBox *buttonBox = widget->findChild<QDialogButtonBox *>(QLatin1String("qt_msgbox_buttonbox"));
- if (buttonBox)
- buttonBox->setContentsMargins(0, 0, 0, 0);
-#endif
- }
-#if QT_CONFIG(inputdialog)
- else if (qobject_cast<QInputDialog *> (widget)) {
- widget->setAttribute(Qt::WA_StyledBackground, false);
-#if QT_CONFIG(dialogbuttonbox)
- QDialogButtonBox *buttonBox = widget->findChild<QDialogButtonBox *>(QLatin1String("qt_inputdlg_buttonbox"));
- if (buttonBox)
- buttonBox->setContentsMargins(0, 0, 0, 0);
-#endif
- }
-#endif // QT_CONFIG(inputdialog)
- else if (QTreeView *tree = qobject_cast<QTreeView *> (widget)) {
- tree->viewport()->setAttribute(Qt::WA_Hover, false);
- }
-#if QT_CONFIG(commandlinkbutton)
- else if (qobject_cast<QCommandLinkButton*>(widget)) {
- QFont font = QApplication::font("QCommandLinkButton");
- QFont widgetFont = widget->font();
- widgetFont.setFamily(font.family()); //Only family set by polish
- widget->setFont(widgetFont);
- }
-#endif // QT_CONFIG(commandlinkbutton)
-}
-
-
-/*!
- \internal
- */
-void QWindowsVistaStyle::unpolish(QApplication *app)
-{
- QWindowsXPStyle::unpolish(app);
-}
-
-/*!
- \internal
- */
-void QWindowsVistaStyle::polish(QPalette &pal)
-{
- QWindowsStyle::polish(pal);
- pal.setBrush(QPalette::AlternateBase, pal.base().color().darker(104));
-}
-
-/*!
- \internal
- */
-QPixmap QWindowsVistaStyle::standardPixmap(StandardPixmap standardPixmap, const QStyleOption *option,
- const QWidget *widget) const
-{
- if (!QWindowsVistaStylePrivate::useVista()) {
- return QWindowsStyle::standardPixmap(standardPixmap, option, widget);
- }
- return QWindowsXPStyle::standardPixmap(standardPixmap, option, widget);
-}
-
-QWindowsVistaStylePrivate::QWindowsVistaStylePrivate() :
- QWindowsXPStylePrivate()
-{
-}
-
-bool QWindowsVistaStylePrivate::transitionsEnabled() const
-{
- BOOL animEnabled = false;
- if (SystemParametersInfo(SPI_GETCLIENTAREAANIMATION, 0, &animEnabled, 0))
- {
- if (animEnabled)
- return true;
- }
- return false;
-}
-
-/*!
-\reimp
-*/
-QIcon QWindowsVistaStyle::standardIcon(StandardPixmap standardIcon,
- const QStyleOption *option,
- const QWidget *widget) const
-{
- if (!QWindowsVistaStylePrivate::useVista()) {
- return QWindowsStyle::standardIcon(standardIcon, option, widget);
- }
-
- QWindowsVistaStylePrivate *d = const_cast<QWindowsVistaStylePrivate *>(d_func());
- switch(standardIcon) {
- case SP_CommandLink:
- {
- XPThemeData theme(nullptr, nullptr,
- QWindowsXPStylePrivate::ButtonTheme,
- BP_COMMANDLINKGLYPH, CMDLGS_NORMAL);
- if (theme.isValid()) {
- const QSize size = (theme.size() * QWindowsStylePrivate::nativeMetricScaleFactor(widget)).toSize();
- QIcon linkGlyph;
- QPixmap pm(size);
- pm.fill(Qt::transparent);
- QPainter p(&pm);
- theme.painter = &p;
- theme.rect = QRect(QPoint(0, 0), size);
- d->drawBackground(theme);
- linkGlyph.addPixmap(pm, QIcon::Normal, QIcon::Off); // Normal
- pm.fill(Qt::transparent);
-
- theme.stateId = CMDLGS_PRESSED;
- d->drawBackground(theme);
- linkGlyph.addPixmap(pm, QIcon::Normal, QIcon::On); // Pressed
- pm.fill(Qt::transparent);
-
- theme.stateId = CMDLGS_HOT;
- d->drawBackground(theme);
- linkGlyph.addPixmap(pm, QIcon::Active, QIcon::Off); // Hover
- pm.fill(Qt::transparent);
-
- theme.stateId = CMDLGS_DISABLED;
- d->drawBackground(theme);
- linkGlyph.addPixmap(pm, QIcon::Disabled, QIcon::Off); // Disabled
- return linkGlyph;
- }
- }
- break;
- default:
- break;
- }
- return QWindowsXPStyle::standardIcon(standardIcon, option, widget);
-}
-
-QT_END_NAMESPACE
diff --git a/src/plugins/styles/windowsvista/qwindowsvistastyle_p_p.h b/src/plugins/styles/windowsvista/qwindowsvistastyle_p_p.h
deleted file mode 100644
index c1d764a60e..0000000000
--- a/src/plugins/styles/windowsvista/qwindowsvistastyle_p_p.h
+++ /dev/null
@@ -1,204 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtWidgets module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and 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 QWINDOWSVISTASTYLE_P_P_H
-#define QWINDOWSVISTASTYLE_P_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists for the convenience
-// of qapplication_*.cpp, qwidget*.cpp and qfiledialog.cpp. This header
-// file may change from version to version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <QtWidgets/private/qtwidgetsglobal_p.h>
-#include "qwindowsvistastyle_p.h"
-#include "qwindowsxpstyle_p_p.h"
-#include <private/qstyleanimation_p.h>
-#include <private/qpaintengine_raster_p.h>
-#include <qpaintengine.h>
-#include <qwidget.h>
-#include <qapplication.h>
-#include <qpixmapcache.h>
-#include <qstyleoption.h>
-#if QT_CONFIG(pushbutton)
-#include <qpushbutton.h>
-#endif
-#include <qradiobutton.h>
-#if QT_CONFIG(lineedit)
-#include <qlineedit.h>
-#endif
-#include <qgroupbox.h>
-#if QT_CONFIG(toolbutton)
-#include <qtoolbutton.h>
-#endif
-#if QT_CONFIG(spinbox)
-#include <qspinbox.h>
-#endif
-#if QT_CONFIG(toolbar)
-#include <qtoolbar.h>
-#endif
-#if QT_CONFIG(combobox)
-#include <qcombobox.h>
-#endif
-#if QT_CONFIG(scrollbar)
-#include <qscrollbar.h>
-#endif
-#if QT_CONFIG(progressbar)
-#include <qprogressbar.h>
-#endif
-#if QT_CONFIG(dockwidget)
-#include <qdockwidget.h>
-#endif
-#if QT_CONFIG(listview)
-#include <qlistview.h>
-#endif
-#if QT_CONFIG(treeview)
-#include <qtreeview.h>
-#endif
-#include <qtextedit.h>
-#include <qmessagebox.h>
-#if QT_CONFIG(dialogbuttonbox)
-#include <qdialogbuttonbox.h>
-#endif
-#include <qinputdialog.h>
-#if QT_CONFIG(tableview)
-#include <qtableview.h>
-#endif
-#include <qdatetime.h>
-#if QT_CONFIG(commandlinkbutton)
-#include <qcommandlinkbutton.h>
-#endif
-
-QT_BEGIN_NAMESPACE
-
-#if !defined(SCHEMA_VERIFY_VSSYM32)
-#define TMT_ANIMATIONDURATION 5006
-#define TMT_TRANSITIONDURATIONS 6000
-#define EP_EDITBORDER_NOSCROLL 6
-#define EP_EDITBORDER_HVSCROLL 9
-#define EP_BACKGROUND 3
-#define EBS_NORMAL 1
-#define EBS_HOT 2
-#define EBS_DISABLED 3
-#define EBS_READONLY 5
-#define PBS_DEFAULTED_ANIMATING 6
-#define MBI_NORMAL 1
-#define MBI_HOT 2
-#define MBI_PUSHED 3
-#define MBI_DISABLED 4
-#define MB_ACTIVE 1
-#define MB_INACTIVE 2
-#define PP_FILL 5
-#define PP_FILLVERT 6
-#define PP_MOVEOVERLAY 8
-#define PP_MOVEOVERLAYVERT 10
-#define MENU_BARBACKGROUND 7
-#define MENU_BARITEM 8
-#define MENU_POPUPCHECK 11
-#define MENU_POPUPCHECKBACKGROUND 12
-#define MENU_POPUPGUTTER 13
-#define MENU_POPUPITEM 14
-#define MENU_POPUPBORDERS 10
-#define MENU_POPUPSEPARATOR 15
-#define MC_CHECKMARKNORMAL 1
-#define MC_CHECKMARKDISABLED 2
-#define MC_BULLETNORMAL 3
-#define MC_BULLETDISABLED 4
-#define ABS_UPHOVER 17
-#define ABS_DOWNHOVER 18
-#define ABS_LEFTHOVER 19
-#define ABS_RIGHTHOVER 20
-#define CP_DROPDOWNBUTTONRIGHT 6
-#define CP_DROPDOWNBUTTONLEFT 7
-#define SCRBS_HOVER 5
-#define TVP_HOTGLYPH 4
-#define SPI_GETCLIENTAREAANIMATION 0x1042
-#define TDLG_PRIMARYPANEL 1
-#define TDLG_SECONDARYPANEL 8
-#endif
-
-class QWindowsVistaAnimation : public QBlendStyleAnimation
-{
- Q_OBJECT
-public:
- QWindowsVistaAnimation(Type type, QObject *target) : QBlendStyleAnimation(type, target) { }
-
- bool isUpdateNeeded() const override;
- void paint(QPainter *painter, const QStyleOption *option);
-};
-
-
-// Handles state transition animations
-class QWindowsVistaTransition : public QWindowsVistaAnimation
-{
- Q_OBJECT
-public:
- QWindowsVistaTransition(QObject *target) : QWindowsVistaAnimation(Transition, target) {}
-};
-
-
-// Handles pulse animations (default buttons)
-class QWindowsVistaPulse: public QWindowsVistaAnimation
-{
- Q_OBJECT
-public:
- QWindowsVistaPulse(QObject *target) : QWindowsVistaAnimation(Pulse, target) {}
-};
-
-
-class QWindowsVistaStylePrivate : public QWindowsXPStylePrivate
-{
- Q_DECLARE_PUBLIC(QWindowsVistaStyle)
-
-public:
- QWindowsVistaStylePrivate();
-
- static int fixedPixelMetric(QStyle::PixelMetric pm);
- static inline bool useVista();
- bool transitionsEnabled() const;
-};
-
-QT_END_NAMESPACE
-
-#endif // QWINDOWSVISTASTYLE_P_P_H
diff --git a/src/plugins/styles/windowsvista/qwindowsxpstyle.cpp b/src/plugins/styles/windowsvista/qwindowsxpstyle.cpp
deleted file mode 100644
index 9d143da169..0000000000
--- a/src/plugins/styles/windowsvista/qwindowsxpstyle.cpp
+++ /dev/null
@@ -1,4202 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtWidgets module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and 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 "qwindowsxpstyle_p.h"
-#include "qwindowsxpstyle_p_p.h"
-
-#include <private/qobject_p.h>
-#include <private/qpaintengine_raster_p.h>
-#include <private/qapplication_p.h>
-#include <qpa/qplatformnativeinterface.h>
-#include <private/qstylehelper_p.h>
-#include <private/qwidget_p.h>
-#include <qpainter.h>
-#include <qpaintengine.h>
-#include <qwidget.h>
-#include <qbackingstore.h>
-#include <qapplication.h>
-#include <qpixmapcache.h>
-#include <private/qapplication_p.h>
-#include <qpa/qplatformnativeinterface.h>
-
-#if QT_CONFIG(toolbutton)
-#include <qtoolbutton.h>
-#endif
-#if QT_CONFIG(tabbar)
-#include <qtabbar.h>
-#endif
-#if QT_CONFIG(combobox)
-#include <qcombobox.h>
-#endif
-#if QT_CONFIG(scrollbar)
-#include <qscrollbar.h>
-#endif
-#include <qheaderview.h>
-#if QT_CONFIG(spinbox)
-#include <qspinbox.h>
-#endif
-#if QT_CONFIG(listview)
-#include <qlistview.h>
-#endif
-#if QT_CONFIG(stackedwidget)
-#include <qstackedwidget.h>
-#endif
-#if QT_CONFIG(pushbutton)
-#include <qpushbutton.h>
-#endif
-#if QT_CONFIG(toolbar)
-#include <qtoolbar.h>
-#endif
-#include <qlabel.h>
-#include <qvarlengtharray.h>
-#include <qdebug.h>
-
-#include <algorithm>
-
-QT_BEGIN_NAMESPACE
-
-// General const values
-static const int windowsItemFrame = 2; // menu item frame width
-static const int windowsItemHMargin = 3; // menu item hor text margin
-static const int windowsItemVMargin = 0; // menu item ver text margin
-static const int windowsArrowHMargin = 6; // arrow horizontal margin
-static const int windowsRightBorder = 12; // right border on windows
-
-// External function calls
-extern Q_WIDGETS_EXPORT HDC qt_win_display_dc();
-extern QRegion qt_region_from_HRGN(HRGN rgn);
-
-// Theme names matching the QWindowsXPStylePrivate::Theme enumeration.
-static const wchar_t *themeNames[QWindowsXPStylePrivate::NThemes] =
-{
- L"BUTTON", L"COMBOBOX", L"EDIT", L"HEADER", L"LISTVIEW",
- L"MENU", L"PROGRESS", L"REBAR", L"SCROLLBAR", L"SPIN",
- L"TAB", L"TASKDIALOG", L"TOOLBAR", L"TOOLTIP", L"TRACKBAR",
- L"TREEVIEW", L"WINDOW", L"STATUS", L"TREEVIEW"
-};
-
-static inline QBackingStore *backingStoreForWidget(const QWidget *widget)
-{
- if (QBackingStore *backingStore = widget->backingStore())
- return backingStore;
- if (const QWidget *topLevel = widget->nativeParentWidget())
- if (QBackingStore *topLevelBackingStore = topLevel->backingStore())
- return topLevelBackingStore;
- return nullptr;
-}
-
-static inline HDC hdcForWidgetBackingStore(const QWidget *widget)
-{
- if (QBackingStore *backingStore = backingStoreForWidget(widget)) {
- QPlatformNativeInterface *nativeInterface = QGuiApplication::platformNativeInterface();
- if (nativeInterface)
- return static_cast<HDC>(nativeInterface->nativeResourceForBackingStore(QByteArrayLiteral("getDC"), backingStore));
- }
- return nullptr;
-}
-
-// Theme data helper ------------------------------------------------------------------------------
-/* \internal
- Returns \c true if the themedata is valid for use.
-*/
-bool XPThemeData::isValid()
-{
- return QWindowsXPStylePrivate::useXP() && theme >= 0 && handle();
-}
-
-
-/* \internal
- Returns the theme engine handle to the specific class.
- If the handle hasn't been opened before, it opens the data, and
- adds it to a static map, for caching.
-*/
-HTHEME XPThemeData::handle()
-{
- if (!QWindowsXPStylePrivate::useXP())
- return nullptr;
-
- if (!htheme)
- htheme = QWindowsXPStylePrivate::createTheme(theme, QWindowsXPStylePrivate::winId(widget));
- return htheme;
-}
-
-/* \internal
- Converts a QRect to the native RECT structure.
-*/
-RECT XPThemeData::toRECT(const QRect &qr)
-{
- RECT r;
- r.left = qr.x();
- r.right = qr.x() + qr.width();
- r.top = qr.y();
- r.bottom = qr.y() + qr.height();
- return r;
-}
-
-/* \internal
- Returns the native region of a part, if the part is considered
- transparent. The region is scaled to the parts size (rect).
-*/
-HRGN XPThemeData::mask(QWidget *widget)
-{
- if (!IsThemeBackgroundPartiallyTransparent(handle(), partId, stateId))
- return nullptr;
-
- HRGN hrgn;
- HDC dc = nullptr;
- if (widget)
- dc = hdcForWidgetBackingStore(widget);
- RECT nativeRect = toRECT(rect);
- GetThemeBackgroundRegion(handle(), dc, partId, stateId, &nativeRect, &hrgn);
- return hrgn;
-}
-
-// QWindowsXPStylePrivate -------------------------------------------------------------------------
-// Static initializations
-HWND QWindowsXPStylePrivate::m_vistaTreeViewHelper = nullptr;
-HTHEME QWindowsXPStylePrivate::m_themes[NThemes];
-bool QWindowsXPStylePrivate::use_xp = false;
-QBasicAtomicInt QWindowsXPStylePrivate::ref = Q_BASIC_ATOMIC_INITIALIZER(-1); // -1 based refcounting
-
-static void qt_add_rect(HRGN &winRegion, QRect r)
-{
- HRGN rgn = CreateRectRgn(r.left(), r.top(), r.x() + r.width(), r.y() + r.height());
- if (rgn) {
- HRGN dest = CreateRectRgn(0,0,0,0);
- int result = CombineRgn(dest, winRegion, rgn, RGN_OR);
- if (result) {
- DeleteObject(winRegion);
- winRegion = dest;
- }
- DeleteObject(rgn);
- }
-}
-
-static HRGN qt_hrgn_from_qregion(const QRegion &region)
-{
- HRGN hRegion = CreateRectRgn(0,0,0,0);
- if (region.rectCount() == 1) {
- qt_add_rect(hRegion, region.boundingRect());
- return hRegion;
- }
- for (const QRect &rect : region)
- qt_add_rect(hRegion, rect);
- return hRegion;
-}
-
-/* \internal
- Checks if the theme engine can/should be used, or if we should
- fall back to Windows style.
-*/
-bool QWindowsXPStylePrivate::useXP(bool update)
-{
- if (update) {
- use_xp = IsThemeActive() && (IsAppThemed() || !QCoreApplication::instance())
- && !QWindowsStylePrivate::isDarkMode();
- }
- return use_xp;
-}
-
-/* \internal
- Handles refcounting, and queries the theme engine for usage.
-*/
-void QWindowsXPStylePrivate::init(bool force)
-{
- if (ref.ref() && !force)
- return;
- if (!force) // -1 based atomic refcounting
- ref.ref();
-
- useXP(true);
- std::fill(m_themes, m_themes + NThemes, nullptr);
-}
-
-/* \internal
- Cleans up all static data.
-*/
-void QWindowsXPStylePrivate::cleanup(bool force)
-{
- if(bufferBitmap) {
- if (bufferDC && nullBitmap)
- SelectObject(bufferDC, nullBitmap);
- DeleteObject(bufferBitmap);
- bufferBitmap = nullptr;
- }
-
- if(bufferDC)
- DeleteDC(bufferDC);
- bufferDC = nullptr;
-
- if (ref.deref() && !force)
- return;
- if (!force) // -1 based atomic refcounting
- ref.deref();
-
- use_xp = false;
- cleanupHandleMap();
-}
-
-/* In order to obtain the correct VistaTreeViewTheme (arrows for PE_IndicatorBranch),
- * we need to set the windows "explorer" theme explicitly on a native
- * window and open the "TREEVIEW" theme handle passing its window handle
- * in order to get Vista-style item view themes (particulary drawBackground()
- * for selected items needs this).
- * We invoke a service of the native Windows interface to create
- * a non-visible window handle, open the theme on it and insert it into
- * the cache so that it is found by XPThemeData::handle() first.
- */
-
-static inline HWND createTreeViewHelperWindow()
-{
- if (QPlatformNativeInterface *ni = QGuiApplication::platformNativeInterface()) {
- void *hwnd = nullptr;
- void *wndProc = reinterpret_cast<void *>(DefWindowProc);
- if (QMetaObject::invokeMethod(ni, "createMessageWindow", Qt::DirectConnection,
- Q_RETURN_ARG(void*, hwnd),
- Q_ARG(QString, QStringLiteral("QTreeViewThemeHelperWindowClass")),
- Q_ARG(QString, QStringLiteral("QTreeViewThemeHelperWindow")),
- Q_ARG(void*, wndProc)) && hwnd) {
- return reinterpret_cast<HWND>(hwnd);
- }
- }
- return nullptr;
-}
-
-bool QWindowsXPStylePrivate::initVistaTreeViewTheming()
-{
- if (m_vistaTreeViewHelper)
- return true;
-
- m_vistaTreeViewHelper = createTreeViewHelperWindow();
- if (!m_vistaTreeViewHelper) {
- qWarning("Unable to create the treeview helper window.");
- return false;
- }
- if (FAILED(SetWindowTheme(m_vistaTreeViewHelper, L"explorer", nullptr))) {
- qErrnoWarning("SetWindowTheme() failed.");
- cleanupVistaTreeViewTheming();
- return false;
- }
- return true;
-}
-
-void QWindowsXPStylePrivate::cleanupVistaTreeViewTheming()
-{
- if (m_vistaTreeViewHelper) {
- DestroyWindow(m_vistaTreeViewHelper);
- m_vistaTreeViewHelper = nullptr;
- }
-}
-
-/* \internal
- Closes all open theme data handles to ensure that we don't leak
- resources, and that we don't refere to old handles when for
- example the user changes the theme style.
-*/
-void QWindowsXPStylePrivate::cleanupHandleMap()
-{
- for (auto &theme : m_themes) {
- if (theme) {
- CloseThemeData(theme);
- theme = nullptr;
- }
- }
- QWindowsXPStylePrivate::cleanupVistaTreeViewTheming();
-}
-
-HTHEME QWindowsXPStylePrivate::createTheme(int theme, HWND hwnd)
-{
- if (Q_UNLIKELY(theme < 0 || theme >= NThemes || !hwnd)) {
- qWarning("Invalid parameters #%d, %p", theme, hwnd);
- return nullptr;
- }
- if (!m_themes[theme]) {
- const wchar_t *name = themeNames[theme];
- if (theme == VistaTreeViewTheme && QWindowsXPStylePrivate::initVistaTreeViewTheming())
- hwnd = QWindowsXPStylePrivate::m_vistaTreeViewHelper;
- m_themes[theme] = OpenThemeData(hwnd, name);
- if (Q_UNLIKELY(!m_themes[theme]))
- qErrnoWarning("OpenThemeData() failed for theme %d (%s).",
- theme, qPrintable(themeName(theme)));
- }
- return m_themes[theme];
-}
-
-QString QWindowsXPStylePrivate::themeName(int theme)
-{
- return theme >= 0 && theme < NThemes ?
- QString::fromWCharArray(themeNames[theme]) :
- QString();
-}
-
-bool QWindowsXPStylePrivate::isItemViewDelegateLineEdit(const QWidget *widget)
-{
- if (!widget)
- return false;
- const QWidget *parent1 = widget->parentWidget();
- // Exlude dialogs or other toplevels parented on item views.
- if (!parent1 || parent1->isWindow())
- return false;
- const QWidget *parent2 = parent1->parentWidget();
- return parent2 && widget->inherits("QLineEdit")
- && parent2->inherits("QAbstractItemView");
-}
-
-// Returns whether base color is set for this widget
-bool QWindowsXPStylePrivate::isLineEditBaseColorSet(const QStyleOption *option, const QWidget *widget)
-{
- uint resolveMask = option->palette.resolve();
- if (widget) {
- // Since spin box includes a line edit we need to resolve the palette mask also from
- // the parent, as while the color is always correct on the palette supplied by panel,
- // the mask can still be empty. If either mask specifies custom base color, use that.
-#if QT_CONFIG(spinbox)
- if (const QAbstractSpinBox *spinbox = qobject_cast<QAbstractSpinBox*>(widget->parentWidget()))
- resolveMask |= spinbox->palette().resolve();
-#endif // QT_CONFIG(spinbox)
- }
- return (resolveMask & (1 << QPalette::Base)) != 0;
-}
-
-/*! \internal
- This function will always return a valid window handle, and might
- create a limbo widget to do so.
- We often need a window handle to for example open theme data, so
- this function ensures that we get one.
-*/
-HWND QWindowsXPStylePrivate::winId(const QWidget *widget)
-{
- if (widget)
- if (const HWND hwnd = QApplicationPrivate::getHWNDForWidget(const_cast<QWidget *>(widget)))
- return hwnd;
-
- // Find top level with native window (there might be dialogs that do not have one).
- const auto allWindows = QGuiApplication::allWindows();
- for (const QWindow *window : allWindows) {
- if (window->isTopLevel() && window->type() != Qt::Desktop && window->handle() != nullptr)
- return reinterpret_cast<HWND>(window->winId());
- }
-
- return GetDesktopWindow();
-}
-
-/*! \internal
- Returns a native buffer (DIB section) of at least the size of
- ( \a x , \a y ). The buffer has a 32 bit depth, to not lose
- the alpha values on proper alpha-pixmaps.
-*/
-HBITMAP QWindowsXPStylePrivate::buffer(int w, int h)
-{
- // If we already have a HBITMAP which is of adequate size, just return that
- if (bufferBitmap) {
- if (bufferW >= w && bufferH >= h)
- return bufferBitmap;
- // Not big enough, discard the old one
- if (bufferDC && nullBitmap)
- SelectObject(bufferDC, nullBitmap);
- DeleteObject(bufferBitmap);
- bufferBitmap = nullptr;
- }
-
- w = qMax(bufferW, w);
- h = qMax(bufferH, h);
-
- if (!bufferDC) {
- HDC displayDC = GetDC(nullptr);
- bufferDC = CreateCompatibleDC(displayDC);
- ReleaseDC(nullptr, displayDC);
- }
-
- // Define the header
- BITMAPINFO bmi;
- memset(&bmi, 0, sizeof(bmi));
- bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
- bmi.bmiHeader.biWidth = w;
- bmi.bmiHeader.biHeight = -h;
- bmi.bmiHeader.biPlanes = 1;
- bmi.bmiHeader.biBitCount = 32;
- bmi.bmiHeader.biCompression = BI_RGB;
-
- // Create the pixmap
- bufferPixels = nullptr;
- bufferBitmap = CreateDIBSection(bufferDC, &bmi, DIB_RGB_COLORS, reinterpret_cast<void **>(&bufferPixels), nullptr, 0);
- GdiFlush();
- nullBitmap = static_cast<HBITMAP>(SelectObject(bufferDC, bufferBitmap));
-
- if (Q_UNLIKELY(!bufferBitmap)) {
- qErrnoWarning("QWindowsXPStylePrivate::buffer(%dx%d), CreateDIBSection() failed.", w, h);
- bufferW = 0;
- bufferH = 0;
- return nullptr;
- }
- if (Q_UNLIKELY(!bufferPixels)) {
- qErrnoWarning("QWindowsXPStylePrivate::buffer(%dx%d), CreateDIBSection() did not allocate pixel data.", w, h);
- bufferW = 0;
- bufferH = 0;
- return nullptr;
- }
- bufferW = w;
- bufferH = h;
-#ifdef DEBUG_XP_STYLE
- qDebug("Creating new dib section (%d, %d)", w, h);
-#endif
- return bufferBitmap;
-}
-
-/*! \internal
- Returns \c true if the part contains any transparency at all. This does
- not indicate what kind of transparency we're dealing with. It can be
- - Alpha transparency
- - Masked transparency
-*/
-bool QWindowsXPStylePrivate::isTransparent(XPThemeData &themeData)
-{
- return IsThemeBackgroundPartiallyTransparent(themeData.handle(), themeData.partId,
- themeData.stateId);
-}
-
-
-/*! \internal
- Returns a QRegion of the region of the part
-*/
-QRegion QWindowsXPStylePrivate::region(XPThemeData &themeData)
-{
- HRGN hRgn = nullptr;
- const qreal factor = QWindowsStylePrivate::nativeMetricScaleFactor(themeData.widget);
- RECT rect = themeData.toRECT(QRect(themeData.rect.topLeft() / factor, themeData.rect.size() / factor));
- if (!SUCCEEDED(GetThemeBackgroundRegion(themeData.handle(), bufferHDC(), themeData.partId,
- themeData.stateId, &rect, &hRgn))) {
- return QRegion();
- }
-
- HRGN dest = CreateRectRgn(0, 0, 0, 0);
- const bool success = CombineRgn(dest, hRgn, nullptr, RGN_COPY) != ERROR;
-
- QRegion region;
-
- if (success) {
- const auto numBytes = GetRegionData(dest, 0, nullptr);
- if (numBytes == 0)
- return QRegion();
-
- char *buf = new (std::nothrow) char[numBytes];
- if (!buf)
- return QRegion();
-
- RGNDATA *rd = reinterpret_cast<RGNDATA*>(buf);
- if (GetRegionData(dest, numBytes, rd) == 0) {
- delete [] buf;
- return QRegion();
- }
-
- RECT *r = reinterpret_cast<RECT*>(rd->Buffer);
- for (uint i = 0; i < rd->rdh.nCount; ++i) {
- QRect rect;
- rect.setCoords(int(r->left * factor), int(r->top * factor), int((r->right - 1) * factor), int((r->bottom - 1) * factor));
- ++r;
- region |= rect;
- }
-
- delete [] buf;
- }
-
- DeleteObject(hRgn);
- DeleteObject(dest);
-
- return region;
-}
-
-/*! \internal
- Returns \c true if the native doublebuffer contains pixels with
- varying alpha value.
-*/
-bool QWindowsXPStylePrivate::hasAlphaChannel(const QRect &rect)
-{
- const int startX = rect.left();
- const int startY = rect.top();
- const int w = rect.width();
- const int h = rect.height();
-
- int firstAlpha = -1;
- for (int y = startY; y < h/2; ++y) {
- auto buffer = reinterpret_cast<const DWORD *>(bufferPixels) + (y * bufferW);
- for (int x = startX; x < w; ++x, ++buffer) {
- int alpha = (*buffer) >> 24;
- if (firstAlpha == -1)
- firstAlpha = alpha;
- else if (alpha != firstAlpha)
- return true;
- }
- }
- return false;
-}
-
-/*! \internal
- When the theme engine paints both a true alpha pixmap and a glyph
- into our buffer, the glyph might not contain a proper alpha value.
- The rule of thumb for premultiplied pixmaps is that the color
- values of a pixel can never be higher than the alpha values, so
- we use this to our advantage here, and fix all instances where
- this occures.
-*/
-bool QWindowsXPStylePrivate::fixAlphaChannel(const QRect &rect)
-{
- const int startX = rect.left();
- const int startY = rect.top();
- const int w = rect.width();
- const int h = rect.height();
- bool hasFixedAlphaValue = false;
-
- for (int y = startY; y < h; ++y) {
- auto buffer = reinterpret_cast<DWORD *>(bufferPixels) + (y * bufferW);
- for (int x = startX; x < w; ++x, ++buffer) {
- uint pixel = *buffer;
- int alpha = qAlpha(pixel);
- if (qRed(pixel) > alpha || qGreen(pixel) > alpha || qBlue(pixel) > alpha) {
- *buffer |= 0xff000000;
- hasFixedAlphaValue = true;
- }
- }
- }
- return hasFixedAlphaValue;
-}
-
-/*! \internal
- Swaps the alpha values on certain pixels:
- 0xFF?????? -> 0x00??????
- 0x00?????? -> 0xFF??????
- Used to determin the mask of a non-alpha transparent pixmap in
- the native doublebuffer, and swap the alphas so we may paint
- the image as a Premultiplied QImage with drawImage(), and obtain
- the mask transparency.
-*/
-bool QWindowsXPStylePrivate::swapAlphaChannel(const QRect &rect, bool allPixels)
-{
- const int startX = rect.left();
- const int startY = rect.top();
- const int w = rect.width();
- const int h = rect.height();
- bool valueChange = false;
-
- // Flip the alphas, so that 255-alpha pixels are 0, and 0-alpha are 255.
- for (int y = startY; y < h; ++y) {
- auto buffer = reinterpret_cast<DWORD *>(bufferPixels) + (y * bufferW);
- for (int x = startX; x < w; ++x, ++buffer) {
- if (allPixels) {
- *buffer |= 0xFF000000;
- continue;
- }
- unsigned int alphaValue = (*buffer) & 0xFF000000;
- if (alphaValue == 0xFF000000) {
- *buffer = 0;
- valueChange = true;
- } else if (alphaValue == 0) {
- *buffer |= 0xFF000000;
- valueChange = true;
- }
- }
- }
- return valueChange;
-}
-
-enum TransformType { SimpleTransform, HighDpiScalingTransform, ComplexTransform };
-
-static inline TransformType transformType(const QTransform &transform, qreal devicePixelRatio)
-{
- if (transform.type() <= QTransform::TxTranslate)
- return SimpleTransform;
- if (transform.type() > QTransform::TxScale)
- return ComplexTransform;
- return qFuzzyCompare(transform.m11(), devicePixelRatio)
- && qFuzzyCompare(transform.m22(), devicePixelRatio)
- ? HighDpiScalingTransform : ComplexTransform;
-}
-
-// QTBUG-60571: Exclude known fully opaque theme parts which produce values
-// invalid in ARGB32_Premultiplied (for example, 0x00ffffff).
-static inline bool isFullyOpaque(const XPThemeData &themeData)
-{
- return themeData.theme == QWindowsXPStylePrivate::TaskDialogTheme && themeData.partId == TDLG_PRIMARYPANEL;
-}
-
-/*! \internal
- Main theme drawing function.
- Determines the correct lowlevel drawing method depending on several
- factors.
- Use drawBackgroundThruNativeBuffer() if:
- - Painter does not have an HDC
- - Theme part is flipped (mirrored horizontally)
- else use drawBackgroundDirectly().
- \note drawBackgroundThruNativeBuffer() can return false for large
- sizes due to buffer()/CreateDIBSection() failing.
-*/
-bool QWindowsXPStylePrivate::drawBackground(XPThemeData &themeData, qreal correctionFactor)
-{
- if (themeData.rect.isEmpty())
- return true;
-
- QPainter *painter = themeData.painter;
- Q_ASSERT_X(painter != nullptr, "QWindowsXPStylePrivate::drawBackground()", "Trying to draw a theme part without a painter");
- if (!painter || !painter->isActive())
- return false;
-
- painter->save();
-
- // Access paintDevice via engine since the painter may
- // return the clip device which can still be a widget device in case of grabWidget().
-
- bool translucentToplevel = false;
- const QPaintDevice *paintDevice = painter->device();
- const qreal aditionalDevicePixelRatio = themeData.widget ? themeData.widget->devicePixelRatioF() : qreal(1);
- if (paintDevice->devType() == QInternal::Widget) {
- const QWidget *window = static_cast<const QWidget *>(paintDevice)->window();
- translucentToplevel = window->testAttribute(Qt::WA_TranslucentBackground);
- }
-
- const TransformType tt = transformType(painter->deviceTransform(), aditionalDevicePixelRatio);
-
- bool canDrawDirectly = false;
- if (themeData.widget && painter->opacity() == 1.0 && !themeData.rotate
- && !isFullyOpaque(themeData)
- && tt != ComplexTransform && !themeData.mirrorVertically
- && !translucentToplevel) {
- // Draw on backing store DC only for real widgets or backing store images.
- const QPaintDevice *enginePaintDevice = painter->paintEngine()->paintDevice();
- switch (enginePaintDevice->devType()) {
- case QInternal::Widget:
- canDrawDirectly = true;
- break;
- case QInternal::Image:
- // Ensure the backing store has received as resize and is initialized.
- if (QBackingStore *bs = backingStoreForWidget(themeData.widget))
- if (bs->size().isValid() && bs->paintDevice() == enginePaintDevice)
- canDrawDirectly = true;
- }
- }
-
- const HDC dc = canDrawDirectly ? hdcForWidgetBackingStore(themeData.widget) : nullptr;
- const bool result = dc && qFuzzyCompare(correctionFactor, qreal(1))
- ? drawBackgroundDirectly(dc, themeData, aditionalDevicePixelRatio)
- : drawBackgroundThruNativeBuffer(themeData, aditionalDevicePixelRatio, correctionFactor);
- painter->restore();
- return result;
-}
-
-static inline QRectF scaleRect(const QRectF &r, qreal factor)
-{
- return r.isValid() && factor > 1
- ? QRectF(r.topLeft() * factor, r.size() * factor)
- : r;
-}
-
-static QRegion scaleRegion(const QRegion &region, qreal factor)
-{
- if (region.isEmpty() || qFuzzyCompare(factor, qreal(1)))
- return region;
- QRegion result;
- for (const QRect &rect : region)
- result += QRectF(QPointF(rect.topLeft()) * factor, QSizeF(rect.size() * factor)).toRect();
- return result;
-}
-
-/*! \internal
- This function draws the theme parts directly to the paintengines HDC.
- Do not use this if you need to perform other transformations on the
- resulting data.
-*/
-bool QWindowsXPStylePrivate::drawBackgroundDirectly(HDC dc, XPThemeData &themeData, qreal additionalDevicePixelRatio)
-{
- QPainter *painter = themeData.painter;
-
- const auto &deviceTransform = painter->deviceTransform();
- const QPointF redirectionDelta(deviceTransform.dx(), deviceTransform.dy());
- const QRect area = scaleRect(QRectF(themeData.rect), additionalDevicePixelRatio).translated(redirectionDelta).toRect();
-
- QRegion sysRgn = painter->paintEngine()->systemClip();
- if (sysRgn.isEmpty())
- sysRgn = area;
- else
- sysRgn &= area;
- if (painter->hasClipping())
- sysRgn &= scaleRegion(painter->clipRegion(), additionalDevicePixelRatio).translated(redirectionDelta.toPoint());
- HRGN hrgn = qt_hrgn_from_qregion(sysRgn);
- SelectClipRgn(dc, hrgn);
-
-#ifdef DEBUG_XP_STYLE
- printf("---[ DIRECT PAINTING ]------------------> Name(%-10s) Part(%d) State(%d)\n",
- qPrintable(themeData.name), themeData.partId, themeData.stateId);
- showProperties(themeData);
-#endif
-
- RECT drawRECT = themeData.toRECT(area);
- DTBGOPTS drawOptions;
- memset(&drawOptions, 0, sizeof(drawOptions));
- drawOptions.dwSize = sizeof(drawOptions);
- drawOptions.rcClip = themeData.toRECT(sysRgn.boundingRect());
- drawOptions.dwFlags = DTBG_CLIPRECT
- | (themeData.noBorder ? DTBG_OMITBORDER : 0)
- | (themeData.noContent ? DTBG_OMITCONTENT : 0)
- | (themeData.mirrorHorizontally ? DTBG_MIRRORDC : 0);
-
- const HRESULT result = DrawThemeBackgroundEx(themeData.handle(), dc, themeData.partId, themeData.stateId, &(drawRECT), &drawOptions);
- SelectClipRgn(dc, nullptr);
- DeleteObject(hrgn);
- return SUCCEEDED(result);
-}
-
-/*! \internal
- This function uses a secondary Native doublebuffer for painting parts.
- It should only be used when the painteengine doesn't provide a proper
- HDC for direct painting (e.g. when doing a grabWidget(), painting to
- other pixmaps etc), or when special transformations are needed (e.g.
- flips (horizonal mirroring only, vertical are handled by the theme
- engine).
-
- \a correctionFactor is an additional factor used to scale up controls
- that are too small on High DPI screens, as has been observed for
- WP_MDICLOSEBUTTON, WP_MDIRESTOREBUTTON, WP_MDIMINBUTTON (QTBUG-75927).
-*/
-bool QWindowsXPStylePrivate::drawBackgroundThruNativeBuffer(XPThemeData &themeData,
- qreal additionalDevicePixelRatio,
- qreal correctionFactor)
-{
- QPainter *painter = themeData.painter;
- QRectF rectF = scaleRect(QRectF(themeData.rect), additionalDevicePixelRatio);
-
- if ((themeData.rotate + 90) % 180 == 0) { // Catch 90,270,etc.. degree flips.
- rectF = QRectF(0, 0, rectF.height(), rectF.width());
- }
- rectF.moveTo(0, 0);
-
- const bool hasCorrectionFactor = !qFuzzyCompare(correctionFactor, qreal(1));
- QRect rect = rectF.toRect();
- QRect drawRect = hasCorrectionFactor
- ? QRectF(rectF.topLeft() / correctionFactor, rectF.size() / correctionFactor).toRect() : rect;
- int partId = themeData.partId;
- int stateId = themeData.stateId;
- int w = rect.width();
- int h = rect.height();
-
- // Values initialized later, either from cached values, or from function calls
- AlphaChannelType alphaType = UnknownAlpha;
- bool stateHasData = true; // We assume so;
- bool hasAlpha = false;
- bool partIsTransparent;
- bool potentialInvalidAlpha;
-
- QString pixmapCacheKey = QStringLiteral("$qt_xp_");
- pixmapCacheKey.append(themeName(themeData.theme));
- pixmapCacheKey.append(QLatin1Char('p'));
- pixmapCacheKey.append(QString::number(partId));
- pixmapCacheKey.append(QLatin1Char('s'));
- pixmapCacheKey.append(QString::number(stateId));
- pixmapCacheKey.append(QLatin1Char('s'));
- pixmapCacheKey.append(themeData.noBorder ? QLatin1Char('0') : QLatin1Char('1'));
- pixmapCacheKey.append(QLatin1Char('b'));
- pixmapCacheKey.append(themeData.noContent ? QLatin1Char('0') : QLatin1Char('1'));
- pixmapCacheKey.append(QString::number(w));
- pixmapCacheKey.append(QLatin1Char('w'));
- pixmapCacheKey.append(QString::number(h));
- pixmapCacheKey.append(QLatin1Char('h'));
- pixmapCacheKey.append(QString::number(additionalDevicePixelRatio));
- pixmapCacheKey.append(QLatin1Char('d'));
- if (hasCorrectionFactor) {
- pixmapCacheKey.append(QLatin1Char('c'));
- pixmapCacheKey.append(QString::number(correctionFactor));
- }
-
- QPixmap cachedPixmap;
- ThemeMapKey key(themeData);
- ThemeMapData data = alphaCache.value(key);
-
- bool haveCachedPixmap = false;
- bool isCached = data.dataValid;
- if (isCached) {
- partIsTransparent = data.partIsTransparent;
- hasAlpha = data.hasAlphaChannel;
- alphaType = data.alphaType;
- potentialInvalidAlpha = data.hadInvalidAlpha;
-
- haveCachedPixmap = QPixmapCache::find(pixmapCacheKey, &cachedPixmap);
-
-#ifdef DEBUG_XP_STYLE
- char buf[25];
- ::sprintf(buf, "+ Pixmap(%3d, %3d) ]", w, h);
- printf("---[ CACHED %s--------> Name(%-10s) Part(%d) State(%d)\n",
- haveCachedPixmap ? buf : "]-------------------",
- qPrintable(themeData.name), themeData.partId, themeData.stateId);
-#endif
- } else {
- // Not cached, so get values from Theme Engine
- BOOL tmt_borderonly = false;
- COLORREF tmt_transparentcolor = 0x0;
- PROPERTYORIGIN proporigin = PO_NOTFOUND;
- GetThemeBool(themeData.handle(), themeData.partId, themeData.stateId, TMT_BORDERONLY, &tmt_borderonly);
- GetThemeColor(themeData.handle(), themeData.partId, themeData.stateId, TMT_TRANSPARENTCOLOR, &tmt_transparentcolor);
- GetThemePropertyOrigin(themeData.handle(), themeData.partId, themeData.stateId, TMT_CAPTIONMARGINS, &proporigin);
-
- partIsTransparent = isTransparent(themeData);
-
- potentialInvalidAlpha = false;
- GetThemePropertyOrigin(themeData.handle(), themeData.partId, themeData.stateId, TMT_GLYPHTYPE, &proporigin);
- if (proporigin == PO_PART || proporigin == PO_STATE) {
- int tmt_glyphtype = GT_NONE;
- GetThemeEnumValue(themeData.handle(), themeData.partId, themeData.stateId, TMT_GLYPHTYPE, &tmt_glyphtype);
- potentialInvalidAlpha = partIsTransparent && tmt_glyphtype == GT_IMAGEGLYPH;
- }
-
-#ifdef DEBUG_XP_STYLE
- printf("---[ NOT CACHED ]-----------------------> Name(%-10s) Part(%d) State(%d)\n",
- qPrintable(themeData.name), themeData.partId, themeData.stateId);
- printf("-->partIsTransparen = %d\n", partIsTransparent);
- printf("-->potentialInvalidAlpha = %d\n", potentialInvalidAlpha);
- showProperties(themeData);
-#endif
- }
- bool wasAlphaSwapped = false;
- bool wasAlphaFixed = false;
-
- // OLD PSDK Workaround ------------------------------------------------------------------------
- // See if we need extra clipping for the older PSDK, which does
- // not have a DrawThemeBackgroundEx function for DTGB_OMITBORDER
- // and DTGB_OMITCONTENT
- bool addBorderContentClipping = false;
- QRegion extraClip;
- QRect area = drawRect;
- if (themeData.noBorder || themeData.noContent) {
- extraClip = area;
- // We are running on a system where the uxtheme.dll does not have
- // the DrawThemeBackgroundEx function, so we need to clip away
- // borders or contents manually.
-
- int borderSize = 0;
- PROPERTYORIGIN origin = PO_NOTFOUND;
- GetThemePropertyOrigin(themeData.handle(), themeData.partId, themeData.stateId, TMT_BORDERSIZE, &origin);
- GetThemeInt(themeData.handle(), themeData.partId, themeData.stateId, TMT_BORDERSIZE, &borderSize);
- borderSize *= additionalDevicePixelRatio;
-
- // Clip away border region
- if ((origin == PO_CLASS || origin == PO_PART || origin == PO_STATE) && borderSize > 0) {
- if (themeData.noBorder) {
- extraClip &= area;
- area = area.adjusted(-borderSize, -borderSize, borderSize, borderSize);
- }
-
- // Clip away content region
- if (themeData.noContent) {
- QRegion content = area.adjusted(borderSize, borderSize, -borderSize, -borderSize);
- extraClip ^= content;
- }
- }
- addBorderContentClipping = (themeData.noBorder | themeData.noContent);
- }
-
- QImage img;
- if (!haveCachedPixmap) { // If the pixmap is not cached, generate it! -------------------------
- if (!buffer(drawRect.width(), drawRect.height())) // Ensure a buffer of at least (w, h) in size
- return false;
- HDC dc = bufferHDC();
-
- // Clear the buffer
- if (alphaType != NoAlpha) {
- // Consider have separate "memset" function for small chunks for more speedup
- memset(bufferPixels, 0x00, bufferW * drawRect.height() * 4);
- }
-
- // Difference between area and rect
- int dx = area.x() - drawRect.x();
- int dy = area.y() - drawRect.y();
-
- // Adjust so painting rect starts from Origo
- rect.moveTo(0,0);
- area.moveTo(dx,dy);
- DTBGOPTS drawOptions;
- drawOptions.dwSize = sizeof(drawOptions);
- drawOptions.rcClip = themeData.toRECT(rect);
- drawOptions.dwFlags = DTBG_CLIPRECT
- | (themeData.noBorder ? DTBG_OMITBORDER : 0)
- | (themeData.noContent ? DTBG_OMITCONTENT : 0);
-
- // Drawing the part into the backing store
- RECT wRect(themeData.toRECT(area));
- DrawThemeBackgroundEx(themeData.handle(), dc, themeData.partId, themeData.stateId, &wRect, &drawOptions);
-
- // If not cached, analyze the buffer data to figure
- // out alpha type, and if it contains data
- if (!isCached) {
- // SHORTCUT: If the part's state has no data, cache it for NOOP later
- if (!stateHasData) {
- memset(static_cast<void *>(&data), 0, sizeof(data));
- data.dataValid = true;
- alphaCache.insert(key, data);
- return true;
- }
- hasAlpha = hasAlphaChannel(rect);
- if (!hasAlpha && partIsTransparent)
- potentialInvalidAlpha = true;
-#if defined(DEBUG_XP_STYLE) && 1
- dumpNativeDIB(drawRect.width(), drawRect.height());
-#endif
- }
-
- // Fix alpha values, if needed
- if (potentialInvalidAlpha)
- wasAlphaFixed = fixAlphaChannel(rect);
-
- QImage::Format format;
- if ((partIsTransparent && !wasAlphaSwapped) || (!partIsTransparent && hasAlpha)) {
- format = QImage::Format_ARGB32_Premultiplied;
- alphaType = RealAlpha;
- } else if (wasAlphaSwapped) {
- format = QImage::Format_ARGB32_Premultiplied;
- alphaType = MaskAlpha;
- } else {
- format = QImage::Format_RGB32;
- // The image data we got from the theme engine does not have any transparency,
- // thus the alpha channel is set to 0.
- // However, Format_RGB32 requires the alpha part to be set to 0xff, thus
- // we must flip it from 0x00 to 0xff
- swapAlphaChannel(rect, true);
- alphaType = NoAlpha;
- }
-#if defined(DEBUG_XP_STYLE) && 1
- printf("Image format is: %s\n", alphaType == RealAlpha ? "Real Alpha" : alphaType == MaskAlpha ? "Masked Alpha" : "No Alpha");
-#endif
- img = QImage(bufferPixels, bufferW, bufferH, format);
- if (hasCorrectionFactor)
- img = img.scaled(w, h, Qt::KeepAspectRatio, Qt::SmoothTransformation);
- img.setDevicePixelRatio(additionalDevicePixelRatio);
- }
-
- // Blitting backing store
- bool useRegion = partIsTransparent && !hasAlpha && !wasAlphaSwapped;
-
- QRegion newRegion;
- QRegion oldRegion;
- if (useRegion) {
- newRegion = region(themeData);
- oldRegion = painter->clipRegion();
- painter->setClipRegion(newRegion);
-#if defined(DEBUG_XP_STYLE) && 0
- printf("Using region:\n");
- for (const QRect &r : newRegion)
- printf(" (%d, %d, %d, %d)\n", r.x(), r.y(), r.right(), r.bottom());
-#endif
- }
-
- if (addBorderContentClipping)
- painter->setClipRegion(scaleRegion(extraClip, 1.0 / additionalDevicePixelRatio), Qt::IntersectClip);
-
- if (!themeData.mirrorHorizontally && !themeData.mirrorVertically && !themeData.rotate) {
- if (!haveCachedPixmap)
- painter->drawImage(themeData.rect, img, rect);
- else
- painter->drawPixmap(themeData.rect, cachedPixmap);
- } else {
- // This is _slow_!
- // Make a copy containing only the necessary data, and mirror
- // on all wanted axes. Then draw the copy.
- // If cached, the normal pixmap is cached, instead of caching
- // all possible orientations for each part and state.
- QImage imgCopy;
- if (!haveCachedPixmap)
- imgCopy = img.copy(rect);
- else
- imgCopy = cachedPixmap.toImage();
-
- if (themeData.rotate) {
- QTransform rotMatrix;
- rotMatrix.rotate(themeData.rotate);
- imgCopy = imgCopy.transformed(rotMatrix);
- }
- if (themeData.mirrorHorizontally || themeData.mirrorVertically) {
- imgCopy = imgCopy.mirrored(themeData.mirrorHorizontally, themeData.mirrorVertically);
- }
- painter->drawImage(themeData.rect,
- imgCopy);
- }
-
- if (useRegion || addBorderContentClipping) {
- if (oldRegion.isEmpty())
- painter->setClipping(false);
- else
- painter->setClipRegion(oldRegion);
- }
-
- // Cache the pixmap to avoid expensive swapAlphaChannel() calls
- if (!haveCachedPixmap && w && h) {
- QPixmap pix = QPixmap::fromImage(img).copy(rect);
- QPixmapCache::insert(pixmapCacheKey, pix);
-#ifdef DEBUG_XP_STYLE
- printf("+++Adding pixmap to cache, size(%d, %d), wasAlphaSwapped(%d), wasAlphaFixed(%d), name(%s)\n",
- w, h, wasAlphaSwapped, wasAlphaFixed, qPrintable(pixmapCacheKey));
-#endif
- }
-
- // Add to theme part cache
- if (!isCached) {
- memset(static_cast<void *>(&data), 0, sizeof(data));
- data.dataValid = true;
- data.partIsTransparent = partIsTransparent;
- data.alphaType = alphaType;
- data.hasAlphaChannel = hasAlpha;
- data.wasAlphaSwapped = wasAlphaSwapped;
- data.hadInvalidAlpha = wasAlphaFixed;
- alphaCache.insert(key, data);
- }
- return true;
-}
-
-
-// ------------------------------------------------------------------------------------------------
-
-/*!
- \class QWindowsXPStyle
- \brief The QWindowsXPStyle class provides a Microsoft Windows XP-like look and feel.
-
- \ingroup appearance
- \inmodule QtWidgets
- \internal
-
- \warning This style is only available on the Windows XP platform
- because it makes use of Windows XP's style engine.
-
- Most of the functions are documented in the base classes
- QWindowsStyle, QCommonStyle, and QStyle, but the
- QWindowsXPStyle overloads of drawComplexControl(), drawControl(),
- drawControlMask(), drawPrimitive(), proxy()->subControlRect(), and
- sizeFromContents(), are documented here.
-
- \image qwindowsxpstyle.png
- \sa QMacStyle, QWindowsStyle, QFusionStyle
-*/
-
-/*!
- Constructs a QWindowsStyle
-*/
-QWindowsXPStyle::QWindowsXPStyle()
- : QWindowsStyle(*new QWindowsXPStylePrivate)
-{
-}
-
-/*!
- Destroys the style.
-*/
-QWindowsXPStyle::~QWindowsXPStyle() = default;
-
-/*! \reimp */
-void QWindowsXPStyle::unpolish(QApplication *app)
-{
- QWindowsStyle::unpolish(app);
-}
-
-/*! \reimp */
-void QWindowsXPStyle::polish(QApplication *app)
-{
- QWindowsStyle::polish(app);
- if (!QWindowsXPStylePrivate::useXP())
- return;
-}
-
-/*! \reimp */
-void QWindowsXPStyle::polish(QWidget *widget)
-{
- QWindowsStyle::polish(widget);
- if (!QWindowsXPStylePrivate::useXP())
- return;
-
- if (false
-#if QT_CONFIG(abstractbutton)
- || qobject_cast<QAbstractButton*>(widget)
-#endif
- || qobject_cast<QToolButton*>(widget)
- || qobject_cast<QTabBar*>(widget)
-#if QT_CONFIG(combobox)
- || qobject_cast<QComboBox*>(widget)
-#endif // QT_CONFIG(combobox)
- || qobject_cast<QScrollBar*>(widget)
- || qobject_cast<QSlider*>(widget)
- || qobject_cast<QHeaderView*>(widget)
-#if QT_CONFIG(spinbox)
- || qobject_cast<QAbstractSpinBox*>(widget)
- || qobject_cast<QSpinBox*>(widget)
-#endif // QT_CONFIG(spinbox)
- ) {
- widget->setAttribute(Qt::WA_Hover);
- }
-
-#if QT_CONFIG(rubberband)
- if (qobject_cast<QRubberBand*>(widget)) {
- widget->setWindowOpacity(0.6);
- }
-#endif
- if (qobject_cast<QStackedWidget*>(widget) &&
- qobject_cast<QTabWidget*>(widget->parent()))
- widget->parentWidget()->setAttribute(Qt::WA_ContentsPropagated);
-
- Q_D(QWindowsXPStyle);
- if (!d->hasInitColors) {
- // Get text color for group box labels
- COLORREF cref;
- XPThemeData theme(widget, nullptr, QWindowsXPStylePrivate::ButtonTheme, 0, 0);
- GetThemeColor(theme.handle(), BP_GROUPBOX, GBS_NORMAL, TMT_TEXTCOLOR, &cref);
- d->groupBoxTextColor = qRgb(GetRValue(cref), GetGValue(cref), GetBValue(cref));
- GetThemeColor(theme.handle(), BP_GROUPBOX, GBS_DISABLED, TMT_TEXTCOLOR, &cref);
- d->groupBoxTextColorDisabled = qRgb(GetRValue(cref), GetGValue(cref), GetBValue(cref));
- // Where does this color come from?
- //GetThemeColor(theme.handle(), TKP_TICS, TSS_NORMAL, TMT_COLOR, &cref);
- d->sliderTickColor = qRgb(165, 162, 148);
- d->hasInitColors = true;
- }
-}
-
-/*! \reimp */
-void QWindowsXPStyle::polish(QPalette &pal)
-{
- QWindowsStyle::polish(pal);
- pal.setBrush(QPalette::AlternateBase, pal.base().color().darker(110));
-}
-
-/*! \reimp */
-void QWindowsXPStyle::unpolish(QWidget *widget)
-{
-#if QT_CONFIG(rubberband)
- if (qobject_cast<QRubberBand*>(widget)) {
- widget->setWindowOpacity(1.0);
- }
-#endif
- Q_D(QWindowsXPStyle);
- // Unpolish of widgets is the first thing that
- // happens when a theme changes, or the theme
- // engine is turned off. So we detect it here.
- bool oldState = QWindowsXPStylePrivate::useXP();
- bool newState = QWindowsXPStylePrivate::useXP(true);
- if ((oldState != newState) && newState) {
- d->cleanup(true);
- d->init(true);
- } else {
- // Cleanup handle map, if just changing style,
- // or turning it on. In both cases the values
- // already in the map might be old (other style).
- d->cleanupHandleMap();
- }
- if (false
-#if QT_CONFIG(abstractbutton)
- || qobject_cast<QAbstractButton*>(widget)
-#endif
- || qobject_cast<QToolButton*>(widget)
- || qobject_cast<QTabBar*>(widget)
-#if QT_CONFIG(combobox)
- || qobject_cast<QComboBox*>(widget)
-#endif // QT_CONFIG(combobox)
- || qobject_cast<QScrollBar*>(widget)
- || qobject_cast<QSlider*>(widget)
- || qobject_cast<QHeaderView*>(widget)
-#if QT_CONFIG(spinbox)
- || qobject_cast<QAbstractSpinBox*>(widget)
- || qobject_cast<QSpinBox*>(widget)
-#endif // QT_CONFIG(spinbox)
- ) {
- widget->setAttribute(Qt::WA_Hover, false);
- }
- QWindowsStyle::unpolish(widget);
-}
-
-/*! \reimp */
-QRect QWindowsXPStyle::subElementRect(SubElement sr, const QStyleOption *option, const QWidget *widget) const
-{
- if (!QWindowsXPStylePrivate::useXP()) {
- return QWindowsStyle::subElementRect(sr, option, widget);
- }
-
- QRect rect(option->rect);
- switch(sr) {
- case SE_DockWidgetCloseButton:
- case SE_DockWidgetFloatButton:
- rect = QWindowsStyle::subElementRect(sr, option, widget);
- return rect.translated(0, 1);
- break;
- case SE_TabWidgetTabContents:
- if (qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(option))
- {
- rect = QWindowsStyle::subElementRect(sr, option, widget);
- if (sr == SE_TabWidgetTabContents) {
- if (const QTabWidget *tabWidget = qobject_cast<const QTabWidget *>(widget)) {
- if (tabWidget->documentMode())
- break;
- }
-
- rect.adjust(0, 0, -2, -2);
- }
- }
- break;
- case SE_TabWidgetTabBar: {
- rect = QWindowsStyle::subElementRect(sr, option, widget);
- const QStyleOptionTabWidgetFrame *twfOption =
- qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(option);
- if (twfOption && twfOption->direction == Qt::RightToLeft
- && (twfOption->shape == QTabBar::RoundedNorth
- || twfOption->shape == QTabBar::RoundedSouth))
- {
- QStyleOptionTab otherOption;
- otherOption.shape = (twfOption->shape == QTabBar::RoundedNorth
- ? QTabBar::RoundedEast : QTabBar::RoundedSouth);
- int overlap = proxy()->pixelMetric(PM_TabBarBaseOverlap, &otherOption, widget);
- int borderThickness = proxy()->pixelMetric(PM_DefaultFrameWidth, option, widget);
- rect.adjust(-overlap + borderThickness, 0, -overlap + borderThickness, 0);
- }
- break;}
-
- case SE_PushButtonContents:
- if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(option)) {
- MARGINS borderSize;
- if (widget) {
- XPThemeData buttontheme(widget, nullptr, QWindowsXPStylePrivate::ButtonTheme);
- HTHEME theme = buttontheme.handle();
- if (theme) {
- int stateId;
- if (!(option->state & State_Enabled))
- stateId = PBS_DISABLED;
- else if (option->state & State_Sunken)
- stateId = PBS_PRESSED;
- else if (option->state & State_MouseOver)
- stateId = PBS_HOT;
- else if (btn->features & QStyleOptionButton::DefaultButton)
- stateId = PBS_DEFAULTED;
- else
- stateId = PBS_NORMAL;
-
- int border = proxy()->pixelMetric(PM_DefaultFrameWidth, btn, widget);
- rect = option->rect.adjusted(border, border, -border, -border);
-
- if (SUCCEEDED(GetThemeMargins(theme, nullptr, BP_PUSHBUTTON, stateId, TMT_CONTENTMARGINS, nullptr, &borderSize))) {
- rect.adjust(borderSize.cxLeftWidth, borderSize.cyTopHeight,
- -borderSize.cxRightWidth, -borderSize.cyBottomHeight);
- rect = visualRect(option->direction, option->rect, rect);
- }
- }
- }
- }
- break;
- case SE_ProgressBarContents:
- rect = QCommonStyle::subElementRect(SE_ProgressBarGroove, option, widget);
- if (option->state & QStyle::State_Horizontal)
- rect.adjust(4, 3, -4, -3);
- else
- rect.adjust(3, 2, -3, -2);
- break;
- default:
- rect = QWindowsStyle::subElementRect(sr, option, widget);
- }
- return rect;
-}
-
-/*!
- \reimp
-*/
-void QWindowsXPStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *option, QPainter *p,
- const QWidget *widget) const
-{
- QWindowsXPStylePrivate *d = const_cast<QWindowsXPStylePrivate*>(d_func());
-
- if (!QWindowsXPStylePrivate::useXP()) {
- QWindowsStyle::drawPrimitive(pe, option, p, widget);
- return;
- }
-
- int themeNumber = -1;
- int partId = 0;
- int stateId = 0;
- QRect rect = option->rect;
- State flags = option->state;
- bool hMirrored = false;
- bool vMirrored = false;
- bool noBorder = false;
- bool noContent = false;
- int rotate = 0;
-
- switch (pe) {
- case PE_FrameTabBarBase:
- if (const QStyleOptionTabBarBase *tbb
- = qstyleoption_cast<const QStyleOptionTabBarBase *>(option)) {
- p->save();
- switch (tbb->shape) {
- case QTabBar::RoundedNorth:
- p->setPen(QPen(tbb->palette.dark(), 0));
- p->drawLine(tbb->rect.topLeft(), tbb->rect.topRight());
- break;
- case QTabBar::RoundedWest:
- p->setPen(QPen(tbb->palette.dark(), 0));
- p->drawLine(tbb->rect.left(), tbb->rect.top(), tbb->rect.left(), tbb->rect.bottom());
- break;
- case QTabBar::RoundedSouth:
- p->setPen(QPen(tbb->palette.dark(), 0));
- p->drawLine(tbb->rect.left(), tbb->rect.top(),
- tbb->rect.right(), tbb->rect.top());
- break;
- case QTabBar::RoundedEast:
- p->setPen(QPen(tbb->palette.dark(), 0));
- p->drawLine(tbb->rect.topLeft(), tbb->rect.bottomLeft());
- break;
- case QTabBar::TriangularNorth:
- case QTabBar::TriangularEast:
- case QTabBar::TriangularWest:
- case QTabBar::TriangularSouth:
- p->restore();
- QWindowsStyle::drawPrimitive(pe, option, p, widget);
- return;
- }
- p->restore();
- }
- return;
- case PE_PanelButtonBevel:
- themeNumber = QWindowsXPStylePrivate::ButtonTheme;
- partId = BP_PUSHBUTTON;
- if (!(flags & State_Enabled))
- stateId = PBS_DISABLED;
- else if ((flags & State_Sunken) || (flags & State_On))
- stateId = PBS_PRESSED;
- else if (flags & State_MouseOver)
- stateId = PBS_HOT;
- //else if (flags & State_ButtonDefault)
- // stateId = PBS_DEFAULTED;
- else
- stateId = PBS_NORMAL;
- break;
-
- case PE_PanelButtonTool:
- if (widget && widget->inherits("QDockWidgetTitleButton")) {
- if (const QWidget *dw = widget->parentWidget())
- if (dw->isWindow())
- return;
- }
- themeNumber = QWindowsXPStylePrivate::ToolBarTheme;
- partId = TP_BUTTON;
- if (!(flags & State_Enabled))
- stateId = TS_DISABLED;
- else if (flags & State_Sunken)
- stateId = TS_PRESSED;
- else if (flags & State_MouseOver)
- stateId = flags & State_On ? TS_HOTCHECKED : TS_HOT;
- else if (flags & State_On)
- stateId = TS_CHECKED;
- else if (!(flags & State_AutoRaise))
- stateId = TS_HOT;
- else
- stateId = TS_NORMAL;
- break;
-
- case PE_IndicatorButtonDropDown:
- themeNumber = QWindowsXPStylePrivate::ToolBarTheme;
- partId = TP_SPLITBUTTONDROPDOWN;
- if (!(flags & State_Enabled))
- stateId = TS_DISABLED;
- else if (flags & State_Sunken)
- stateId = TS_PRESSED;
- else if (flags & State_MouseOver)
- stateId = flags & State_On ? TS_HOTCHECKED : TS_HOT;
- else if (flags & State_On)
- stateId = TS_CHECKED;
- else if (!(flags & State_AutoRaise))
- stateId = TS_HOT;
- else
- stateId = TS_NORMAL;
- if (option->direction == Qt::RightToLeft)
- hMirrored = true;
- break;
-
- case PE_IndicatorCheckBox:
- themeNumber = QWindowsXPStylePrivate::ButtonTheme;
- partId = BP_CHECKBOX;
- if (!(flags & State_Enabled))
- stateId = CBS_UNCHECKEDDISABLED;
- else if (flags & State_Sunken)
- stateId = CBS_UNCHECKEDPRESSED;
- else if (flags & State_MouseOver)
- stateId = CBS_UNCHECKEDHOT;
- else
- stateId = CBS_UNCHECKEDNORMAL;
-
- if (flags & State_On)
- stateId += CBS_CHECKEDNORMAL-1;
- else if (flags & State_NoChange)
- stateId += CBS_MIXEDNORMAL-1;
-
- break;
-
- case PE_IndicatorRadioButton:
- themeNumber = QWindowsXPStylePrivate::ButtonTheme;
- partId = BP_RADIOBUTTON;
- if (!(flags & State_Enabled))
- stateId = RBS_UNCHECKEDDISABLED;
- else if (flags & State_Sunken)
- stateId = RBS_UNCHECKEDPRESSED;
- else if (flags & State_MouseOver)
- stateId = RBS_UNCHECKEDHOT;
- else
- stateId = RBS_UNCHECKEDNORMAL;
-
- if (flags & State_On)
- stateId += RBS_CHECKEDNORMAL-1;
- break;
-
- case PE_IndicatorDockWidgetResizeHandle:
- return;
-
-case PE_Frame:
- {
- if (flags & State_Raised)
- return;
- themeNumber = QWindowsXPStylePrivate::ListViewTheme;
- partId = LVP_LISTGROUP;
- XPThemeData theme(widget, nullptr, themeNumber, partId);
-
- if (!(flags & State_Enabled))
- stateId = ETS_DISABLED;
- else
- stateId = ETS_NORMAL;
- int fillType;
- if (GetThemeEnumValue(theme.handle(), partId, stateId, TMT_BGTYPE, &fillType) == S_OK) {
- if (fillType == BT_BORDERFILL) {
- COLORREF bcRef;
- GetThemeColor(theme.handle(), partId, stateId, TMT_BORDERCOLOR, &bcRef);
- QColor bordercolor(qRgb(GetRValue(bcRef), GetGValue(bcRef), GetBValue(bcRef)));
- QPen oldPen = p->pen();
- // int borderSize = 1;
- // GetThemeInt(theme.handle(), partId, stateId, TMT_BORDERCOLOR, &borderSize);
-
- // Inner white border
- p->setPen(QPen(option->palette.base().color(), 0));
- const qreal dpi = QStyleHelper::dpi(option);
- const auto topLevelAdjustment = QStyleHelper::dpiScaled(0.5, dpi);
- const auto bottomRightAdjustment = QStyleHelper::dpiScaled(-1, dpi);
- p->drawRect(QRectF(option->rect).adjusted(topLevelAdjustment, topLevelAdjustment,
- bottomRightAdjustment, bottomRightAdjustment));
- // Outer dark border
- p->setPen(QPen(bordercolor, 0));
- p->drawRect(QRectF(option->rect).adjusted(0, 0, -topLevelAdjustment, -topLevelAdjustment));
- p->setPen(oldPen);
- return;
- }
- if (fillType == BT_NONE)
- return;
- }
- break;
- }
- case PE_FrameLineEdit: {
- // we try to check if this lineedit is a delegate on a QAbstractItemView-derived class.
- if (QWindowsXPStylePrivate::isItemViewDelegateLineEdit(widget)) {
- QPen oldPen = p->pen();
- // Inner white border
- p->setPen(QPen(option->palette.base().color(), 1));
- p->drawRect(option->rect.adjusted(1, 1, -2, -2));
- // Outer dark border
- p->setPen(QPen(option->palette.shadow().color(), 1));
- p->drawRect(option->rect.adjusted(0, 0, -1, -1));
- p->setPen(oldPen);
- return;
- }
- if (qstyleoption_cast<const QStyleOptionFrame *>(option)) {
- themeNumber = QWindowsXPStylePrivate::EditTheme;
- partId = EP_EDITTEXT;
- noContent = true;
- if (!(flags & State_Enabled))
- stateId = ETS_DISABLED;
- else
- stateId = ETS_NORMAL;
- }
- break;
- }
-
- case PE_PanelLineEdit:
- if (const QStyleOptionFrame *panel = qstyleoption_cast<const QStyleOptionFrame *>(option)) {
- themeNumber = QWindowsXPStylePrivate::EditTheme;
- partId = EP_EDITTEXT;
- noBorder = true;
- bool isEnabled = flags & State_Enabled;
-
- stateId = isEnabled ? ETS_NORMAL : ETS_DISABLED;
-
- if (QWindowsXPStylePrivate::isLineEditBaseColorSet(option, widget)) {
- p->fillRect(panel->rect, panel->palette.brush(QPalette::Base));
- } else {
- XPThemeData theme(nullptr, p, themeNumber, partId, stateId, rect);
- if (!theme.isValid()) {
- QWindowsStyle::drawPrimitive(pe, option, p, widget);
- return;
- }
- int bgType;
- GetThemeEnumValue(theme.handle(), partId, stateId, TMT_BGTYPE, &bgType);
- if( bgType == BT_IMAGEFILE ) {
- theme.mirrorHorizontally = hMirrored;
- theme.mirrorVertically = vMirrored;
- theme.noBorder = noBorder;
- theme.noContent = noContent;
- theme.rotate = rotate;
- d->drawBackground(theme);
- } else {
- QBrush fillColor = option->palette.brush(QPalette::Base);
-
- if (!isEnabled) {
- PROPERTYORIGIN origin = PO_NOTFOUND;
- GetThemePropertyOrigin(theme.handle(), theme.partId, theme.stateId, TMT_FILLCOLOR, &origin);
- // Use only if the fill property comes from our part
- if ((origin == PO_PART || origin == PO_STATE)) {
- COLORREF bgRef;
- GetThemeColor(theme.handle(), partId, stateId, TMT_FILLCOLOR, &bgRef);
- fillColor = QBrush(qRgb(GetRValue(bgRef), GetGValue(bgRef), GetBValue(bgRef)));
- }
- }
- p->fillRect(option->rect, fillColor);
- }
- }
-
- if (panel->lineWidth > 0)
- proxy()->drawPrimitive(PE_FrameLineEdit, panel, p, widget);
- return;
- }
- break;
-
- case PE_FrameTabWidget:
- if (const QStyleOptionTabWidgetFrame *tab = qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(option))
- {
- themeNumber = QWindowsXPStylePrivate::TabTheme;
- partId = TABP_PANE;
-
- if (widget) {
- bool useGradient = true;
- const int maxlength = 256;
- wchar_t themeFileName[maxlength];
- wchar_t themeColor[maxlength];
- // Due to a a scaling issue with the XP Silver theme, tab gradients are not used with it
- if (GetCurrentThemeName(themeFileName, maxlength, themeColor, maxlength, nullptr, 0) == S_OK) {
- wchar_t *offset = nullptr;
- if ((offset = wcsrchr(themeFileName, QChar(QLatin1Char('\\')).unicode())) != nullptr) {
- offset++;
- if (!lstrcmp(offset, L"Luna.msstyles") && !lstrcmp(offset, L"Metallic")) {
- useGradient = false;
- }
- }
- }
- // This should work, but currently there's an error in the ::drawBackgroundDirectly()
- // code, when using the HDC directly..
- if (useGradient) {
- QStyleOptionTabWidgetFrame frameOpt = *tab;
- frameOpt.rect = widget->rect();
- QRect contentsRect = subElementRect(SE_TabWidgetTabContents, &frameOpt, widget);
- QRegion reg = option->rect;
- reg -= contentsRect;
- p->setClipRegion(reg);
- XPThemeData theme(widget, p, themeNumber, partId, stateId, rect);
- theme.mirrorHorizontally = hMirrored;
- theme.mirrorVertically = vMirrored;
- d->drawBackground(theme);
- p->setClipRect(contentsRect);
- partId = TABP_BODY;
- }
- }
- switch (tab->shape) {
- case QTabBar::RoundedNorth:
- case QTabBar::TriangularNorth:
- break;
- case QTabBar::RoundedSouth:
- case QTabBar::TriangularSouth:
- vMirrored = true;
- break;
- case QTabBar::RoundedEast:
- case QTabBar::TriangularEast:
- rotate = 90;
- break;
- case QTabBar::RoundedWest:
- case QTabBar::TriangularWest:
- rotate = 90;
- hMirrored = true;
- break;
- default:
- break;
- }
- }
- break;
-
- case PE_FrameMenu:
- p->save();
- p->setPen(option->palette.dark().color());
- p->drawRect(rect.adjusted(0, 0, -1, -1));
- p->restore();
- return;
-
- case PE_PanelMenuBar:
- break;
-
- case PE_FrameDockWidget:
- if (const QStyleOptionFrame *frm = qstyleoption_cast<const QStyleOptionFrame *>(option))
- {
- themeNumber = QWindowsXPStylePrivate::WindowTheme;
- if (flags & State_Active)
- stateId = FS_ACTIVE;
- else
- stateId = FS_INACTIVE;
-
- int fwidth = proxy()->pixelMetric(PM_DockWidgetFrameWidth, frm, widget);
-
- XPThemeData theme(widget, p, themeNumber, 0, stateId);
- if (!theme.isValid())
- break;
- theme.rect = QRect(frm->rect.x(), frm->rect.y(), frm->rect.x()+fwidth, frm->rect.height()-fwidth); theme.partId = WP_SMALLFRAMELEFT;
- d->drawBackground(theme);
- theme.rect = QRect(frm->rect.width()-fwidth, frm->rect.y(), fwidth, frm->rect.height()-fwidth);
- theme.partId = WP_SMALLFRAMERIGHT;
- d->drawBackground(theme);
- theme.rect = QRect(frm->rect.x(), frm->rect.bottom()-fwidth+1, frm->rect.width(), fwidth);
- theme.partId = WP_SMALLFRAMEBOTTOM;
- d->drawBackground(theme);
- return;
- }
- break;
-
- case PE_IndicatorHeaderArrow:
- {
-#if 0 // XP theme engine doesn't know about this :(
- name = QWindowsXPStylePrivate::HeaderTheme;
- partId = HP_HEADERSORTARROW;
- if (flags & State_Down)
- stateId = HSAS_SORTEDDOWN;
- else
- stateId = HSAS_SORTEDUP;
-#else
- if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(option)) {
- p->save();
- p->setPen(option->palette.dark().color());
- p->translate(0, option->rect.height()/2 - 4);
- if (header->sortIndicator & QStyleOptionHeader::SortUp) { // invert logic to follow Windows style guide
- p->drawLine(option->rect.x(), option->rect.y(), option->rect.x()+8, option->rect.y());
- p->drawLine(option->rect.x()+1, option->rect.y()+1, option->rect.x()+7, option->rect.y()+1);
- p->drawLine(option->rect.x()+2, option->rect.y()+2, option->rect.x()+6, option->rect.y()+2);
- p->drawLine(option->rect.x()+3, option->rect.y()+3, option->rect.x()+5, option->rect.y()+3);
- p->drawPoint(option->rect.x()+4, option->rect.y()+4);
- } else if(header->sortIndicator & QStyleOptionHeader::SortDown) {
- p->drawLine(option->rect.x(), option->rect.y()+4, option->rect.x()+8, option->rect.y()+4);
- p->drawLine(option->rect.x()+1, option->rect.y()+3, option->rect.x()+7, option->rect.y()+3);
- p->drawLine(option->rect.x()+2, option->rect.y()+2, option->rect.x()+6, option->rect.y()+2);
- p->drawLine(option->rect.x()+3, option->rect.y()+1, option->rect.x()+5, option->rect.y()+1);
- p->drawPoint(option->rect.x()+4, option->rect.y());
- }
- p->restore();
- return;
- }
-#endif
- }
- break;
-
- case PE_FrameStatusBarItem:
- themeNumber = QWindowsXPStylePrivate::StatusTheme;
- partId = SP_PANE;
- break;
-
- case PE_FrameGroupBox:
- themeNumber = QWindowsXPStylePrivate::ButtonTheme;
- partId = BP_GROUPBOX;
- if (!(flags & State_Enabled))
- stateId = GBS_DISABLED;
- else
- stateId = GBS_NORMAL;
- if (const QStyleOptionFrame *frame = qstyleoption_cast<const QStyleOptionFrame *>(option)) {
- if (frame->features & QStyleOptionFrame::Flat) {
- // Windows XP does not have a theme part for a flat GroupBox, paint it with the windows style
- QRect fr = frame->rect;
- QPoint p1(fr.x(), fr.y() + 1);
- QPoint p2(fr.x() + fr.width(), p1.y() + 1);
- rect = QRect(p1, p2);
- themeNumber = -1;
- }
- }
- break;
-
- case PE_IndicatorProgressChunk:
- {
- Qt::Orientation orient = Qt::Horizontal;
- bool inverted = false;
- if (const QStyleOptionProgressBar *pb = qstyleoption_cast<const QStyleOptionProgressBar *>(option)) {
- orient = pb->orientation;
- inverted = pb->invertedAppearance;
- }
- if (orient == Qt::Horizontal) {
- partId = PP_CHUNK;
- rect = QRect(option->rect.x(), option->rect.y(), option->rect.width(), option->rect.height() );
- if (inverted && option->direction == Qt::LeftToRight)
- hMirrored = true;
- } else {
- partId = PP_CHUNKVERT;
- rect = QRect(option->rect.x(), option->rect.y(), option->rect.width(), option->rect.height());
- }
- themeNumber = QWindowsXPStylePrivate::ProgressTheme;
- stateId = 1;
- }
- break;
-
- case PE_FrameWindow:
- if (const QStyleOptionFrame *frm = qstyleoption_cast<const QStyleOptionFrame *>(option))
- {
- themeNumber = QWindowsXPStylePrivate::WindowTheme;
- if (flags & State_Active)
- stateId = FS_ACTIVE;
- else
- stateId = FS_INACTIVE;
-
- int fwidth = int((frm->lineWidth + frm->midLineWidth) / QWindowsStylePrivate::nativeMetricScaleFactor(widget));
-
- XPThemeData theme(widget, p, themeNumber, 0, stateId);
- if (!theme.isValid())
- break;
-
- // May fail due to too-large buffers for large widgets, fall back to Windows style.
- theme.rect = QRect(option->rect.x(), option->rect.y()+fwidth, option->rect.x()+fwidth, option->rect.height()-fwidth);
- theme.partId = WP_FRAMELEFT;
- if (!d->drawBackground(theme)) {
- QWindowsStyle::drawPrimitive(pe, option, p, widget);
- return;
- }
- theme.rect = QRect(option->rect.width()-fwidth, option->rect.y()+fwidth, fwidth, option->rect.height()-fwidth);
- theme.partId = WP_FRAMERIGHT;
- if (!d->drawBackground(theme)) {
- QWindowsStyle::drawPrimitive(pe, option, p, widget);
- return;
- }
- theme.rect = QRect(option->rect.x(), option->rect.height()-fwidth, option->rect.width(), fwidth);
- theme.partId = WP_FRAMEBOTTOM;
- if (!d->drawBackground(theme)) {
- QWindowsStyle::drawPrimitive(pe, option, p, widget);
- return;
- }
- theme.rect = QRect(option->rect.x(), option->rect.y(), option->rect.width(), option->rect.y()+fwidth);
- theme.partId = WP_CAPTION;
- if (!d->drawBackground(theme))
- QWindowsStyle::drawPrimitive(pe, option, p, widget);
- return;
- }
- break;
-
- case PE_IndicatorBranch:
- {
- static const int decoration_size = 9;
- int mid_h = option->rect.x() + option->rect.width() / 2;
- int mid_v = option->rect.y() + option->rect.height() / 2;
- int bef_h = mid_h;
- int bef_v = mid_v;
- int aft_h = mid_h;
- int aft_v = mid_v;
- QBrush brush(option->palette.dark().color(), Qt::Dense4Pattern);
- if (option->state & State_Item) {
- if (option->direction == Qt::RightToLeft)
- p->fillRect(option->rect.left(), mid_v, bef_h - option->rect.left(), 1, brush);
- else
- p->fillRect(aft_h, mid_v, option->rect.right() - aft_h + 1, 1, brush);
- }
- if (option->state & State_Sibling)
- p->fillRect(mid_h, aft_v, 1, option->rect.bottom() - aft_v + 1, brush);
- if (option->state & (State_Open | State_Children | State_Item | State_Sibling))
- p->fillRect(mid_h, option->rect.y(), 1, bef_v - option->rect.y(), brush);
- if (option->state & State_Children) {
- int delta = decoration_size / 2;
- bef_h -= delta;
- bef_v -= delta;
- aft_h += delta;
- aft_v += delta;
- XPThemeData theme(nullptr, p, QWindowsXPStylePrivate::XpTreeViewTheme);
- theme.rect = QRect(bef_h, bef_v, decoration_size, decoration_size);
- theme.partId = TVP_GLYPH;
- theme.stateId = flags & QStyle::State_Open ? GLPS_OPENED : GLPS_CLOSED;
- d->drawBackground(theme);
- }
- }
- return;
-
- case PE_IndicatorToolBarSeparator:
- if (option->rect.height() < 3) {
- // XP style requires a few pixels for the separator
- // to be visible.
- QWindowsStyle::drawPrimitive(pe, option, p, widget);
- return;
- }
- themeNumber = QWindowsXPStylePrivate::ToolBarTheme;
- partId = TP_SEPARATOR;
-
- if (option->state & State_Horizontal)
- partId = TP_SEPARATOR;
- else
- partId = TP_SEPARATORVERT;
-
- break;
-
- case PE_IndicatorToolBarHandle:
-
- themeNumber = QWindowsXPStylePrivate::RebarTheme;
- partId = RP_GRIPPER;
- if (option->state & State_Horizontal) {
- partId = RP_GRIPPER;
- rect.adjust(0, 0, -2, 0);
- }
- else {
- partId = RP_GRIPPERVERT;
- rect.adjust(0, 0, 0, -2);
- }
- break;
-
- case PE_IndicatorItemViewItemCheck: {
- QStyleOptionButton button;
- button.QStyleOption::operator=(*option);
- button.state &= ~State_MouseOver;
- proxy()->drawPrimitive(PE_IndicatorCheckBox, &button, p, widget);
- return;
- }
-
- default:
- break;
- }
-
- XPThemeData theme(widget, p, themeNumber, partId, stateId, rect);
- if (!theme.isValid()) {
- QWindowsStyle::drawPrimitive(pe, option, p, widget);
- return;
- }
- theme.mirrorHorizontally = hMirrored;
- theme.mirrorVertically = vMirrored;
- theme.noBorder = noBorder;
- theme.noContent = noContent;
- theme.rotate = rotate;
- d->drawBackground(theme);
-}
-
-/*!
- \reimp
-*/
-void QWindowsXPStyle::drawControl(ControlElement element, const QStyleOption *option, QPainter *p,
- const QWidget *widget) const
-{
- QWindowsXPStylePrivate *d = const_cast<QWindowsXPStylePrivate*>(d_func());
- if (!QWindowsXPStylePrivate::useXP()) {
- QWindowsStyle::drawControl(element, option, p, widget);
- return;
- }
-
- QRect rect(option->rect);
- State flags = option->state;
-
- int rotate = 0;
- bool hMirrored = false;
- bool vMirrored = false;
-
- int themeNumber = -1;
- int partId = 0;
- int stateId = 0;
- switch (element) {
- case CE_SizeGrip:
- {
- themeNumber = QWindowsXPStylePrivate::StatusTheme;
- partId = SP_GRIPPER;
- XPThemeData theme(nullptr, p, themeNumber, partId);
- QSize size = (theme.size() * QWindowsStylePrivate::nativeMetricScaleFactor(widget)).toSize();
- size.rheight()--;
- if (const QStyleOptionSizeGrip *sg = qstyleoption_cast<const QStyleOptionSizeGrip *>(option)) {
- switch (sg->corner) {
- case Qt::BottomRightCorner:
- rect = QRect(QPoint(rect.right() - size.width(), rect.bottom() - size.height()), size);
- break;
- case Qt::BottomLeftCorner:
- rect = QRect(QPoint(rect.left() + 1, rect.bottom() - size.height()), size);
- hMirrored = true;
- break;
- case Qt::TopRightCorner:
- rect = QRect(QPoint(rect.right() - size.width(), rect.top() + 1), size);
- vMirrored = true;
- break;
- case Qt::TopLeftCorner:
- rect = QRect(rect.topLeft() + QPoint(1, 1), size);
- hMirrored = vMirrored = true;
- }
- }
- }
- break;
-
- case CE_HeaderSection:
- themeNumber = QWindowsXPStylePrivate::HeaderTheme;
- partId = HP_HEADERITEM;
- if (flags & State_Sunken)
- stateId = HIS_PRESSED;
- else if (flags & State_MouseOver)
- stateId = HIS_HOT;
- else
- stateId = HIS_NORMAL;
- break;
-
- case CE_Splitter:
- p->eraseRect(option->rect);
- return;
-
- case CE_PushButtonBevel:
- if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(option))
- {
- themeNumber = QWindowsXPStylePrivate::ButtonTheme;
- partId = BP_PUSHBUTTON;
- bool justFlat = ((btn->features & QStyleOptionButton::Flat) && !(flags & (State_On|State_Sunken)))
- || ((btn->features & QStyleOptionButton::CommandLinkButton)
- && !(flags & State_MouseOver)
- && !(btn->features & QStyleOptionButton::DefaultButton));
- if (!(flags & State_Enabled) && !(btn->features & QStyleOptionButton::Flat))
- stateId = PBS_DISABLED;
- else if (justFlat)
- ;
- else if (flags & (State_Sunken | State_On))
- stateId = PBS_PRESSED;
- else if (flags & State_MouseOver)
- stateId = PBS_HOT;
- else if (btn->features & QStyleOptionButton::DefaultButton)
- stateId = PBS_DEFAULTED;
- else
- stateId = PBS_NORMAL;
-
- if (!justFlat) {
- XPThemeData theme(widget, p, themeNumber, partId, stateId, rect);
- d->drawBackground(theme);
- }
-
- if (btn->features & QStyleOptionButton::HasMenu) {
- int mbiw = 0, mbih = 0;
- XPThemeData theme(widget, nullptr,
- QWindowsXPStylePrivate::ToolBarTheme,
- TP_SPLITBUTTONDROPDOWN);
- if (theme.isValid()) {
- const QSize size = (theme.size() * QWindowsStylePrivate::nativeMetricScaleFactor(widget)).toSize();
- mbiw = size.width();
- mbih = size.height();
- }
-
- QRect ir = btn->rect;
- QStyleOptionButton newBtn = *btn;
- newBtn.rect = QRect(ir.right() - mbiw - 1, 1 + (ir.height()/2) - (mbih/2), mbiw, mbih);
- proxy()->drawPrimitive(PE_IndicatorArrowDown, &newBtn, p, widget);
- }
- return;
- }
- break;
- case CE_TabBarTab:
- if (const QStyleOptionTab *tab = qstyleoption_cast<const QStyleOptionTab *>(option))
- {
- stateId = tab->state & State_Enabled ? TIS_NORMAL : TIS_DISABLED;
- }
- break;
-
- case CE_TabBarTabShape:
- if (const QStyleOptionTab *tab = qstyleoption_cast<const QStyleOptionTab *>(option))
- {
- themeNumber = QWindowsXPStylePrivate::TabTheme;
- bool isDisabled = !(tab->state & State_Enabled);
- bool hasFocus = tab->state & State_HasFocus;
- bool isHot = tab->state & State_MouseOver;
- bool selected = tab->state & State_Selected;
- bool lastTab = tab->position == QStyleOptionTab::End;
- bool firstTab = tab->position == QStyleOptionTab::Beginning;
- bool onlyOne = tab->position == QStyleOptionTab::OnlyOneTab;
- bool leftAligned = proxy()->styleHint(SH_TabBar_Alignment, tab, widget) == Qt::AlignLeft;
- bool centerAligned = proxy()->styleHint(SH_TabBar_Alignment, tab, widget) == Qt::AlignCenter;
- int borderThickness = proxy()->pixelMetric(PM_DefaultFrameWidth, option, widget);
- int tabOverlap = proxy()->pixelMetric(PM_TabBarTabOverlap, option, widget);
-
- if (isDisabled)
- stateId = TIS_DISABLED;
- else if (selected)
- stateId = TIS_SELECTED;
- else if (hasFocus)
- stateId = TIS_FOCUSED;
- else if (isHot)
- stateId = TIS_HOT;
- else
- stateId = TIS_NORMAL;
-
- // Selecting proper part depending on position
- if (firstTab || onlyOne) {
- if (leftAligned) {
- partId = TABP_TABITEMLEFTEDGE;
- } else if (centerAligned) {
- partId = TABP_TABITEM;
- } else { // rightAligned
- partId = TABP_TABITEMRIGHTEDGE;
- }
- } else {
- partId = TABP_TABITEM;
- }
-
- if (tab->direction == Qt::RightToLeft
- && (tab->shape == QTabBar::RoundedNorth
- || tab->shape == QTabBar::RoundedSouth)) {
- bool temp = firstTab;
- firstTab = lastTab;
- lastTab = temp;
- }
- bool begin = firstTab || onlyOne;
- bool end = lastTab || onlyOne;
- switch (tab->shape) {
- case QTabBar::RoundedNorth:
- if (selected)
- rect.adjust(begin ? 0 : -tabOverlap, 0, end ? 0 : tabOverlap, borderThickness);
- else
- rect.adjust(begin? tabOverlap : 0, tabOverlap, end ? -tabOverlap : 0, 0);
- break;
- case QTabBar::RoundedSouth:
- //vMirrored = true;
- rotate = 180; // Not 100% correct, but works
- if (selected)
- rect.adjust(begin ? 0 : -tabOverlap , -borderThickness, end ? 0 : tabOverlap, 0);
- else
- rect.adjust(begin ? tabOverlap : 0, 0, end ? -tabOverlap : 0 , -tabOverlap);
- break;
- case QTabBar::RoundedEast:
- rotate = 90;
- if (selected) {
- rect.adjust(-borderThickness, begin ? 0 : -tabOverlap, 0, end ? 0 : tabOverlap);
- }else{
- rect.adjust(0, begin ? tabOverlap : 0, -tabOverlap, end ? -tabOverlap : 0);
- }
- break;
- case QTabBar::RoundedWest:
- hMirrored = true;
- rotate = 90;
- if (selected) {
- rect.adjust(0, begin ? 0 : -tabOverlap, borderThickness, end ? 0 : tabOverlap);
- }else{
- rect.adjust(tabOverlap, begin ? tabOverlap : 0, 0, end ? -tabOverlap : 0);
- }
- break;
- default:
- themeNumber = -1; // Do our own painting for triangular
- break;
- }
-
- if (!selected) {
- switch (tab->shape) {
- case QTabBar::RoundedNorth:
- rect.adjust(0,0, 0,-1);
- break;
- case QTabBar::RoundedSouth:
- rect.adjust(0,1, 0,0);
- break;
- case QTabBar::RoundedEast:
- rect.adjust( 1,0, 0,0);
- break;
- case QTabBar::RoundedWest:
- rect.adjust(0,0, -1,0);
- break;
- default:
- break;
- }
- }
- }
- break;
-
- case CE_ProgressBarGroove:
- {
- Qt::Orientation orient = Qt::Horizontal;
- if (const QStyleOptionProgressBar *pb = qstyleoption_cast<const QStyleOptionProgressBar *>(option))
- orient = pb->orientation;
- partId = (orient == Qt::Horizontal) ? PP_BAR : PP_BARVERT;
- themeNumber = QWindowsXPStylePrivate::ProgressTheme;
- stateId = 1;
- }
- break;
-
- case CE_MenuEmptyArea:
- case CE_MenuItem:
- if (const QStyleOptionMenuItem *menuitem = qstyleoption_cast<const QStyleOptionMenuItem *>(option))
- {
- int tab = menuitem->tabWidth;
- bool dis = !(menuitem->state & State_Enabled);
- bool act = menuitem->state & State_Selected;
- bool checkable = menuitem->menuHasCheckableItems;
- bool checked = checkable ? menuitem->checked : false;
-
- // windows always has a check column, regardless whether we have an icon or not
- int checkcol = qMax(menuitem->maxIconWidth, 12);
-
- int x, y, w, h;
- rect.getRect(&x, &y, &w, &h);
-
- QBrush fill = menuitem->palette.brush(act ? QPalette::Highlight : QPalette::Button);
- p->fillRect(rect, fill);
-
- if (element == CE_MenuEmptyArea)
- break;
-
- // draw separator -------------------------------------------------
- if (menuitem->menuItemType == QStyleOptionMenuItem::Separator) {
- int yoff = y-1 + h / 2;
- p->setPen(menuitem->palette.dark().color());
- p->drawLine(x, yoff, x+w, yoff);
- ++yoff;
- p->setPen(menuitem->palette.light().color());
- p->drawLine(x, yoff, x+w, yoff);
- return;
- }
-
- int xpos = x;
-
- // draw icon ------------------------------------------------------
- if (!menuitem->icon.isNull()) {
- QIcon::Mode mode = dis ? QIcon::Disabled : QIcon::Normal;
- if (act && !dis)
- mode = QIcon::Active;
- 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);
- iconRect.moveCenter(QRect(xpos, y, checkcol, h).center());
- QRect vIconRect = visualRect(option->direction, option->rect, iconRect);
- p->setPen(menuitem->palette.text().color());
- p->setBrush(Qt::NoBrush);
- if (checked)
- p->drawRect(vIconRect.adjusted(-1, -1, 0, 0));
- p->drawPixmap(vIconRect.topLeft(), pixmap);
-
- // draw checkmark -------------------------------------------------
- } else if (checked) {
- QStyleOptionMenuItem newMi = *menuitem;
- newMi.state = State_None;
- if (!dis)
- newMi.state |= State_Enabled;
- if (act)
- newMi.state |= State_On;
-
- QRect checkMarkRect = QRect(menuitem->rect.x() + windowsItemFrame,
- menuitem->rect.y() + windowsItemFrame,
- checkcol - 2 * windowsItemFrame,
- menuitem->rect.height() - 2*windowsItemFrame);
- newMi.rect = visualRect(option->direction, option->rect, checkMarkRect);
- proxy()->drawPrimitive(PE_IndicatorMenuCheckMark, &newMi, p, widget);
- }
-
- QColor textColor = dis ? menuitem->palette.text().color() :
- act ? menuitem->palette.highlightedText().color() : menuitem->palette.buttonText().color();
- p->setPen(textColor);
-
- // draw text ------------------------------------------------------
- int xm = windowsItemFrame + checkcol + windowsItemHMargin;
- xpos = menuitem->rect.x() + xm;
- QRect textRect(xpos, y + windowsItemVMargin, w - xm - windowsRightBorder - tab + 1, h - 2 * windowsItemVMargin);
- QRect vTextRect = visualRect(option->direction, option->rect, textRect);
- QString s = menuitem->text;
- if (!s.isEmpty()) {
- p->save();
- int t = s.indexOf(QLatin1Char('\t'));
- int text_flags = Qt::AlignVCenter|Qt::TextShowMnemonic | Qt::TextDontClip | Qt::TextSingleLine | Qt::AlignLeft;
- if (!proxy()->styleHint(SH_UnderlineShortcut, menuitem, widget))
- text_flags |= Qt::TextHideMnemonic;
- // draw tab text ----------------
- if (t >= 0) {
- QRect vShortcutRect = visualRect(option->direction, option->rect, QRect(textRect.topRight(), menuitem->rect.bottomRight()));
- if (dis && !act && proxy()->styleHint(SH_EtchDisabledText, option, widget)) {
- p->setPen(menuitem->palette.light().color());
- p->drawText(vShortcutRect.adjusted(1,1,1,1), text_flags, s.mid(t + 1));
- p->setPen(textColor);
- }
- p->drawText(vShortcutRect, text_flags, s.mid(t + 1));
- s = s.left(t);
- }
- QFont font = menuitem->font;
- if (menuitem->menuItemType == QStyleOptionMenuItem::DefaultItem)
- font.setBold(true);
- p->setFont(font);
- if (dis && !act && proxy()->styleHint(SH_EtchDisabledText, option, widget)) {
- p->setPen(menuitem->palette.light().color());
- p->drawText(vTextRect.adjusted(1,1,1,1), text_flags, s.left(t));
- p->setPen(textColor);
- }
- p->drawText(vTextRect, text_flags, s);
- p->restore();
- }
-
- // draw sub menu arrow --------------------------------------------
- if (menuitem->menuItemType == QStyleOptionMenuItem::SubMenu) {
- int dim = (h - 2) / 2;
- PrimitiveElement arrow;
- arrow = (option->direction == Qt::RightToLeft) ? PE_IndicatorArrowLeft : PE_IndicatorArrowRight;
- xpos = x + w - windowsArrowHMargin - windowsItemFrame - dim;
- QRect vSubMenuRect = visualRect(option->direction, option->rect, QRect(xpos, y + h / 2 - dim / 2, dim, dim));
- QStyleOptionMenuItem newMI = *menuitem;
- newMI.rect = vSubMenuRect;
- newMI.state = dis ? State_None : State_Enabled;
- if (act)
- newMI.palette.setColor(QPalette::ButtonText, newMI.palette.highlightedText().color());
- proxy()->drawPrimitive(arrow, &newMI, p, widget);
- }
- }
- return;
-
- case CE_MenuBarItem:
- if (const QStyleOptionMenuItem *mbi = qstyleoption_cast<const QStyleOptionMenuItem *>(option))
- {
- if (mbi->menuItemType == QStyleOptionMenuItem::DefaultItem)
- break;
-
- bool act = mbi->state & State_Selected;
- bool dis = !(mbi->state & State_Enabled);
-
- QBrush fill = mbi->palette.brush(act ? QPalette::Highlight : QPalette::Button);
- QPalette::ColorRole textRole = dis ? QPalette::Text:
- act ? QPalette::HighlightedText : QPalette::ButtonText;
- QPixmap pix = mbi->icon.pixmap(proxy()->pixelMetric(PM_SmallIconSize, option, widget), QIcon::Normal);
-
- uint alignment = Qt::AlignCenter | Qt::TextShowMnemonic | Qt::TextDontClip | Qt::TextSingleLine;
- if (!proxy()->styleHint(SH_UnderlineShortcut, mbi, widget))
- alignment |= Qt::TextHideMnemonic;
-
- p->fillRect(rect, fill);
- if (!pix.isNull())
- drawItemPixmap(p, mbi->rect, alignment, pix);
- else
- drawItemText(p, mbi->rect, alignment, mbi->palette, mbi->state & State_Enabled, mbi->text, textRole);
- }
- return;
-#if QT_CONFIG(dockwidget)
- case CE_DockWidgetTitle:
- if (const QStyleOptionDockWidget *dwOpt = qstyleoption_cast<const QStyleOptionDockWidget *>(option))
- {
- int buttonMargin = 4;
- int mw = proxy()->pixelMetric(QStyle::PM_DockWidgetTitleMargin, dwOpt, widget);
- int fw = proxy()->pixelMetric(PM_DockWidgetFrameWidth, dwOpt, widget);
- bool isFloating = widget && widget->isWindow();
- bool isActive = dwOpt->state & State_Active;
-
- const bool verticalTitleBar = dwOpt->verticalTitleBar;
-
- if (verticalTitleBar) {
- rect = rect.transposed();
-
- p->translate(rect.left() - 1, rect.top() + rect.width());
- p->rotate(-90);
- p->translate(-rect.left() + 1, -rect.top());
- }
- QRect r = rect.adjusted(0, 2, -1, -3);
- QRect titleRect = r;
-
- if (dwOpt->closable) {
- QSize sz = proxy()->standardIcon(QStyle::SP_TitleBarCloseButton, dwOpt, widget).actualSize(QSize(10, 10));
- titleRect.adjust(0, 0, -sz.width() - mw - buttonMargin, 0);
- }
-
- if (dwOpt->floatable) {
- QSize sz = proxy()->standardIcon(QStyle::SP_TitleBarMaxButton, dwOpt, widget).actualSize(QSize(10, 10));
- titleRect.adjust(0, 0, -sz.width() - mw - buttonMargin, 0);
- }
-
- if (isFloating) {
- titleRect.adjust(0, -fw, 0, 0);
- if (widget != nullptr && widget->windowIcon().cacheKey() != QApplication::windowIcon().cacheKey())
- titleRect.adjust(titleRect.height() + mw, 0, 0, 0);
- } else {
- titleRect.adjust(mw, 0, 0, 0);
- if (!dwOpt->floatable && !dwOpt->closable)
- titleRect.adjust(0, 0, -mw, 0);
- }
-
- if (!verticalTitleBar)
- titleRect = visualRect(dwOpt->direction, r, titleRect);
-
- if (!isFloating) {
- QPen oldPen = p->pen();
- QString titleText = p->fontMetrics().elidedText(dwOpt->title, Qt::ElideRight, titleRect.width());
- p->setPen(dwOpt->palette.color(QPalette::Dark));
- p->drawRect(r);
-
- if (!titleText.isEmpty()) {
- drawItemText(p, titleRect,
- Qt::AlignLeft | Qt::AlignVCenter | Qt::TextShowMnemonic, dwOpt->palette,
- dwOpt->state & State_Enabled, titleText,
- QPalette::WindowText);
- }
-
- p->setPen(oldPen);
- } else {
- themeNumber = QWindowsXPStylePrivate::WindowTheme;
- if (isActive)
- stateId = CS_ACTIVE;
- else
- stateId = CS_INACTIVE;
-
- int titleHeight = rect.height() - 2;
- rect = rect.adjusted(-fw, -fw, fw, 0);
-
- XPThemeData theme(widget, p, themeNumber, 0, stateId);
- if (!theme.isValid())
- break;
-
- // Draw small type title bar
- theme.rect = rect;
- theme.partId = WP_SMALLCAPTION;
- d->drawBackground(theme);
-
- // Figure out maximal button space on title bar
-
- QIcon ico = widget->windowIcon();
- bool hasIcon = (ico.cacheKey() != QApplication::windowIcon().cacheKey());
- if (hasIcon) {
- QPixmap pxIco = ico.pixmap(titleHeight);
- if (!verticalTitleBar && dwOpt->direction == Qt::RightToLeft)
- p->drawPixmap(rect.width() - titleHeight - pxIco.width(), rect.bottom() - titleHeight - 2, pxIco);
- else
- p->drawPixmap(fw, rect.bottom() - titleHeight - 2, pxIco);
- }
- if (!dwOpt->title.isEmpty()) {
- QPen oldPen = p->pen();
- QFont oldFont = p->font();
- QFont titleFont = oldFont;
- titleFont.setBold(true);
- p->setFont(titleFont);
- QString titleText
- = p->fontMetrics().elidedText(dwOpt->title, Qt::ElideRight, titleRect.width());
-
- int result = TST_NONE;
- GetThemeEnumValue(theme.handle(), WP_SMALLCAPTION, isActive ? CS_ACTIVE : CS_INACTIVE, TMT_TEXTSHADOWTYPE, &result);
- if (result != TST_NONE) {
- COLORREF textShadowRef;
- GetThemeColor(theme.handle(), WP_SMALLCAPTION, isActive ? CS_ACTIVE : CS_INACTIVE, TMT_TEXTSHADOWCOLOR, &textShadowRef);
- QColor textShadow = qRgb(GetRValue(textShadowRef), GetGValue(textShadowRef), GetBValue(textShadowRef));
- p->setPen(textShadow);
- drawItemText(p, titleRect.adjusted(1, 1, 1, 1),
- Qt::AlignLeft | Qt::AlignBottom, dwOpt->palette,
- dwOpt->state & State_Enabled, titleText);
- }
-
- COLORREF captionText = GetSysColor(isActive ? COLOR_CAPTIONTEXT : COLOR_INACTIVECAPTIONTEXT);
- QColor textColor = qRgb(GetRValue(captionText), GetGValue(captionText), GetBValue(captionText));
- p->setPen(textColor);
- drawItemText(p, titleRect,
- Qt::AlignLeft | Qt::AlignBottom, dwOpt->palette,
- dwOpt->state & State_Enabled, titleText);
- p->setFont(oldFont);
- p->setPen(oldPen);
- }
-
- }
-
- return;
- }
- break;
-#endif // QT_CONFIG(dockwidget)
-#if QT_CONFIG(rubberband)
- case CE_RubberBand:
- if (qstyleoption_cast<const QStyleOptionRubberBand *>(option)) {
- QColor highlight = option->palette.color(QPalette::Active, QPalette::Highlight);
- p->save();
- p->setPen(highlight.darker(120));
- QColor dimHighlight(qMin(highlight.red()/2 + 110, 255),
- qMin(highlight.green()/2 + 110, 255),
- qMin(highlight.blue()/2 + 110, 255),
- (widget && widget->isTopLevel())? 255 : 127);
- p->setBrush(dimHighlight);
- p->drawRect(option->rect.adjusted(0, 0, -1, -1));
- p->restore();
- return;
- }
- break;
-#endif // QT_CONFIG(rubberband)
- case CE_HeaderEmptyArea:
- if (option->state & State_Horizontal)
- {
- themeNumber = QWindowsXPStylePrivate::HeaderTheme;
- stateId = HIS_NORMAL;
- }
- else {
- QWindowsStyle::drawControl(CE_HeaderEmptyArea, option, p, widget);
- return;
- }
- break;
- default:
- break;
- }
-
- XPThemeData theme(widget, p, themeNumber, partId, stateId, rect);
- if (!theme.isValid()) {
- QWindowsStyle::drawControl(element, option, p, widget);
- return;
- }
-
- theme.rotate = rotate;
- theme.mirrorHorizontally = hMirrored;
- theme.mirrorVertically = vMirrored;
- d->drawBackground(theme);
-}
-
-QRect QWindowsXPStylePrivate::scrollBarGripperBounds(QStyle::State flags, const QWidget *widget, XPThemeData *theme)
-{
- const bool horizontal = flags & QStyle::State_Horizontal;
- const qreal factor = QWindowsStylePrivate::nativeMetricScaleFactor(widget);
- const QMargins contentsMargin =
- (theme->margins(theme->rect, TMT_SIZINGMARGINS) * factor).toMargins();
- theme->partId = horizontal ? SBP_GRIPPERHORZ : SBP_GRIPPERVERT;
- const QSize size = (theme->size() * factor).toSize();
-
- const int hSpace = theme->rect.width() - size.width();
- const int vSpace = theme->rect.height() - size.height();
- const bool sufficientSpace = (horizontal && hSpace > (contentsMargin.left() + contentsMargin.right()))
- || vSpace > contentsMargin.top() + contentsMargin.bottom();
- return sufficientSpace ? QRect(theme->rect.topLeft() + QPoint(hSpace, vSpace) / 2, size) : QRect();
-}
-
-#if QT_CONFIG(mdiarea)
-// Helper for drawing MDI buttons into the corner widget of QMenuBar in case a
-// QMdiSubWindow is maximized.
-static void populateMdiButtonTheme(const QStyle *proxy, const QWidget *widget,
- const QStyleOptionComplex *option,
- QStyle::SubControl subControl, int part,
- XPThemeData *theme)
-{
- theme->partId = part;
- theme->rect = proxy->subControlRect(QStyle::CC_MdiControls, option, subControl, widget);
- if (!option->state.testFlag(QStyle::State_Enabled))
- theme->stateId = CBS_INACTIVE;
- else if (option->state.testFlag(QStyle::State_Sunken) && option->activeSubControls.testFlag(subControl))
- theme->stateId = CBS_PUSHED;
- else if (option->state.testFlag(QStyle::State_MouseOver) && option->activeSubControls.testFlag(subControl))
- theme->stateId = CBS_HOT;
- else
- theme->stateId = CBS_NORMAL;
-}
-
-// 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)
-{
- const auto dpr = pd ? pd->devicePixelRatioF() : qApp->devicePixelRatio();
- const QSizeF nativeSize = QSizeF(theme.size()) / dpr;
- const QSizeF requestedSize(theme.rect.size());
- const auto rawFactor = qMin(requestedSize.width() / nativeSize.width(),
- requestedSize.height() / nativeSize.height());
- const auto factor = rawFactor >= qreal(2) ? qreal(2) : qreal(1);
- return factor;
-}
-#endif // QT_CONFIG(mdiarea)
-
-static void populateTitleBarButtonTheme(const QStyle *proxy, const QWidget *widget,
- const QStyleOptionComplex *option,
- QStyle::SubControl subControl,
- bool isTitleBarActive, int part,
- XPThemeData *theme)
-{
- theme->rect = proxy->subControlRect(QStyle::CC_TitleBar, option, subControl, widget);
- theme->partId = part;
- if (widget && !widget->isEnabled())
- theme->stateId = RBS_DISABLED;
- else if (option->activeSubControls == subControl && option->state.testFlag(QStyle::State_Sunken))
- theme->stateId = RBS_PUSHED;
- else if (option->activeSubControls == subControl && option->state.testFlag(QStyle::State_MouseOver))
- theme->stateId = RBS_HOT;
- else if (!isTitleBarActive)
- theme->stateId = RBS_INACTIVE;
- else
- theme->stateId = RBS_NORMAL;
-}
-
-/*!
- \reimp
-*/
-void QWindowsXPStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex *option,
- QPainter *p, const QWidget *widget) const
-{
- QWindowsXPStylePrivate *d = const_cast<QWindowsXPStylePrivate*>(d_func());
-
- if (!QWindowsXPStylePrivate::useXP()) {
- QWindowsStyle::drawComplexControl(cc, option, p, widget);
- return;
- }
-
- State flags = option->state;
- SubControls sub = option->subControls;
- QRect r = option->rect;
-
- int partId = 0;
- int stateId = 0;
- if (widget && widget->testAttribute(Qt::WA_UnderMouse) && widget->isActiveWindow())
- flags |= State_MouseOver;
-
- switch (cc) {
-#if QT_CONFIG(spinbox)
- case CC_SpinBox:
- if (const QStyleOptionSpinBox *sb = qstyleoption_cast<const QStyleOptionSpinBox *>(option))
- {
- XPThemeData theme(widget, p, QWindowsXPStylePrivate::SpinTheme);
-
- if (sb->frame && (sub & SC_SpinBoxFrame)) {
- partId = EP_EDITTEXT;
- if (!(flags & State_Enabled))
- stateId = ETS_DISABLED;
- else if (flags & State_HasFocus)
- stateId = ETS_FOCUSED;
- else
- stateId = ETS_NORMAL;
-
- XPThemeData ftheme(widget, p, QWindowsXPStylePrivate::EditTheme,
- partId, stateId, r);
- ftheme.noContent = true;
- d->drawBackground(ftheme);
- }
- if (sub & SC_SpinBoxUp) {
- theme.rect = proxy()->subControlRect(CC_SpinBox, option, SC_SpinBoxUp, widget);
- partId = SPNP_UP;
- if (!(sb->stepEnabled & QAbstractSpinBox::StepUpEnabled) || !(flags & State_Enabled))
- stateId = UPS_DISABLED;
- else if (sb->activeSubControls == SC_SpinBoxUp && (sb->state & State_Sunken))
- stateId = UPS_PRESSED;
- else if (sb->activeSubControls == SC_SpinBoxUp && (sb->state & State_MouseOver))
- stateId = UPS_HOT;
- else
- stateId = UPS_NORMAL;
- theme.partId = partId;
- theme.stateId = stateId;
- d->drawBackground(theme);
- }
- if (sub & SC_SpinBoxDown) {
- theme.rect = proxy()->subControlRect(CC_SpinBox, option, SC_SpinBoxDown, widget);
- partId = SPNP_DOWN;
- if (!(sb->stepEnabled & QAbstractSpinBox::StepDownEnabled) || !(flags & State_Enabled))
- stateId = DNS_DISABLED;
- else if (sb->activeSubControls == SC_SpinBoxDown && (sb->state & State_Sunken))
- stateId = DNS_PRESSED;
- else if (sb->activeSubControls == SC_SpinBoxDown && (sb->state & State_MouseOver))
- stateId = DNS_HOT;
- else
- stateId = DNS_NORMAL;
- theme.partId = partId;
- theme.stateId = stateId;
- d->drawBackground(theme);
- }
- }
- break;
-#endif // QT_CONFIG(spinbox)
-#if QT_CONFIG(combobox)
- case CC_ComboBox:
- if (const QStyleOptionComboBox *cmb = qstyleoption_cast<const QStyleOptionComboBox *>(option))
- {
- if (sub & SC_ComboBoxEditField) {
- if (cmb->frame) {
- partId = EP_EDITTEXT;
- if (!(flags & State_Enabled))
- stateId = ETS_DISABLED;
- else if (flags & State_HasFocus)
- stateId = ETS_FOCUSED;
- else
- stateId = ETS_NORMAL;
- XPThemeData theme(widget, p, QWindowsXPStylePrivate::EditTheme, partId, stateId, r);
- d->drawBackground(theme);
- } else {
- QBrush editBrush = cmb->palette.brush(QPalette::Base);
- p->fillRect(option->rect, editBrush);
- }
- if (!cmb->editable) {
- QRect re = proxy()->subControlRect(CC_ComboBox, option, SC_ComboBoxEditField, widget);
- if (option->state & State_HasFocus) {
- p->fillRect(re, option->palette.highlight());
- p->setPen(option->palette.highlightedText().color());
- p->setBackground(option->palette.highlight());
- } else {
- p->fillRect(re, option->palette.base());
- p->setPen(option->palette.text().color());
- p->setBackground(option->palette.base());
- }
- }
- }
-
- if (sub & SC_ComboBoxArrow) {
- XPThemeData theme(widget, p, QWindowsXPStylePrivate::ComboboxTheme);
- theme.rect = proxy()->subControlRect(CC_ComboBox, option, SC_ComboBoxArrow, widget);
- partId = CP_DROPDOWNBUTTON;
- if (!(flags & State_Enabled))
- stateId = CBXS_DISABLED;
- else if (cmb->activeSubControls == SC_ComboBoxArrow && (cmb->state & State_Sunken))
- stateId = CBXS_PRESSED;
- else if (cmb->activeSubControls == SC_ComboBoxArrow && (cmb->state & State_MouseOver))
- stateId = CBXS_HOT;
- else
- stateId = CBXS_NORMAL;
- theme.partId = partId;
- theme.stateId = stateId;
- d->drawBackground(theme);
- }
- }
- break;
-#endif // QT_CONFIG(combobox)
- case CC_ScrollBar:
- if (const QStyleOptionSlider *scrollbar = qstyleoption_cast<const QStyleOptionSlider *>(option))
- {
- XPThemeData theme(widget, p, QWindowsXPStylePrivate::ScrollBarTheme);
- bool maxedOut = (scrollbar->maximum == scrollbar->minimum);
- if (maxedOut)
- flags &= ~State_Enabled;
-
- bool isHorz = flags & State_Horizontal;
- bool isRTL = option->direction == Qt::RightToLeft;
- if (sub & SC_ScrollBarAddLine) {
- theme.rect = proxy()->subControlRect(CC_ScrollBar, option, SC_ScrollBarAddLine, widget);
- partId = SBP_ARROWBTN;
- if (!(flags & State_Enabled))
- stateId = (isHorz ? (isRTL ? ABS_LEFTDISABLED : ABS_RIGHTDISABLED) : ABS_DOWNDISABLED);
- else if (scrollbar->activeSubControls & SC_ScrollBarAddLine && (scrollbar->state & State_Sunken))
- stateId = (isHorz ? (isRTL ? ABS_LEFTPRESSED : ABS_RIGHTPRESSED) : ABS_DOWNPRESSED);
- else if (scrollbar->activeSubControls & SC_ScrollBarAddLine && (scrollbar->state & State_MouseOver))
- stateId = (isHorz ? (isRTL ? ABS_LEFTHOT : ABS_RIGHTHOT) : ABS_DOWNHOT);
- else
- stateId = (isHorz ? (isRTL ? ABS_LEFTNORMAL : ABS_RIGHTNORMAL) : ABS_DOWNNORMAL);
- theme.partId = partId;
- theme.stateId = stateId;
- d->drawBackground(theme);
- }
- if (sub & SC_ScrollBarSubLine) {
- theme.rect = proxy()->subControlRect(CC_ScrollBar, option, SC_ScrollBarSubLine, widget);
- partId = SBP_ARROWBTN;
- if (!(flags & State_Enabled))
- stateId = (isHorz ? (isRTL ? ABS_RIGHTDISABLED : ABS_LEFTDISABLED) : ABS_UPDISABLED);
- else if (scrollbar->activeSubControls & SC_ScrollBarSubLine && (scrollbar->state & State_Sunken))
- stateId = (isHorz ? (isRTL ? ABS_RIGHTPRESSED : ABS_LEFTPRESSED) : ABS_UPPRESSED);
- else if (scrollbar->activeSubControls & SC_ScrollBarSubLine && (scrollbar->state & State_MouseOver))
- stateId = (isHorz ? (isRTL ? ABS_RIGHTHOT : ABS_LEFTHOT) : ABS_UPHOT);
- else
- stateId = (isHorz ? (isRTL ? ABS_RIGHTNORMAL : ABS_LEFTNORMAL) : ABS_UPNORMAL);
- theme.partId = partId;
- theme.stateId = stateId;
- d->drawBackground(theme);
- }
- if (maxedOut) {
- theme.rect = proxy()->subControlRect(CC_ScrollBar, option, SC_ScrollBarSlider, widget);
- theme.rect = theme.rect.united(proxy()->subControlRect(CC_ScrollBar, option, SC_ScrollBarSubPage, widget));
- theme.rect = theme.rect.united(proxy()->subControlRect(CC_ScrollBar, option, SC_ScrollBarAddPage, widget));
- partId = scrollbar->orientation == Qt::Horizontal ? SBP_LOWERTRACKHORZ : SBP_LOWERTRACKVERT;
- stateId = SCRBS_DISABLED;
- theme.partId = partId;
- theme.stateId = stateId;
- d->drawBackground(theme);
- } else {
- if (sub & SC_ScrollBarSubPage) {
- theme.rect = proxy()->subControlRect(CC_ScrollBar, option, SC_ScrollBarSubPage, widget);
- partId = flags & State_Horizontal ? SBP_UPPERTRACKHORZ : SBP_UPPERTRACKVERT;
- if (!(flags & State_Enabled))
- stateId = SCRBS_DISABLED;
- else if (scrollbar->activeSubControls & SC_ScrollBarSubPage && (scrollbar->state & State_Sunken))
- stateId = SCRBS_PRESSED;
- else if (scrollbar->activeSubControls & SC_ScrollBarSubPage && (scrollbar->state & State_MouseOver))
- stateId = SCRBS_HOT;
- else
- stateId = SCRBS_NORMAL;
- theme.partId = partId;
- theme.stateId = stateId;
- d->drawBackground(theme);
- }
- if (sub & SC_ScrollBarAddPage) {
- theme.rect = proxy()->subControlRect(CC_ScrollBar, option, SC_ScrollBarAddPage, widget);
- partId = flags & State_Horizontal ? SBP_LOWERTRACKHORZ : SBP_LOWERTRACKVERT;
- if (!(flags & State_Enabled))
- stateId = SCRBS_DISABLED;
- else if (scrollbar->activeSubControls & SC_ScrollBarAddPage && (scrollbar->state & State_Sunken))
- stateId = SCRBS_PRESSED;
- else if (scrollbar->activeSubControls & SC_ScrollBarAddPage && (scrollbar->state & State_MouseOver))
- stateId = SCRBS_HOT;
- else
- stateId = SCRBS_NORMAL;
- theme.partId = partId;
- theme.stateId = stateId;
- d->drawBackground(theme);
- }
- if (sub & SC_ScrollBarSlider) {
- theme.rect = proxy()->subControlRect(CC_ScrollBar, option, SC_ScrollBarSlider, widget);
- if (!(flags & State_Enabled))
- stateId = SCRBS_DISABLED;
- else if (scrollbar->activeSubControls & SC_ScrollBarSlider && (scrollbar->state & State_Sunken))
- stateId = SCRBS_PRESSED;
- else if (scrollbar->activeSubControls & SC_ScrollBarSlider && (scrollbar->state & State_MouseOver))
- stateId = SCRBS_HOT;
- else
- stateId = SCRBS_NORMAL;
-
- // Draw handle
- theme.partId = flags & State_Horizontal ? SBP_THUMBBTNHORZ : SBP_THUMBBTNVERT;
- theme.stateId = stateId;
- d->drawBackground(theme);
-
- const QRect gripperBounds = QWindowsXPStylePrivate::scrollBarGripperBounds(flags, widget, &theme);
- // Draw gripper if there is enough space
- if (!gripperBounds.isEmpty()) {
- p->save();
- theme.rect = gripperBounds;
- p->setClipRegion(d->region(theme));// Only change inside the region of the gripper
- d->drawBackground(theme); // Transparent gripper ontop of background
- p->restore();
- }
- }
- }
- }
- break;
-
-#if QT_CONFIG(slider)
- case CC_Slider:
- if (const QStyleOptionSlider *slider = qstyleoption_cast<const QStyleOptionSlider *>(option))
- {
- XPThemeData theme(widget, p, QWindowsXPStylePrivate::TrackBarTheme);
- QRect slrect = slider->rect;
- QRegion tickreg = slrect;
- if (sub & SC_SliderGroove) {
- theme.rect = proxy()->subControlRect(CC_Slider, option, SC_SliderGroove, widget);
- if (slider->orientation == Qt::Horizontal) {
- partId = TKP_TRACK;
- stateId = TRS_NORMAL;
- theme.rect = QRect(slrect.left(), theme.rect.center().y() - 2, slrect.width(), 4);
- } else {
- partId = TKP_TRACKVERT;
- stateId = TRVS_NORMAL;
- theme.rect = QRect(theme.rect.center().x() - 2, slrect.top(), 4, slrect.height());
- }
- theme.partId = partId;
- theme.stateId = stateId;
- d->drawBackground(theme);
- tickreg -= theme.rect;
- }
- if (sub & SC_SliderTickmarks) {
- int tickOffset = proxy()->pixelMetric(PM_SliderTickmarkOffset, slider, widget);
- int ticks = slider->tickPosition;
- int thickness = proxy()->pixelMetric(PM_SliderControlThickness, slider, widget);
- int len = proxy()->pixelMetric(PM_SliderLength, slider, widget);
- int available = proxy()->pixelMetric(PM_SliderSpaceAvailable, slider, widget);
- int interval = slider->tickInterval;
- if (interval <= 0) {
- interval = slider->singleStep;
- if (QStyle::sliderPositionFromValue(slider->minimum, slider->maximum, interval,
- available)
- - QStyle::sliderPositionFromValue(slider->minimum, slider->maximum,
- 0, available) < 3)
- interval = slider->pageStep;
- }
- if (!interval)
- interval = 1;
- int fudge = len / 2;
- int pos;
- int bothOffset = (ticks & QSlider::TicksAbove && ticks & QSlider::TicksBelow) ? 1 : 0;
- p->setPen(d->sliderTickColor);
- QVarLengthArray<QLine, 32> lines;
- int v = slider->minimum;
- while (v <= slider->maximum + 1) {
- if (v == slider->maximum + 1 && interval == 1)
- break;
- const int v_ = qMin(v, slider->maximum);
- int tickLength = (v_ == slider->minimum || v_ >= slider->maximum) ? 4 : 3;
- pos = QStyle::sliderPositionFromValue(slider->minimum, slider->maximum,
- v_, available) + fudge;
- if (slider->orientation == Qt::Horizontal) {
- if (ticks & QSlider::TicksAbove)
- lines.append(QLine(pos, tickOffset - 1 - bothOffset,
- pos, tickOffset - 1 - bothOffset - tickLength));
-
- if (ticks & QSlider::TicksBelow)
- lines.append(QLine(pos, tickOffset + thickness + bothOffset,
- pos, tickOffset + thickness + bothOffset + tickLength));
- } else {
- if (ticks & QSlider::TicksAbove)
- lines.append(QLine(tickOffset - 1 - bothOffset, pos,
- tickOffset - 1 - bothOffset - tickLength, pos));
-
- if (ticks & QSlider::TicksBelow)
- lines.append(QLine(tickOffset + thickness + bothOffset, pos,
- tickOffset + thickness + bothOffset + tickLength, pos));
- }
- // in the case where maximum is max int
- int nextInterval = v + interval;
- if (nextInterval < v)
- break;
- v = nextInterval;
- }
- if (!lines.isEmpty()) {
- p->save();
- p->translate(slrect.topLeft());
- p->drawLines(lines.constData(), lines.size());
- p->restore();
- }
- }
- if (sub & SC_SliderHandle) {
- theme.rect = proxy()->subControlRect(CC_Slider, option, SC_SliderHandle, widget);
- if (slider->orientation == Qt::Horizontal) {
- if (slider->tickPosition == QSlider::TicksAbove)
- partId = TKP_THUMBTOP;
- else if (slider->tickPosition == QSlider::TicksBelow)
- partId = TKP_THUMBBOTTOM;
- else
- partId = TKP_THUMB;
-
- if (!(slider->state & State_Enabled))
- stateId = TUS_DISABLED;
- else if (slider->activeSubControls & SC_SliderHandle && (slider->state & State_Sunken))
- stateId = TUS_PRESSED;
- else if (slider->activeSubControls & SC_SliderHandle && (slider->state & State_MouseOver))
- stateId = TUS_HOT;
- else if (flags & State_HasFocus)
- stateId = TUS_FOCUSED;
- else
- stateId = TUS_NORMAL;
- } else {
- if (slider->tickPosition == QSlider::TicksLeft)
- partId = TKP_THUMBLEFT;
- else if (slider->tickPosition == QSlider::TicksRight)
- partId = TKP_THUMBRIGHT;
- else
- partId = TKP_THUMBVERT;
-
- if (!(slider->state & State_Enabled))
- stateId = TUVS_DISABLED;
- else if (slider->activeSubControls & SC_SliderHandle && (slider->state & State_Sunken))
- stateId = TUVS_PRESSED;
- else if (slider->activeSubControls & SC_SliderHandle && (slider->state & State_MouseOver))
- stateId = TUVS_HOT;
- else if (flags & State_HasFocus)
- stateId = TUVS_FOCUSED;
- else
- stateId = TUVS_NORMAL;
- }
- theme.partId = partId;
- theme.stateId = stateId;
- d->drawBackground(theme);
- }
- if (slider->state & State_HasFocus) {
- QStyleOptionFocusRect fropt;
- fropt.QStyleOption::operator=(*slider);
- fropt.rect = subElementRect(SE_SliderFocusRect, slider, widget);
- proxy()->drawPrimitive(PE_FrameFocusRect, &fropt, p, widget);
- }
- }
- break;
-#endif
-#if QT_CONFIG(toolbutton)
- case CC_ToolButton:
- if (const QStyleOptionToolButton *toolbutton
- = qstyleoption_cast<const QStyleOptionToolButton *>(option)) {
- QRect button, menuarea;
- button = proxy()->subControlRect(cc, toolbutton, SC_ToolButton, widget);
- menuarea = proxy()->subControlRect(cc, toolbutton, SC_ToolButtonMenu, widget);
-
- State bflags = toolbutton->state & ~State_Sunken;
- State mflags = bflags;
- bool autoRaise = flags & State_AutoRaise;
- if (autoRaise) {
- if (!(bflags & State_MouseOver) || !(bflags & State_Enabled)) {
- bflags &= ~State_Raised;
- }
- }
-
- if (toolbutton->state & State_Sunken) {
- if (toolbutton->activeSubControls & SC_ToolButton) {
- bflags |= State_Sunken;
- mflags |= State_MouseOver | State_Sunken;
- } else if (toolbutton->activeSubControls & SC_ToolButtonMenu) {
- mflags |= State_Sunken;
- bflags |= State_MouseOver;
- }
- }
-
- QStyleOption tool = *toolbutton;
- if (toolbutton->subControls & SC_ToolButton) {
- if (flags & (State_Sunken | State_On | State_Raised) || !autoRaise) {
- if (toolbutton->features & QStyleOptionToolButton::MenuButtonPopup && autoRaise) {
- XPThemeData theme(widget, p, QWindowsXPStylePrivate::ToolBarTheme);
- theme.partId = TP_SPLITBUTTON;
- theme.rect = button;
- if (!(bflags & State_Enabled))
- stateId = TS_DISABLED;
- else if (bflags & State_Sunken)
- stateId = TS_PRESSED;
- else if (bflags & State_MouseOver || !(flags & State_AutoRaise))
- stateId = flags & State_On ? TS_HOTCHECKED : TS_HOT;
- else if (bflags & State_On)
- stateId = TS_CHECKED;
- else
- stateId = TS_NORMAL;
- if (option->direction == Qt::RightToLeft)
- theme.mirrorHorizontally = true;
- theme.stateId = stateId;
- d->drawBackground(theme);
- } else {
- tool.rect = option->rect;
- tool.state = bflags;
- if (autoRaise) // for tool bars
- proxy()->drawPrimitive(PE_PanelButtonTool, &tool, p, widget);
- else
- proxy()->drawPrimitive(PE_PanelButtonBevel, &tool, p, widget);
- }
- }
- }
-
- if (toolbutton->state & State_HasFocus) {
- QStyleOptionFocusRect fr;
- fr.QStyleOption::operator=(*toolbutton);
- fr.rect.adjust(3, 3, -3, -3);
- if (toolbutton->features & QStyleOptionToolButton::MenuButtonPopup)
- fr.rect.adjust(0, 0, -proxy()->pixelMetric(QStyle::PM_MenuButtonIndicator,
- toolbutton, widget), 0);
- proxy()->drawPrimitive(PE_FrameFocusRect, &fr, p, widget);
- }
- QStyleOptionToolButton label = *toolbutton;
- label.state = bflags;
- int fw = 2;
- if (!autoRaise)
- label.state &= ~State_Sunken;
- label.rect = button.adjusted(fw, fw, -fw, -fw);
- proxy()->drawControl(CE_ToolButtonLabel, &label, p, widget);
-
- if (toolbutton->subControls & SC_ToolButtonMenu) {
- tool.rect = menuarea;
- tool.state = mflags;
- if (autoRaise) {
- proxy()->drawPrimitive(PE_IndicatorButtonDropDown, &tool, p, widget);
- } else {
- tool.state = mflags;
- menuarea.adjust(-2, 0, 0, 0);
- // Draw menu button
- if ((bflags & State_Sunken) != (mflags & State_Sunken)){
- p->save();
- p->setClipRect(menuarea);
- tool.rect = option->rect;
- proxy()->drawPrimitive(PE_PanelButtonBevel, &tool, p, nullptr);
- p->restore();
- }
- // Draw arrow
- p->save();
- p->setPen(option->palette.dark().color());
- p->drawLine(menuarea.left(), menuarea.top() + 3,
- menuarea.left(), menuarea.bottom() - 3);
- p->setPen(option->palette.light().color());
- p->drawLine(menuarea.left() - 1, menuarea.top() + 3,
- menuarea.left() - 1, menuarea.bottom() - 3);
-
- tool.rect = menuarea.adjusted(2, 3, -2, -1);
- proxy()->drawPrimitive(PE_IndicatorArrowDown, &tool, p, widget);
- p->restore();
- }
- } else if (toolbutton->features & QStyleOptionToolButton::HasMenu) {
- int mbi = proxy()->pixelMetric(PM_MenuButtonIndicator, toolbutton, widget);
- QRect ir = toolbutton->rect;
- QStyleOptionToolButton newBtn = *toolbutton;
- newBtn.rect = QRect(ir.right() + 4 - mbi, ir.height() - mbi + 4, mbi - 5, mbi - 5);
- proxy()->drawPrimitive(PE_IndicatorArrowDown, &newBtn, p, widget);
- }
- }
- break;
-#endif // QT_CONFIG(toolbutton)
-
- case CC_TitleBar:
- {
- if (const QStyleOptionTitleBar *tb = qstyleoption_cast<const QStyleOptionTitleBar *>(option))
- {
- const qreal factor = QWindowsStylePrivate::nativeMetricScaleFactor(widget);
- bool isActive = tb->titleBarState & QStyle::State_Active;
- XPThemeData theme(widget, p, QWindowsXPStylePrivate::WindowTheme);
- if (sub & SC_TitleBarLabel) {
-
- partId = (tb->titleBarState & Qt::WindowMinimized) ? WP_MINCAPTION : WP_CAPTION;
- theme.rect = option->rect;
- if (widget && !widget->isEnabled())
- stateId = CS_DISABLED;
- else if (isActive)
- stateId = CS_ACTIVE;
- else
- stateId = CS_INACTIVE;
-
- theme.partId = partId;
- theme.stateId = stateId;
- d->drawBackground(theme);
-
- QRect ir = proxy()->subControlRect(CC_TitleBar, tb, SC_TitleBarLabel, widget);
-
- int result = TST_NONE;
- GetThemeEnumValue(theme.handle(), WP_CAPTION, isActive ? CS_ACTIVE : CS_INACTIVE, TMT_TEXTSHADOWTYPE, &result);
- if (result != TST_NONE) {
- COLORREF textShadowRef;
- GetThemeColor(theme.handle(), WP_CAPTION, isActive ? CS_ACTIVE : CS_INACTIVE, TMT_TEXTSHADOWCOLOR, &textShadowRef);
- QColor textShadow = qRgb(GetRValue(textShadowRef), GetGValue(textShadowRef), GetBValue(textShadowRef));
- p->setPen(textShadow);
- p->drawText(int(ir.x() + 3 * factor), int(ir.y() + 2 * factor),
- int(ir.width() - 1 * factor), ir.height(),
- Qt::AlignLeft | Qt::AlignVCenter | Qt::TextSingleLine, tb->text);
- }
- COLORREF captionText = GetSysColor(isActive ? COLOR_CAPTIONTEXT : COLOR_INACTIVECAPTIONTEXT);
- QColor textColor = qRgb(GetRValue(captionText), GetGValue(captionText), GetBValue(captionText));
- p->setPen(textColor);
- p->drawText(int(ir.x() + 2 * factor), int(ir.y() + 1 * factor),
- int(ir.width() - 2 * factor), ir.height(),
- Qt::AlignLeft | Qt::AlignVCenter | Qt::TextSingleLine, tb->text);
- }
- if (sub & SC_TitleBarSysMenu && tb->titleBarFlags & Qt::WindowSystemMenuHint) {
- theme.rect = proxy()->subControlRect(CC_TitleBar, option, SC_TitleBarSysMenu, widget);
- partId = WP_SYSBUTTON;
- if ((widget && !widget->isEnabled()) || !isActive)
- stateId = SBS_DISABLED;
- else if (option->activeSubControls == SC_TitleBarSysMenu && (option->state & State_Sunken))
- stateId = SBS_PUSHED;
- else if (option->activeSubControls == SC_TitleBarSysMenu && (option->state & State_MouseOver))
- stateId = SBS_HOT;
- else
- stateId = SBS_NORMAL;
- if (!tb->icon.isNull()) {
- tb->icon.paint(p, theme.rect);
- } else {
- theme.partId = partId;
- theme.stateId = stateId;
- if (theme.size().isEmpty()) {
- int iconSize = proxy()->pixelMetric(PM_SmallIconSize, tb, widget);
- QPixmap pm = proxy()->standardIcon(SP_TitleBarMenuButton, tb, widget).pixmap(iconSize, iconSize);
- p->save();
- drawItemPixmap(p, theme.rect, Qt::AlignCenter, pm);
- p->restore();
- } else {
- d->drawBackground(theme);
- }
- }
- }
-
- if (sub & SC_TitleBarMinButton && tb->titleBarFlags & Qt::WindowMinimizeButtonHint
- && !(tb->titleBarState & Qt::WindowMinimized)) {
- populateTitleBarButtonTheme(proxy(), widget, option, SC_TitleBarMinButton, isActive, WP_MINBUTTON, &theme);
- d->drawBackground(theme);
- }
- if (sub & SC_TitleBarMaxButton && tb->titleBarFlags & Qt::WindowMaximizeButtonHint
- && !(tb->titleBarState & Qt::WindowMaximized)) {
- populateTitleBarButtonTheme(proxy(), widget, option, SC_TitleBarMaxButton, isActive, WP_MAXBUTTON, &theme);
- d->drawBackground(theme);
- }
- if (sub & SC_TitleBarContextHelpButton
- && tb->titleBarFlags & Qt::WindowContextHelpButtonHint) {
- populateTitleBarButtonTheme(proxy(), widget, option, SC_TitleBarContextHelpButton, isActive, WP_HELPBUTTON, &theme);
- d->drawBackground(theme);
- }
- bool drawNormalButton = (sub & SC_TitleBarNormalButton)
- && (((tb->titleBarFlags & Qt::WindowMinimizeButtonHint)
- && (tb->titleBarState & Qt::WindowMinimized))
- || ((tb->titleBarFlags & Qt::WindowMaximizeButtonHint)
- && (tb->titleBarState & Qt::WindowMaximized)));
- if (drawNormalButton) {
- populateTitleBarButtonTheme(proxy(), widget, option, SC_TitleBarNormalButton, isActive, WP_RESTOREBUTTON, &theme);
- d->drawBackground(theme);
- }
- if (sub & SC_TitleBarShadeButton && tb->titleBarFlags & Qt::WindowShadeButtonHint
- && !(tb->titleBarState & Qt::WindowMinimized)) {
- populateTitleBarButtonTheme(proxy(), widget, option, SC_TitleBarShadeButton, isActive, WP_MINBUTTON, &theme);
- d->drawBackground(theme);
- }
- if (sub & SC_TitleBarUnshadeButton && tb->titleBarFlags & Qt::WindowShadeButtonHint
- && tb->titleBarState & Qt::WindowMinimized) {
- populateTitleBarButtonTheme(proxy(), widget, option, SC_TitleBarUnshadeButton, isActive, WP_RESTOREBUTTON, &theme);
- d->drawBackground(theme);
- }
- if (sub & SC_TitleBarCloseButton && tb->titleBarFlags & Qt::WindowSystemMenuHint) {
- populateTitleBarButtonTheme(proxy(), widget, option, SC_TitleBarCloseButton, isActive, WP_CLOSEBUTTON, &theme);
- d->drawBackground(theme);
- }
- }
- }
- break;
-
-#if QT_CONFIG(mdiarea)
- case CC_MdiControls:
- {
- XPThemeData theme(widget, p, QWindowsXPStylePrivate::WindowTheme, WP_MDICLOSEBUTTON, CBS_NORMAL);
- if (Q_UNLIKELY(!theme.isValid()))
- return;
-
- if (option->subControls.testFlag(SC_MdiCloseButton)) {
- populateMdiButtonTheme(proxy(), widget, option, SC_MdiCloseButton, WP_MDICLOSEBUTTON, &theme);
- d->drawBackground(theme, mdiButtonCorrectionFactor(theme, widget));
- }
- if (option->subControls.testFlag(SC_MdiNormalButton)) {
- populateMdiButtonTheme(proxy(), widget, option, SC_MdiNormalButton, WP_MDIRESTOREBUTTON, &theme);
- d->drawBackground(theme, mdiButtonCorrectionFactor(theme, widget));
- }
- if (option->subControls.testFlag(QStyle::SC_MdiMinButton)) {
- populateMdiButtonTheme(proxy(), widget, option, SC_MdiMinButton, WP_MDIMINBUTTON, &theme);
- d->drawBackground(theme, mdiButtonCorrectionFactor(theme, widget));
- }
- }
- break;
-#endif // QT_CONFIG(mdiarea)
-#if QT_CONFIG(dial)
- case CC_Dial:
- if (const QStyleOptionSlider *dial = qstyleoption_cast<const QStyleOptionSlider *>(option))
- QStyleHelper::drawDial(dial, p);
- break;
-#endif // QT_CONFIG(dial)
- default:
- QWindowsStyle::drawComplexControl(cc, option, p, widget);
- break;
- }
-}
-
-static inline Qt::Orientation progressBarOrientation(const QStyleOption *option = nullptr)
-{
- if (const QStyleOptionProgressBar *pb = qstyleoption_cast<const QStyleOptionProgressBar *>(option))
- return pb->orientation;
- return Qt::Horizontal;
-}
-
-int QWindowsXPStylePrivate::pixelMetricFromSystemDp(QStyle::PixelMetric pm, const QStyleOption *option, const QWidget *widget)
-{
- switch (pm) {
- case QStyle::PM_IndicatorWidth:
- return XPThemeData::themeSize(widget, nullptr, QWindowsXPStylePrivate::ButtonTheme, BP_CHECKBOX, CBS_UNCHECKEDNORMAL).width();
- case QStyle::PM_IndicatorHeight:
- return XPThemeData::themeSize(widget, nullptr, QWindowsXPStylePrivate::ButtonTheme, BP_CHECKBOX, CBS_UNCHECKEDNORMAL).height();
- case QStyle::PM_ExclusiveIndicatorWidth:
- return XPThemeData::themeSize(widget, nullptr, QWindowsXPStylePrivate::ButtonTheme, BP_RADIOBUTTON, RBS_UNCHECKEDNORMAL).width();
- case QStyle::PM_ExclusiveIndicatorHeight:
- return XPThemeData::themeSize(widget, nullptr, QWindowsXPStylePrivate::ButtonTheme, BP_RADIOBUTTON, RBS_UNCHECKEDNORMAL).height();
- case QStyle::PM_ProgressBarChunkWidth:
- return progressBarOrientation(option) == Qt::Horizontal
- ? XPThemeData::themeSize(widget, nullptr, QWindowsXPStylePrivate::ProgressTheme, PP_CHUNK).width()
- : XPThemeData::themeSize(widget, nullptr, QWindowsXPStylePrivate::ProgressTheme, PP_CHUNKVERT).height();
- case QStyle::PM_SliderThickness:
- return XPThemeData::themeSize(widget, nullptr, QWindowsXPStylePrivate::TrackBarTheme, TKP_THUMB).height();
- case QStyle::PM_TitleBarHeight:
- return widget && (widget->windowType() == Qt::Tool)
- ? GetSystemMetrics(SM_CYSMCAPTION) + GetSystemMetrics(SM_CXSIZEFRAME)
- : GetSystemMetrics(SM_CYCAPTION) + GetSystemMetrics(SM_CXSIZEFRAME);
- case QStyle::PM_MdiSubWindowFrameWidth:
- return XPThemeData::themeSize(widget, nullptr, QWindowsXPStylePrivate::WindowTheme, WP_FRAMELEFT, FS_ACTIVE).width();
- case QStyle::PM_DockWidgetFrameWidth:
- return XPThemeData::themeSize(widget, nullptr, QWindowsXPStylePrivate::WindowTheme, WP_SMALLFRAMERIGHT, FS_ACTIVE).width();
- default:
- break;
- }
- return QWindowsXPStylePrivate::InvalidMetric;
-}
-
-/*! \reimp */
-int QWindowsXPStyle::pixelMetric(PixelMetric pm, const QStyleOption *option, const QWidget *widget) const
-{
- if (!QWindowsXPStylePrivate::useXP())
- return QWindowsStyle::pixelMetric(pm, option, widget);
-
- int res = QWindowsXPStylePrivate::pixelMetricFromSystemDp(pm, option, widget);
- if (res != QWindowsStylePrivate::InvalidMetric)
- return qRound(qreal(res) * QWindowsStylePrivate::nativeMetricScaleFactor(widget));
-
- res = 0;
- switch (pm) {
- case PM_MenuBarPanelWidth:
- case PM_ButtonDefaultIndicator:
- res = 0;
- break;
-
- case PM_DefaultFrameWidth:
- res = qobject_cast<const QListView*>(widget) ? 2 : 1;
- break;
- case PM_MenuPanelWidth:
- case PM_SpinBoxFrameWidth:
- res = 1;
- break;
-
- case PM_TabBarTabOverlap:
- case PM_MenuHMargin:
- case PM_MenuVMargin:
- res = 2;
- break;
-
- case PM_TabBarBaseOverlap:
- if (const QStyleOptionTab *tab = qstyleoption_cast<const QStyleOptionTab *>(option)) {
- switch (tab->shape) {
- case QTabBar::RoundedNorth:
- case QTabBar::TriangularNorth:
- case QTabBar::RoundedWest:
- case QTabBar::TriangularWest:
- res = 1;
- break;
- case QTabBar::RoundedSouth:
- case QTabBar::TriangularSouth:
- res = 2;
- break;
- case QTabBar::RoundedEast:
- case QTabBar::TriangularEast:
- res = 3;
- break;
- }
- }
- break;
-
- case PM_SplitterWidth:
- res = qMax(int(QStyleHelper::dpiScaled(5., option)),
- QApplication::globalStrut().width());
- break;
-
- case PM_MdiSubWindowMinimizedWidth:
- res = 160;
- break;
-
-#if QT_CONFIG(toolbar)
- case PM_ToolBarHandleExtent:
- res = int(QStyleHelper::dpiScaled(8., option));
- break;
-
-#endif // QT_CONFIG(toolbar)
- case PM_DockWidgetSeparatorExtent:
- case PM_DockWidgetTitleMargin:
- res = int(QStyleHelper::dpiScaled(4., option));
- break;
-
- case PM_ButtonShiftHorizontal:
- case PM_ButtonShiftVertical:
- res = qstyleoption_cast<const QStyleOptionToolButton *>(option) ? 1 : 0;
- break;
-
- default:
- res = QWindowsStyle::pixelMetric(pm, option, widget);
- }
-
- return res;
-}
-
-/*
- This function is used by subControlRect to check if a button
- should be drawn for the given subControl given a set of window flags.
-*/
-static bool buttonVisible(const QStyle::SubControl sc, const QStyleOptionTitleBar *tb){
-
- bool isMinimized = tb->titleBarState & Qt::WindowMinimized;
- bool isMaximized = tb->titleBarState & Qt::WindowMaximized;
- const uint flags = tb->titleBarFlags;
- bool retVal = false;
- switch (sc) {
- case QStyle::SC_TitleBarContextHelpButton:
- if (flags & Qt::WindowContextHelpButtonHint)
- retVal = true;
- break;
- case QStyle::SC_TitleBarMinButton:
- if (!isMinimized && (flags & Qt::WindowMinimizeButtonHint))
- retVal = true;
- break;
- case QStyle::SC_TitleBarNormalButton:
- if (isMinimized && (flags & Qt::WindowMinimizeButtonHint))
- retVal = true;
- else if (isMaximized && (flags & Qt::WindowMaximizeButtonHint))
- retVal = true;
- break;
- case QStyle::SC_TitleBarMaxButton:
- if (!isMaximized && (flags & Qt::WindowMaximizeButtonHint))
- retVal = true;
- break;
- case QStyle::SC_TitleBarShadeButton:
- if (!isMinimized && flags & Qt::WindowShadeButtonHint)
- retVal = true;
- break;
- case QStyle::SC_TitleBarUnshadeButton:
- if (isMinimized && flags & Qt::WindowShadeButtonHint)
- retVal = true;
- break;
- case QStyle::SC_TitleBarCloseButton:
- if (flags & Qt::WindowSystemMenuHint)
- retVal = true;
- break;
- case QStyle::SC_TitleBarSysMenu:
- if (flags & Qt::WindowSystemMenuHint)
- retVal = true;
- break;
- default :
- retVal = true;
- }
- return retVal;
-}
-
-/*!
- \reimp
-*/
-QRect QWindowsXPStyle::subControlRect(ComplexControl cc, const QStyleOptionComplex *option,
- SubControl subControl, const QWidget *widget) const
-{
- if (!QWindowsXPStylePrivate::useXP())
- return QWindowsStyle::subControlRect(cc, option, subControl, widget);
-
- QRect rect;
-
- switch (cc) {
- case CC_TitleBar:
- if (const QStyleOptionTitleBar *tb = qstyleoption_cast<const QStyleOptionTitleBar *>(option)) {
- if (!buttonVisible(subControl, tb))
- return rect;
- const bool isToolTitle = false;
- const int height = tb->rect.height();
- const int width = tb->rect.width();
- const int buttonMargin = int(QStyleHelper::dpiScaled(4, option));
- const qreal factor = QWindowsStylePrivate::nativeMetricScaleFactor(widget);
- int buttonHeight = qRound(qreal(GetSystemMetrics(SM_CYSIZE)) * factor)
- - buttonMargin;
- int buttonWidth = qRound(qreal(GetSystemMetrics(SM_CXSIZE)) * factor)
- - buttonMargin;
- const int delta = buttonWidth + 2;
- int controlTop = option->rect.bottom() - buttonHeight - 2;
- const int frameWidth = proxy()->pixelMetric(PM_MdiSubWindowFrameWidth, option, widget);
- const bool sysmenuHint = (tb->titleBarFlags & Qt::WindowSystemMenuHint) != 0;
- const bool minimizeHint = (tb->titleBarFlags & Qt::WindowMinimizeButtonHint) != 0;
- const bool maximizeHint = (tb->titleBarFlags & Qt::WindowMaximizeButtonHint) != 0;
- const bool contextHint = (tb->titleBarFlags & Qt::WindowContextHelpButtonHint) != 0;
- const bool shadeHint = (tb->titleBarFlags & Qt::WindowShadeButtonHint) != 0;
- bool isMinimized = tb->titleBarState & Qt::WindowMinimized;
- bool isMaximized = tb->titleBarState & Qt::WindowMaximized;
- int offset = 0;
-
- switch (subControl) {
- case SC_TitleBarLabel:
- rect = QRect(frameWidth, 0, width - (buttonWidth + frameWidth + 10), height);
- if (isToolTitle) {
- if (sysmenuHint) {
- rect.adjust(0, 0, -buttonWidth - 3, 0);
- }
- if (minimizeHint || maximizeHint)
- rect.adjust(0, 0, -buttonWidth - 2, 0);
- } else {
- if (sysmenuHint) {
- const int leftOffset = height - 8;
- rect.adjust(leftOffset, 0, 0, 0);
- }
- if (minimizeHint)
- rect.adjust(0, 0, -buttonWidth - 2, 0);
- if (maximizeHint)
- rect.adjust(0, 0, -buttonWidth - 2, 0);
- if (contextHint)
- rect.adjust(0, 0, -buttonWidth - 2, 0);
- if (shadeHint)
- rect.adjust(0, 0, -buttonWidth - 2, 0);
- }
- break;
-
- case SC_TitleBarContextHelpButton:
- if (tb->titleBarFlags & Qt::WindowContextHelpButtonHint)
- offset += delta;
- Q_FALLTHROUGH();
- case SC_TitleBarMinButton:
- if (!isMinimized && (tb->titleBarFlags & Qt::WindowMinimizeButtonHint))
- offset += delta;
- else if (subControl == SC_TitleBarMinButton)
- break;
- Q_FALLTHROUGH();
- case SC_TitleBarNormalButton:
- if (isMinimized && (tb->titleBarFlags & Qt::WindowMinimizeButtonHint))
- offset += delta;
- else if (isMaximized && (tb->titleBarFlags & Qt::WindowMaximizeButtonHint))
- offset += delta;
- else if (subControl == SC_TitleBarNormalButton)
- break;
- Q_FALLTHROUGH();
- case SC_TitleBarMaxButton:
- if (!isMaximized && (tb->titleBarFlags & Qt::WindowMaximizeButtonHint))
- offset += delta;
- else if (subControl == SC_TitleBarMaxButton)
- break;
- Q_FALLTHROUGH();
- case SC_TitleBarShadeButton:
- if (!isMinimized && (tb->titleBarFlags & Qt::WindowShadeButtonHint))
- offset += delta;
- else if (subControl == SC_TitleBarShadeButton)
- break;
- Q_FALLTHROUGH();
- case SC_TitleBarUnshadeButton:
- if (isMinimized && (tb->titleBarFlags & Qt::WindowShadeButtonHint))
- offset += delta;
- else if (subControl == SC_TitleBarUnshadeButton)
- break;
- Q_FALLTHROUGH();
- case SC_TitleBarCloseButton:
- if (tb->titleBarFlags & Qt::WindowSystemMenuHint)
- offset += delta;
- else if (subControl == SC_TitleBarCloseButton)
- break;
-
- rect.setRect(width - offset - controlTop + 1, controlTop,
- buttonWidth, buttonHeight);
- break;
-
- case SC_TitleBarSysMenu:
- {
- const int controlTop = 6;
- const int controlHeight = height - controlTop - 3;
- const int iconExtent = proxy()->pixelMetric(PM_SmallIconSize);
- QSize iconSize = tb->icon.actualSize(QSize(iconExtent, iconExtent));
- if (tb->icon.isNull())
- iconSize = QSize(controlHeight, controlHeight);
- int hPad = (controlHeight - iconSize.height())/2;
- int vPad = (controlHeight - iconSize.width())/2;
- rect = QRect(frameWidth + hPad, controlTop + vPad, iconSize.width(), iconSize.height());
- }
- break;
- default:
- break;
- }
- }
- break;
-
- case CC_ComboBox:
- if (const QStyleOptionComboBox *cmb = qstyleoption_cast<const QStyleOptionComboBox *>(option)) {
- const int x = cmb->rect.x(), y = cmb->rect.y(), wi = cmb->rect.width(), he = cmb->rect.height();
- const int xpos = x + wi - qRound(QStyleHelper::dpiScaled(1 + 16, option));
-
- switch (subControl) {
- case SC_ComboBoxFrame:
- rect = cmb->rect;
- break;
-
- case SC_ComboBoxArrow: {
- const qreal dpi = QStyleHelper::dpi(option);
- rect = QRect(xpos, y + qRound(QStyleHelper::dpiScaled(1, dpi)),
- qRound(QStyleHelper::dpiScaled(16, dpi)),
- he - qRound(QStyleHelper::dpiScaled(2, dpi)));
- }
- break;
-
- case SC_ComboBoxEditField: {
- const qreal dpi = QStyleHelper::dpi(option);
- const int frame = qRound(QStyleHelper::dpiScaled(2, dpi));
- rect = QRect(x + frame, y + frame,
- wi - qRound(QStyleHelper::dpiScaled(3 + 16, dpi)),
- he - qRound(QStyleHelper::dpiScaled(4, dpi)));
- }
- break;
-
- case SC_ComboBoxListBoxPopup:
- rect = cmb->rect;
- break;
-
- default:
- break;
- }
- }
- break;
-#if QT_CONFIG(mdiarea)
- case CC_MdiControls:
- {
- int numSubControls = 0;
- if (option->subControls & SC_MdiCloseButton)
- ++numSubControls;
- if (option->subControls & SC_MdiMinButton)
- ++numSubControls;
- if (option->subControls & SC_MdiNormalButton)
- ++numSubControls;
- if (numSubControls == 0)
- break;
-
- int buttonWidth = option->rect.width() / numSubControls;
- int offset = 0;
- switch (subControl) {
- case SC_MdiCloseButton:
- // Only one sub control, no offset needed.
- if (numSubControls == 1)
- break;
- offset += buttonWidth;
- Q_FALLTHROUGH();
- case SC_MdiNormalButton:
- // No offset needed if
- // 1) There's only one sub control
- // 2) We have a close button and a normal button (offset already added in SC_MdiClose)
- if (numSubControls == 1 || (numSubControls == 2 && !(option->subControls & SC_MdiMinButton)))
- break;
- if (option->subControls & SC_MdiNormalButton)
- offset += buttonWidth;
- break;
- default:
- break;
- }
- rect = QRect(offset, 0, buttonWidth, option->rect.height());
- break;
- }
-#endif // QT_CONFIG(mdiarea)
-
- default:
- rect = visualRect(option->direction, option->rect,
- QWindowsStyle::subControlRect(cc, option, subControl, widget));
- break;
- }
- return visualRect(option->direction, option->rect, rect);
-}
-
-/*!
- \reimp
-*/
-QSize QWindowsXPStyle::sizeFromContents(ContentsType ct, const QStyleOption *option,
- const QSize &contentsSize, const QWidget *widget) const
-{
- if (!QWindowsXPStylePrivate::useXP())
- return QWindowsStyle::sizeFromContents(ct, option, contentsSize, widget);
-
- QSize sz(contentsSize);
- switch (ct) {
- case CT_LineEdit:
- case CT_ComboBox:
- {
- XPThemeData buttontheme(widget, nullptr, QWindowsXPStylePrivate::ButtonTheme, BP_PUSHBUTTON, PBS_NORMAL);
- if (buttontheme.isValid()) {
- const qreal factor = QWindowsXPStylePrivate::nativeMetricScaleFactor(widget);
- const QMarginsF borderSize = buttontheme.margins() * factor;
- if (!borderSize.isNull()) {
- const qreal margin = qreal(2) * factor;
- sz.rwidth() += qRound(borderSize.left() + borderSize.right() - margin);
- sz.rheight() += int(borderSize.bottom() + borderSize.top() - margin
- + qreal(1) / factor - 1);
- }
- const int textMargins = 2*(proxy()->pixelMetric(PM_FocusFrameHMargin) + 1);
- sz += QSize(qMax(pixelMetric(QStyle::PM_ScrollBarExtent, option, widget)
- + textMargins, 23), 0); //arrow button
- }
- }
- break;
- case CT_SpinBox:
- {
- //Spinbox adds frame twice
- sz = QWindowsStyle::sizeFromContents(ct, option, contentsSize, widget);
- int border = proxy()->pixelMetric(PM_SpinBoxFrameWidth, option, widget);
- sz -= QSize(2*border, 2*border);
- }
- break;
- case CT_TabWidget:
- sz += QSize(6, 6);
- break;
- case CT_Menu:
- sz += QSize(1, 0);
- break;
-#if QT_CONFIG(menubar)
- case CT_MenuBarItem:
- if (!sz.isEmpty())
- sz += QSize(windowsItemHMargin * 5 + 1, 6);
- break;
-#endif
- case CT_MenuItem:
- if (const QStyleOptionMenuItem *menuitem = qstyleoption_cast<const QStyleOptionMenuItem *>(option))
- {
- if (menuitem->menuItemType != QStyleOptionMenuItem::Separator) {
- sz = QWindowsStyle::sizeFromContents(ct, option, sz, widget);
- sz.setHeight(sz.height() - 2);
- return sz;
- }
- }
- sz = QWindowsStyle::sizeFromContents(ct, option, sz, widget);
- break;
-
- case CT_MdiControls: {
- sz.setHeight(int(QStyleHelper::dpiScaled(19, option)));
- int width = 54;
- if (const QStyleOptionComplex *styleOpt = qstyleoption_cast<const QStyleOptionComplex *>(option)) {
- width = 0;
- if (styleOpt->subControls & SC_MdiMinButton)
- width += 17 + 1;
- if (styleOpt->subControls & SC_MdiNormalButton)
- width += 17 + 1;
- if (styleOpt->subControls & SC_MdiCloseButton)
- width += 17 + 1;
- }
- sz.setWidth(int(QStyleHelper::dpiScaled(width, option)));
- }
- break;
-
- default:
- sz = QWindowsStyle::sizeFromContents(ct, option, sz, widget);
- break;
- }
-
- return sz;
-}
-
-
-/*! \reimp */
-int QWindowsXPStyle::styleHint(StyleHint hint, const QStyleOption *option, const QWidget *widget,
- QStyleHintReturn *returnData) const
-{
- QWindowsXPStylePrivate *d = const_cast<QWindowsXPStylePrivate*>(d_func());
- if (!QWindowsXPStylePrivate::useXP())
- return QWindowsStyle::styleHint(hint, option, widget, returnData);
-
- int res = 0;
- switch (hint) {
-
- case SH_EtchDisabledText:
- res = (qobject_cast<const QLabel*>(widget) != 0);
- break;
-
- case SH_SpinControls_DisableOnBounds:
- res = 0;
- break;
-
- case SH_TitleBar_AutoRaise:
- case SH_TitleBar_NoBorder:
- res = 1;
- break;
-
- case SH_GroupBox_TextLabelColor:
- if (!widget || (widget && widget->isEnabled()))
- res = d->groupBoxTextColor;
- else
- res = d->groupBoxTextColorDisabled;
- break;
-
- case SH_Table_GridLineColor:
- res = 0xC0C0C0;
- break;
-
- case SH_WindowFrame_Mask:
- {
- res = 1;
- QStyleHintReturnMask *mask = qstyleoption_cast<QStyleHintReturnMask *>(returnData);
- const QStyleOptionTitleBar *titlebar = qstyleoption_cast<const QStyleOptionTitleBar *>(option);
- if (mask && titlebar) {
- // Note certain themes will not return the whole window frame but only the titlebar part when
- // queried This function needs to return the entire window mask, hence we will only fetch the mask for the
- // titlebar itself and add the remaining part of the window rect at the bottom.
- int tbHeight = proxy()->pixelMetric(PM_TitleBarHeight, option, widget);
- QRect titleBarRect = option->rect;
- titleBarRect.setHeight(tbHeight);
- XPThemeData themeData;
- if (titlebar->titleBarState & Qt::WindowMinimized) {
- themeData = XPThemeData(widget, nullptr,
- QWindowsXPStylePrivate::WindowTheme,
- WP_MINCAPTION, CS_ACTIVE, titleBarRect);
- } else
- themeData = XPThemeData(widget, nullptr,
- QWindowsXPStylePrivate::WindowTheme,
- WP_CAPTION, CS_ACTIVE, titleBarRect);
- mask->region = d->region(themeData) +
- QRect(0, tbHeight, option->rect.width(), option->rect.height() - tbHeight);
- }
- }
- break;
-#if QT_CONFIG(rubberband)
- case SH_RubberBand_Mask:
- if (qstyleoption_cast<const QStyleOptionRubberBand *>(option))
- res = 0;
- break;
-#endif // QT_CONFIG(rubberband)
-
- case SH_ItemView_DrawDelegateFrame:
- res = 1;
- break;
-
- default:
- res =QWindowsStyle::styleHint(hint, option, widget, returnData);
- }
-
- return res;
-}
-
-/*! \reimp */
-QPalette QWindowsXPStyle::standardPalette() const
-{
- return QWindowsXPStylePrivate::useXP() ? QPalette() : QWindowsStyle::standardPalette();
-}
-
-/*!
- \reimp
-*/
-QPixmap QWindowsXPStyle::standardPixmap(StandardPixmap standardPixmap, const QStyleOption *option,
- const QWidget *widget) const
-{
- if (!QWindowsXPStylePrivate::useXP())
- return QWindowsStyle::standardPixmap(standardPixmap, option, widget);
-
- switch(standardPixmap) {
- case SP_TitleBarMaxButton:
- case SP_TitleBarCloseButton:
- if (qstyleoption_cast<const QStyleOptionDockWidget *>(option))
- {
- if (widget && widget->isWindow()) {
- XPThemeData theme(widget, nullptr, QWindowsXPStylePrivate::WindowTheme, WP_SMALLCLOSEBUTTON, CBS_NORMAL);
- if (theme.isValid()) {
- const QSize size = (theme.size() * QWindowsStylePrivate::nativeMetricScaleFactor(widget)).toSize();
- return QIcon(QWindowsStyle::standardPixmap(standardPixmap, option, widget)).pixmap(size);
- }
- }
- }
- break;
- default:
- break;
- }
- return QWindowsStyle::standardPixmap(standardPixmap, option, widget);
-}
-
-/*!
- \reimp
-*/
-QIcon QWindowsXPStyle::standardIcon(StandardPixmap standardIcon,
- const QStyleOption *option,
- const QWidget *widget) const
-{
- if (!QWindowsXPStylePrivate::useXP()) {
- return QWindowsStyle::standardIcon(standardIcon, option, widget);
- }
-
- QWindowsXPStylePrivate *d = const_cast<QWindowsXPStylePrivate*>(d_func());
- switch(standardIcon) {
- case SP_TitleBarMaxButton:
- if (qstyleoption_cast<const QStyleOptionDockWidget *>(option))
- {
- if (d->dockFloat.isNull()) {
- XPThemeData themeSize(nullptr, nullptr, QWindowsXPStylePrivate::WindowTheme,
- WP_SMALLCLOSEBUTTON, CBS_NORMAL);
- XPThemeData theme(nullptr, nullptr, QWindowsXPStylePrivate::WindowTheme,
- WP_MAXBUTTON, MAXBS_NORMAL);
- if (theme.isValid()) {
- const QSize size = (themeSize.size() * QWindowsStylePrivate::nativeMetricScaleFactor(widget)).toSize();
- QPixmap pm(size);
- pm.fill(Qt::transparent);
- QPainter p(&pm);
- theme.painter = &p;
- theme.rect = QRect(QPoint(0, 0), size);
- d->drawBackground(theme);
- d->dockFloat.addPixmap(pm, QIcon::Normal, QIcon::Off); // Normal
- pm.fill(Qt::transparent);
- theme.stateId = MAXBS_PUSHED;
- d->drawBackground(theme);
- d->dockFloat.addPixmap(pm, QIcon::Normal, QIcon::On); // Pressed
- pm.fill(Qt::transparent);
- theme.stateId = MAXBS_HOT;
- d->drawBackground(theme);
- d->dockFloat.addPixmap(pm, QIcon::Active, QIcon::Off); // Hover
- pm.fill(Qt::transparent);
- theme.stateId = MAXBS_INACTIVE;
- d->drawBackground(theme);
- d->dockFloat.addPixmap(pm, QIcon::Disabled, QIcon::Off); // Disabled
- }
- }
- if (widget && widget->isWindow())
- return d->dockFloat;
-
- }
- break;
- case SP_TitleBarCloseButton:
- if (qstyleoption_cast<const QStyleOptionDockWidget *>(option))
- {
- if (d->dockClose.isNull()) {
- XPThemeData theme(nullptr, nullptr, QWindowsXPStylePrivate::WindowTheme,
- WP_SMALLCLOSEBUTTON, CBS_NORMAL);
- if (theme.isValid()) {
- const QSize size = (theme.size() * QWindowsStylePrivate::nativeMetricScaleFactor(widget)).toSize();
- QPixmap pm(size);
- pm.fill(Qt::transparent);
- QPainter p(&pm);
- theme.painter = &p;
- theme.partId = WP_CLOSEBUTTON; // ####
- theme.rect = QRect(QPoint(0, 0), size);
- d->drawBackground(theme);
- d->dockClose.addPixmap(pm, QIcon::Normal, QIcon::Off); // Normal
- pm.fill(Qt::transparent);
- theme.stateId = CBS_PUSHED;
- d->drawBackground(theme);
- d->dockClose.addPixmap(pm, QIcon::Normal, QIcon::On); // Pressed
- pm.fill(Qt::transparent);
- theme.stateId = CBS_HOT;
- d->drawBackground(theme);
- d->dockClose.addPixmap(pm, QIcon::Active, QIcon::Off); // Hover
- pm.fill(Qt::transparent);
- theme.stateId = CBS_INACTIVE;
- d->drawBackground(theme);
- d->dockClose.addPixmap(pm, QIcon::Disabled, QIcon::Off); // Disabled
- }
- }
- if (widget && widget->isWindow())
- return d->dockClose;
- }
- break;
- case SP_TitleBarNormalButton:
- if (qstyleoption_cast<const QStyleOptionDockWidget *>(option))
- {
- if (d->dockFloat.isNull()) {
- XPThemeData themeSize(nullptr, nullptr, QWindowsXPStylePrivate::WindowTheme,
- WP_SMALLCLOSEBUTTON, CBS_NORMAL);
- XPThemeData theme(nullptr, nullptr, QWindowsXPStylePrivate::WindowTheme,
- WP_RESTOREBUTTON, RBS_NORMAL);
- if (theme.isValid()) {
- const QSize size = (themeSize.size() * QWindowsStylePrivate::nativeMetricScaleFactor(widget)).toSize();
- QPixmap pm(size);
- pm.fill(Qt::transparent);
- QPainter p(&pm);
- theme.painter = &p;
- theme.rect = QRect(QPoint(0, 0), size);
- d->drawBackground(theme);
- d->dockFloat.addPixmap(pm, QIcon::Normal, QIcon::Off); // Normal
- pm.fill(Qt::transparent);
- theme.stateId = RBS_PUSHED;
- d->drawBackground(theme);
- d->dockFloat.addPixmap(pm, QIcon::Normal, QIcon::On); // Pressed
- pm.fill(Qt::transparent);
- theme.stateId = RBS_HOT;
- d->drawBackground(theme);
- d->dockFloat.addPixmap(pm, QIcon::Active, QIcon::Off); // Hover
- pm.fill(Qt::transparent);
- theme.stateId = RBS_INACTIVE;
- d->drawBackground(theme);
- d->dockFloat.addPixmap(pm, QIcon::Disabled, QIcon::Off); // Disabled
- }
- }
- if (widget && widget->isWindow())
- return d->dockFloat;
-
- }
- break;
- default:
- break;
- }
-
- return QWindowsStyle::standardIcon(standardIcon, option, widget);
-}
-
-/*!
- \internal
-
- Constructs a QWindowsXPStyle object.
-*/
-QWindowsXPStyle::QWindowsXPStyle(QWindowsXPStylePrivate &dd) : QWindowsStyle(dd)
-{
-}
-
-#ifndef QT_NO_DEBUG_STREAM
-QDebug operator<<(QDebug d, const XPThemeData &t)
-{
- QDebugStateSaver saver(d);
- d.nospace();
- d << "XPThemeData(" << t.widget << ", theme=#" << t.theme << ", " << t.htheme
- << ", partId=" << t.partId << ", stateId=" << t.stateId << ", rect=" << t.rect
- << ", mirrorHorizontally=" << t.mirrorHorizontally << ", mirrorVertically="
- << t.mirrorVertically << ", noBorder=" << t.noBorder << ", noContent=" << t.noContent
- << ", rotate=" << t.rotate << ')';
- return d;
-}
-
-QDebug operator<<(QDebug d, const ThemeMapKey &k)
-{
- QDebugStateSaver saver(d);
- d.nospace();
- d << "ThemeMapKey(theme=#" << k.theme
- << ", partId=" << k.partId << ", stateId=" << k.stateId
- << ", noBorder=" << k.noBorder << ", noContent=" << k.noContent << ')';
- return d;
-}
-
-QDebug operator<<(QDebug d, const ThemeMapData &td)
-{
- QDebugStateSaver saver(d);
- d.nospace();
- d << "ThemeMapData(alphaType=" << td.alphaType
- << ", dataValid=" << td.dataValid << ", partIsTransparent=" << td.partIsTransparent
- << ", hasAlphaChannel=" << td.hasAlphaChannel << ", wasAlphaSwapped=" << td.wasAlphaSwapped
- << ", hadInvalidAlpha=" << td.hadInvalidAlpha << ')';
- return d;
-}
-#endif // QT_NO_DEBUG_STREAM
-
-// Debugging code ---------------------------------------------------------------------[ START ]---
-// The code for this point on is not compiled by default, but only used as assisting
-// debugging code when you uncomment the DEBUG_XP_STYLE define at the top of the file.
-
-#ifdef DEBUG_XP_STYLE
-// The schema file expects these to be defined by the user.
-#define TMT_ENUMDEF 8
-#define TMT_ENUMVAL TEXT('A')
-#define TMT_ENUM TEXT('B')
-#define SCHEMA_STRINGS // For 2nd pass on schema file
-QT_BEGIN_INCLUDE_NAMESPACE
-#include <tmschema.h>
-QT_END_INCLUDE_NAMESPACE
-
-// A property's value, type and name combo
-struct PropPair {
- int propValue;
- int propType;
- LPCWSTR propName;
-};
-
-// Operator for sorting of PropPairs
-bool operator<(PropPair a, PropPair b) {
- return wcscmp(a.propName, b.propName) < 0;
-}
-
-// Our list of all possible properties
-static QList<PropPair> all_props;
-
-
-/*! \internal
- Dumps a portion of the full native DIB section double buffer.
- The DIB section double buffer is only used when doing special
- transformations to the theme part, or when the real double
- buffer in the paintengine does not have an HDC we may use
- directly.
- Since we cannot rely on the pixel data we get from Microsoft
- when drawing into the DIB section, we use this function to
- see the actual data we got, and can determin the appropriate
- action.
-*/
-void QWindowsXPStylePrivate::dumpNativeDIB(int w, int h)
-{
- if (w && h) {
- static int pCount = 0;
- DWORD *bufPix = (DWORD*)bufferPixels;
-
- char *bufferDump = new char[bufferH * bufferW * 16];
- char *bufferPos = bufferDump;
-
- memset(bufferDump, 0, sizeof(bufferDump));
- bufferPos += sprintf(bufferPos, "const int pixelBufferW%d = %d;\n", pCount, w);
- bufferPos += sprintf(bufferPos, "const int pixelBufferH%d = %d;\n", pCount, h);
- bufferPos += sprintf(bufferPos, "const unsigned DWORD pixelBuffer%d[] = {", pCount);
- for (int iy = 0; iy < h; ++iy) {
- bufferPos += sprintf(bufferPos, "\n ");
- bufPix = (DWORD*)(bufferPixels + (iy * bufferW * 4));
- for (int ix = 0; ix < w; ++ix) {
- bufferPos += sprintf(bufferPos, "0x%08x, ", *bufPix);
- ++bufPix;
- }
- }
- bufferPos += sprintf(bufferPos, "\n};\n\n");
- printf(bufferDump);
-
- delete[] bufferDump;
- ++pCount;
- }
-}
-
-/*! \internal
- Shows the value of a given property for a part.
-*/
-static void showProperty(XPThemeData &themeData, const PropPair &prop)
-{
- PROPERTYORIGIN origin = PO_NOTFOUND;
- GetThemePropertyOrigin(themeData.handle(), themeData.partId, themeData.stateId, prop.propValue, &origin);
- const char *originStr;
- switch(origin) {
- case PO_STATE:
- originStr = "State ";
- break;
- case PO_PART:
- originStr = "Part ";
- break;
- case PO_CLASS:
- originStr = "Class ";
- break;
- case PO_GLOBAL:
- originStr = "Globl ";
- break;
- case PO_NOTFOUND:
- default:
- originStr = "Unkwn ";
- break;
- }
-
- switch(prop.propType) {
- case TMT_STRING:
- {
- wchar_t buffer[512];
- GetThemeString(themeData.handle(), themeData.partId, themeData.stateId, prop.propValue, buffer, 512);
- printf(" (%sString) %-20S: %S\n", originStr, prop.propName, buffer);
- }
- break;
- case TMT_ENUM:
- {
- int result = -1;
- GetThemeEnumValue(themeData.handle(), themeData.partId, themeData.stateId, prop.propValue, &result);
- printf(" (%sEnum) %-20S: %d\n", originStr, prop.propName, result);
- }
- break;
- case TMT_INT:
- {
- int result = -1;
- GetThemeInt(themeData.handle(), themeData.partId, themeData.stateId, prop.propValue, &result);
- printf(" (%sint) %-20S: %d\n", originStr, prop.propName, result);
- }
- break;
- case TMT_BOOL:
- {
- BOOL result = false;
- GetThemeBool(themeData.handle(), themeData.partId, themeData.stateId, prop.propValue, &result);
- printf(" (%sbool) %-20S: %d\n", originStr, prop.propName, result);
- }
- break;
- case TMT_COLOR:
- {
- COLORREF result = 0;
- GetThemeColor(themeData.handle(), themeData.partId, themeData.stateId, prop.propValue, &result);
- printf(" (%scolor) %-20S: 0x%08X\n", originStr, prop.propName, result);
- }
- break;
- case TMT_MARGINS:
- {
- MARGINS result;
- memset(&result, 0, sizeof(result));
- GetThemeMargins(themeData.handle(), 0, themeData.partId, themeData.stateId, prop.propValue, 0, &result);
- printf(" (%smargins) %-20S: (%d, %d, %d, %d)\n", originStr,
- prop.propName, result.cxLeftWidth, result.cyTopHeight, result.cxRightWidth, result.cyBottomHeight);
- }
- break;
- case TMT_FILENAME:
- {
- wchar_t buffer[512];
- GetThemeFilename(themeData.handle(), themeData.partId, themeData.stateId, prop.propValue, buffer, 512);
- printf(" (%sfilename)%-20S: %S\n", originStr, prop.propName, buffer);
- }
- break;
- case TMT_SIZE:
- {
- SIZE result1;
- SIZE result2;
- SIZE result3;
- memset(&result1, 0, sizeof(result1));
- memset(&result2, 0, sizeof(result2));
- memset(&result3, 0, sizeof(result3));
- GetThemePartSize(themeData.handle(), 0, themeData.partId, themeData.stateId, 0, TS_MIN, &result1);
- GetThemePartSize(themeData.handle(), 0, themeData.partId, themeData.stateId, 0, TS_TRUE, &result2);
- GetThemePartSize(themeData.handle(), 0, themeData.partId, themeData.stateId, 0, TS_DRAW, &result3);
- printf(" (%ssize) %-20S: Min (%d, %d), True(%d, %d), Draw(%d, %d)\n", originStr, prop.propName,
- result1.cx, result1.cy, result2.cx, result2.cy, result3.cx, result3.cy);
- }
- break;
- case TMT_POSITION:
- {
- POINT result;
- memset(&result, 0, sizeof(result));
- GetThemePosition(themeData.handle(), themeData.partId, themeData.stateId, prop.propValue, &result);
- printf(" (%sPosition)%-20S: (%d, %d)\n", originStr, prop.propName, result.x, result.y);
- }
- break;
- case TMT_RECT:
- {
- RECT result;
- memset(&result, 0, sizeof(result));
- GetThemeRect(themeData.handle(), themeData.partId, themeData.stateId, prop.propValue, &result);
- printf(" (%sRect) %-20S: (%d, %d, %d, %d)\n", originStr, prop.propName, result.left, result.top, result.right, result.bottom);
- }
- break;
- case TMT_FONT:
- {
- LOGFONT result;
- memset(&result, 0, sizeof(result));
- GetThemeFont(themeData.handle(), 0, themeData.partId, themeData.stateId, prop.propValue, &result);
- printf(" (%sFont) %-20S: %S height(%d) width(%d) weight(%d)\n", originStr, prop.propName,
- result.lfFaceName, result.lfHeight, result.lfWidth, result.lfWeight);
- }
- break;
- case TMT_INTLIST:
- {
- INTLIST result;
- memset(&result, 0, sizeof(result));
- GetThemeIntList(themeData.handle(), themeData.partId, themeData.stateId, prop.propValue, &result);
- printf(" (%sInt list)%-20S: { ", originStr, prop.propName);
- for (int i = 0; i < result.iValueCount; ++i)
- printf("%d ", result.iValues[i]);
- printf("}\n");
- }
- break;
- default:
- printf(" %s%S : Unknown property type (%d)!\n", originStr, prop.propName, prop.propType);
- }
-}
-
-/*! \internal
- Dump all valid properties for a part.
- If it's the first time this function is called, then the name,
- enum value and documentation of all properties are shown, as
- well as all global properties.
-*/
-void QWindowsXPStylePrivate::showProperties(XPThemeData &themeData)
-{
- if (!all_props.count()) {
- const TMSCHEMAINFO *infoTable = GetSchemaInfo();
- for (int i = 0; i < infoTable->iPropCount; ++i) {
- int propType = infoTable->pPropTable[i].bPrimVal;
- int propValue = infoTable->pPropTable[i].sEnumVal;
- LPCWSTR propName = infoTable->pPropTable[i].pszName;
-
- switch(propType) {
- case TMT_ENUMDEF:
- case TMT_ENUMVAL:
- continue;
- default:
- if (propType != propValue) {
- PropPair prop;
- prop.propValue = propValue;
- prop.propName = propName;
- prop.propType = propType;
- all_props.append(prop);
- }
- }
- }
- std::sort(all_props.begin(), all_props.end());
-
- {// List all properties
- printf("part properties count = %d:\n", all_props.count());
- printf(" Enum Property Name Description\n");
- printf("-----------------------------------------------------------\n");
- wchar_t themeName[256];
- pGetCurrentThemeName(themeName, 256, 0, 0, 0, 0);
- for (int j = 0; j < all_props.count(); ++j) {
- PropPair prop = all_props.at(j);
- wchar_t buf[500];
- GetThemeDocumentationProperty(themeName, prop.propName, buf, 500);
- printf("%3d: (%4d) %-20S %S\n", j, prop.propValue, prop.propName, buf);
- }
- }
-
- {// Show Global values
- printf("Global Properties:\n");
- for (int j = 0; j < all_props.count(); ++j) {
- PropPair prop = all_props.at(j);
- PROPERTYORIGIN origin = PO_NOTFOUND;
- GetThemePropertyOrigin(themeData.handle(), themeData.partId, themeData.stateId, prop.propValue, &origin);
- if (origin == PO_GLOBAL) {
- showProperty(themeData, prop);
- }
- }
- }
- }
-
- for (int j = 0; j < all_props.count(); ++j) {
- PropPair prop = all_props.at(j);
- PROPERTYORIGIN origin = PO_NOTFOUND;
- GetThemePropertyOrigin(themeData.handle(), themeData.partId, themeData.stateId, prop.propValue, &origin);
- if (origin != PO_NOTFOUND)
- {
- showProperty(themeData, prop);
- }
- }
-}
-#endif
-// Debugging code -----------------------------------------------------------------------[ END ]---
-
-
-QT_END_NAMESPACE
diff --git a/src/plugins/styles/windowsvista/qwindowsxpstyle_p.h b/src/plugins/styles/windowsvista/qwindowsxpstyle_p.h
deleted file mode 100644
index 0f70105b0e..0000000000
--- a/src/plugins/styles/windowsvista/qwindowsxpstyle_p.h
+++ /dev/null
@@ -1,106 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtWidgets module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and 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 QWINDOWSXPSTYLE_P_H
-#define QWINDOWSXPSTYLE_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 <QtWidgets/private/qtwidgetsglobal_p.h>
-#include <QtWidgets/private/qwindowsstyle_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class QWindowsXPStylePrivate;
-class QWindowsXPStyle : public QWindowsStyle
-{
- Q_OBJECT
-public:
- QWindowsXPStyle();
- QWindowsXPStyle(QWindowsXPStylePrivate &dd);
- ~QWindowsXPStyle() override;
-
- void unpolish(QApplication*) override;
- void polish(QApplication*) override;
- void polish(QWidget*) override;
- void polish(QPalette&) override;
- void unpolish(QWidget*) override;
-
- void drawPrimitive(PrimitiveElement pe, const QStyleOption *option, QPainter *p,
- const QWidget *widget = nullptr) const override;
- void drawControl(ControlElement element, const QStyleOption *option, QPainter *p,
- const QWidget *wwidget = nullptr) const override;
- QRect subElementRect(SubElement r, const QStyleOption *option,
- const QWidget *widget = nullptr) const override;
- QRect subControlRect(ComplexControl cc, const QStyleOptionComplex *option, SubControl sc,
- const QWidget *widget = nullptr) const override;
- void drawComplexControl(ComplexControl cc, const QStyleOptionComplex *option, QPainter *p,
- const QWidget *widget = nullptr) const override;
- QSize sizeFromContents(ContentsType ct, const QStyleOption *option, const QSize &contentsSize,
- const QWidget *widget = nullptr) const override;
- int pixelMetric(PixelMetric pm, const QStyleOption *option = nullptr,
- const QWidget *widget = nullptr) const override;
- int styleHint(StyleHint hint, const QStyleOption *option = nullptr,
- const QWidget *widget = nullptr,
- QStyleHintReturn *returnData = nullptr) const override;
-
- QPalette standardPalette() const override;
- QPixmap standardPixmap(StandardPixmap standardIcon, const QStyleOption *option,
- const QWidget *widget = nullptr) const override;
- QIcon standardIcon(StandardPixmap standardIcon, const QStyleOption *option = nullptr,
- const QWidget *widget = nullptr) const override;
-
-private:
- Q_DISABLE_COPY_MOVE(QWindowsXPStyle)
- Q_DECLARE_PRIVATE(QWindowsXPStyle)
- friend class QStyleFactory;
-};
-
-QT_END_NAMESPACE
-
-#endif // QWINDOWSXPSTYLE_P_H
diff --git a/src/plugins/styles/windowsvista/qwindowsxpstyle_p_p.h b/src/plugins/styles/windowsvista/qwindowsxpstyle_p_p.h
deleted file mode 100644
index 06b37a6e5c..0000000000
--- a/src/plugins/styles/windowsvista/qwindowsxpstyle_p_p.h
+++ /dev/null
@@ -1,345 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtWidgets module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and 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 QWINDOWSXPSTYLE_P_P_H
-#define QWINDOWSXPSTYLE_P_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists for the convenience
-// of qapplication_*.cpp, qwidget*.cpp and qfiledialog.cpp. This header
-// file may change from version to version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <QtWidgets/private/qtwidgetsglobal_p.h>
-#include "qwindowsxpstyle_p.h"
-#include <QtWidgets/private/qwindowsstyle_p_p.h>
-#include <qmap.h>
-#include <qt_windows.h>
-
-#include <uxtheme.h>
-#include <vssym32.h>
-
-#include <limits.h>
-
-QT_BEGIN_NAMESPACE
-
-class QDebug;
-
-// TMT_TEXTSHADOWCOLOR is wrongly defined in mingw
-#if TMT_TEXTSHADOWCOLOR != 3818
-#undef TMT_TEXTSHADOWCOLOR
-#define TMT_TEXTSHADOWCOLOR 3818
-#endif
-#ifndef TST_NONE
-# define TST_NONE 0
-#endif
-
-// These defines are missing from the tmschema, but still exist as
-// states for their parts
-#ifndef MINBS_INACTIVE
-#define MINBS_INACTIVE 5
-#endif
-#ifndef MAXBS_INACTIVE
-#define MAXBS_INACTIVE 5
-#endif
-#ifndef RBS_INACTIVE
-#define RBS_INACTIVE 5
-#endif
-#ifndef HBS_INACTIVE
-#define HBS_INACTIVE 5
-#endif
-#ifndef CBS_INACTIVE
-#define CBS_INACTIVE 5
-#endif
-
-// Uncomment define below to build debug assisting code, and output
-// #define DEBUG_XP_STYLE
-
-// Declarations -----------------------------------------------------------------------------------
-class XPThemeData
-{
-public:
- explicit XPThemeData(const QWidget *w = nullptr, QPainter *p = nullptr, int themeIn = -1,
- int part = 0, int state = 0, const QRect &r = QRect())
- : widget(w), painter(p), theme(themeIn), partId(part), stateId(state),
- mirrorHorizontally(false), mirrorVertically(false), noBorder(false),
- noContent(false), rect(r)
- {}
-
- HRGN mask(QWidget *widget);
- HTHEME handle();
-
- static RECT toRECT(const QRect &qr);
- bool isValid();
-
- QSizeF size();
- QMarginsF margins(const QRect &rect, int propId = TMT_CONTENTMARGINS);
- QMarginsF margins(int propId = TMT_CONTENTMARGINS);
-
- static QSizeF themeSize(const QWidget *w = nullptr, QPainter *p = nullptr, int themeIn = -1, int part = 0, int state = 0);
- static QMarginsF themeMargins(const QRect &rect, const QWidget *w = nullptr, QPainter *p = nullptr, int themeIn = -1,
- int part = 0, int state = 0, int propId = TMT_CONTENTMARGINS);
- static QMarginsF themeMargins(const QWidget *w = nullptr, QPainter *p = nullptr, int themeIn = -1,
- int part = 0, int state = 0, int propId = TMT_CONTENTMARGINS);
-
- const QWidget *widget;
- QPainter *painter;
-
- int theme;
- HTHEME htheme = nullptr;
- int partId;
- int stateId;
-
- uint mirrorHorizontally : 1;
- uint mirrorVertically : 1;
- uint noBorder : 1;
- uint noContent : 1;
- uint rotate = 0;
- QRect rect;
-};
-
-struct ThemeMapKey {
- int theme = 0;
- int partId = -1;
- int stateId = -1;
- bool noBorder = false;
- bool noContent = false;
-
- ThemeMapKey() = default;
- ThemeMapKey(const XPThemeData &data)
- : theme(data.theme), partId(data.partId), stateId(data.stateId),
- noBorder(data.noBorder), noContent(data.noContent) {}
-
-};
-
-inline uint qHash(const ThemeMapKey &key)
-{ return key.theme ^ key.partId ^ key.stateId; }
-
-inline bool operator==(const ThemeMapKey &k1, const ThemeMapKey &k2)
-{
- return k1.theme == k2.theme
- && k1.partId == k2.partId
- && k1.stateId == k2.stateId;
-}
-
-enum AlphaChannelType {
- UnknownAlpha = -1, // Alpha of part & state not yet known
- NoAlpha, // Totally opaque, no need to touch alpha (RGB)
- MaskAlpha, // Alpha channel must be fixed (ARGB)
- RealAlpha // Proper alpha values from Windows (ARGB_Premultiplied)
-};
-
-struct ThemeMapData {
- AlphaChannelType alphaType = UnknownAlpha; // Which type of alpha on part & state
-
- bool dataValid : 1; // Only used to detect if hash value is ok
- bool partIsTransparent : 1;
- bool hasAlphaChannel : 1; // True = part & state has real Alpha
- bool wasAlphaSwapped : 1; // True = alpha channel needs to be swapped
- bool hadInvalidAlpha : 1; // True = alpha channel contained invalid alpha values
-
- ThemeMapData() : dataValid(false), partIsTransparent(false),
- hasAlphaChannel(false), wasAlphaSwapped(false), hadInvalidAlpha(false) {}
-};
-
-#ifndef QT_NO_DEBUG_STREAM
-QDebug operator<<(QDebug d, const XPThemeData &t);
-QDebug operator<<(QDebug d, const ThemeMapKey &k);
-QDebug operator<<(QDebug d, const ThemeMapData &td);
-#endif
-
-class QWindowsXPStylePrivate : public QWindowsStylePrivate
-{
- Q_DECLARE_PUBLIC(QWindowsXPStyle)
-public:
- enum Theme {
- ButtonTheme,
- ComboboxTheme,
- EditTheme,
- HeaderTheme,
- ListViewTheme,
- MenuTheme,
- ProgressTheme,
- RebarTheme,
- ScrollBarTheme,
- SpinTheme,
- TabTheme,
- TaskDialogTheme,
- ToolBarTheme,
- ToolTipTheme,
- TrackBarTheme,
- XpTreeViewTheme, // '+'/'-' shape treeview indicators (XP)
- WindowTheme,
- StatusTheme,
- VistaTreeViewTheme, // arrow shape treeview indicators (Vista) obtained from "explorer" theme.
- NThemes
- };
-
- QWindowsXPStylePrivate()
- { init(); }
-
- ~QWindowsXPStylePrivate()
- { cleanup(); }
-
- static int pixelMetricFromSystemDp(QStyle::PixelMetric pm, const QStyleOption *option = nullptr, const QWidget *widget = nullptr);
- static int fixedPixelMetric(QStyle::PixelMetric pm, const QStyleOption *option = nullptr, const QWidget *widget = nullptr);
-
- static HWND winId(const QWidget *widget);
-
- void init(bool force = false);
- void cleanup(bool force = false);
- void cleanupHandleMap();
-
- HBITMAP buffer(int w = 0, int h = 0);
- HDC bufferHDC()
- { return bufferDC;}
-
- static bool useXP(bool update = false);
- static QRect scrollBarGripperBounds(QStyle::State flags, const QWidget *widget, XPThemeData *theme);
-
- bool isTransparent(XPThemeData &themeData);
- QRegion region(XPThemeData &themeData);
-
- bool drawBackground(XPThemeData &themeData, qreal correctionFactor = 1);
- bool drawBackgroundThruNativeBuffer(XPThemeData &themeData, qreal aditionalDevicePixelRatio, qreal correctionFactor);
- bool drawBackgroundDirectly(HDC dc, XPThemeData &themeData, qreal aditionalDevicePixelRatio);
-
- bool hasAlphaChannel(const QRect &rect);
- bool fixAlphaChannel(const QRect &rect);
- bool swapAlphaChannel(const QRect &rect, bool allPixels = false);
-
- QRgb groupBoxTextColor = 0;
- QRgb groupBoxTextColorDisabled = 0;
- QRgb sliderTickColor = 0;
- bool hasInitColors = false;
-
- static HTHEME createTheme(int theme, HWND hwnd);
- static QString themeName(int theme);
- static inline bool hasTheme(int theme) { return theme >= 0 && theme < NThemes && m_themes[theme]; }
- static bool isItemViewDelegateLineEdit(const QWidget *widget);
- static bool isLineEditBaseColorSet(const QStyleOption *option, const QWidget *widget);
-
- QIcon dockFloat, dockClose;
-
-private:
-#ifdef DEBUG_XP_STYLE
- void dumpNativeDIB(int w, int h);
- void showProperties(XPThemeData &themeData);
-#endif
-
- static bool initVistaTreeViewTheming();
- static void cleanupVistaTreeViewTheming();
-
- static QBasicAtomicInt ref;
- static bool use_xp;
-
- QHash<ThemeMapKey, ThemeMapData> alphaCache;
- HDC bufferDC = nullptr;
- HBITMAP bufferBitmap = nullptr;
- HBITMAP nullBitmap = nullptr;
- uchar *bufferPixels = nullptr;
- int bufferW = 0;
- int bufferH = 0;
-
- static HWND m_vistaTreeViewHelper;
- static HTHEME m_themes[NThemes];
-};
-
-inline QSizeF XPThemeData::size()
-{
- QSizeF result(0, 0);
- if (isValid()) {
- SIZE size;
- if (SUCCEEDED(GetThemePartSize(handle(), nullptr, partId, stateId, nullptr, TS_TRUE, &size)))
- result = QSize(size.cx, size.cy);
- }
- return result;
-}
-
-inline QMarginsF XPThemeData::margins(const QRect &qRect, int propId)
-{
- QMarginsF result(0, 0, 0 ,0);
- if (isValid()) {
- MARGINS margins;
- RECT rect = XPThemeData::toRECT(qRect);
- if (SUCCEEDED(GetThemeMargins(handle(), nullptr, partId, stateId, propId, &rect, &margins)))
- result = QMargins(margins.cxLeftWidth, margins.cyTopHeight, margins.cxRightWidth, margins.cyBottomHeight);
- }
- return result;
-}
-
-inline QMarginsF XPThemeData::margins(int propId)
-{
- QMarginsF result(0, 0, 0 ,0);
- if (isValid()) {
- MARGINS margins;
- if (SUCCEEDED(GetThemeMargins(handle(), nullptr, partId, stateId, propId, nullptr, &margins)))
- result = QMargins(margins.cxLeftWidth, margins.cyTopHeight, margins.cxRightWidth, margins.cyBottomHeight);
- }
- return result;
-}
-
-inline QSizeF XPThemeData::themeSize(const QWidget *w, QPainter *p, int themeIn, int part, int state)
-{
- XPThemeData theme(w, p, themeIn, part, state);
- return theme.size();
-}
-
-inline QMarginsF XPThemeData::themeMargins(const QRect &rect, const QWidget *w, QPainter *p, int themeIn,
- int part, int state, int propId)
-{
- XPThemeData theme(w, p, themeIn, part, state);
- return theme.margins(rect, propId);
-}
-
-inline QMarginsF XPThemeData::themeMargins(const QWidget *w, QPainter *p, int themeIn,
- int part, int state, int propId)
-{
- XPThemeData theme(w, p, themeIn, part, state);
- return theme.margins(propId);
-}
-
-QT_END_NAMESPACE
-
-#endif //QWINDOWSXPSTYLE_P_P_H
diff --git a/src/plugins/styles/windowsvista/windowsvista.pro b/src/plugins/styles/windowsvista/windowsvista.pro
deleted file mode 100644
index 483914c13d..0000000000
--- a/src/plugins/styles/windowsvista/windowsvista.pro
+++ /dev/null
@@ -1,20 +0,0 @@
-TARGET = qwindowsvistastyle
-
-QT += widgets-private
-
-SOURCES += main.cpp
-
-HEADERS += qwindowsvistastyle_p.h qwindowsvistastyle_p_p.h
-SOURCES += qwindowsvistastyle.cpp
-
-HEADERS += qwindowsxpstyle_p.h qwindowsxpstyle_p_p.h
-SOURCES += qwindowsxpstyle.cpp
-
-QMAKE_USE_PRIVATE += user32 gdi32
-LIBS_PRIVATE *= -luxtheme
-
-DISTFILES += windowsvistastyle.json
-
-PLUGIN_TYPE = styles
-PLUGIN_CLASS_NAME = QWindowsVistaStylePlugin
-load(qt_plugin)
diff --git a/src/plugins/styles/windowsvista/windowsvistastyle.json b/src/plugins/styles/windowsvista/windowsvistastyle.json
deleted file mode 100644
index 771aa0c600..0000000000
--- a/src/plugins/styles/windowsvista/windowsvistastyle.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "Keys": [ "windowsvista" ]
-}
diff --git a/src/plugins/tls/CMakeLists.txt b/src/plugins/tls/CMakeLists.txt
new file mode 100644
index 0000000000..91b9267123
--- /dev/null
+++ b/src/plugins/tls/CMakeLists.txt
@@ -0,0 +1,16 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+if(QT_FEATURE_securetransport)
+ add_subdirectory(securetransport)
+endif()
+
+if (QT_FEATURE_openssl OR QT_FEATURE_openssl_linked)
+ add_subdirectory(openssl)
+endif()
+
+if (QT_FEATURE_schannel)
+ add_subdirectory(schannel)
+endif()
+
+add_subdirectory(certonly)
diff --git a/src/plugins/tls/certonly/CMakeLists.txt b/src/plugins/tls/certonly/CMakeLists.txt
new file mode 100644
index 0000000000..495f408144
--- /dev/null
+++ b/src/plugins/tls/certonly/CMakeLists.txt
@@ -0,0 +1,20 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+qt_internal_add_plugin(QTlsBackendCertOnlyPlugin
+ OUTPUT_NAME qcertonlybackend
+ CLASS_NAME QTlsBackendCertOnly
+ 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
+ ../shared/qx509_base.cpp
+ ../shared/qx509_generic_p.h
+ ../shared/qx509_generic.cpp
+ ../shared/qasn1element_p.h
+ ../shared/qasn1element.cpp
+ qtlsbackend_cert.cpp
+ qtlsbackend_cert_p.h
+ LIBRARIES
+ Qt::NetworkPrivate
+)
diff --git a/src/plugins/tls/certonly/qtlsbackend_cert.cpp b/src/plugins/tls/certonly/qtlsbackend_cert.cpp
new file mode 100644
index 0000000000..da3baaba70
--- /dev/null
+++ b/src/plugins/tls/certonly/qtlsbackend_cert.cpp
@@ -0,0 +1,56 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qtlsbackend_cert_p.h"
+
+#include "../shared/qx509_generic_p.h"
+
+#include <qssl.h>
+
+#include <qlist.h>
+
+QT_BEGIN_NAMESPACE
+
+QString QTlsBackendCertOnly::backendName() const
+{
+ return builtinBackendNames[nameIndexCertOnly];
+}
+
+
+QList<QSsl::SslProtocol> QTlsBackendCertOnly::supportedProtocols() const
+{
+ return {};
+}
+
+QList<QSsl::SupportedFeature> QTlsBackendCertOnly::supportedFeatures() const
+{
+ return {};
+}
+
+QList<QSsl::ImplementedClass> QTlsBackendCertOnly::implementedClasses() const
+{
+ QList<QSsl::ImplementedClass> classes;
+ classes << QSsl::ImplementedClass::Certificate;
+
+ return classes;
+}
+
+QTlsPrivate::X509Certificate *QTlsBackendCertOnly::createCertificate() const
+{
+ return new QTlsPrivate::X509CertificateGeneric;
+}
+
+QTlsPrivate::X509PemReaderPtr QTlsBackendCertOnly::X509PemReader() const
+{
+ return QTlsPrivate::X509CertificateGeneric::certificatesFromPem;
+}
+
+QTlsPrivate::X509DerReaderPtr QTlsBackendCertOnly::X509DerReader() const
+{
+ return QTlsPrivate::X509CertificateGeneric::certificatesFromDer;
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qtlsbackend_cert_p.cpp"
+
diff --git a/src/plugins/tls/certonly/qtlsbackend_cert_p.h b/src/plugins/tls/certonly/qtlsbackend_cert_p.h
new file mode 100644
index 0000000000..946e4b49dc
--- /dev/null
+++ b/src/plugins/tls/certonly/qtlsbackend_cert_p.h
@@ -0,0 +1,45 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QTLSBACKEND_CERT_P_H
+#define QTLSBACKEND_CERT_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 <QtNetwork/private/qtnetworkglobal_p.h>
+
+#include <QtNetwork/private/qtlsbackend_p.h>
+
+#include <QtCore/qglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+class QTlsBackendCertOnly final : public QTlsBackend
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID QTlsBackend_iid)
+ Q_INTERFACES(QTlsBackend)
+private:
+ QString backendName() const override;
+
+ QList<QSsl::SslProtocol> supportedProtocols() const override;
+ QList<QSsl::SupportedFeature> supportedFeatures() const override;
+ QList<QSsl::ImplementedClass> implementedClasses() const override;
+
+ QTlsPrivate::X509Certificate *createCertificate() const override;
+ QTlsPrivate::X509PemReaderPtr X509PemReader() const override;
+ QTlsPrivate::X509DerReaderPtr X509DerReader() const override;
+};
+
+QT_END_NAMESPACE
+
+#endif // QTLSBACKEND_CERT_P_H
diff --git a/src/plugins/tls/openssl/CMakeLists.txt b/src/plugins/tls/openssl/CMakeLists.txt
new file mode 100644
index 0000000000..0e0a7a1552
--- /dev/null
+++ b/src/plugins/tls/openssl/CMakeLists.txt
@@ -0,0 +1,63 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+qt_internal_add_plugin(QTlsBackendOpenSSLPlugin
+ OUTPUT_NAME qopensslbackend
+ CLASS_NAME QTlsBackendOpenSSL
+ PLUGIN_TYPE tls
+ SOURCES
+ ../shared/qx509_base.cpp ../shared/qx509_base_p.h
+ ../shared/qtlskey_base.cpp ../shared/qtlskey_base_p.h
+ ../shared/qasn1element.cpp ../shared/qasn1element_p.h
+ qtlsbackend_openssl.cpp qtlsbackend_openssl_p.h
+ qx509_openssl.cpp qx509_openssl_p.h
+ qtlskey_openssl.cpp qtlskey_openssl_p.h
+ qtls_openssl.cpp qtls_openssl_p.h
+ qssldiffiehellmanparameters_openssl.cpp
+ qsslcontext_openssl.cpp qsslcontext_openssl_p.h
+ qsslsocket_openssl_symbols.cpp qsslsocket_openssl_symbols_p.h
+ qopenssl_p.h
+ LIBRARIES
+ Qt::NetworkPrivate
+ Qt::CorePrivate
+ DEFINES
+ OPENSSL_API_COMPAT=0x10100000L
+)
+
+if (WIN32) # Windows header issues
+ set_target_properties(QTlsBackendOpenSSLPlugin PROPERTIES UNITY_BUILD OFF)
+endif()
+
+qt_internal_extend_target(QTlsBackendOpenSSLPlugin CONDITION QT_FEATURE_dtls
+ SOURCES
+ qdtls_openssl.cpp qdtls_openssl_p.h
+ ../shared/qdtls_base.cpp ../shared/qdtls_base_p.h
+)
+
+qt_internal_extend_target(QTlsBackendOpenSSLPlugin CONDITION APPLE
+ SOURCES
+ ../shared/qsslsocket_mac_shared.cpp
+ LIBRARIES
+ ${FWCoreFoundation}
+ ${FWSecurity}
+)
+
+qt_internal_extend_target(QTlsBackendOpenSSLPlugin CONDITION ANDROID
+ SOURCES
+ qsslsocket_openssl_android.cpp
+)
+
+qt_internal_extend_target(QTlsBackendOpenSSLPlugin CONDITION WIN32
+ SOURCES
+ qwindowscarootfetcher.cpp qwindowscarootfetcher_p.h
+ ../shared/qwincrypt_p.h
+ LIBRARIES
+ crypt32
+)
+
+if(QT_FEATURE_openssl_linked)
+ target_link_libraries(QTlsBackendOpenSSLPlugin PRIVATE WrapOpenSSL::WrapOpenSSL)
+else()
+ qt_internal_add_target_include_dirs(QTlsBackendOpenSSLPlugin
+ WrapOpenSSLHeaders::WrapOpenSSLHeaders)
+endif()
diff --git a/src/plugins/tls/openssl/qdtls_openssl.cpp b/src/plugins/tls/openssl/qdtls_openssl.cpp
new file mode 100644
index 0000000000..fc07a29ec8
--- /dev/null
+++ b/src/plugins/tls/openssl/qdtls_openssl.cpp
@@ -0,0 +1,1417 @@
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <QtNetwork/private/qnativesocketengine_p_p.h>
+
+#include "qsslsocket_openssl_symbols_p.h"
+#include "qdtls_openssl_p.h"
+#include "qx509_openssl_p.h"
+
+#include <QtNetwork/private/qsslpresharedkeyauthenticator_p.h>
+#include <QtNetwork/private/qsslcertificate_p.h>
+#include <QtNetwork/private/qssl_p.h>
+
+#include <QtNetwork/qudpsocket.h>
+
+#include <QtCore/qmessageauthenticationcode.h>
+#include <QtCore/qcryptographichash.h>
+
+#include <QtCore/qdebug.h>
+
+#include <cstring>
+#include <cstddef>
+
+QT_BEGIN_NAMESPACE
+
+#define QT_DTLS_VERBOSE 0
+
+#if QT_DTLS_VERBOSE
+
+#define qDtlsWarning(arg) qWarning(arg)
+#define qDtlsDebug(arg) qDebug(arg)
+
+#else
+
+#define qDtlsWarning(arg)
+#define qDtlsDebug(arg)
+
+#endif // QT_DTLS_VERBOSE
+
+namespace dtlsutil
+{
+
+QByteArray cookie_for_peer(SSL *ssl)
+{
+ Q_ASSERT(ssl);
+
+ // SSL_get_rbio does not increment the reference count
+ BIO *readBIO = q_SSL_get_rbio(ssl);
+ if (!readBIO) {
+ qCWarning(lcTlsBackend, "No BIO (dgram) found in SSL object");
+ return {};
+ }
+
+ auto listener = static_cast<dtlsopenssl::DtlsState *>(q_BIO_get_app_data(readBIO));
+ if (!listener) {
+ qCWarning(lcTlsBackend, "BIO_get_app_data returned invalid (nullptr) value");
+ return {};
+ }
+
+ const QHostAddress peerAddress(listener->remoteAddress);
+ const quint16 peerPort(listener->remotePort);
+ QByteArray peerData;
+ if (peerAddress.protocol() == QAbstractSocket::IPv6Protocol) {
+ const Q_IPV6ADDR sin6_addr(peerAddress.toIPv6Address());
+ peerData.resize(int(sizeof sin6_addr + sizeof peerPort));
+ char *dst = peerData.data();
+ std::memcpy(dst, &peerPort, sizeof peerPort);
+ dst += sizeof peerPort;
+ std::memcpy(dst, &sin6_addr, sizeof sin6_addr);
+ } else if (peerAddress.protocol() == QAbstractSocket::IPv4Protocol) {
+ const quint32 sin_addr(peerAddress.toIPv4Address());
+ peerData.resize(int(sizeof sin_addr + sizeof peerPort));
+ char *dst = peerData.data();
+ std::memcpy(dst, &peerPort, sizeof peerPort);
+ dst += sizeof peerPort;
+ std::memcpy(dst, &sin_addr, sizeof sin_addr);
+ } else {
+ Q_UNREACHABLE();
+ }
+
+ return peerData;
+}
+
+struct FallbackCookieSecret
+{
+ FallbackCookieSecret()
+ {
+ key.resize(32);
+ const int status = q_RAND_bytes(reinterpret_cast<unsigned char *>(key.data()),
+ key.size());
+ if (status <= 0)
+ key.clear();
+ }
+
+ QByteArray key;
+
+ Q_DISABLE_COPY_MOVE(FallbackCookieSecret)
+};
+
+QByteArray fallbackSecret()
+{
+ static const FallbackCookieSecret generator;
+ return generator.key;
+}
+
+int next_timeoutMs(SSL *tlsConnection)
+{
+ Q_ASSERT(tlsConnection);
+ timeval timeLeft = {};
+ q_DTLSv1_get_timeout(tlsConnection, &timeLeft);
+ return timeLeft.tv_sec * 1000;
+}
+
+
+void delete_connection(SSL *ssl)
+{
+ // The 'deleter' for QSharedPointer<SSL>.
+ if (ssl)
+ q_SSL_free(ssl);
+}
+
+void delete_BIO_ADDR(BIO_ADDR *bio)
+{
+ // A deleter for QSharedPointer<BIO_ADDR>
+ if (bio)
+ q_BIO_ADDR_free(bio);
+}
+
+void delete_bio_method(BIO_METHOD *method)
+{
+ // The 'deleter' for QSharedPointer<BIO_METHOD>.
+ if (method)
+ q_BIO_meth_free(method);
+}
+
+// The path MTU discovery is non-trivial: it's a mix of getsockopt/setsockopt
+// (IP_MTU/IP6_MTU/IP_MTU_DISCOVER) and fallback MTU values. It's not
+// supported on all platforms, worse so - imposes specific requirements on
+// underlying UDP socket etc. So for now, we either try a user-proposed MTU
+// hint or rely on our own fallback value. As a fallback mtu OpenSSL uses 576
+// for IPv4 and 1280 for IPv6 (RFC 791, RFC 2460). To KIS we use 576. This
+// rather small MTU value does not affect the size that can be read/written
+// by QDtls, only a handshake (which is allowed to fragment).
+enum class MtuGuess : long
+{
+ defaultMtu = 576
+};
+
+} // namespace dtlsutil
+
+namespace dtlscallbacks
+{
+
+extern "C" int q_generate_cookie_callback(SSL *ssl, unsigned char *dst,
+ unsigned *cookieLength)
+{
+ if (!ssl || !dst || !cookieLength) {
+ qCWarning(lcTlsBackend,
+ "Failed to generate cookie - invalid (nullptr) parameter(s)");
+ return 0;
+ }
+
+ void *generic = q_SSL_get_ex_data(ssl, QTlsBackendOpenSSL::s_indexForSSLExtraData);
+ if (!generic) {
+ qCWarning(lcTlsBackend, "SSL_get_ex_data returned nullptr, cannot generate cookie");
+ return 0;
+ }
+
+ *cookieLength = 0;
+
+ auto dtls = static_cast<dtlsopenssl::DtlsState *>(generic);
+ if (!dtls->secret.size())
+ return 0;
+
+ const QByteArray peerData(dtlsutil::cookie_for_peer(ssl));
+ if (!peerData.size())
+ return 0;
+
+ QMessageAuthenticationCode hmac(dtls->hashAlgorithm, dtls->secret);
+ hmac.addData(peerData);
+ const QByteArrayView cookie = hmac.resultView();
+ Q_ASSERT(cookie.size() >= 0);
+ // DTLS1_COOKIE_LENGTH is erroneously 256 bytes long, must be 255 - RFC 6347, 4.2.1.
+ *cookieLength = qMin(DTLS1_COOKIE_LENGTH - 1, cookie.size());
+ std::memcpy(dst, cookie.constData(), *cookieLength);
+
+ return 1;
+}
+
+extern "C" int q_verify_cookie_callback(SSL *ssl, const unsigned char *cookie,
+ unsigned cookieLength)
+{
+ if (!ssl || !cookie || !cookieLength) {
+ qCWarning(lcTlsBackend, "Could not verify cookie, invalid (nullptr or zero) parameters");
+ return 0;
+ }
+
+ unsigned char newCookie[DTLS1_COOKIE_LENGTH] = {};
+ unsigned newCookieLength = 0;
+ if (q_generate_cookie_callback(ssl, newCookie, &newCookieLength) != 1)
+ return 0;
+
+ return newCookieLength == cookieLength
+ && !q_CRYPTO_memcmp(cookie, newCookie, size_t(cookieLength));
+}
+
+extern "C" int q_X509DtlsCallback(int ok, X509_STORE_CTX *ctx)
+{
+ if (!ok) {
+ // Store the error and at which depth the error was detected.
+ SSL *ssl = static_cast<SSL *>(q_X509_STORE_CTX_get_ex_data(ctx, q_SSL_get_ex_data_X509_STORE_CTX_idx()));
+ if (!ssl) {
+ qCWarning(lcTlsBackend, "X509_STORE_CTX_get_ex_data returned nullptr, handshake failure");
+ return 0;
+ }
+
+ void *generic = q_SSL_get_ex_data(ssl, QTlsBackendOpenSSL::s_indexForSSLExtraData);
+ if (!generic) {
+ qCWarning(lcTlsBackend, "SSL_get_ex_data returned nullptr, handshake failure");
+ return 0;
+ }
+
+ auto dtls = static_cast<dtlsopenssl::DtlsState *>(generic);
+ dtls->x509Errors.append(QTlsPrivate::X509CertificateOpenSSL::errorEntryFromStoreContext(ctx));
+ }
+
+ // Always return 1 (OK) to allow verification to continue. We handle the
+ // errors gracefully after collecting all errors, after verification has
+ // completed.
+ return 1;
+}
+
+extern "C" unsigned q_PSK_client_callback(SSL *ssl, const char *hint, char *identity,
+ unsigned max_identity_len, unsigned char *psk,
+ unsigned max_psk_len)
+{
+ auto *dtls = static_cast<dtlsopenssl::DtlsState *>(q_SSL_get_ex_data(ssl,
+ QTlsBackendOpenSSL::s_indexForSSLExtraData));
+ if (!dtls)
+ return 0;
+
+ Q_ASSERT(dtls->dtlsPrivate);
+ return dtls->dtlsPrivate->pskClientCallback(hint, identity, max_identity_len, psk, max_psk_len);
+}
+
+extern "C" unsigned q_PSK_server_callback(SSL *ssl, const char *identity, unsigned char *psk,
+ unsigned max_psk_len)
+{
+ auto *dtls = static_cast<dtlsopenssl::DtlsState *>(q_SSL_get_ex_data(ssl,
+ QTlsBackendOpenSSL::s_indexForSSLExtraData));
+ if (!dtls)
+ return 0;
+
+ Q_ASSERT(dtls->dtlsPrivate);
+ return dtls->dtlsPrivate->pskServerCallback(identity, psk, max_psk_len);
+}
+
+} // namespace dtlscallbacks
+
+namespace dtlsbio
+{
+
+extern "C" int q_dgram_read(BIO *bio, char *dst, int bytesToRead)
+{
+ if (!bio || !dst || bytesToRead <= 0) {
+ qCWarning(lcTlsBackend, "invalid input parameter(s)");
+ return 0;
+ }
+
+ q_BIO_clear_retry_flags(bio);
+
+ auto dtls = static_cast<dtlsopenssl::DtlsState *>(q_BIO_get_app_data(bio));
+ // It's us who set data, if OpenSSL does too, the logic here is wrong
+ // then and we have to use BIO_set_app_data then!
+ Q_ASSERT(dtls);
+ int bytesRead = 0;
+ if (dtls->dgram.size()) {
+ bytesRead = qMin(dtls->dgram.size(), bytesToRead);
+ std::memcpy(dst, dtls->dgram.constData(), bytesRead);
+
+ if (!dtls->peeking)
+ dtls->dgram = dtls->dgram.mid(bytesRead);
+ } else {
+ bytesRead = -1;
+ }
+
+ if (bytesRead <= 0)
+ q_BIO_set_retry_read(bio);
+
+ return bytesRead;
+}
+
+extern "C" int q_dgram_write(BIO *bio, const char *src, int bytesToWrite)
+{
+ if (!bio || !src || bytesToWrite <= 0) {
+ qCWarning(lcTlsBackend, "invalid input parameter(s)");
+ return 0;
+ }
+
+ q_BIO_clear_retry_flags(bio);
+
+ auto dtls = static_cast<dtlsopenssl::DtlsState *>(q_BIO_get_app_data(bio));
+ Q_ASSERT(dtls);
+ if (dtls->writeSuppressed) {
+ // See the comment in QDtls::startHandshake.
+ return bytesToWrite;
+ }
+
+ QUdpSocket *udpSocket = dtls->udpSocket;
+ Q_ASSERT(udpSocket);
+
+ const QByteArray dgram(QByteArray::fromRawData(src, bytesToWrite));
+ qint64 bytesWritten = -1;
+ if (udpSocket->state() == QAbstractSocket::ConnectedState) {
+ bytesWritten = udpSocket->write(dgram);
+ } else {
+ bytesWritten = udpSocket->writeDatagram(dgram, dtls->remoteAddress,
+ dtls->remotePort);
+ }
+
+ if (bytesWritten <= 0)
+ q_BIO_set_retry_write(bio);
+
+ Q_ASSERT(bytesWritten <= std::numeric_limits<int>::max());
+ return int(bytesWritten);
+}
+
+extern "C" int q_dgram_puts(BIO *bio, const char *src)
+{
+ if (!bio || !src) {
+ qCWarning(lcTlsBackend, "invalid input parameter(s)");
+ return 0;
+ }
+
+ return q_dgram_write(bio, src, int(std::strlen(src)));
+}
+
+extern "C" long q_dgram_ctrl(BIO *bio, int cmd, long num, void *ptr)
+{
+ // This is our custom BIO_ctrl. bio.h defines a lot of BIO_CTRL_*
+ // and BIO_* constants and BIO_somename macros that expands to BIO_ctrl
+ // call with one of those constants as argument. What exactly BIO_ctrl
+ // does - depends on the 'cmd' and the type of BIO (so BIO_ctrl does
+ // not even have a single well-defined value meaning success or failure).
+ // We handle only the most generic commands - the ones documented for
+ // BIO_ctrl - and also DGRAM specific ones. And even for them - in most
+ // cases we do nothing but report a success or some non-error value.
+ // Documents also state: "Source/sink BIOs return an 0 if they do not
+ // recognize the BIO_ctrl() operation." - these are covered by 'default'
+ // label in the switch-statement below. Debug messages in the switch mean:
+ // 1) we got a command that is unexpected for dgram BIO, or:
+ // 2) we do not call any function that would lead to OpenSSL using this
+ // command.
+
+ if (!bio) {
+ qDebug(lcTlsBackend, "invalid 'bio' parameter (nullptr)");
+ return -1;
+ }
+
+ auto dtls = static_cast<dtlsopenssl::DtlsState *>(q_BIO_get_app_data(bio));
+ Q_ASSERT(dtls);
+
+ switch (cmd) {
+ // Let's start from the most generic ones, in the order in which they are
+ // documented (as BIO_ctrl):
+ case BIO_CTRL_RESET:
+ // BIO_reset macro.
+ // From documentation:
+ // "BIO_reset() normally returns 1 for success and 0 or -1 for failure.
+ // File BIOs are an exception, they return 0 for success and -1 for
+ // failure."
+ // We have nothing to reset and we are not file BIO.
+ return 1;
+ case BIO_C_FILE_SEEK:
+ case BIO_C_FILE_TELL:
+ qDtlsWarning("Unexpected cmd (BIO_C_FILE_SEEK/BIO_C_FILE_TELL)");
+ // These are for BIO_seek, BIO_tell. We are not a file BIO.
+ // Non-negative return value means success.
+ return 0;
+ case BIO_CTRL_FLUSH:
+ // BIO_flush, nothing to do, we do not buffer any data.
+ // 0 or -1 means error, 1 - success.
+ return 1;
+ case BIO_CTRL_EOF:
+ qDtlsWarning("Unexpected cmd (BIO_CTRL_EOF)");
+ // BIO_eof, 1 means EOF read. Makes no sense for us.
+ return 0;
+ case BIO_CTRL_SET_CLOSE:
+ // BIO_set_close with BIO_CLOSE/BIO_NOCLOSE flags. Documented as
+ // always returning 1.
+ // From the documentation:
+ // "Typically BIO_CLOSE is used in a source/sink BIO to indicate that
+ // the underlying I/O stream should be closed when the BIO is freed."
+ //
+ // QUdpSocket we work with is not BIO's business, ignoring.
+ return 1;
+ case BIO_CTRL_GET_CLOSE:
+ // BIO_get_close. No, never, see the comment above.
+ return 0;
+ case BIO_CTRL_PENDING:
+ qDtlsWarning("Unexpected cmd (BIO_CTRL_PENDING)");
+ // BIO_pending. Not used by DTLS/OpenSSL (we are not buffering).
+ return 0;
+ case BIO_CTRL_WPENDING:
+ // No, we have nothing buffered.
+ return 0;
+ // The constants below are not documented as a part BIO_ctrl documentation,
+ // but they are also not type-specific.
+ case BIO_CTRL_DUP:
+ qDtlsWarning("Unexpected cmd (BIO_CTRL_DUP)");
+ // BIO_dup_state, not used by DTLS (and socket-related BIOs in general).
+ // For some very specific BIO type this 'cmd' would copy some state
+ // from 'bio' to (BIO*)'ptr'. 1 means success.
+ return 0;
+ case BIO_CTRL_SET_CALLBACK:
+ qDtlsWarning("Unexpected cmd (BIO_CTRL_SET_CALLBACK)");
+ // BIO_set_info_callback. We never call this, OpenSSL does not do this
+ // on its own (normally it's used if client code wants to have some
+ // debug information, for example, dumping handshake state via
+ // BIO_printf from SSL info_callback).
+ return 0;
+ case BIO_CTRL_GET_CALLBACK:
+ qDtlsWarning("Unexpected cmd (BIO_CTRL_GET_CALLBACK)");
+ // BIO_get_info_callback. We never call this.
+ if (ptr)
+ *static_cast<bio_info_cb **>(ptr) = nullptr;
+ return 0;
+ case BIO_CTRL_SET:
+ case BIO_CTRL_GET:
+ qDtlsWarning("Unexpected cmd (BIO_CTRL_SET/BIO_CTRL_GET)");
+ // Somewhat 'documented' as setting/getting IO type. Not used anywhere
+ // except BIO_buffer_get_num_lines (which contradics 'get IO type').
+ // Ignoring.
+ return 0;
+ // DGRAM-specific operation, we have to return some reasonable value
+ // (so far, I've encountered only peek mode switching, connect).
+ case BIO_CTRL_DGRAM_CONNECT:
+ // BIO_ctrl_dgram_connect. Not needed. Our 'dtls' already knows
+ // the peer's address/port. Report success though.
+ return 1;
+ case BIO_CTRL_DGRAM_SET_CONNECTED:
+ qDtlsWarning("Unexpected cmd (BIO_CTRL_DGRAM_SET_CONNECTED)");
+ // BIO_ctrl_dgram_set_connected. We never call it, OpenSSL does
+ // not call it on its own (so normally it's done by client code).
+ // Similar to BIO_CTRL_DGRAM_CONNECT, but it also informs the BIO
+ // that its UDP socket is connected. We never need it though.
+ return -1;
+ case BIO_CTRL_DGRAM_SET_RECV_TIMEOUT:
+ qDtlsWarning("Unexpected cmd (BIO_CTRL_DGRAM_SET_RECV_TIMEOUT)");
+ // Essentially setsockopt with SO_RCVTIMEO, not needed, our sockets
+ // are non-blocking.
+ return -1;
+ case BIO_CTRL_DGRAM_GET_RECV_TIMEOUT:
+ qDtlsWarning("Unexpected cmd (BIO_CTRL_DGRAM_GET_RECV_TIMEOUT)");
+ // getsockopt with SO_RCVTIMEO, not needed, our sockets are
+ // non-blocking. ptr is timeval *.
+ return -1;
+ case BIO_CTRL_DGRAM_SET_SEND_TIMEOUT:
+ qDtlsWarning("Unexpected cmd (BIO_CTRL_DGRAM_SET_SEND_TIMEOUT)");
+ // setsockopt, SO_SNDTIMEO, cannot happen.
+ return -1;
+ case BIO_CTRL_DGRAM_GET_SEND_TIMEOUT:
+ qDtlsWarning("Unexpected cmd (BIO_CTRL_DGRAM_GET_SEND_TIMEOUT)");
+ // getsockopt, SO_SNDTIMEO, cannot happen.
+ return -1;
+ case BIO_CTRL_DGRAM_GET_RECV_TIMER_EXP:
+ // BIO_dgram_recv_timedout. No, we are non-blocking.
+ return 0;
+ case BIO_CTRL_DGRAM_GET_SEND_TIMER_EXP:
+ // BIO_dgram_send_timedout. No, we are non-blocking.
+ return 0;
+ case BIO_CTRL_DGRAM_MTU_DISCOVER:
+ qDtlsWarning("Unexpected cmd (BIO_CTRL_DGRAM_MTU_DISCOVER)");
+ // setsockopt, IP_MTU_DISCOVER/IP6_MTU_DISCOVER, to be done
+ // in QUdpSocket instead. OpenSSL never calls it, only client
+ // code.
+ return 1;
+ case BIO_CTRL_DGRAM_QUERY_MTU:
+ qDtlsWarning("Unexpected cmd (BIO_CTRL_DGRAM_QUERY_MTU)");
+ // To be done in QUdpSocket instead.
+ return 1;
+ case BIO_CTRL_DGRAM_GET_FALLBACK_MTU:
+ qDtlsWarning("Unexpected command *BIO_CTRL_DGRAM_GET_FALLBACK_MTU)");
+ // Without SSL_OP_NO_QUERY_MTU set on SSL, OpenSSL can request for
+ // fallback MTU after several re-transmissions.
+ // Should never happen in our case.
+ return long(dtlsutil::MtuGuess::defaultMtu);
+ case BIO_CTRL_DGRAM_GET_MTU:
+ qDtlsWarning("Unexpected cmd (BIO_CTRL_DGRAM_GET_MTU)");
+ return -1;
+ case BIO_CTRL_DGRAM_SET_MTU:
+ qDtlsWarning("Unexpected cmd (BIO_CTRL_DGRAM_SET_MTU)");
+ // Should not happen (we don't call BIO_ctrl with this parameter)
+ // and set MTU on SSL instead.
+ return -1; // num is mtu and it's a return value meaning success.
+ case BIO_CTRL_DGRAM_MTU_EXCEEDED:
+ qDtlsWarning("Unexpected cmd (BIO_CTRL_DGRAM_MTU_EXCEEDED)");
+ return 0;
+ case BIO_CTRL_DGRAM_GET_PEER:
+ qDtlsDebug("BIO_CTRL_DGRAM_GET_PEER");
+ // BIO_dgram_get_peer. We do not return a real address (DTLS is not
+ // using this address), but let's pretend a success.
+ switch (dtls->remoteAddress.protocol()) {
+ case QAbstractSocket::IPv6Protocol:
+ return sizeof(sockaddr_in6);
+ case QAbstractSocket::IPv4Protocol:
+ return sizeof(sockaddr_in);
+ default:
+ return -1;
+ }
+ case BIO_CTRL_DGRAM_SET_PEER:
+ // Similar to BIO_CTRL_DGRAM_CONNECTED.
+ return 1;
+ case BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT:
+ // DTLSTODO: I'm not sure yet, how it's used by OpenSSL.
+ return 1;
+ case BIO_CTRL_DGRAM_SET_DONT_FRAG:
+ qDtlsDebug("BIO_CTRL_DGRAM_SET_DONT_FRAG");
+ // To be done in QUdpSocket, it's about IP_DONTFRAG etc.
+ return 1;
+ case BIO_CTRL_DGRAM_GET_MTU_OVERHEAD:
+ // AFAIK it's 28 for IPv4 and 48 for IPv6, but let's pretend it's 0
+ // so that OpenSSL does not start suddenly fragmenting the first
+ // client hello (which will result in DTLSv1_listen rejecting it).
+ return 0;
+ case BIO_CTRL_DGRAM_SET_PEEK_MODE:
+ dtls->peeking = num;
+ return 1;
+ default:;
+#if QT_DTLS_VERBOSE
+ qWarning() << "Unexpected cmd (" << cmd << ")";
+#endif
+ }
+
+ return 0;
+}
+
+extern "C" int q_dgram_create(BIO *bio)
+{
+
+ q_BIO_set_init(bio, 1);
+ // With a custom BIO you'd normally allocate some implementation-specific
+ // data and append it to this new BIO using BIO_set_data. We don't need
+ // it and thus q_dgram_destroy below is a noop.
+ return 1;
+}
+
+extern "C" int q_dgram_destroy(BIO *bio)
+{
+ Q_UNUSED(bio);
+ return 1;
+}
+
+const char * const qdtlsMethodName = "qdtlsbio";
+
+} // namespace dtlsbio
+
+namespace dtlsopenssl
+{
+
+bool DtlsState::init(QDtlsBasePrivate *dtlsBase, QUdpSocket *socket,
+ const QHostAddress &remote, quint16 port,
+ const QByteArray &receivedMessage)
+{
+ Q_ASSERT(dtlsBase);
+ Q_ASSERT(socket);
+
+ if (!tlsContext && !initTls(dtlsBase))
+ return false;
+
+ udpSocket = socket;
+
+ setLinkMtu(dtlsBase);
+
+ dgram = receivedMessage;
+ remoteAddress = remote;
+ remotePort = port;
+
+ // SSL_get_rbio does not increment a reference count.
+ BIO *bio = q_SSL_get_rbio(tlsConnection.data());
+ Q_ASSERT(bio);
+ q_BIO_set_app_data(bio, this);
+
+ return true;
+}
+
+void DtlsState::reset()
+{
+ tlsConnection.reset();
+ tlsContext.reset();
+}
+
+bool DtlsState::initTls(QDtlsBasePrivate *dtlsBase)
+{
+ if (tlsContext)
+ return true;
+
+ if (!QSslSocket::supportsSsl())
+ return false;
+
+ if (!initCtxAndConnection(dtlsBase))
+ return false;
+
+ if (!initBIO(dtlsBase)) {
+ tlsConnection.reset();
+ tlsContext.reset();
+ return false;
+ }
+
+ return true;
+}
+
+static QString msgFunctionFailed(const char *function)
+{
+ //: %1: Some function
+ return QDtls::tr("%1 failed").arg(QLatin1StringView(function));
+}
+
+bool DtlsState::initCtxAndConnection(QDtlsBasePrivate *dtlsBase)
+{
+ Q_ASSERT(dtlsBase);
+ Q_ASSERT(QSslSocket::supportsSsl());
+
+ if (dtlsBase->mode == QSslSocket::UnencryptedMode) {
+ dtlsBase->setDtlsError(QDtlsError::TlsInitializationError,
+ QDtls::tr("Invalid SslMode, SslServerMode or SslClientMode expected"));
+ return false;
+ }
+
+ if (!QDtlsBasePrivate::isDtlsProtocol(dtlsBase->dtlsConfiguration.protocol())) {
+ dtlsBase->setDtlsError(QDtlsError::TlsInitializationError,
+ QDtls::tr("Invalid protocol version, DTLS protocol expected"));
+ return false;
+ }
+
+ const bool rootsOnDemand = QTlsBackend::rootLoadingOnDemandAllowed(dtlsBase->dtlsConfiguration);
+ TlsContext newContext(QSslContext::sharedFromConfiguration(dtlsBase->mode, dtlsBase->dtlsConfiguration,
+ rootsOnDemand));
+
+ if (newContext->error() != QSslError::NoError) {
+ dtlsBase->setDtlsError(QDtlsError::TlsInitializationError, newContext->errorString());
+ return false;
+ }
+
+ TlsConnection newConnection(newContext->createSsl(), dtlsutil::delete_connection);
+ if (!newConnection.data()) {
+ dtlsBase->setDtlsError(QDtlsError::TlsInitializationError,
+ msgFunctionFailed("SSL_new"));
+ return false;
+ }
+
+ const int set = q_SSL_set_ex_data(newConnection.data(),
+ QTlsBackendOpenSSL::s_indexForSSLExtraData,
+ this);
+
+ if (set != 1 && dtlsBase->dtlsConfiguration.peerVerifyMode() != QSslSocket::VerifyNone) {
+ dtlsBase->setDtlsError(QDtlsError::TlsInitializationError,
+ msgFunctionFailed("SSL_set_ex_data"));
+ return false;
+ }
+
+ if (dtlsBase->mode == QSslSocket::SslServerMode) {
+ if (dtlsBase->dtlsConfiguration.dtlsCookieVerificationEnabled())
+ q_SSL_set_options(newConnection.data(), SSL_OP_COOKIE_EXCHANGE);
+ q_SSL_set_psk_server_callback(newConnection.data(), dtlscallbacks::q_PSK_server_callback);
+ } else {
+ q_SSL_set_psk_client_callback(newConnection.data(), dtlscallbacks::q_PSK_client_callback);
+ }
+
+ tlsContext.swap(newContext);
+ tlsConnection.swap(newConnection);
+
+ return true;
+}
+
+bool DtlsState::initBIO(QDtlsBasePrivate *dtlsBase)
+{
+ Q_ASSERT(dtlsBase);
+ Q_ASSERT(tlsContext && tlsConnection);
+
+ BioMethod customMethod(q_BIO_meth_new(BIO_TYPE_DGRAM, dtlsbio::qdtlsMethodName),
+ dtlsutil::delete_bio_method);
+ if (!customMethod.data()) {
+ dtlsBase->setDtlsError(QDtlsError::TlsInitializationError,
+ msgFunctionFailed("BIO_meth_new"));
+ return false;
+ }
+
+ BIO_METHOD *biom = customMethod.data();
+ q_BIO_meth_set_create(biom, dtlsbio::q_dgram_create);
+ q_BIO_meth_set_destroy(biom, dtlsbio::q_dgram_destroy);
+ q_BIO_meth_set_read(biom, dtlsbio::q_dgram_read);
+ q_BIO_meth_set_write(biom, dtlsbio::q_dgram_write);
+ q_BIO_meth_set_puts(biom, dtlsbio::q_dgram_puts);
+ q_BIO_meth_set_ctrl(biom, dtlsbio::q_dgram_ctrl);
+
+ BIO *bio = q_BIO_new(biom);
+ if (!bio) {
+ dtlsBase->setDtlsError(QDtlsError::TlsInitializationError,
+ msgFunctionFailed("BIO_new"));
+ return false;
+ }
+
+ q_SSL_set_bio(tlsConnection.data(), bio, bio);
+
+ bioMethod.swap(customMethod);
+
+ return true;
+}
+
+void DtlsState::setLinkMtu(QDtlsBasePrivate *dtlsBase)
+{
+ Q_ASSERT(dtlsBase);
+ Q_ASSERT(udpSocket);
+ Q_ASSERT(tlsConnection.data());
+
+ long mtu = dtlsBase->mtuHint;
+ if (!mtu) {
+ // If the underlying QUdpSocket was connected, getsockopt with
+ // IP_MTU/IP6_MTU can give us some hint:
+ bool optionFound = false;
+ if (udpSocket->state() == QAbstractSocket::ConnectedState) {
+ const QVariant val(udpSocket->socketOption(QAbstractSocket::PathMtuSocketOption));
+ if (val.isValid() && val.canConvert<int>())
+ mtu = val.toInt(&optionFound);
+ }
+
+ if (!optionFound || mtu <= 0) {
+ // OK, our own initial guess.
+ mtu = long(dtlsutil::MtuGuess::defaultMtu);
+ }
+ }
+
+ // For now, we disable this option.
+ q_SSL_set_options(tlsConnection.data(), SSL_OP_NO_QUERY_MTU);
+
+ q_DTLS_set_link_mtu(tlsConnection.data(), mtu);
+}
+
+} // namespace dtlsopenssl
+
+QDtlsClientVerifierOpenSSL::QDtlsClientVerifierOpenSSL()
+ : QDtlsBasePrivate(QSslSocket::SslServerMode, dtlsutil::fallbackSecret())
+{
+}
+
+bool QDtlsClientVerifierOpenSSL::verifyClient(QUdpSocket *socket, const QByteArray &dgram,
+ const QHostAddress &address, quint16 port)
+{
+ Q_ASSERT(socket);
+ Q_ASSERT(dgram.size());
+ Q_ASSERT(!address.isNull());
+ Q_ASSERT(port);
+
+ clearDtlsError();
+ verifiedClientHello.clear();
+
+ if (!dtls.init(this, socket, address, port, dgram))
+ return false;
+
+ dtls.secret = secret;
+ dtls.hashAlgorithm = hashAlgorithm;
+
+ Q_ASSERT(dtls.tlsConnection.data());
+ QSharedPointer<BIO_ADDR> peer(q_BIO_ADDR_new(), dtlsutil::delete_BIO_ADDR);
+ if (!peer.data()) {
+ setDtlsError(QDtlsError::TlsInitializationError,
+ QDtlsClientVerifier::tr("BIO_ADDR_new failed, ignoring client hello"));
+ return false;
+ }
+
+ const int ret = q_DTLSv1_listen(dtls.tlsConnection.data(), peer.data());
+ if (ret < 0) {
+ // Since 1.1 - it's a fatal error (not so in 1.0.2 for non-blocking socket)
+ setDtlsError(QDtlsError::TlsFatalError, QTlsBackendOpenSSL::getErrorsFromOpenSsl());
+ return false;
+ }
+
+ if (ret > 0) {
+ verifiedClientHello = dgram;
+ return true;
+ }
+
+ return false;
+}
+
+QByteArray QDtlsClientVerifierOpenSSL::verifiedHello() const
+{
+ return verifiedClientHello;
+}
+
+void QDtlsPrivateOpenSSL::TimeoutHandler::start(int hintMs)
+{
+ Q_ASSERT(timerId == -1);
+ timerId = startTimer(hintMs > 0 ? hintMs : timeoutMs, Qt::PreciseTimer);
+}
+
+void QDtlsPrivateOpenSSL::TimeoutHandler::doubleTimeout()
+{
+ if (timeoutMs * 2 < 60000)
+ timeoutMs *= 2;
+ else
+ timeoutMs = 60000;
+}
+
+void QDtlsPrivateOpenSSL::TimeoutHandler::stop()
+{
+ if (timerId != -1) {
+ killTimer(timerId);
+ timerId = -1;
+ }
+}
+
+void QDtlsPrivateOpenSSL::TimeoutHandler::timerEvent(QTimerEvent *event)
+{
+ Q_UNUSED(event);
+ Q_ASSERT(timerId != -1);
+
+ killTimer(timerId);
+ timerId = -1;
+
+ Q_ASSERT(dtlsConnection);
+ dtlsConnection->reportTimeout();
+}
+
+QDtlsPrivateOpenSSL::QDtlsPrivateOpenSSL(QDtls *qObject, QSslSocket::SslMode side)
+ : QDtlsBasePrivate(side, dtlsutil::fallbackSecret()), q(qObject)
+{
+ Q_ASSERT(qObject);
+
+ dtls.dtlsPrivate = this;
+}
+
+QSslSocket::SslMode QDtlsPrivateOpenSSL::cryptographMode() const
+{
+ return mode;
+}
+
+void QDtlsPrivateOpenSSL::setPeer(const QHostAddress &addr, quint16 port, const QString &name)
+{
+ remoteAddress = addr;
+ remotePort = port;
+ peerVfyName = name;
+}
+
+QHostAddress QDtlsPrivateOpenSSL::peerAddress() const
+{
+ return remoteAddress;
+}
+
+quint16 QDtlsPrivateOpenSSL::peerPort() const
+{
+ return remotePort;
+}
+
+void QDtlsPrivateOpenSSL::setPeerVerificationName(const QString &name)
+{
+ peerVfyName = name;
+}
+
+QString QDtlsPrivateOpenSSL::peerVerificationName() const
+{
+ return peerVfyName;
+}
+
+void QDtlsPrivateOpenSSL::setDtlsMtuHint(quint16 mtu)
+{
+ mtuHint = mtu;
+}
+
+quint16 QDtlsPrivateOpenSSL::dtlsMtuHint() const
+{
+ return mtuHint;
+}
+
+QDtls::HandshakeState QDtlsPrivateOpenSSL::state() const
+{
+ return handshakeState;
+}
+
+bool QDtlsPrivateOpenSSL::isConnectionEncrypted() const
+{
+ return connectionEncrypted;
+}
+
+bool QDtlsPrivateOpenSSL::startHandshake(QUdpSocket *socket, const QByteArray &dgram)
+{
+ Q_ASSERT(socket);
+ Q_ASSERT(handshakeState == QDtls::HandshakeNotStarted);
+
+ clearDtlsError();
+ connectionEncrypted = false;
+
+ if (!dtls.init(this, socket, remoteAddress, remotePort, dgram))
+ return false;
+
+ if (mode == QSslSocket::SslServerMode && dtlsConfiguration.dtlsCookieVerificationEnabled()) {
+ dtls.secret = secret;
+ dtls.hashAlgorithm = hashAlgorithm;
+ // Let's prepare the state machine so that message sequence 1 does not
+ // surprise DTLS/OpenSSL (such a message would be disregarded as
+ // 'stale or future' in SSL_accept otherwise):
+ int result = 0;
+ QSharedPointer<BIO_ADDR> peer(q_BIO_ADDR_new(), dtlsutil::delete_BIO_ADDR);
+ if (!peer.data()) {
+ setDtlsError(QDtlsError::TlsInitializationError,
+ QDtls::tr("BIO_ADD_new failed, cannot start handshake"));
+ return false;
+ }
+
+ // If it's an invalid/unexpected ClientHello, we don't want to send
+ // VerifyClientRequest - it's a job of QDtlsClientVerifier - so we
+ // suppress any attempts to write into socket:
+ dtls.writeSuppressed = true;
+ result = q_DTLSv1_listen(dtls.tlsConnection.data(), peer.data());
+ dtls.writeSuppressed = false;
+
+ if (result <= 0) {
+ setDtlsError(QDtlsError::TlsFatalError,
+ QDtls::tr("Cannot start the handshake, verified client hello expected"));
+ dtls.reset();
+ return false;
+ }
+ }
+
+ handshakeState = QDtls::HandshakeInProgress;
+ opensslErrors.clear();
+ tlsErrors.clear();
+
+ return continueHandshake(socket, dgram);
+}
+
+bool QDtlsPrivateOpenSSL::continueHandshake(QUdpSocket *socket, const QByteArray &dgram)
+{
+ Q_ASSERT(socket);
+
+ Q_ASSERT(handshakeState == QDtls::HandshakeInProgress);
+
+ clearDtlsError();
+
+ if (timeoutHandler.data())
+ timeoutHandler->stop();
+
+ if (!dtls.init(this, socket, remoteAddress, remotePort, dgram))
+ return false;
+
+ dtls.x509Errors.clear();
+
+ int result = 0;
+ if (mode == QSslSocket::SslServerMode)
+ result = q_SSL_accept(dtls.tlsConnection.data());
+ else
+ result = q_SSL_connect(dtls.tlsConnection.data());
+
+ // DTLSTODO: Investigate/test if it makes sense - QSslSocket can emit
+ // peerVerifyError at this point (and thus potentially client code
+ // will close the underlying TCP connection immediately), but we are using
+ // QUdpSocket, no connection to close, our verification callback returns 1
+ // (verified OK) and this probably means OpenSSL has already sent a reply
+ // to the server's hello/certificate.
+
+ opensslErrors << dtls.x509Errors;
+
+ if (result <= 0) {
+ const auto code = q_SSL_get_error(dtls.tlsConnection.data(), result);
+ switch (code) {
+ case SSL_ERROR_WANT_READ:
+ case SSL_ERROR_WANT_WRITE:
+ // DTLSTODO: to be tested - in principle, if it was the first call to
+ // continueHandshake and server for some reason discards the client
+ // hello message (even the verified one) - our 'this' will probably
+ // forever stay in this strange InProgress state? (the client
+ // will dully re-transmit the same hello and we discard it again?)
+ // SSL_get_state can provide more information about state
+ // machine and we can switch to NotStarted (since we have not
+ // replied with our hello ...)
+ if (!timeoutHandler.data()) {
+ timeoutHandler.reset(new TimeoutHandler);
+ timeoutHandler->dtlsConnection = this;
+ } else {
+ // Back to 1s.
+ timeoutHandler->resetTimeout();
+ }
+
+ timeoutHandler->start();
+
+ return true; // The handshake is not yet complete.
+ default:
+ storePeerCertificates();
+ setDtlsError(QDtlsError::TlsFatalError,
+ QTlsBackendOpenSSL::msgErrorsDuringHandshake());
+ dtls.reset();
+ handshakeState = QDtls::HandshakeNotStarted;
+ return false;
+ }
+ }
+
+ storePeerCertificates();
+ fetchNegotiatedParameters();
+
+ const bool doVerifyPeer = dtlsConfiguration.peerVerifyMode() == QSslSocket::VerifyPeer
+ || (dtlsConfiguration.peerVerifyMode() == QSslSocket::AutoVerifyPeer
+ && mode == QSslSocket::SslClientMode);
+
+ if (!doVerifyPeer || verifyPeer() || tlsErrorsWereIgnored()) {
+ connectionEncrypted = true;
+ handshakeState = QDtls::HandshakeComplete;
+ return true;
+ }
+
+ setDtlsError(QDtlsError::PeerVerificationError, QDtls::tr("Peer verification failed"));
+ handshakeState = QDtls::PeerVerificationFailed;
+ return false;
+}
+
+
+bool QDtlsPrivateOpenSSL::handleTimeout(QUdpSocket *socket)
+{
+ Q_ASSERT(socket);
+
+ Q_ASSERT(timeoutHandler.data());
+ Q_ASSERT(dtls.tlsConnection.data());
+
+ clearDtlsError();
+
+ dtls.udpSocket = socket;
+
+ if (q_DTLSv1_handle_timeout(dtls.tlsConnection.data()) > 0) {
+ timeoutHandler->doubleTimeout();
+ timeoutHandler->start();
+ } else {
+ timeoutHandler->start(dtlsutil::next_timeoutMs(dtls.tlsConnection.data()));
+ }
+
+ return true;
+}
+
+bool QDtlsPrivateOpenSSL::resumeHandshake(QUdpSocket *socket)
+{
+ Q_UNUSED(socket);
+ Q_ASSERT(socket);
+ Q_ASSERT(handshakeState == QDtls::PeerVerificationFailed);
+
+ clearDtlsError();
+
+ if (tlsErrorsWereIgnored()) {
+ handshakeState = QDtls::HandshakeComplete;
+ connectionEncrypted = true;
+ tlsErrors.clear();
+ tlsErrorsToIgnore.clear();
+ return true;
+ }
+
+ return false;
+}
+
+void QDtlsPrivateOpenSSL::abortHandshake(QUdpSocket *socket)
+{
+ Q_ASSERT(socket);
+ Q_ASSERT(handshakeState == QDtls::PeerVerificationFailed
+ || handshakeState == QDtls::HandshakeInProgress);
+
+ clearDtlsError();
+
+ if (handshakeState == QDtls::PeerVerificationFailed) {
+ // Yes, while peer verification failed, we were actually encrypted.
+ // Let's play it nice - inform our peer about connection shut down.
+ sendShutdownAlert(socket);
+ } else {
+ resetDtls();
+ }
+}
+
+void QDtlsPrivateOpenSSL::sendShutdownAlert(QUdpSocket *socket)
+{
+ Q_ASSERT(socket);
+
+ clearDtlsError();
+
+ if (connectionEncrypted && !connectionWasShutdown) {
+ dtls.udpSocket = socket;
+ Q_ASSERT(dtls.tlsConnection.data());
+ q_SSL_shutdown(dtls.tlsConnection.data());
+ }
+
+ resetDtls();
+}
+
+QList<QSslError> QDtlsPrivateOpenSSL::peerVerificationErrors() const
+{
+ return tlsErrors;
+}
+
+void QDtlsPrivateOpenSSL::ignoreVerificationErrors(const QList<QSslError> &errorsToIgnore)
+{
+ tlsErrorsToIgnore = errorsToIgnore;
+}
+
+QSslCipher QDtlsPrivateOpenSSL::dtlsSessionCipher() const
+{
+ return sessionCipher;
+}
+
+QSsl::SslProtocol QDtlsPrivateOpenSSL::dtlsSessionProtocol() const
+{
+ return sessionProtocol;
+}
+
+qint64 QDtlsPrivateOpenSSL::writeDatagramEncrypted(QUdpSocket *socket,
+ const QByteArray &dgram)
+{
+ Q_ASSERT(socket);
+ Q_ASSERT(dtls.tlsConnection.data());
+ Q_ASSERT(connectionEncrypted);
+
+ clearDtlsError();
+
+ dtls.udpSocket = socket;
+ const int written = q_SSL_write(dtls.tlsConnection.data(),
+ dgram.constData(), dgram.size());
+ if (written > 0)
+ return written;
+
+ const unsigned long errorCode = q_ERR_get_error();
+ if (!dgram.size() && errorCode == SSL_ERROR_NONE) {
+ // With OpenSSL <= 1.1 this can happen. For example, DTLS client
+ // tries to reconnect (while re-using the same address/port) -
+ // DTLS server drops a message with unexpected epoch but says - no
+ // error. We leave to client code to resolve such problems until
+ // OpenSSL provides something better.
+ return 0;
+ }
+
+ switch (errorCode) {
+ case SSL_ERROR_WANT_WRITE:
+ case SSL_ERROR_WANT_READ:
+ // We do not set any error/description ... a user can probably re-try
+ // sending a datagram.
+ break;
+ case SSL_ERROR_ZERO_RETURN:
+ connectionWasShutdown = true;
+ setDtlsError(QDtlsError::TlsFatalError, QDtls::tr("The DTLS connection has been closed"));
+ handshakeState = QDtls::HandshakeNotStarted;
+ dtls.reset();
+ break;
+ case SSL_ERROR_SYSCALL:
+ case SSL_ERROR_SSL:
+ default:
+ // DTLSTODO: we don't know yet what to do. Tests needed - probably,
+ // some errors can be just ignored (it's UDP, not TCP after all).
+ // Unlike QSslSocket we do not abort though.
+ QString description(QTlsBackendOpenSSL::getErrorsFromOpenSsl());
+ if (socket->error() != QAbstractSocket::UnknownSocketError && description.isEmpty()) {
+ setDtlsError(QDtlsError::UnderlyingSocketError, socket->errorString());
+ } else {
+ setDtlsError(QDtlsError::TlsFatalError,
+ QDtls::tr("Error while writing: %1").arg(description));
+ }
+ }
+
+ return -1;
+}
+
+QByteArray QDtlsPrivateOpenSSL::decryptDatagram(QUdpSocket *socket, const QByteArray &tlsdgram)
+{
+ Q_ASSERT(socket);
+ Q_ASSERT(tlsdgram.size());
+
+ Q_ASSERT(dtls.tlsConnection.data());
+ Q_ASSERT(connectionEncrypted);
+
+ dtls.dgram = tlsdgram;
+ dtls.udpSocket = socket;
+
+ clearDtlsError();
+
+ QByteArray dgram;
+ dgram.resize(tlsdgram.size());
+ const int read = q_SSL_read(dtls.tlsConnection.data(), dgram.data(),
+ dgram.size());
+
+ if (read > 0) {
+ dgram.resize(read);
+ return dgram;
+ }
+
+ dgram.clear();
+ unsigned long errorCode = q_ERR_get_error();
+ if (errorCode == SSL_ERROR_NONE) {
+ const int shutdown = q_SSL_get_shutdown(dtls.tlsConnection.data());
+ if (shutdown & SSL_RECEIVED_SHUTDOWN)
+ errorCode = SSL_ERROR_ZERO_RETURN;
+ else
+ return dgram;
+ }
+
+ switch (errorCode) {
+ case SSL_ERROR_WANT_READ:
+ case SSL_ERROR_WANT_WRITE:
+ return dgram;
+ case SSL_ERROR_ZERO_RETURN:
+ // "The connection was shut down cleanly" ... hmm, whatever,
+ // needs testing (DTLSTODO).
+ connectionWasShutdown = true;
+ setDtlsError(QDtlsError::RemoteClosedConnectionError,
+ QDtls::tr("The DTLS connection has been shutdown"));
+ dtls.reset();
+ connectionEncrypted = false;
+ handshakeState = QDtls::HandshakeNotStarted;
+ return dgram;
+ case SSL_ERROR_SYSCALL: // some IO error
+ case SSL_ERROR_SSL: // error in the SSL library
+ // DTLSTODO: Apparently, some errors can be ignored, for example,
+ // ECONNRESET etc. This all needs a lot of testing!!!
+ default:
+ setDtlsError(QDtlsError::TlsNonFatalError,
+ QDtls::tr("Error while reading: %1")
+ .arg(QTlsBackendOpenSSL::getErrorsFromOpenSsl()));
+ return dgram;
+ }
+}
+
+unsigned QDtlsPrivateOpenSSL::pskClientCallback(const char *hint, char *identity,
+ unsigned max_identity_len,
+ unsigned char *psk,
+ unsigned max_psk_len)
+{
+ // The code below is taken (with some modifications) from qsslsocket_openssl
+ // - alas, we cannot simply re-use it, it's in QSslSocketPrivate.
+ {
+ QSslPreSharedKeyAuthenticator authenticator;
+ // Fill in some read-only fields (for client code)
+ if (hint) {
+ identityHint.clear();
+ identityHint.append(hint);
+ }
+
+ QTlsBackend::setupClientPskAuth(&authenticator, hint ? identityHint.constData() : nullptr,
+ hint ? int(std::strlen(hint)) : 0, max_identity_len, max_psk_len);
+ pskAuthenticator.swap(authenticator);
+ }
+
+ // Let the client provide the remaining bits...
+ emit q->pskRequired(&pskAuthenticator);
+
+ // No PSK set? Return now to make the handshake fail
+ if (pskAuthenticator.preSharedKey().isEmpty())
+ return 0;
+
+ // Copy data back into OpenSSL
+ const int identityLength = qMin(pskAuthenticator.identity().size(),
+ pskAuthenticator.maximumIdentityLength());
+ std::memcpy(identity, pskAuthenticator.identity().constData(), identityLength);
+ identity[identityLength] = 0;
+
+ const int pskLength = qMin(pskAuthenticator.preSharedKey().size(),
+ pskAuthenticator.maximumPreSharedKeyLength());
+ std::memcpy(psk, pskAuthenticator.preSharedKey().constData(), pskLength);
+
+ return pskLength;
+}
+
+unsigned QDtlsPrivateOpenSSL::pskServerCallback(const char *identity, unsigned char *psk,
+ unsigned max_psk_len)
+{
+ {
+ QSslPreSharedKeyAuthenticator authenticator;
+ // Fill in some read-only fields (for the user)
+ QTlsBackend::setupServerPskAuth(&authenticator, identity, dtlsConfiguration.preSharedKeyIdentityHint(),
+ max_psk_len);
+ pskAuthenticator.swap(authenticator);
+ }
+
+ // Let the client provide the remaining bits...
+ emit q->pskRequired(&pskAuthenticator);
+
+ // No PSK set? Return now to make the handshake fail
+ if (pskAuthenticator.preSharedKey().isEmpty())
+ return 0;
+
+ // Copy data back into OpenSSL
+ const int pskLength = qMin(pskAuthenticator.preSharedKey().size(),
+ pskAuthenticator.maximumPreSharedKeyLength());
+
+ std::memcpy(psk, pskAuthenticator.preSharedKey().constData(), pskLength);
+
+ return pskLength;
+}
+
+bool QDtlsPrivateOpenSSL::verifyPeer()
+{
+ QList<QSslError> errors;
+
+ // Check the whole chain for blacklisting (including root, as we check for
+ // subjectInfo and issuer)
+ const auto &peerCertificateChain = dtlsConfiguration.peerCertificateChain();
+ for (const QSslCertificate &cert : peerCertificateChain) {
+ if (QSslCertificatePrivate::isBlacklisted(cert))
+ errors << QSslError(QSslError::CertificateBlacklisted, cert);
+ }
+
+ const auto peerCertificate = dtlsConfiguration.peerCertificate();
+ if (peerCertificate.isNull()) {
+ errors << QSslError(QSslError::NoPeerCertificate);
+ } else if (mode == QSslSocket::SslClientMode) {
+ // Check the peer certificate itself. First try the subject's common name
+ // (CN) as a wildcard, then try all alternate subject name DNS entries the
+ // same way.
+
+ // QSslSocket has a rather twisted logic: if verificationPeerName
+ // is empty, we call QAbstractSocket::peerName(), which returns
+ // either peerName (can be set by setPeerName) or host name
+ // (can be set as a result of connectToHost).
+ QString name = peerVfyName;
+ if (name.isEmpty()) {
+ Q_ASSERT(dtls.udpSocket);
+ name = dtls.udpSocket->peerName();
+ }
+
+ if (!QTlsPrivate::TlsCryptograph::isMatchingHostname(peerCertificate, name))
+ errors << QSslError(QSslError::HostNameMismatch, peerCertificate);
+ }
+
+ // Translate errors from the error list into QSslErrors
+ using CertClass = QTlsPrivate::X509CertificateOpenSSL;
+ errors.reserve(errors.size() + opensslErrors.size());
+ for (const auto &error : std::as_const(opensslErrors)) {
+ const auto value = peerCertificateChain.value(error.depth);
+ errors << CertClass::openSSLErrorToQSslError(error.code, value);
+ }
+
+ tlsErrors = errors;
+ return tlsErrors.isEmpty();
+}
+
+void QDtlsPrivateOpenSSL::storePeerCertificates()
+{
+ Q_ASSERT(dtls.tlsConnection.data());
+ // Store the peer certificate and chain. For clients, the peer certificate
+ // chain includes the peer certificate; for servers, it doesn't. Both the
+ // peer certificate and the chain may be empty if the peer didn't present
+ // any certificate.
+ X509 *x509 = q_SSL_get_peer_certificate(dtls.tlsConnection.data());
+ const auto peerCertificate = QTlsPrivate::X509CertificateOpenSSL::certificateFromX509(x509);
+ QTlsBackend::storePeerCertificate(dtlsConfiguration, peerCertificate);
+ q_X509_free(x509);
+
+ auto peerCertificateChain = dtlsConfiguration.peerCertificateChain();
+ if (peerCertificateChain.isEmpty()) {
+ auto stack = q_SSL_get_peer_cert_chain(dtls.tlsConnection.data());
+ peerCertificateChain = QTlsPrivate::X509CertificateOpenSSL::stackOfX509ToQSslCertificates(stack);
+ if (!peerCertificate.isNull() && mode == QSslSocket::SslServerMode)
+ peerCertificateChain.prepend(peerCertificate);
+ QTlsBackend::storePeerCertificateChain(dtlsConfiguration, peerCertificateChain);
+ }
+}
+
+bool QDtlsPrivateOpenSSL::tlsErrorsWereIgnored() const
+{
+ // check whether the errors we got are all in the list of expected errors
+ // (applies only if the method QDtlsConnection::ignoreTlsErrors(const
+ // QList<QSslError> &errors) was called)
+ for (const QSslError &error : tlsErrors) {
+ if (!tlsErrorsToIgnore.contains(error))
+ return false;
+ }
+
+ return !tlsErrorsToIgnore.empty();
+}
+
+void QDtlsPrivateOpenSSL::fetchNegotiatedParameters()
+{
+ Q_ASSERT(dtls.tlsConnection.data());
+
+ if (const SSL_CIPHER *cipher = q_SSL_get_current_cipher(dtls.tlsConnection.data()))
+ sessionCipher = QTlsBackendOpenSSL::qt_OpenSSL_cipher_to_QSslCipher(cipher);
+ else
+ sessionCipher = {};
+
+ // Note: cipher's protocol version will be reported as either TLS 1.0 or
+ // 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;
+ default:
+ qCWarning(lcTlsBackend, "unknown protocol version");
+ sessionProtocol = QSsl::UnknownProtocol;
+ }
+}
+
+void QDtlsPrivateOpenSSL::reportTimeout()
+{
+ emit q->handshakeTimeout();
+}
+
+void QDtlsPrivateOpenSSL::resetDtls()
+{
+ dtls.reset();
+ connectionEncrypted = false;
+ tlsErrors.clear();
+ tlsErrorsToIgnore.clear();
+ QTlsBackend::clearPeerCertificates(dtlsConfiguration);
+ connectionWasShutdown = false;
+ handshakeState = QDtls::HandshakeNotStarted;
+ sessionCipher = {};
+ sessionProtocol = QSsl::UnknownProtocol;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/tls/openssl/qdtls_openssl_p.h b/src/plugins/tls/openssl/qdtls_openssl_p.h
new file mode 100644
index 0000000000..44be86f1ed
--- /dev/null
+++ b/src/plugins/tls/openssl/qdtls_openssl_p.h
@@ -0,0 +1,214 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QDTLS_OPENSSL_P_H
+#define QDTLS_OPENSSL_P_H
+
+#include <QtNetwork/private/qtnetworkglobal_p.h>
+
+#include "qsslcontext_openssl_p.h"
+#include "qtlsbackend_openssl_p.h"
+#include "qtls_openssl_p.h"
+#include "qopenssl_p.h"
+
+#include "../shared/qdtls_base_p.h"
+
+#include <QtNetwork/private/qdtls_p.h>
+
+#include <QtNetwork/qsslpresharedkeyauthenticator.h>
+#include <QtNetwork/qhostaddress.h>
+
+#include <QtCore/qsharedpointer.h>
+#include <QtCore/qbytearray.h>
+#include <QtCore/qglobal.h>
+#include <QtCore/qlist.h>
+
+#include <openssl/ossl_typ.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.
+//
+
+QT_REQUIRE_CONFIG(openssl);
+QT_REQUIRE_CONFIG(dtls);
+
+QT_BEGIN_NAMESPACE
+
+class QDtlsPrivateOpenSSL;
+class QDtlsBasePrivate;
+class QUdpSocket;
+
+namespace dtlsopenssl
+{
+
+class DtlsState
+{
+public:
+ // Note, bioMethod _must_ outlive BIOs it was used to create. Thus
+ // the order of declarations here matters.
+ using BioMethod = QSharedPointer<BIO_METHOD>;
+ BioMethod bioMethod;
+
+ using TlsContext = std::shared_ptr<QSslContext>;
+ TlsContext tlsContext;
+
+ using TlsConnection = QSharedPointer<SSL>;
+ TlsConnection tlsConnection;
+
+ QByteArray dgram;
+
+ QHostAddress remoteAddress;
+ quint16 remotePort = 0;
+
+ QList<QSslErrorEntry> x509Errors;
+
+ long peeking = false;
+ QUdpSocket *udpSocket = nullptr;
+ bool writeSuppressed = false;
+
+ bool init(QDtlsBasePrivate *dtlsBase, QUdpSocket *socket,
+ const QHostAddress &remote, quint16 port,
+ const QByteArray &receivedMessage);
+
+ void reset();
+
+ QDtlsPrivateOpenSSL *dtlsPrivate = nullptr;
+ QByteArray secret;
+
+#ifdef QT_CRYPTOGRAPHICHASH_ONLY_SHA1
+ QCryptographicHash::Algorithm hashAlgorithm = QCryptographicHash::Sha1;
+#else
+ QCryptographicHash::Algorithm hashAlgorithm = QCryptographicHash::Sha256;
+#endif
+
+private:
+
+ bool initTls(QDtlsBasePrivate *dtlsBase);
+ bool initCtxAndConnection(QDtlsBasePrivate *dtlsBase);
+ bool initBIO(QDtlsBasePrivate *dtlsBase);
+ void setLinkMtu(QDtlsBasePrivate *dtlsBase);
+};
+
+} // namespace dtlsopenssl
+
+// The trick with 'right' ancestor in the tree overriding (only once) some shared
+// virtual functions is intentional. Too bad MSVC warns me about ... exactly the
+// feature of C++ that I want to use.
+
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_MSVC(4250)
+
+class QDtlsClientVerifierOpenSSL : public QTlsPrivate::DtlsCookieVerifier, public QDtlsBasePrivate
+{
+public:
+ QDtlsClientVerifierOpenSSL();
+
+ bool verifyClient(QUdpSocket *socket, const QByteArray &dgram,
+ const QHostAddress &address, quint16 port) override;
+ QByteArray verifiedHello() const override;
+
+private:
+ dtlsopenssl::DtlsState dtls;
+ QByteArray verifiedClientHello;
+};
+
+class QDtlsPrivateOpenSSL : public QTlsPrivate::DtlsCryptograph, public QDtlsBasePrivate
+{
+public:
+
+ QDtlsPrivateOpenSSL(QDtls *qObject, QSslSocket::SslMode mode);
+
+private:
+
+ QSslSocket::SslMode cryptographMode() const override;
+ void setPeer(const QHostAddress &addr, quint16 port, const QString &name) override;
+ QHostAddress peerAddress() const override;
+ quint16 peerPort() const override;
+ void setPeerVerificationName(const QString &name) override;
+ QString peerVerificationName() const override;
+
+ virtual void setDtlsMtuHint(quint16 mtu) override;
+ virtual quint16 dtlsMtuHint() const override;
+
+ virtual QDtls::HandshakeState state() const override;
+ virtual bool isConnectionEncrypted() const override;
+
+ bool startHandshake(QUdpSocket *socket, const QByteArray &datagram) override;
+ bool continueHandshake(QUdpSocket *socket, const QByteArray &datagram) override;
+ bool resumeHandshake(QUdpSocket *socket) override;
+ void abortHandshake(QUdpSocket *socket) override;
+ bool handleTimeout(QUdpSocket *socket) override;
+ void sendShutdownAlert(QUdpSocket *socket) override;
+
+ QList<QSslError> peerVerificationErrors() const override;
+ void ignoreVerificationErrors(const QList<QSslError> &errorsToIgnore) override;
+
+ QSslCipher dtlsSessionCipher() const override;
+ QSsl::SslProtocol dtlsSessionProtocol() const override;
+
+ qint64 writeDatagramEncrypted(QUdpSocket *socket, const QByteArray &datagram) override;
+ QByteArray decryptDatagram(QUdpSocket *socket, const QByteArray &tlsdgram) override;
+
+public:
+ unsigned pskClientCallback(const char *hint, char *identity, unsigned max_identity_len,
+ unsigned char *psk, unsigned max_psk_len);
+ unsigned pskServerCallback(const char *identity, unsigned char *psk,
+ unsigned max_psk_len);
+
+private:
+
+ bool verifyPeer();
+ void storePeerCertificates();
+ bool tlsErrorsWereIgnored() const;
+ void fetchNegotiatedParameters();
+ void reportTimeout();
+ void resetDtls();
+
+ QList<QSslErrorEntry> opensslErrors;
+ dtlsopenssl::DtlsState dtls;
+
+ // We have to externally handle timeouts since we have non-blocking
+ // sockets and OpenSSL(DTLS) with non-blocking UDP sockets does not
+ // know if a timeout has occurred.
+ struct TimeoutHandler : QObject
+ {
+ TimeoutHandler() = default;
+
+ void start(int hintMs = 0);
+ void doubleTimeout();
+ void resetTimeout() {timeoutMs = 1000;}
+ void stop();
+ void timerEvent(QTimerEvent *event) override;
+
+ int timerId = -1;
+ int timeoutMs = 1000;
+
+ QDtlsPrivateOpenSSL *dtlsConnection = nullptr;
+ };
+
+ QDtls *q = nullptr;
+ QDtls::HandshakeState handshakeState = QDtls::HandshakeNotStarted;
+
+ QList<QSslError> tlsErrors;
+ QList<QSslError> tlsErrorsToIgnore;
+ bool connectionEncrypted = false;
+ // We will initialize it 'lazily', just in case somebody wants to move
+ // QDtls to another thread.
+ QScopedPointer<TimeoutHandler> timeoutHandler;
+ bool connectionWasShutdown = false;
+ QSslPreSharedKeyAuthenticator pskAuthenticator;
+ QByteArray identityHint;
+};
+
+QT_WARNING_POP // C4250
+
+QT_END_NAMESPACE
+
+#endif // QDTLS_OPENSSL_P_H
diff --git a/src/plugins/tls/openssl/qopenssl_p.h b/src/plugins/tls/openssl/qopenssl_p.h
new file mode 100644
index 0000000000..370b974630
--- /dev/null
+++ b/src/plugins/tls/openssl/qopenssl_p.h
@@ -0,0 +1,82 @@
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+/****************************************************************************
+**
+** In addition, as a special exception, the copyright holders listed above give
+** permission to link the code of its release of Qt with the OpenSSL project's
+** "OpenSSL" library (or modified versions of the "OpenSSL" library that use the
+** same license as the original version), and distribute the linked executables.
+**
+** You must comply with the GNU General Public License version 2 in all
+** respects for all of the code used other than the "OpenSSL" code. If you
+** modify this file, you may extend this exception to your version of the file,
+** but you are not obligated to do so. If you do not wish to do so, delete
+** this exception statement from your version of this file.
+**
+****************************************************************************/
+
+#ifndef QSSLSOCKET_OPENSSL_P_H
+#define QSSLSOCKET_OPENSSL_P_H
+
+//
+// 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 <QtNetwork/private/qtnetworkglobal_p.h>
+
+#include <QtNetwork/private/qsslsocket_p.h>
+
+#include <QtNetwork/qsslcipher.h>
+
+#ifdef Q_OS_WIN
+#include <qt_windows.h>
+#if defined(OCSP_RESPONSE)
+#undef OCSP_RESPONSE
+#endif
+#if defined(X509_NAME)
+#undef X509_NAME
+#endif
+#endif // Q_OS_WIN
+
+// This file is included in several *.cpp files and provides different
+// openssl declarations where they are needed.
+#include <openssl/asn1.h>
+#include <openssl/bio.h>
+#include <openssl/bn.h>
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include <openssl/pem.h>
+#include <openssl/pkcs12.h>
+#include <openssl/pkcs7.h>
+#include <openssl/rand.h>
+#include <openssl/ssl.h>
+#include <openssl/stack.h>
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+#include <openssl/x509_vfy.h>
+#include <openssl/dsa.h>
+#include <openssl/rsa.h>
+#include <openssl/crypto.h>
+#include <openssl/tls1.h>
+#include <openssl/dh.h>
+
+QT_BEGIN_NAMESPACE
+
+struct QSslErrorEntry {
+ int code = 0;
+ int depth = 0;
+};
+
+Q_DECLARE_TYPEINFO(QSslErrorEntry, Q_PRIMITIVE_TYPE);
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/plugins/tls/openssl/qsslcontext_openssl.cpp b/src/plugins/tls/openssl/qsslcontext_openssl.cpp
new file mode 100644
index 0000000000..75c192bd01
--- /dev/null
+++ b/src/plugins/tls/openssl/qsslcontext_openssl.cpp
@@ -0,0 +1,815 @@
+// Copyright (C) 2017 The Qt Company Ltd.
+// Copyright (C) 2014 BlackBerry Limited. All rights reserved.
+// Copyright (C) 2014 Governikus GmbH & Co. KG.
+// Copyright (C) 2016 Richard J. Moore <rich@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <QtNetwork/qsslsocket.h>
+#include <QtNetwork/qssldiffiehellmanparameters.h>
+
+#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>
+#include <QtNetwork/private/qsslsocket_p.h>
+#include <QtNetwork/private/qtlsbackend_p.h>
+
+#include <QtNetwork/private/qssldiffiehellmanparameters_p.h>
+
+#include <vector>
+
+QT_BEGIN_NAMESPACE
+
+Q_GLOBAL_STATIC(bool, forceSecurityLevel)
+
+namespace QTlsPrivate
+{
+// These callback functions are defined in qtls_openssl.cpp.
+extern "C" int q_X509Callback(int ok, X509_STORE_CTX *ctx);
+extern "C" int q_X509CallbackDirect(int ok, X509_STORE_CTX *ctx);
+
+#if QT_CONFIG(ocsp)
+extern "C" int qt_OCSP_status_server_callback(SSL *ssl, void *);
+#endif // ocsp
+
+} // namespace QTlsPrivate
+
+#if QT_CONFIG(dtls)
+// defined in qdtls_openssl.cpp:
+namespace dtlscallbacks
+{
+extern "C" int q_X509DtlsCallback(int ok, X509_STORE_CTX *ctx);
+extern "C" int q_generate_cookie_callback(SSL *ssl, unsigned char *dst,
+ unsigned *cookieLength);
+extern "C" int q_verify_cookie_callback(SSL *ssl, const unsigned char *cookie,
+ unsigned cookieLength);
+}
+#endif // dtls
+
+#ifdef TLS1_3_VERSION
+extern "C" int q_ssl_sess_set_new_cb(SSL *context, SSL_SESSION *session);
+#endif // TLS1_3_VERSION
+
+static inline QString msgErrorSettingBackendConfig(const QString &why)
+{
+ return QSslSocket::tr("Error when setting the OpenSSL configuration (%1)").arg(why);
+}
+
+static inline QString msgErrorSettingEllipticCurves(const QString &why)
+{
+ return QSslSocket::tr("Error when setting the elliptic curves (%1)").arg(why);
+}
+
+qssloptions QSslContext::setupOpenSslOptions(QSsl::SslProtocol protocol, QSsl::SslOptions sslOptions)
+{
+ qssloptions options;
+ switch (protocol) {
+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;
+ case QSsl::TlsV1_3OrLater:
+ options = SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1_2;
+ break;
+ default:
+ options = SSL_OP_ALL;
+ }
+
+ // This option is disabled by default, so we need to be able to clear it
+ if (sslOptions & QSsl::SslOptionDisableEmptyFragments)
+ options |= SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS;
+ else
+ options &= ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS;
+
+#ifdef SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION
+ // This option is disabled by default, so we need to be able to clear it
+ if (sslOptions & QSsl::SslOptionDisableLegacyRenegotiation)
+ options &= ~SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION;
+ else
+ options |= SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION;
+#endif
+
+#ifdef SSL_OP_NO_TICKET
+ if (sslOptions & QSsl::SslOptionDisableSessionTickets)
+ options |= SSL_OP_NO_TICKET;
+#endif
+#ifdef SSL_OP_NO_COMPRESSION
+ if (sslOptions & QSsl::SslOptionDisableCompression)
+ options |= SSL_OP_NO_COMPRESSION;
+#endif
+
+ if (!(sslOptions & QSsl::SslOptionDisableServerCipherPreference))
+ options |= SSL_OP_CIPHER_SERVER_PREFERENCE;
+
+ return options;
+}
+
+QSslContext::QSslContext()
+ : ctx(nullptr),
+ pkey(nullptr),
+ session(nullptr),
+ m_sessionTicketLifeTimeHint(-1)
+{
+}
+
+QSslContext::~QSslContext()
+{
+ if (ctx)
+ // This will decrement the reference count by 1 and free the context eventually when possible
+ q_SSL_CTX_free(ctx);
+
+ if (pkey)
+ q_EVP_PKEY_free(pkey);
+
+ if (session)
+ q_SSL_SESSION_free(session);
+}
+
+std::shared_ptr<QSslContext> QSslContext::sharedFromConfiguration(QSslSocket::SslMode mode, const QSslConfiguration &configuration, bool allowRootCertOnDemandLoading)
+{
+ struct AccessToPrivateCtor : QSslContext {};
+ std::shared_ptr<QSslContext> sslContext = std::make_shared<AccessToPrivateCtor>();
+ initSslContext(sslContext.get(), mode, configuration, allowRootCertOnDemandLoading);
+ return sslContext;
+}
+
+std::shared_ptr<QSslContext> QSslContext::sharedFromPrivateConfiguration(QSslSocket::SslMode mode, QSslConfigurationPrivate *privConfiguration,
+ bool allowRootCertOnDemandLoading)
+{
+ return sharedFromConfiguration(mode, privConfiguration, allowRootCertOnDemandLoading);
+}
+
+#ifndef OPENSSL_NO_NEXTPROTONEG
+
+static int next_proto_cb(SSL *, unsigned char **out, unsigned char *outlen,
+ const unsigned char *in, unsigned int inlen, void *arg)
+{
+ QSslContext::NPNContext *ctx = reinterpret_cast<QSslContext::NPNContext *>(arg);
+
+ // comment out to debug:
+// QList<QByteArray> supportedVersions;
+// for (unsigned int i = 0; i < inlen; ) {
+// QByteArray version(reinterpret_cast<const char *>(&in[i+1]), in[i]);
+// supportedVersions << version;
+// i += in[i] + 1;
+// }
+
+ int proto = q_SSL_select_next_proto(out, outlen, in, inlen, ctx->data, ctx->len);
+ switch (proto) {
+ case OPENSSL_NPN_UNSUPPORTED:
+ ctx->status = QSslConfiguration::NextProtocolNegotiationNone;
+ break;
+ case OPENSSL_NPN_NEGOTIATED:
+ ctx->status = QSslConfiguration::NextProtocolNegotiationNegotiated;
+ break;
+ case OPENSSL_NPN_NO_OVERLAP:
+ ctx->status = QSslConfiguration::NextProtocolNegotiationUnsupported;
+ break;
+ default:
+ qCWarning(lcTlsBackend, "OpenSSL sent unknown NPN status");
+ }
+
+ return SSL_TLSEXT_ERR_OK;
+}
+
+QSslContext::NPNContext QSslContext::npnContext() const
+{
+ return m_npnContext;
+}
+#endif // !OPENSSL_NO_NEXTPROTONEG
+
+
+
+// Needs to be deleted by caller
+SSL* QSslContext::createSsl()
+{
+ SSL* ssl = q_SSL_new(ctx);
+ q_SSL_clear(ssl);
+
+ if (!session && !sessionASN1().isEmpty()
+ && !sslConfiguration.testSslOption(QSsl::SslOptionDisableSessionPersistence)) {
+ const unsigned char *data = reinterpret_cast<const unsigned char *>(m_sessionASN1.constData());
+ session = q_d2i_SSL_SESSION(nullptr, &data, m_sessionASN1.size());
+ // 'session' has refcount 1 already, set by the function above
+ }
+
+ if (session) {
+ // Try to resume the last session we cached
+ if (!q_SSL_set_session(ssl, session)) {
+ qCWarning(lcTlsBackend, "could not set SSL session");
+ q_SSL_SESSION_free(session);
+ session = nullptr;
+ }
+ }
+
+#ifndef OPENSSL_NO_NEXTPROTONEG
+ QList<QByteArray> protocols = sslConfiguration.d.constData()->nextAllowedProtocols;
+ if (!protocols.isEmpty()) {
+ m_supportedNPNVersions.clear();
+ for (int a = 0; a < protocols.size(); ++a) {
+ if (protocols.at(a).size() > 255) {
+ qCWarning(lcTlsBackend) << "TLS NPN extension" << protocols.at(a)
+ << "is too long and will be ignored.";
+ continue;
+ } else if (protocols.at(a).isEmpty()) {
+ continue;
+ }
+ m_supportedNPNVersions.append(protocols.at(a).size()).append(protocols.at(a));
+ }
+ if (m_supportedNPNVersions.size()) {
+ m_npnContext.data = reinterpret_cast<unsigned char *>(m_supportedNPNVersions.data());
+ m_npnContext.len = m_supportedNPNVersions.size();
+ m_npnContext.status = QSslConfiguration::NextProtocolNegotiationNone;
+ // Callback's type has a parameter 'const unsigned char ** out'
+ // since it was introduced in 1.0.2. Internally, OpenSSL's own code
+ // (tests/examples) cast it to unsigned char * (since it's 'out').
+ // We just re-use our NPN callback and cast here:
+ typedef int (*alpn_callback_t) (SSL *, const unsigned char **, unsigned char *,
+ const unsigned char *, unsigned int, void *);
+ // With ALPN callback is for a server side only, for a client m_npnContext.status
+ // will stay in NextProtocolNegotiationNone.
+ q_SSL_CTX_set_alpn_select_cb(ctx, alpn_callback_t(next_proto_cb), &m_npnContext);
+ // Client:
+ q_SSL_set_alpn_protos(ssl, m_npnContext.data, m_npnContext.len);
+ // And in case our peer does not support ALPN, but supports NPN:
+ q_SSL_CTX_set_next_proto_select_cb(ctx, next_proto_cb, &m_npnContext);
+ }
+ }
+#endif // !OPENSSL_NO_NEXTPROTONEG
+
+ return ssl;
+}
+
+// We cache exactly one session here
+bool QSslContext::cacheSession(SSL* ssl)
+{
+ // don't cache the same session again
+ if (session && session == q_SSL_get_session(ssl))
+ return true;
+
+ // decrease refcount of currently stored session
+ // (this might happen if there are several concurrent handshakes in flight)
+ if (session)
+ q_SSL_SESSION_free(session);
+
+ // cache the session the caller gave us and increase reference count
+ session = q_SSL_get1_session(ssl);
+
+ if (session && !sslConfiguration.testSslOption(QSsl::SslOptionDisableSessionPersistence)) {
+ int sessionSize = q_i2d_SSL_SESSION(session, nullptr);
+ if (sessionSize > 0) {
+ m_sessionASN1.resize(sessionSize);
+ unsigned char *data = reinterpret_cast<unsigned char *>(m_sessionASN1.data());
+ if (!q_i2d_SSL_SESSION(session, &data))
+ qCWarning(lcTlsBackend, "could not store persistent version of SSL session");
+ m_sessionTicketLifeTimeHint = q_SSL_SESSION_get_ticket_lifetime_hint(session);
+ }
+ }
+
+ return (session != nullptr);
+}
+
+QByteArray QSslContext::sessionASN1() const
+{
+ return m_sessionASN1;
+}
+
+void QSslContext::setSessionASN1(const QByteArray &session)
+{
+ m_sessionASN1 = session;
+}
+
+int QSslContext::sessionTicketLifeTimeHint() const
+{
+ return m_sessionTicketLifeTimeHint;
+}
+
+void QSslContext::forceAutoTestSecurityLevel()
+{
+ *forceSecurityLevel() = true;
+}
+
+QSslError::SslError QSslContext::error() const
+{
+ return errorCode;
+}
+
+QString QSslContext::errorString() const
+{
+ return errorStr;
+}
+
+void QSslContext::initSslContext(QSslContext *sslContext, QSslSocket::SslMode mode,
+ const QSslConfiguration &configuration,
+ bool allowRootCertOnDemandLoading)
+{
+ sslContext->sslConfiguration = configuration;
+ sslContext->errorCode = QSslError::NoError;
+
+ bool client = (mode == QSslSocket::SslClientMode);
+
+ bool reinitialized = false;
+ bool unsupportedProtocol = false;
+ 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)
+ isDtls = true;
+ sslContext->ctx = q_SSL_CTX_new(client ? q_DTLS_client_method() : q_DTLS_server_method());
+#else // dtls
+ sslContext->ctx = nullptr;
+ unsupportedProtocol = true;
+ qCWarning(lcTlsBackend, "DTLS protocol requested, but feature 'dtls' is disabled");
+#endif // dtls
+ break;
+ case QSsl::TlsV1_3:
+ case QSsl::TlsV1_3OrLater:
+#if !defined(TLS1_3_VERSION)
+ qCWarning(lcTlsBackend, "TLS 1.3 is not supported");
+ sslContext->ctx = nullptr;
+ unsupportedProtocol = true;
+ break;
+#endif // TLS1_3_VERSION
+ default:
+ // The ssl options will actually control the supported methods
+ sslContext->ctx = q_SSL_CTX_new(client ? q_TLS_client_method() : q_TLS_server_method());
+ }
+
+ if (!sslContext->ctx) {
+ // After stopping Flash 10 the SSL library loses its ciphers. Try re-adding them
+ // by re-initializing the library.
+ if (!reinitialized) {
+ reinitialized = true;
+ if (q_OPENSSL_init_ssl(0, nullptr) == 1)
+ goto init_context;
+ }
+
+ sslContext->errorStr = QSslSocket::tr("Error creating SSL context (%1)").arg(
+ unsupportedProtocol ? QSslSocket::tr("unsupported protocol") : QTlsBackendOpenSSL::getErrorsFromOpenSsl()
+ );
+ sslContext->errorCode = QSslError::UnspecifiedError;
+ return;
+ }
+
+ // A nasty hacked OpenSSL using a level that will make our auto-tests fail:
+ if (q_SSL_CTX_get_security_level(sslContext->ctx) > 1 && *forceSecurityLevel())
+ q_SSL_CTX_set_security_level(sslContext->ctx, 1);
+
+ const long anyVersion =
+#if QT_CONFIG(dtls)
+ isDtls ? DTLS_ANY_VERSION : TLS_ANY_VERSION;
+#else
+ TLS_ANY_VERSION;
+#endif // dtls
+ long minVersion = anyVersion;
+ long maxVersion = anyVersion;
+
+ switch (sslContext->sslConfiguration.protocol()) {
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
+ case QSsl::TlsV1_0:
+ minVersion = TLS1_VERSION;
+ maxVersion = TLS1_VERSION;
+ break;
+ case QSsl::TlsV1_1:
+ minVersion = TLS1_1_VERSION;
+ maxVersion = TLS1_1_VERSION;
+ break;
+QT_WARNING_POP
+ case QSsl::TlsV1_2:
+ minVersion = TLS1_2_VERSION;
+ maxVersion = TLS1_2_VERSION;
+ break;
+ case QSsl::TlsV1_3:
+#ifdef TLS1_3_VERSION
+ minVersion = TLS1_3_VERSION;
+ maxVersion = TLS1_3_VERSION;
+#else
+ // This protocol is not supported by OpenSSL 1.1 and we handle
+ // it as an error (see the code above).
+ Q_UNREACHABLE();
+#endif // TLS1_3_VERSION
+ break;
+ // Ranges:
+ case QSsl::AnyProtocol:
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
+ case QSsl::TlsV1_0OrLater:
+ minVersion = TLS1_VERSION;
+ maxVersion = 0;
+ break;
+ case QSsl::TlsV1_1OrLater:
+ 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 = 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 = 0;
+ break;
+ case QSsl::TlsV1_3OrLater:
+#ifdef TLS1_3_VERSION
+ minVersion = TLS1_3_VERSION;
+ maxVersion = 0;
+ break;
+#else
+ // This protocol is not supported by OpenSSL 1.1 and we handle
+ // it as an error (see the code above).
+ Q_UNREACHABLE();
+ break;
+#endif // TLS1_3_VERSION
+ case QSsl::UnknownProtocol:
+ break;
+ }
+
+ if (minVersion != anyVersion
+ && !q_SSL_CTX_set_min_proto_version(sslContext->ctx, minVersion)) {
+ sslContext->errorStr = QSslSocket::tr("Error while setting the minimal protocol version");
+ sslContext->errorCode = QSslError::UnspecifiedError;
+ return;
+ }
+
+ if (maxVersion != anyVersion
+ && !q_SSL_CTX_set_max_proto_version(sslContext->ctx, maxVersion)) {
+ sslContext->errorStr = QSslSocket::tr("Error while setting the maximum protocol version");
+ sslContext->errorCode = QSslError::UnspecifiedError;
+ return;
+ }
+
+ // Enable bug workarounds.
+ const qssloptions options = setupOpenSslOptions(configuration.protocol(), configuration.d->sslOptions);
+ q_SSL_CTX_set_options(sslContext->ctx, options);
+
+ // Tell OpenSSL to release memory early
+ // http://www.openssl.org/docs/ssl/SSL_CTX_set_mode.html
+ q_SSL_CTX_set_mode(sslContext->ctx, SSL_MODE_RELEASE_BUFFERS);
+
+ auto filterCiphers = [](const QList<QSslCipher> &ciphers, bool selectTls13)
+ {
+ QByteArray cipherString;
+
+ for (const QSslCipher &cipher : ciphers) {
+ const bool isTls13Cipher = cipher.protocol() == QSsl::TlsV1_3 || cipher.protocol() == QSsl::TlsV1_3OrLater;
+ if (selectTls13 != isTls13Cipher)
+ continue;
+
+ if (cipherString.size())
+ cipherString.append(':');
+ cipherString.append(cipher.name().toLatin1());
+ }
+ return cipherString;
+ };
+
+ // Initialize ciphers
+ QList<QSslCipher> ciphers = sslContext->sslConfiguration.ciphers();
+ if (ciphers.isEmpty())
+ ciphers = isDtls ? QTlsBackend::defaultDtlsCiphers() : QTlsBackend::defaultCiphers();
+
+ const QByteArray preTls13Ciphers = filterCiphers(ciphers, false);
+
+ if (preTls13Ciphers.size()) {
+ if (!q_SSL_CTX_set_cipher_list(sslContext->ctx, preTls13Ciphers.data())) {
+ sslContext->errorStr = QSslSocket::tr("Invalid or empty cipher list (%1)").arg(QTlsBackendOpenSSL::getErrorsFromOpenSsl());
+ sslContext->errorCode = QSslError::UnspecifiedError;
+ return;
+ }
+ }
+
+ const QByteArray tls13Ciphers = filterCiphers(ciphers, true);
+#ifdef TLS1_3_VERSION
+ if (tls13Ciphers.size()) {
+ if (!q_SSL_CTX_set_ciphersuites(sslContext->ctx, tls13Ciphers.data())) {
+ sslContext->errorStr = QSslSocket::tr("Invalid or empty cipher list (%1)").arg(QTlsBackendOpenSSL::getErrorsFromOpenSsl());
+ sslContext->errorCode = QSslError::UnspecifiedError;
+ return;
+ }
+ }
+#endif // TLS1_3_VERSION
+ if (!preTls13Ciphers.size() && !tls13Ciphers.size()) {
+ sslContext->errorStr = QSslSocket::tr("Invalid or empty cipher list (%1)").arg(QStringLiteral(""));
+ sslContext->errorCode = QSslError::UnspecifiedError;
+ return;
+ }
+
+ const QDateTime now = QDateTime::currentDateTimeUtc();
+
+ // Add all our CAs to this store.
+ const auto caCertificates = sslContext->sslConfiguration.caCertificates();
+ for (const QSslCertificate &caCertificate : caCertificates) {
+ // From https://www.openssl.org/docs/ssl/SSL_CTX_load_verify_locations.html:
+ //
+ // If several CA certificates matching the name, key identifier, and
+ // serial number condition are available, only the first one will be
+ // examined. This may lead to unexpected results if the same CA
+ // certificate is available with different expiration dates. If a
+ // ``certificate expired'' verification error occurs, no other
+ // certificate will be searched. Make sure to not have expired
+ // certificates mixed with valid ones.
+ //
+ // See also: QSslSocketBackendPrivate::verify()
+ if (caCertificate.expiryDate() >= now) {
+ q_X509_STORE_add_cert(q_SSL_CTX_get_cert_store(sslContext->ctx), (X509 *)caCertificate.handle());
+ }
+ }
+
+ if (QSslSocketPrivate::rootCertOnDemandLoadingSupported() && allowRootCertOnDemandLoading) {
+ // tell OpenSSL the directories where to look up the root certs on demand
+ const QList<QByteArray> unixDirs = QSslSocketPrivate::unixRootCertDirectories();
+ int success = 1;
+#if OPENSSL_VERSION_MAJOR < 3
+ for (const QByteArray &unixDir : unixDirs) {
+ if ((success = q_SSL_CTX_load_verify_locations(sslContext->ctx, nullptr, unixDir.constData())) != 1)
+ break;
+ }
+#else
+ for (const QByteArray &unixDir : unixDirs) {
+ if ((success = q_SSL_CTX_load_verify_dir(sslContext->ctx, unixDir.constData())) != 1)
+ break;
+ }
+#endif // OPENSSL_VERSION_MAJOR
+ if (success != 1) {
+ const auto qtErrors = QTlsBackendOpenSSL::getErrorsFromOpenSsl();
+ qCWarning(lcTlsBackend) << "An error encountered while to set root certificates location:"
+ << qtErrors;
+ }
+ }
+
+ if (!sslContext->sslConfiguration.localCertificate().isNull()) {
+ // Require a private key as well.
+ if (sslContext->sslConfiguration.privateKey().isNull()) {
+ sslContext->errorStr = QSslSocket::tr("Cannot provide a certificate with no key");
+ sslContext->errorCode = QSslError::UnspecifiedError;
+ return;
+ }
+
+ // Load certificate
+ if (!q_SSL_CTX_use_certificate(sslContext->ctx, (X509 *)sslContext->sslConfiguration.localCertificate().handle())) {
+ sslContext->errorStr = QSslSocket::tr("Error loading local certificate, %1").arg(QTlsBackendOpenSSL::getErrorsFromOpenSsl());
+ sslContext->errorCode = QSslError::UnspecifiedError;
+ return;
+ }
+
+ 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.
+ // this lead to a memory leak. Now we use the *_set1_* functions which do not
+ // take ownership of the RSA/DSA key instance because the QSslKey already has ownership.
+ if (configuration.d->privateKey.algorithm() == QSsl::Rsa)
+ q_EVP_PKEY_set1_RSA(sslContext->pkey, reinterpret_cast<RSA *>(configuration.d->privateKey.handle()));
+ else if (configuration.d->privateKey.algorithm() == QSsl::Dsa)
+ q_EVP_PKEY_set1_DSA(sslContext->pkey, reinterpret_cast<DSA *>(configuration.d->privateKey.handle()));
+#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 // OPENSSL_NO_EC
+#endif // OPENSSL_NO_DEPRECATED_3_0
+ }
+ auto pkey = sslContext->pkey;
+ if (configuration.d->privateKey.algorithm() == QSsl::Opaque)
+ sslContext->pkey = nullptr; // Don't free the private key, it belongs to QSslKey
+
+ if (!q_SSL_CTX_use_PrivateKey(sslContext->ctx, pkey)) {
+ sslContext->errorStr = QSslSocket::tr("Error loading private key, %1").arg(QTlsBackendOpenSSL::getErrorsFromOpenSsl());
+ sslContext->errorCode = QSslError::UnspecifiedError;
+ return;
+ }
+
+ // Check if the certificate matches the private key.
+ if (!q_SSL_CTX_check_private_key(sslContext->ctx)) {
+ sslContext->errorStr = QSslSocket::tr("Private key does not certify public key, %1").arg(QTlsBackendOpenSSL::getErrorsFromOpenSsl());
+ sslContext->errorCode = QSslError::UnspecifiedError;
+ return;
+ }
+
+ // If we have any intermediate certificates then we need to add them to our chain
+ bool first = true;
+ for (const QSslCertificate &cert : std::as_const(configuration.d->localCertificateChain)) {
+ if (first) {
+ first = false;
+ continue;
+ }
+ q_SSL_CTX_ctrl(sslContext->ctx, SSL_CTRL_EXTRA_CHAIN_CERT, 0,
+ q_X509_dup(reinterpret_cast<X509 *>(cert.handle())));
+ }
+ }
+
+ // Initialize peer verification, different callbacks, TLS/DTLS verification first
+ // (note, all these set_some_callback do not have return value):
+ if (sslContext->sslConfiguration.peerVerifyMode() == QSslSocket::VerifyNone) {
+ q_SSL_CTX_set_verify(sslContext->ctx, SSL_VERIFY_NONE, nullptr);
+ } else {
+ auto verificationCallback =
+ #if QT_CONFIG(dtls)
+ isDtls ? dtlscallbacks::q_X509DtlsCallback :
+ #endif // dtls
+ QTlsPrivate::q_X509Callback;
+
+ if (!isDtls && configuration.handshakeMustInterruptOnError())
+ verificationCallback = QTlsPrivate::q_X509CallbackDirect;
+
+ auto verificationMode = SSL_VERIFY_PEER;
+ if (!isDtls && sslContext->sslConfiguration.missingCertificateIsFatal())
+ verificationMode |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
+
+ q_SSL_CTX_set_verify(sslContext->ctx, verificationMode, verificationCallback);
+ }
+
+#ifdef TLS1_3_VERSION
+ // NewSessionTicket callback:
+ if (mode == QSslSocket::SslClientMode && !isDtls) {
+ q_SSL_CTX_sess_set_new_cb(sslContext->ctx, q_ssl_sess_set_new_cb);
+ q_SSL_CTX_set_session_cache_mode(sslContext->ctx, SSL_SESS_CACHE_CLIENT);
+ }
+
+#endif // TLS1_3_VERSION
+
+#if QT_CONFIG(dtls)
+ // DTLS cookies:
+ if (mode == QSslSocket::SslServerMode && isDtls && configuration.dtlsCookieVerificationEnabled()) {
+ q_SSL_CTX_set_cookie_generate_cb(sslContext->ctx, dtlscallbacks::q_generate_cookie_callback);
+ q_SSL_CTX_set_cookie_verify_cb(sslContext->ctx, dtlscallbacks::q_verify_cookie_callback);
+ }
+#endif // dtls
+
+ // Set verification depth.
+ if (sslContext->sslConfiguration.peerVerifyDepth() != 0)
+ q_SSL_CTX_set_verify_depth(sslContext->ctx, sslContext->sslConfiguration.peerVerifyDepth());
+
+ // set persisted session if the user set it
+ if (!configuration.sessionTicket().isEmpty())
+ sslContext->setSessionASN1(configuration.sessionTicket());
+
+ // Set temp DH params
+ QSslDiffieHellmanParameters dhparams = configuration.diffieHellmanParameters();
+
+ if (!dhparams.isValid()) {
+ sslContext->errorStr = QSslSocket::tr("Diffie-Hellman parameters are not valid");
+ sslContext->errorCode = QSslError::UnspecifiedError;
+ return;
+ }
+
+ if (dhparams.isEmpty()) {
+ q_SSL_CTX_set_dh_auto(sslContext->ctx, 1);
+ } else {
+#ifndef OPENSSL_NO_DEPRECATED_3_0
+ const QByteArray &params = dhparams.d->derData;
+ const char *ptr = params.constData();
+ DH *dh = q_d2i_DHparams(nullptr, reinterpret_cast<const unsigned char **>(&ptr),
+ params.size());
+ if (dh == nullptr)
+ qFatal("q_d2i_DHparams failed to convert QSslDiffieHellmanParameters to DER form");
+ q_SSL_CTX_set_tmp_dh(sslContext->ctx, dh);
+ q_DH_free(dh);
+#else
+ qCWarning(lcTlsBackend, "Diffie-Hellman parameters are not supported, because OpenSSL v3 was built with deprecated API removed");
+#endif
+ }
+
+#ifndef OPENSSL_NO_PSK
+ if (!client)
+ q_SSL_CTX_use_psk_identity_hint(sslContext->ctx, sslContext->sslConfiguration.preSharedKeyIdentityHint().constData());
+#endif // !OPENSSL_NO_PSK
+
+ const auto qcurves = sslContext->sslConfiguration.ellipticCurves();
+ if (!qcurves.isEmpty()) {
+#ifdef OPENSSL_NO_EC
+ sslContext->errorStr = msgErrorSettingEllipticCurves(QSslSocket::tr("OpenSSL version with disabled elliptic curves"));
+ sslContext->errorCode = QSslError::UnspecifiedError;
+ return;
+#else
+ // Set the curves to be used.
+ std::vector<int> curves;
+ curves.reserve(qcurves.size());
+ for (const auto &sslCurve : qcurves)
+ curves.push_back(sslCurve.id);
+ if (!q_SSL_CTX_ctrl(sslContext->ctx, SSL_CTRL_SET_CURVES, long(curves.size()), &curves[0])) {
+ sslContext->errorStr = msgErrorSettingEllipticCurves(QTlsBackendOpenSSL::getErrorsFromOpenSsl());
+ sslContext->errorCode = QSslError::UnspecifiedError;
+ return;
+ }
+#endif
+ }
+
+ applyBackendConfig(sslContext);
+}
+
+void QSslContext::applyBackendConfig(QSslContext *sslContext)
+{
+ const QMap<QByteArray, QVariant> &conf = sslContext->sslConfiguration.backendConfiguration();
+ if (conf.isEmpty())
+ return;
+
+#if QT_CONFIG(ocsp)
+ auto ocspResponsePos = conf.find("Qt-OCSP-response");
+ if (ocspResponsePos != conf.end()) {
+ // This is our private, undocumented configuration option, existing only for
+ // the purpose of testing OCSP status responses. We don't even check this
+ // callback was set. If no - the test must fail.
+ q_SSL_CTX_set_tlsext_status_cb(sslContext->ctx, QTlsPrivate::qt_OCSP_status_server_callback);
+ if (conf.size() == 1)
+ return;
+ }
+#endif // ocsp
+
+ QSharedPointer<SSL_CONF_CTX> cctx(q_SSL_CONF_CTX_new(), &q_SSL_CONF_CTX_free);
+ if (cctx) {
+ q_SSL_CONF_CTX_set_ssl_ctx(cctx.data(), sslContext->ctx);
+ q_SSL_CONF_CTX_set_flags(cctx.data(), SSL_CONF_FLAG_FILE);
+
+ for (auto i = conf.constBegin(); i != conf.constEnd(); ++i) {
+ if (i.key() == "Qt-OCSP-response") // This never goes to SSL_CONF_cmd().
+ continue;
+
+ if (!i.value().canConvert(QMetaType(QMetaType::QByteArray))) {
+ sslContext->errorCode = QSslError::UnspecifiedError;
+ sslContext->errorStr = msgErrorSettingBackendConfig(
+ QSslSocket::tr("Expecting QByteArray for %1").arg(
+ QString::fromUtf8(i.key())));
+ return;
+ }
+
+ const QByteArray &value = i.value().toByteArray();
+ const int result = q_SSL_CONF_cmd(cctx.data(), i.key().constData(), value.constData());
+ if (result == 2)
+ continue;
+
+ sslContext->errorCode = QSslError::UnspecifiedError;
+ switch (result) {
+ case 0:
+ sslContext->errorStr = msgErrorSettingBackendConfig(
+ QSslSocket::tr("An error occurred attempting to set %1 to %2").arg(
+ QString::fromUtf8(i.key()), QString::fromUtf8(value)));
+ return;
+ case 1:
+ sslContext->errorStr = msgErrorSettingBackendConfig(
+ QSslSocket::tr("Wrong value for %1 (%2)").arg(
+ QString::fromUtf8(i.key()), QString::fromUtf8(value)));
+ return;
+ default:
+ sslContext->errorStr = msgErrorSettingBackendConfig(
+ QSslSocket::tr("Unrecognized command %1 = %2").arg(
+ QString::fromUtf8(i.key()), QString::fromUtf8(value)));
+ return;
+ }
+ }
+
+ if (q_SSL_CONF_CTX_finish(cctx.data()) == 0) {
+ sslContext->errorStr = msgErrorSettingBackendConfig(QSslSocket::tr("SSL_CONF_finish() failed"));
+ sslContext->errorCode = QSslError::UnspecifiedError;
+ }
+ } else {
+ sslContext->errorStr = msgErrorSettingBackendConfig(QSslSocket::tr("SSL_CONF_CTX_new() failed"));
+ sslContext->errorCode = QSslError::UnspecifiedError;
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/tls/openssl/qsslcontext_openssl_p.h b/src/plugins/tls/openssl/qsslcontext_openssl_p.h
new file mode 100644
index 0000000000..3bd39baf0c
--- /dev/null
+++ b/src/plugins/tls/openssl/qsslcontext_openssl_p.h
@@ -0,0 +1,96 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2014 BlackBerry Limited. All rights reserved.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+
+#ifndef QSSLCONTEXT_OPENSSL_P_H
+#define QSSLCONTEXT_OPENSSL_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 <QtNetwork/private/qtnetworkglobal_p.h>
+#include <QtCore/qvariant.h>
+#include <QtNetwork/qsslcertificate.h>
+#include <QtNetwork/qsslconfiguration.h>
+#include <openssl/ssl.h>
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_SSL
+
+class QSslContext
+{
+public:
+
+ ~QSslContext();
+
+ static std::shared_ptr<QSslContext> sharedFromConfiguration(QSslSocket::SslMode mode, const QSslConfiguration &configuration,
+ bool allowRootCertOnDemandLoading);
+ static std::shared_ptr<QSslContext> sharedFromPrivateConfiguration(QSslSocket::SslMode mode, QSslConfigurationPrivate *privConfiguration,
+ bool allowRootCertOnDemandLoading);
+
+ static qssloptions setupOpenSslOptions(QSsl::SslProtocol protocol, QSsl::SslOptions sslOptions);
+
+ QSslError::SslError error() const;
+ QString errorString() const;
+
+ SSL* createSsl();
+ bool cacheSession(SSL*); // should be called when handshake completed
+
+ QByteArray sessionASN1() const;
+ void setSessionASN1(const QByteArray &sessionASN1);
+ int sessionTicketLifeTimeHint() const;
+
+ static void forceAutoTestSecurityLevel();
+
+#ifndef OPENSSL_NO_NEXTPROTONEG
+ // must be public because we want to use it from an OpenSSL callback
+ struct NPNContext {
+ NPNContext() : data(nullptr),
+ len(0),
+ status(QSslConfiguration::NextProtocolNegotiationNone)
+ { }
+ unsigned char *data;
+ unsigned short len;
+ QSslConfiguration::NextProtocolNegotiationStatus status;
+ };
+ NPNContext npnContext() const;
+#endif // !OPENSSL_NO_NEXTPROTONEG
+
+protected:
+ QSslContext();
+
+private:
+ static void initSslContext(QSslContext* sslContext, QSslSocket::SslMode mode, const QSslConfiguration &configuration,
+ bool allowRootCertOnDemandLoading);
+ static void applyBackendConfig(QSslContext *sslContext);
+
+private:
+ SSL_CTX* ctx;
+ EVP_PKEY *pkey;
+ SSL_SESSION *session;
+ QByteArray m_sessionASN1;
+ int m_sessionTicketLifeTimeHint;
+ QSslError::SslError errorCode;
+ QString errorStr;
+ QSslConfiguration sslConfiguration;
+#ifndef OPENSSL_NO_NEXTPROTONEG
+ QByteArray m_supportedNPNVersions;
+ NPNContext m_npnContext;
+#endif // !OPENSSL_NO_NEXTPROTONEG
+};
+
+#endif // QT_NO_SSL
+
+QT_END_NAMESPACE
+
+#endif // QSSLCONTEXT_OPENSSL_P_H
diff --git a/src/plugins/tls/openssl/qssldiffiehellmanparameters_openssl.cpp b/src/plugins/tls/openssl/qssldiffiehellmanparameters_openssl.cpp
new file mode 100644
index 0000000000..16e31e605f
--- /dev/null
+++ b/src/plugins/tls/openssl/qssldiffiehellmanparameters_openssl.cpp
@@ -0,0 +1,159 @@
+// Copyright (C) 2015 Mikkel Krautz <mikkel@krautz.dk>
+// Copyright (C) 2016 Richard J. Moore <rich@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qsslsocket_openssl_symbols_p.h"
+#include "qtlsbackend_openssl_p.h"
+
+#include <QtNetwork/private/qsslsocket_p.h>
+
+#include <QtCore/qscopeguard.h>
+#include <QtCore/qbytearray.h>
+#include <QtCore/qiodevice.h>
+#include <QtCore/qdebug.h>
+
+#include <openssl/bn.h>
+#include <openssl/dh.h>
+
+QT_BEGIN_NAMESPACE
+
+#ifndef OPENSSL_NO_DEPRECATED_3_0
+
+namespace {
+
+bool isSafeDH(DH *dh)
+{
+ int status = 0;
+ int bad = 0;
+
+ // TLSTODO: check it's needed or if supportsSsl()
+ // is enough.
+ QSslSocketPrivate::ensureInitialized();
+
+ // From https://wiki.openssl.org/index.php/Diffie-Hellman_parameters:
+ //
+ // The additional call to BN_mod_word(dh->p, 24)
+ // (and unmasking of DH_NOT_SUITABLE_GENERATOR)
+ // is performed to ensure your program accepts
+ // IETF group parameters. OpenSSL checks the prime
+ // is congruent to 11 when g = 2; while the IETF's
+ // primes are congruent to 23 when g = 2.
+ // Without the test, the IETF parameters would
+ // fail validation. For details, see Diffie-Hellman
+ // Parameter Check (when g = 2, must p mod 24 == 11?).
+ // Mark p < 1024 bits as unsafe.
+ if (q_DH_bits(dh) < 1024)
+ return false;
+
+ if (q_DH_check(dh, &status) != 1)
+ return false;
+
+ const BIGNUM *p = nullptr;
+ const BIGNUM *q = nullptr;
+ const BIGNUM *g = nullptr;
+ q_DH_get0_pqg(dh, &p, &q, &g);
+
+ if (q_BN_is_word(const_cast<BIGNUM *>(g), DH_GENERATOR_2)) {
+ const unsigned long residue = q_BN_mod_word(p, 24);
+ if (residue == 11 || residue == 23)
+ status &= ~DH_NOT_SUITABLE_GENERATOR;
+ }
+
+ bad |= DH_CHECK_P_NOT_PRIME;
+ bad |= DH_CHECK_P_NOT_SAFE_PRIME;
+ bad |= DH_NOT_SUITABLE_GENERATOR;
+
+ return !(status & bad);
+}
+
+} // unnamed namespace
+
+#endif
+
+int QTlsBackendOpenSSL::dhParametersFromDer(const QByteArray &der, QByteArray *derData) const
+{
+#ifndef OPENSSL_NO_DEPRECATED_3_0
+ Q_ASSERT(derData);
+
+ if (der.isEmpty())
+ return DHParams::InvalidInputDataError;
+
+ const unsigned char *data = reinterpret_cast<const unsigned char *>(der.data());
+ const int len = der.size();
+
+ // TLSTODO: check it's needed (loading ciphers and certs in
+ // addition to the library!)
+ QSslSocketPrivate::ensureInitialized();
+
+ DH *dh = q_d2i_DHparams(nullptr, &data, len);
+ if (dh) {
+ const auto dhRaii = qScopeGuard([dh] {q_DH_free(dh);});
+
+ if (isSafeDH(dh))
+ *derData = der;
+ else
+ return DHParams::UnsafeParametersError;
+ } else {
+ return DHParams::InvalidInputDataError;
+ }
+#else
+ Q_UNUSED(der);
+ Q_UNUSED(derData);
+ qCWarning(lcTlsBackend, "Diffie-Hellman parameters are not supported, because OpenSSL v3 was built with deprecated API removed");
+#endif
+ return DHParams::NoError;
+}
+
+int QTlsBackendOpenSSL::dhParametersFromPem(const QByteArray &pem, QByteArray *data) const
+{
+#ifndef OPENSSL_NO_DEPRECATED_3_0
+ Q_ASSERT(data);
+
+ if (pem.isEmpty())
+ return DHParams::InvalidInputDataError;
+
+ // TLSTODO: check it was not a cargo-cult programming in case of
+ // DH ...
+ QSslSocketPrivate::ensureInitialized();
+
+ BIO *bio = q_BIO_new_mem_buf(const_cast<char *>(pem.data()), pem.size());
+ if (!bio)
+ return DHParams::InvalidInputDataError;
+
+ const auto bioRaii = qScopeGuard([bio]
+ {
+ q_BIO_free(bio);
+ });
+
+ DH *dh = nullptr;
+ q_PEM_read_bio_DHparams(bio, &dh, nullptr, nullptr);
+
+ if (dh) {
+ const auto dhGuard = qScopeGuard([dh]
+ {
+ q_DH_free(dh);
+ });
+
+ if (isSafeDH(dh)) {
+ char *buf = nullptr;
+ const int len = q_i2d_DHparams(dh, reinterpret_cast<unsigned char **>(&buf));
+ const auto freeBuf = qScopeGuard([&] { q_OPENSSL_free(buf); });
+ if (len > 0)
+ data->assign({buf, len});
+ else
+ return DHParams::InvalidInputDataError;
+ } else {
+ return DHParams::UnsafeParametersError;
+ }
+ } else {
+ return DHParams::InvalidInputDataError;
+ }
+#else
+ Q_UNUSED(pem);
+ Q_UNUSED(data);
+ qCWarning(lcTlsBackend, "Diffie-Hellman parameters are not supported, because OpenSSL v3 was built with deprecated API removed");
+#endif
+ return DHParams::NoError;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/tls/openssl/qsslsocket_openssl_android.cpp b/src/plugins/tls/openssl/qsslsocket_openssl_android.cpp
new file mode 100644
index 0000000000..6c02215c55
--- /dev/null
+++ b/src/plugins/tls/openssl/qsslsocket_openssl_android.cpp
@@ -0,0 +1,58 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+/****************************************************************************
+**
+** In addition, as a special exception, the copyright holders listed above give
+** permission to link the code of its release of Qt with the OpenSSL project's
+** "OpenSSL" library (or modified versions of the "OpenSSL" library that use the
+** same license as the original version), and distribute the linked executables.
+**
+** You must comply with the GNU General Public License version 2 in all
+** respects for all of the code used other than the "OpenSSL" code. If you
+** modify this file, you may extend this exception to your version of the file,
+** but you are not obligated to do so. If you do not wish to do so, delete
+** this exception statement from your version of this file.
+**
+****************************************************************************/
+
+#include <QtCore/QJniEnvironment>
+#include <QtCore/QJniObject>
+#include <QtCore/QList>
+#include <QtCore/QByteArray>
+
+QT_BEGIN_NAMESPACE
+
+namespace QTlsPrivate {
+
+QList<QByteArray> fetchSslCertificateData()
+{
+ QList<QByteArray> certificateData;
+
+ QJniObject certificates = QJniObject::callStaticObjectMethod("org/qtproject/qt/android/QtNative",
+ "getSSLCertificates",
+ "()[[B");
+ if (!certificates.isValid())
+ return certificateData;
+
+ QJniEnvironment env;
+ jobjectArray jcertificates = certificates.object<jobjectArray>();
+ const jint nCertificates = env->GetArrayLength(jcertificates);
+ certificateData.reserve(static_cast<int>(nCertificates));
+
+ for (int i = 0; i < nCertificates; ++i) {
+ jbyteArray jCert = static_cast<jbyteArray>(env->GetObjectArrayElement(jcertificates, i));
+ const uint sz = env->GetArrayLength(jCert);
+ jbyte *buffer = env->GetByteArrayElements(jCert, 0);
+ certificateData.append(QByteArray(reinterpret_cast<char*>(buffer), sz));
+
+ env->ReleaseByteArrayElements(jCert, buffer, JNI_ABORT); // don't copy back the elements
+ env->DeleteLocalRef(jCert);
+ }
+
+ return certificateData;
+}
+
+} // namespace QTlsPrivate
+
+QT_END_NAMESPACE
diff --git a/src/plugins/tls/openssl/qsslsocket_openssl_symbols.cpp b/src/plugins/tls/openssl/qsslsocket_openssl_symbols.cpp
new file mode 100644
index 0000000000..4aa9ca6fb1
--- /dev/null
+++ b/src/plugins/tls/openssl/qsslsocket_openssl_symbols.cpp
@@ -0,0 +1,1266 @@
+// Copyright (C) 2017 The Qt Company Ltd.
+// Copyright (C) 2014 BlackBerry Limited. All rights reserved.
+// Copyright (C) 2016 Richard J. Moore <rich@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+/****************************************************************************
+**
+** In addition, as a special exception, the copyright holders listed above give
+** permission to link the code of its release of Qt with the OpenSSL project's
+** "OpenSSL" library (or modified versions of the "OpenSSL" library that use the
+** same license as the original version), and distribute the linked executables.
+**
+** You must comply with the GNU General Public License version 2 in all
+** respects for all of the code used other than the "OpenSSL" code. If you
+** modify this file, you may extend this exception to your version of the file,
+** but you are not obligated to do so. If you do not wish to do so, delete
+** this exception statement from your version of this file.
+**
+****************************************************************************/
+
+#include "qsslsocket_openssl_symbols_p.h"
+#include "qtlsbackend_openssl_p.h"
+
+#include <QtNetwork/private/qssl_p.h>
+
+#ifdef Q_OS_WIN
+# include <QtCore/private/qsystemlibrary_p.h>
+#elif QT_CONFIG(library)
+# include <QtCore/qlibrary.h>
+#endif
+#include <QtCore/qdatetime.h>
+#if defined(Q_OS_UNIX)
+#include <QtCore/qdir.h>
+#endif
+#include <QtCore/private/qduplicatetracker_p.h>
+#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)
+#include <link.h>
+#endif
+#ifdef Q_OS_DARWIN
+#include <QtCore/private/qcore_mac_p.h>
+#endif
+
+#include <algorithm>
+
+QT_BEGIN_NAMESPACE
+
+using namespace Qt::StringLiterals;
+
+/*
+ Note to maintainer:
+ -------------------
+
+ We load OpenSSL symbols dynamically. Because symbols are known to
+ disappear, and signatures sometimes change, between releases, we need to
+ be careful about how this is done. To ensure we don't end up dereferencing
+ null function pointers, and continue running even if certain functions are
+ missing, we define helper functions for each of the symbols we load from
+ OpenSSL, all prefixed with "q_" (declared in
+ qsslsocket_openssl_symbols_p.h). So instead of calling SSL_connect
+ directly, we call q_SSL_connect, which is a function that checks if the
+ actual SSL_connect fptr is null, and returns a failure if it is, or calls
+ SSL_connect if it isn't.
+
+ This requires a somewhat tedious process of declaring each function we
+ want to call in OpenSSL thrice: once with the q_, in _p.h, once using the
+ DEFINEFUNC macros below, and once in the function that actually resolves
+ the symbols, below the DEFINEFUNC declarations below.
+
+ There's one DEFINEFUNC macro declared for every number of arguments
+ exposed by OpenSSL (feel free to extend when needed). The easiest thing to
+ do is to find an existing entry that matches the arg count of the function
+ you want to import, and do the same.
+
+ The first macro arg is the function return type. The second is the
+ verbatim name of the function/symbol. Then follows a list of N pairs of
+ argument types with a variable name, and just the variable name (char *a,
+ a, char *b, b, etc). Finally there's two arguments - a suitable return
+ statement for the error case (for an int function, return 0 or return -1
+ is usually right). Then either just "return" or DUMMYARG, the latter being
+ for void functions.
+
+ Note: Take into account that these macros and declarations are processed
+ at compile-time, and the result depends on the OpenSSL headers the
+ compiling host has installed, but the symbols are resolved at run-time,
+ possibly with a different version of OpenSSL.
+*/
+
+#ifndef QT_LINKED_OPENSSL
+
+namespace {
+void qsslSocketUnresolvedSymbolWarning(const char *functionName)
+{
+ qCWarning(lcTlsBackend, "QSslSocket: cannot call unresolved function %s", functionName);
+}
+
+#if QT_CONFIG(library)
+void qsslSocketCannotResolveSymbolWarning(const char *functionName)
+{
+ qCWarning(lcTlsBackend, "QSslSocket: cannot resolve %s", functionName);
+}
+#endif
+
+}
+
+#endif // QT_LINKED_OPENSSL
+
+DEFINEFUNC(const unsigned char *, ASN1_STRING_get0_data, const ASN1_STRING *a, a, return nullptr, return)
+DEFINEFUNC2(int, OPENSSL_init_ssl, uint64_t opts, opts, const OPENSSL_INIT_SETTINGS *settings, settings, return 0, return)
+DEFINEFUNC2(int, OPENSSL_init_crypto, uint64_t opts, opts, const OPENSSL_INIT_SETTINGS *settings, settings, return 0, return)
+DEFINEFUNC(BIO *, BIO_new, const BIO_METHOD *a, a, return nullptr, return)
+DEFINEFUNC(const BIO_METHOD *, BIO_s_mem, void, DUMMYARG, return nullptr, return)
+DEFINEFUNC2(int, BN_is_word, BIGNUM *a, a, BN_ULONG w, w, return 0, return)
+DEFINEFUNC(int, EVP_CIPHER_CTX_reset, EVP_CIPHER_CTX *c, c, return 0, return)
+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, 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)
+DEFINEFUNC2(void, OPENSSL_sk_push, OPENSSL_STACK *a, a, void *b, b, return, DUMMYARG)
+DEFINEFUNC(void, OPENSSL_sk_free, OPENSSL_STACK *a, a, return, DUMMYARG)
+DEFINEFUNC2(void *, OPENSSL_sk_value, OPENSSL_STACK *a, a, int b, b, return nullptr, return)
+DEFINEFUNC(int, SSL_session_reused, SSL *a, a, return 0, return)
+DEFINEFUNC2(qssloptions, SSL_CTX_set_options, SSL_CTX *ctx, ctx, qssloptions op, op, return 0, return)
+using info_callback = void (*) (const SSL *ssl, int type, int val);
+DEFINEFUNC2(void, SSL_set_info_callback, SSL *ssl, ssl, info_callback cb, cb, return, return)
+DEFINEFUNC(const char *, SSL_alert_type_string, int value, value, return nullptr, return)
+DEFINEFUNC(const char *, SSL_alert_desc_string_long, int value, value, return nullptr, return)
+DEFINEFUNC(int, SSL_CTX_get_security_level, const SSL_CTX *ctx, ctx, return -1, return)
+DEFINEFUNC2(void, SSL_CTX_set_security_level, SSL_CTX *ctx, ctx, int level, level, return, return)
+#ifdef TLS1_3_VERSION
+DEFINEFUNC2(int, SSL_CTX_set_ciphersuites, SSL_CTX *ctx, ctx, const char *str, str, return 0, return)
+DEFINEFUNC2(void, SSL_set_psk_use_session_callback, SSL *ssl, ssl, q_SSL_psk_use_session_cb_func_t callback, callback, return, DUMMYARG)
+DEFINEFUNC2(void, SSL_CTX_sess_set_new_cb, SSL_CTX *ctx, ctx, NewSessionCallback cb, cb, return, return)
+DEFINEFUNC(int, SSL_SESSION_is_resumable, const SSL_SESSION *s, s, return 0, return)
+#endif
+DEFINEFUNC3(size_t, SSL_get_client_random, SSL *a, a, unsigned char *out, out, size_t outlen, outlen, return 0, return)
+DEFINEFUNC3(size_t, SSL_SESSION_get_master_key, const SSL_SESSION *ses, ses, unsigned char *out, out, size_t outlen, outlen, return 0, return)
+DEFINEFUNC6(int, CRYPTO_get_ex_new_index, int class_index, class_index, long argl, argl, void *argp, argp, CRYPTO_EX_new *new_func, new_func, CRYPTO_EX_dup *dup_func, dup_func, CRYPTO_EX_free *free_func, free_func, return -1, return)
+DEFINEFUNC2(unsigned long, SSL_set_options, SSL *ssl, ssl, unsigned long op, op, return 0, return)
+
+DEFINEFUNC(const SSL_METHOD *, TLS_method, DUMMYARG, DUMMYARG, return nullptr, return)
+DEFINEFUNC(const SSL_METHOD *, TLS_client_method, DUMMYARG, DUMMYARG, return nullptr, return)
+DEFINEFUNC(const SSL_METHOD *, TLS_server_method, DUMMYARG, DUMMYARG, return nullptr, return)
+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)
+DEFINEFUNC3(int, X509_STORE_set_ex_data, X509_STORE *a, a, int idx, idx, void *data, data, return 0, return)
+DEFINEFUNC2(void *, X509_STORE_get_ex_data, X509_STORE *r, r, int idx, idx, return nullptr, return)
+DEFINEFUNC(STACK_OF(X509) *, X509_STORE_CTX_get0_chain, X509_STORE_CTX *a, a, return nullptr, return)
+DEFINEFUNC3(void, CRYPTO_free, void *str, str, const char *file, file, int line, line, return, DUMMYARG)
+DEFINEFUNC3(int, CRYPTO_memcmp, const void * in_a, in_a, const void * in_b, in_b, size_t len, len, return 1, return);
+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)
+
+#if QT_CONFIG(dtls)
+DEFINEFUNC2(int, DTLSv1_listen, SSL *s, s, BIO_ADDR *c, c, return -1, return)
+DEFINEFUNC(BIO_ADDR *, BIO_ADDR_new, DUMMYARG, DUMMYARG, return nullptr, return)
+DEFINEFUNC(void, BIO_ADDR_free, BIO_ADDR *ap, ap, return, DUMMYARG)
+DEFINEFUNC2(BIO_METHOD *, BIO_meth_new, int type, type, const char *name, name, return nullptr, return)
+DEFINEFUNC(void, BIO_meth_free, BIO_METHOD *biom, biom, return, DUMMYARG)
+DEFINEFUNC2(int, BIO_meth_set_write, BIO_METHOD *biom, biom, DgramWriteCallback write, write, return 0, return)
+DEFINEFUNC2(int, BIO_meth_set_read, BIO_METHOD *biom, biom, DgramReadCallback read, read, return 0, return)
+DEFINEFUNC2(int, BIO_meth_set_puts, BIO_METHOD *biom, biom, DgramPutsCallback puts, puts, return 0, return)
+DEFINEFUNC2(int, BIO_meth_set_ctrl, BIO_METHOD *biom, biom, DgramCtrlCallback ctrl, ctrl, return 0, return)
+DEFINEFUNC2(int, BIO_meth_set_create, BIO_METHOD *biom, biom, DgramCreateCallback crt, crt, return 0, return)
+DEFINEFUNC2(int, BIO_meth_set_destroy, BIO_METHOD *biom, biom, DgramDestroyCallback dtr, dtr, return 0, return)
+#endif // dtls
+
+#if QT_CONFIG(ocsp)
+DEFINEFUNC(const OCSP_CERTID *, OCSP_SINGLERESP_get0_id, const OCSP_SINGLERESP *x, x, return nullptr, return)
+DEFINEFUNC3(OCSP_RESPONSE *, d2i_OCSP_RESPONSE, OCSP_RESPONSE **a, a, const unsigned char **in, in, long len, len, return nullptr, return)
+DEFINEFUNC(void, OCSP_RESPONSE_free, OCSP_RESPONSE *rs, rs, return, DUMMYARG)
+DEFINEFUNC(OCSP_BASICRESP *, OCSP_response_get1_basic, OCSP_RESPONSE *resp, resp, return nullptr, return)
+DEFINEFUNC(void, OCSP_BASICRESP_free, OCSP_BASICRESP *bs, bs, return, DUMMYARG)
+DEFINEFUNC(int, OCSP_response_status, OCSP_RESPONSE *resp, resp, return OCSP_RESPONSE_STATUS_INTERNALERROR, return)
+DEFINEFUNC4(int, OCSP_basic_verify, OCSP_BASICRESP *bs, bs, STACK_OF(X509) *certs, certs, X509_STORE *st, st, unsigned long flags, flags, return -1, return)
+DEFINEFUNC(int, OCSP_resp_count, OCSP_BASICRESP *bs, bs, return 0, return)
+DEFINEFUNC2(OCSP_SINGLERESP *, OCSP_resp_get0, OCSP_BASICRESP *bs, bs, int idx, idx, return nullptr, return)
+DEFINEFUNC5(int, OCSP_single_get0_status, OCSP_SINGLERESP *single, single, int *reason, reason, ASN1_GENERALIZEDTIME **revtime, revtime,
+ ASN1_GENERALIZEDTIME **thisupd, thisupd, ASN1_GENERALIZEDTIME **nextupd, nextupd, return -1, return)
+DEFINEFUNC4(int, OCSP_check_validity, ASN1_GENERALIZEDTIME *thisupd, thisupd, ASN1_GENERALIZEDTIME *nextupd, nextupd, long nsec, nsec, long maxsec, maxsec, return 0, return)
+DEFINEFUNC3(OCSP_CERTID *, OCSP_cert_to_id, const EVP_MD *dgst, dgst, X509 *subject, subject, X509 *issuer, issuer, return nullptr, return)
+DEFINEFUNC(void, OCSP_CERTID_free, OCSP_CERTID *cid, cid, return, DUMMYARG)
+DEFINEFUNC5(int, OCSP_id_get0_info, ASN1_OCTET_STRING **piNameHash, piNameHash, ASN1_OBJECT **pmd, pmd,
+ ASN1_OCTET_STRING **piKeyHash, piKeyHash, ASN1_INTEGER **pserial, pserial, OCSP_CERTID *cid, cid,
+ return 0, return)
+DEFINEFUNC2(OCSP_RESPONSE *, OCSP_response_create, int status, status, OCSP_BASICRESP *bs, bs, return nullptr, return)
+DEFINEFUNC(const STACK_OF(X509) *, OCSP_resp_get0_certs, const OCSP_BASICRESP *bs, bs, return nullptr, return)
+DEFINEFUNC2(int, OCSP_id_cmp, OCSP_CERTID *a, a, OCSP_CERTID *b, b, return -1, return)
+DEFINEFUNC7(OCSP_SINGLERESP *, OCSP_basic_add1_status, OCSP_BASICRESP *r, r, OCSP_CERTID *c, c, int s, s,
+ int re, re, ASN1_TIME *rt, rt, ASN1_TIME *t, t, ASN1_TIME *n, n, return nullptr, return)
+DEFINEFUNC(OCSP_BASICRESP *, OCSP_BASICRESP_new, DUMMYARG, DUMMYARG, return nullptr, return)
+DEFINEFUNC2(int, i2d_OCSP_RESPONSE, OCSP_RESPONSE *r, r, unsigned char **ppout, ppout, return 0, return)
+DEFINEFUNC6(int, OCSP_basic_sign, OCSP_BASICRESP *br, br, X509 *signer, signer, EVP_PKEY *key, key,
+ 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)
+DEFINEFUNC(int, BIO_get_shutdown, BIO *a, a, return -1, return)
+DEFINEFUNC2(void, BIO_set_shutdown, BIO *a, a, int shut, shut, return, DUMMYARG)
+
+DEFINEFUNC(long, ASN1_INTEGER_get, ASN1_INTEGER *a, a, return 0, return)
+DEFINEFUNC2(int, ASN1_INTEGER_cmp, const ASN1_INTEGER *a, a, const ASN1_INTEGER *b, b, return 1, return)
+DEFINEFUNC(int, ASN1_STRING_length, ASN1_STRING *a, a, return 0, return)
+DEFINEFUNC2(int, ASN1_STRING_to_UTF8, unsigned char **a, a, ASN1_STRING *b, b, return 0, return)
+DEFINEFUNC2(int, ASN1_TIME_to_tm, const ASN1_TIME *s, s, struct tm *tm, tm, return 0, return)
+DEFINEFUNC4(long, BIO_ctrl, BIO *a, a, int b, b, long c, c, void *d, d, return -1, return)
+DEFINEFUNC(int, BIO_free, BIO *a, a, return 0, return)
+DEFINEFUNC2(BIO *, BIO_new_mem_buf, void *a, a, int b, b, return nullptr, return)
+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)
+DEFINEFUNC3(X509 *, d2i_X509, X509 **a, a, const unsigned char **b, b, long c, c, return nullptr, return)
+DEFINEFUNC2(char *, ERR_error_string, unsigned long a, a, char *b, b, return nullptr, return)
+DEFINEFUNC3(void, ERR_error_string_n, unsigned long e, e, char *b, b, size_t len, len, return, DUMMYARG)
+DEFINEFUNC(unsigned long, ERR_get_error, DUMMYARG, DUMMYARG, return 0, return)
+DEFINEFUNC(EVP_CIPHER_CTX *, EVP_CIPHER_CTX_new, void, DUMMYARG, return nullptr, return)
+DEFINEFUNC(void, EVP_CIPHER_CTX_free, EVP_CIPHER_CTX *a, a, return, DUMMYARG)
+DEFINEFUNC4(int, EVP_CIPHER_CTX_ctrl, EVP_CIPHER_CTX *ctx, ctx, int type, type, int arg, arg, void *ptr, ptr, return 0, return)
+DEFINEFUNC2(int, EVP_CIPHER_CTX_set_key_length, EVP_CIPHER_CTX *ctx, ctx, int keylen, keylen, return 0, return)
+DEFINEFUNC5(int, EVP_CipherInit, EVP_CIPHER_CTX *ctx, ctx, const EVP_CIPHER *type, type, const unsigned char *key, key, const unsigned char *iv, iv, int enc, enc, return 0, return)
+DEFINEFUNC6(int, EVP_CipherInit_ex, EVP_CIPHER_CTX *ctx, ctx, const EVP_CIPHER *cipher, cipher, ENGINE *impl, impl, const unsigned char *key, key, const unsigned char *iv, iv, int enc, enc, return 0, return)
+DEFINEFUNC5(int, EVP_CipherUpdate, EVP_CIPHER_CTX *ctx, ctx, unsigned char *out, out, int *outl, outl, const unsigned char *in, in, int inl, inl, return 0, return)
+DEFINEFUNC3(int, EVP_CipherFinal, EVP_CIPHER_CTX *ctx, ctx, unsigned char *out, out, int *outl, outl, return 0, return)
+DEFINEFUNC(const EVP_MD *, EVP_get_digestbyname, const char *name, name, return nullptr, return)
+#ifndef OPENSSL_NO_DES
+DEFINEFUNC(const EVP_CIPHER *, EVP_des_cbc, DUMMYARG, DUMMYARG, return nullptr, return)
+DEFINEFUNC(const EVP_CIPHER *, EVP_des_ede3_cbc, DUMMYARG, DUMMYARG, return nullptr, return)
+#endif
+#ifndef OPENSSL_NO_RC2
+DEFINEFUNC(const EVP_CIPHER *, EVP_rc2_cbc, DUMMYARG, DUMMYARG, return nullptr, return)
+#endif
+#ifndef OPENSSL_NO_AES
+DEFINEFUNC(const EVP_CIPHER *, EVP_aes_128_cbc, DUMMYARG, DUMMYARG, return nullptr, return)
+DEFINEFUNC(const EVP_CIPHER *, EVP_aes_192_cbc, DUMMYARG, DUMMYARG, return nullptr, return)
+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)
+DEFINEFUNC(void, EVP_PKEY_free, EVP_PKEY *a, a, return, DUMMYARG)
+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)
+DEFINEFUNC(const char *, OBJ_nid2sn, int a, a, return nullptr, return)
+DEFINEFUNC(const char *, OBJ_nid2ln, int a, a, return nullptr, return)
+DEFINEFUNC(int, OBJ_sn2nid, const char *s, s, return 0, return)
+DEFINEFUNC(int, OBJ_ln2nid, const char *s, s, return 0, return)
+DEFINEFUNC3(int, i2t_ASN1_OBJECT, char *a, a, int b, b, ASN1_OBJECT *c, c, return -1, return)
+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)
+
+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)
+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)
+DEFINEFUNC2(int, RAND_bytes, unsigned char *b, b, int n, n, return 0, return)
+DEFINEFUNC(int, SSL_accept, SSL *a, a, return -1, return)
+DEFINEFUNC(int, SSL_clear, SSL *a, a, return -1, return)
+DEFINEFUNC3(char *, SSL_CIPHER_description, const SSL_CIPHER *a, a, char *b, b, int c, c, return nullptr, return)
+DEFINEFUNC2(int, SSL_CIPHER_get_bits, const SSL_CIPHER *a, a, int *b, b, return 0, return)
+DEFINEFUNC(BIO *, SSL_get_rbio, const SSL *s, s, return nullptr, return)
+DEFINEFUNC(int, SSL_connect, SSL *a, a, return -1, return)
+DEFINEFUNC(int, SSL_CTX_check_private_key, const SSL_CTX *a, a, return -1, return)
+DEFINEFUNC4(long, SSL_CTX_ctrl, SSL_CTX *a, a, int b, b, long c, c, void *d, d, return -1, return)
+DEFINEFUNC(void, SSL_CTX_free, SSL_CTX *a, a, return, DUMMYARG)
+DEFINEFUNC(SSL_CTX *, SSL_CTX_new, const SSL_METHOD *a, a, return nullptr, return)
+DEFINEFUNC2(int, SSL_CTX_set_cipher_list, SSL_CTX *a, a, const char *b, b, return -1, return)
+DEFINEFUNC3(long, SSL_CTX_callback_ctrl, SSL_CTX *ctx, ctx, int dst, dst, GenericCallbackType cb, cb, return 0, return)
+DEFINEFUNC(int, SSL_CTX_set_default_verify_paths, SSL_CTX *a, a, return -1, return)
+DEFINEFUNC3(void, SSL_CTX_set_verify, SSL_CTX *a, a, int b, b, int (*c)(int, X509_STORE_CTX *), c, return, DUMMYARG)
+DEFINEFUNC2(void, SSL_CTX_set_verify_depth, SSL_CTX *a, a, int b, b, return, DUMMYARG)
+DEFINEFUNC2(int, SSL_CTX_use_certificate, SSL_CTX *a, a, X509 *b, b, return -1, return)
+DEFINEFUNC3(int, SSL_CTX_use_certificate_file, SSL_CTX *a, a, const char *b, b, int c, c, return -1, return)
+DEFINEFUNC2(int, SSL_CTX_use_PrivateKey, SSL_CTX *a, a, EVP_PKEY *b, b, return -1, return)
+DEFINEFUNC3(int, SSL_CTX_use_PrivateKey_file, SSL_CTX *a, a, const char *b, b, int c, c, return -1, return)
+DEFINEFUNC(X509_STORE *, SSL_CTX_get_cert_store, const SSL_CTX *a, a, return nullptr, return)
+DEFINEFUNC(SSL_CONF_CTX *, SSL_CONF_CTX_new, DUMMYARG, DUMMYARG, return nullptr, return);
+DEFINEFUNC(void, SSL_CONF_CTX_free, SSL_CONF_CTX *a, a, return ,return);
+DEFINEFUNC2(void, SSL_CONF_CTX_set_ssl_ctx, SSL_CONF_CTX *a, a, SSL_CTX *b, b, return, return);
+DEFINEFUNC2(unsigned int, SSL_CONF_CTX_set_flags, SSL_CONF_CTX *a, a, unsigned int b, b, return 0, return);
+DEFINEFUNC(int, SSL_CONF_CTX_finish, SSL_CONF_CTX *a, a, return 0, return);
+DEFINEFUNC3(int, SSL_CONF_cmd, SSL_CONF_CTX *a, a, const char *b, b, const char *c, c, return 0, return);
+DEFINEFUNC(void, SSL_free, SSL *a, a, return, DUMMYARG)
+DEFINEFUNC(STACK_OF(SSL_CIPHER) *, SSL_get_ciphers, const SSL *a, a, return nullptr, return)
+DEFINEFUNC(const SSL_CIPHER *, SSL_get_current_cipher, SSL *a, a, return nullptr, return)
+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)
+DEFINEFUNC4(long, SSL_ctrl, SSL *a, a, int cmd, cmd, long larg, larg, void *parg, parg, return -1, return)
+DEFINEFUNC3(int, SSL_read, SSL *a, a, void *b, b, int c, c, return -1, return)
+DEFINEFUNC3(void, SSL_set_bio, SSL *a, a, BIO *b, b, BIO *c, c, return, DUMMYARG)
+DEFINEFUNC(void, SSL_set_accept_state, SSL *a, a, return, DUMMYARG)
+DEFINEFUNC(void, SSL_set_connect_state, SSL *a, a, return, DUMMYARG)
+DEFINEFUNC(int, SSL_shutdown, SSL *a, a, return -1, return)
+DEFINEFUNC(int, SSL_in_init, const SSL *a, a, return 0, return)
+DEFINEFUNC(int, SSL_get_shutdown, const SSL *ssl, ssl, return 0, return)
+DEFINEFUNC2(int, SSL_set_session, SSL* to, to, SSL_SESSION *session, session, return -1, return)
+DEFINEFUNC(void, SSL_SESSION_free, SSL_SESSION *ses, ses, return, DUMMYARG)
+DEFINEFUNC(SSL_SESSION*, SSL_get1_session, SSL *ssl, ssl, return nullptr, return)
+DEFINEFUNC(SSL_SESSION*, SSL_get_session, const SSL *ssl, ssl, return nullptr, return)
+DEFINEFUNC3(int, SSL_set_ex_data, SSL *ssl, ssl, int idx, idx, void *arg, arg, return 0, return)
+DEFINEFUNC2(void *, SSL_get_ex_data, const SSL *ssl, ssl, int idx, idx, return nullptr, return)
+
+#ifndef OPENSSL_NO_PSK
+DEFINEFUNC2(void, SSL_set_psk_client_callback, SSL* ssl, ssl, q_psk_client_callback_t callback, callback, return, DUMMYARG)
+DEFINEFUNC2(void, SSL_set_psk_server_callback, SSL* ssl, ssl, q_psk_server_callback_t callback, callback, return, DUMMYARG)
+DEFINEFUNC2(int, SSL_CTX_use_psk_identity_hint, SSL_CTX* ctx, ctx, const char *hint, hint, return 0, return)
+#endif // !OPENSSL_NO_PSK
+
+DEFINEFUNC3(int, SSL_write, SSL *a, a, const void *b, b, int c, c, return -1, return)
+DEFINEFUNC2(int, X509_cmp, X509 *a, a, X509 *b, b, return -1, return)
+DEFINEFUNC4(int, X509_digest, const X509 *x509, x509, const EVP_MD *type, type, unsigned char *md, md, unsigned int *len, len, return -1, return)
+DEFINEFUNC(X509 *, X509_dup, X509 *a, a, return nullptr, return)
+DEFINEFUNC2(void, X509_print, BIO *a, a, X509 *b, b, return, DUMMYARG);
+DEFINEFUNC(ASN1_OBJECT *, X509_EXTENSION_get_object, X509_EXTENSION *a, a, return nullptr, return)
+DEFINEFUNC(void, X509_free, X509 *a, a, return, DUMMYARG)
+//Q_AUTOTEST_EXPORT ASN1_TIME *q_X509_gmtime_adj(ASN1_TIME *s, long adj);
+DEFINEFUNC2(ASN1_TIME *, X509_gmtime_adj, ASN1_TIME *s, s, long adj, adj, return nullptr, return)
+DEFINEFUNC(void, ASN1_TIME_free, ASN1_TIME *t, t, return, DUMMYARG)
+DEFINEFUNC2(X509_EXTENSION *, X509_get_ext, X509 *a, a, int b, b, return nullptr, return)
+DEFINEFUNC(int, X509_get_ext_count, X509 *a, a, return 0, return)
+DEFINEFUNC4(void *, X509_get_ext_d2i, X509 *a, a, int b, b, int *c, c, int *d, d, return nullptr, return)
+DEFINEFUNC(const X509V3_EXT_METHOD *, X509V3_EXT_get, X509_EXTENSION *a, a, return nullptr, return)
+DEFINEFUNC(void *, X509V3_EXT_d2i, X509_EXTENSION *a, a, return nullptr, return)
+DEFINEFUNC(int, X509_EXTENSION_get_critical, X509_EXTENSION *a, a, return 0, return)
+DEFINEFUNC(ASN1_OCTET_STRING *, X509_EXTENSION_get_data, X509_EXTENSION *a, a, return nullptr, return)
+DEFINEFUNC(void, BASIC_CONSTRAINTS_free, BASIC_CONSTRAINTS *a, a, return, DUMMYARG)
+DEFINEFUNC(void, AUTHORITY_KEYID_free, AUTHORITY_KEYID *a, a, return, DUMMYARG)
+DEFINEFUNC(void, GENERAL_NAME_free, GENERAL_NAME *a, a, return, DUMMYARG)
+DEFINEFUNC2(int, ASN1_STRING_print, BIO *a, a, const ASN1_STRING *b, b, return 0, return)
+DEFINEFUNC2(int, X509_check_issued, X509 *a, a, X509 *b, b, return -1, return)
+DEFINEFUNC(X509_NAME *, X509_get_issuer_name, X509 *a, a, return nullptr, return)
+DEFINEFUNC(X509_NAME *, X509_get_subject_name, X509 *a, a, return nullptr, return)
+DEFINEFUNC(ASN1_INTEGER *, X509_get_serialNumber, X509 *a, a, return nullptr, return)
+DEFINEFUNC(int, X509_verify_cert, X509_STORE_CTX *a, a, return -1, return)
+DEFINEFUNC(int, X509_NAME_entry_count, X509_NAME *a, a, return 0, return)
+DEFINEFUNC2(X509_NAME_ENTRY *, X509_NAME_get_entry, X509_NAME *a, a, int b, b, return nullptr, return)
+DEFINEFUNC(ASN1_STRING *, X509_NAME_ENTRY_get_data, X509_NAME_ENTRY *a, a, return nullptr, return)
+DEFINEFUNC(ASN1_OBJECT *, X509_NAME_ENTRY_get_object, X509_NAME_ENTRY *a, a, return nullptr, return)
+DEFINEFUNC(EVP_PKEY *, X509_PUBKEY_get, X509_PUBKEY *a, a, return nullptr, return)
+DEFINEFUNC(void, X509_STORE_free, X509_STORE *a, a, return, DUMMYARG)
+DEFINEFUNC(X509_STORE *, X509_STORE_new, DUMMYARG, DUMMYARG, return nullptr, return)
+DEFINEFUNC2(int, X509_STORE_add_cert, X509_STORE *a, a, X509 *b, b, return 0, return)
+DEFINEFUNC(void, X509_STORE_CTX_free, X509_STORE_CTX *a, a, return, DUMMYARG)
+DEFINEFUNC4(int, X509_STORE_CTX_init, X509_STORE_CTX *a, a, X509_STORE *b, b, X509 *c, c, STACK_OF(X509) *d, d, return -1, return)
+DEFINEFUNC2(int, X509_STORE_CTX_set_purpose, X509_STORE_CTX *a, a, int b, b, return -1, return)
+DEFINEFUNC(int, X509_STORE_CTX_get_error, X509_STORE_CTX *a, a, return -1, return)
+DEFINEFUNC(int, X509_STORE_CTX_get_error_depth, X509_STORE_CTX *a, a, return -1, return)
+DEFINEFUNC(X509 *, X509_STORE_CTX_get_current_cert, X509_STORE_CTX *a, a, return nullptr, return)
+DEFINEFUNC(X509_STORE *, X509_STORE_CTX_get0_store, X509_STORE_CTX *ctx, ctx, return nullptr, return)
+DEFINEFUNC(X509_STORE_CTX *, X509_STORE_CTX_new, DUMMYARG, DUMMYARG, return nullptr, return)
+DEFINEFUNC2(void *, X509_STORE_CTX_get_ex_data, X509_STORE_CTX *ctx, ctx, int idx, idx, return nullptr, return)
+DEFINEFUNC(int, SSL_get_ex_data_X509_STORE_CTX_idx, DUMMYARG, DUMMYARG, return -1, return)
+
+#if OPENSSL_VERSION_MAJOR < 3
+DEFINEFUNC3(int, SSL_CTX_load_verify_locations, SSL_CTX *ctx, ctx, const char *CAfile, CAfile, const char *CApath, CApath, return 0, return)
+#else
+DEFINEFUNC2(int, SSL_CTX_load_verify_dir, SSL_CTX *ctx, ctx, const char *CApath, CApath, return 0, return)
+#endif // OPENSSL_VERSION_MAJOR
+
+DEFINEFUNC2(int, i2d_SSL_SESSION, SSL_SESSION *in, in, unsigned char **pp, pp, return 0, return)
+DEFINEFUNC3(SSL_SESSION *, d2i_SSL_SESSION, SSL_SESSION **a, a, const unsigned char **pp, pp, long length, length, return nullptr, return)
+
+#ifndef OPENSSL_NO_NEXTPROTONEG
+DEFINEFUNC6(int, SSL_select_next_proto, unsigned char **out, out, unsigned char *outlen, outlen,
+ const unsigned char *in, in, unsigned int inlen, inlen,
+ const unsigned char *client, client, unsigned int client_len, client_len,
+ return -1, return)
+DEFINEFUNC3(void, SSL_CTX_set_next_proto_select_cb, SSL_CTX *s, s,
+ int (*cb) (SSL *ssl, unsigned char **out,
+ unsigned char *outlen,
+ const unsigned char *in,
+ unsigned int inlen, void *arg), cb,
+ void *arg, arg, return, DUMMYARG)
+DEFINEFUNC3(void, SSL_get0_next_proto_negotiated, const SSL *s, s,
+ const unsigned char **data, data, unsigned *len, len, return, DUMMYARG)
+DEFINEFUNC3(int, SSL_set_alpn_protos, SSL *s, s, const unsigned char *protos, protos,
+ unsigned protos_len, protos_len, return -1, return)
+DEFINEFUNC3(void, SSL_CTX_set_alpn_select_cb, SSL_CTX *s, s,
+ int (*cb) (SSL *ssl, const unsigned char **out,
+ unsigned char *outlen,
+ const unsigned char *in,
+ unsigned int inlen, void *arg), cb,
+ void *arg, arg, return, DUMMYARG)
+DEFINEFUNC3(void, SSL_get0_alpn_selected, const SSL *s, s, const unsigned char **data, data,
+ unsigned *len, len, return, DUMMYARG)
+#endif // !OPENSSL_NO_NEXTPROTONEG
+
+// DTLS:
+#if QT_CONFIG(dtls)
+DEFINEFUNC2(void, SSL_CTX_set_cookie_generate_cb, SSL_CTX *ctx, ctx, CookieGenerateCallback cb, cb, return, DUMMYARG)
+DEFINEFUNC2(void, SSL_CTX_set_cookie_verify_cb, SSL_CTX *ctx, ctx, CookieVerifyCallback cb, cb, return, DUMMYARG)
+DEFINEFUNC(const SSL_METHOD *, DTLS_server_method, DUMMYARG, DUMMYARG, return nullptr, return)
+DEFINEFUNC(const SSL_METHOD *, DTLS_client_method, DUMMYARG, DUMMYARG, return nullptr, return)
+#endif // dtls
+DEFINEFUNC2(void, BIO_set_flags, BIO *b, b, int flags, flags, return, DUMMYARG)
+DEFINEFUNC2(void, BIO_clear_flags, BIO *b, b, int flags, flags, return, DUMMYARG)
+DEFINEFUNC2(void *, BIO_get_ex_data, BIO *b, b, int idx, idx, return nullptr, return)
+DEFINEFUNC3(int, BIO_set_ex_data, BIO *b, b, int idx, idx, void *data, data, return -1, return)
+
+DEFINEFUNC3(void *, CRYPTO_malloc, size_t num, num, const char *file, file, int line, line, return nullptr, return)
+
+#ifndef OPENSSL_NO_DEPRECATED_3_0
+DEFINEFUNC(DH *, DH_new, DUMMYARG, DUMMYARG, return nullptr, return)
+DEFINEFUNC(void, DH_free, DH *dh, dh, return, DUMMYARG)
+DEFINEFUNC2(int, DH_check, DH *dh, dh, int *codes, codes, 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)
+
+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)
+
+DEFINEFUNC4(DH *, PEM_read_bio_DHparams, BIO *a, a, DH **b, b, pem_password_cb *c, c, void *d, d, return nullptr, return)
+#endif
+DEFINEFUNC3(BIGNUM *, BN_bin2bn, const unsigned char *s, s, int len, len, BIGNUM *ret, ret, return nullptr, return)
+
+
+#ifndef OPENSSL_NO_EC
+DEFINEFUNC2(size_t, EC_get_builtin_curves, EC_builtin_curve * r, r, size_t nitems, nitems, return 0, return)
+DEFINEFUNC(int, EC_curve_nist2nid, const char *name, name, return 0, return)
+#endif // OPENSSL_NO_EC
+
+DEFINEFUNC5(int, PKCS12_parse, PKCS12 *p12, p12, const char *pass, pass, EVP_PKEY **pkey, pkey, \
+ X509 **cert, cert, STACK_OF(X509) **ca, ca, return 1, return);
+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)
+
+DEFINEFUNC2(int, SSL_CTX_use_RSAPrivateKey, SSL_CTX *a, a, RSA *b, b, return -1, return)
+
+DEFINEFUNC(DSA *, DSA_new, DUMMYARG, DUMMYARG, return nullptr, return)
+DEFINEFUNC(void, DSA_free, DSA *a, a, return, DUMMYARG)
+
+DEFINEFUNC(RSA *, RSA_new, DUMMYARG, DUMMYARG, return nullptr, return)
+DEFINEFUNC(void, RSA_free, RSA *a, a, return, DUMMYARG)
+
+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)
+
+DEFINEFUNC(EC_KEY *, EC_KEY_dup, const EC_KEY *ec, ec, return nullptr, return)
+DEFINEFUNC(EC_KEY *, EC_KEY_new_by_curve_name, int nid, nid, return nullptr, return)
+DEFINEFUNC(void, EC_KEY_free, EC_KEY *ecdh, ecdh, return, DUMMYARG)
+
+#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)))) \
+ qsslSocketCannotResolveSymbolWarning(#func);
+
+#if !defined QT_LINKED_OPENSSL
+
+#if !QT_CONFIG(library)
+bool q_resolveOpenSslSymbols()
+{
+ qCWarning(lcTlsBackend, "QSslSocket: unable to resolve symbols. Qt is configured without the "
+ "'library' feature, which means runtime resolving of libraries won't work.");
+ qCWarning(lcTlsBackend, "Either compile Qt statically or with support for runtime resolving "
+ "of libraries.");
+ return false;
+}
+#else
+
+# ifdef Q_OS_UNIX
+struct NumericallyLess
+{
+ typedef bool result_type;
+ result_type operator()(QStringView lhs, QStringView rhs) const
+ {
+ bool ok = false;
+ int b = 0;
+ int a = lhs.toInt(&ok);
+ if (ok)
+ b = rhs.toInt(&ok);
+ if (ok) {
+ // both toInt succeeded
+ return a < b;
+ } else {
+ // compare as strings;
+ return lhs < rhs;
+ }
+ }
+};
+
+struct LibGreaterThan
+{
+ typedef bool result_type;
+ result_type operator()(QStringView lhs, QStringView rhs) const
+ {
+ const auto lhsparts = lhs.split(u'.');
+ const auto rhsparts = rhs.split(u'.');
+ Q_ASSERT(lhsparts.size() > 1 && rhsparts.size() > 1);
+
+ // note: checking rhs < lhs, the same as lhs > rhs
+ return std::lexicographical_compare(rhsparts.begin() + 1, rhsparts.end(),
+ lhsparts.begin() + 1, lhsparts.end(),
+ NumericallyLess());
+ }
+};
+
+#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)
+static int dlIterateCallback(struct dl_phdr_info *info, size_t size, void *data)
+{
+ if (size < sizeof (info->dlpi_addr) + sizeof (info->dlpi_name))
+ return 1;
+ QDuplicateTracker<QString> *paths = (QDuplicateTracker<QString> *)data;
+ QString path = QString::fromLocal8Bit(info->dlpi_name);
+ if (!path.isEmpty()) {
+ QFileInfo fi(path);
+ path = fi.absolutePath();
+ if (!path.isEmpty())
+ (void)paths->hasSeen(std::move(path));
+ }
+ return 0;
+}
+#endif
+
+static QStringList libraryPathList()
+{
+ QStringList paths;
+# ifdef Q_OS_DARWIN
+ paths = QString::fromLatin1(qgetenv("DYLD_LIBRARY_PATH")).split(u':', Qt::SkipEmptyParts);
+
+ // search in .app/Contents/Frameworks
+ UInt32 packageType;
+ CFBundleGetPackageInfo(CFBundleGetMainBundle(), &packageType, nullptr);
+ if (packageType == FOUR_CHAR_CODE('APPL')) {
+ QUrl bundleUrl = QUrl::fromCFURL(QCFType<CFURLRef>(CFBundleCopyBundleURL(CFBundleGetMainBundle())));
+ QUrl frameworksUrl = QUrl::fromCFURL(QCFType<CFURLRef>(CFBundleCopyPrivateFrameworksURL(CFBundleGetMainBundle())));
+ paths << bundleUrl.resolved(frameworksUrl).path();
+ }
+# else
+ paths = QString::fromLatin1(qgetenv("LD_LIBRARY_PATH")).split(u':', Qt::SkipEmptyParts);
+# endif
+ paths << "/lib"_L1 << "/usr/lib"_L1 << "/usr/local/lib"_L1;
+ paths << "/lib64"_L1 << "/usr/lib64"_L1 << "/usr/local/lib64"_L1;
+ paths << "/lib32"_L1 << "/usr/lib32"_L1 << "/usr/local/lib32"_L1;
+
+#if defined(Q_OS_ANDROID)
+ paths << "/system/lib"_L1;
+#elif defined(Q_OS_LINUX)
+ // discover paths of already loaded libraries
+ QDuplicateTracker<QString> loadedPaths;
+ dl_iterate_phdr(dlIterateCallback, &loadedPaths);
+ std::move(loadedPaths).appendTo(paths);
+#endif
+
+ return paths;
+}
+
+Q_NEVER_INLINE
+static QStringList findAllLibs(QLatin1StringView filter)
+{
+ const QStringList paths = libraryPathList();
+ QStringList found;
+ const QStringList filters((QString(filter)));
+
+ for (const QString &path : paths) {
+ QDir dir(path);
+ QStringList entryList = dir.entryList(filters, QDir::Files);
+
+ std::sort(entryList.begin(), entryList.end(), LibGreaterThan());
+ for (const QString &entry : std::as_const(entryList))
+ found << path + u'/' + entry;
+ }
+
+ return found;
+}
+
+static QStringList findAllLibSsl()
+{
+ return findAllLibs("libssl.*"_L1);
+}
+
+static QStringList findAllLibCrypto()
+{
+ return findAllLibs("libcrypto.*"_L1);
+}
+# endif
+
+#if (OPENSSL_VERSION_NUMBER >> 28) < 3
+#define QT_OPENSSL_VERSION "1_1"
+#elif OPENSSL_VERSION_MAJOR == 3 // Starting with 3.0 this define is available
+#define QT_OPENSSL_VERSION "3"
+#endif // > 3 intentionally left undefined
+
+#ifdef Q_OS_WIN
+
+struct LoadedOpenSsl {
+ std::unique_ptr<QSystemLibrary> ssl, crypto;
+};
+
+static bool tryToLoadOpenSslWin32Library(QLatin1StringView ssleay32LibName, QLatin1StringView libeay32LibName, LoadedOpenSsl &result)
+{
+ auto ssleay32 = std::make_unique<QSystemLibrary>(ssleay32LibName);
+ if (!ssleay32->load(false)) {
+ return FALSE;
+ }
+
+ auto libeay32 = std::make_unique<QSystemLibrary>(libeay32LibName);
+ if (!libeay32->load(false)) {
+ return FALSE;
+ }
+
+ result.ssl = std::move(ssleay32);
+ result.crypto = std::move(libeay32);
+ return TRUE;
+}
+
+static LoadedOpenSsl loadOpenSsl()
+{
+ LoadedOpenSsl result;
+
+ // With OpenSSL 1.1 the names have changed to libssl-1_1 and libcrypto-1_1 for builds using
+ // MSVC and GCC. For 3.0 the version suffix changed again, to just '3'.
+ // For non-x86 builds, an architecture suffix is also appended.
+
+#if defined(Q_PROCESSOR_X86_64)
+#define QT_SSL_SUFFIX "-x64"
+#elif defined(Q_PROCESSOR_ARM_64)
+#define QT_SSL_SUFFIX "-arm64"
+#elif defined(Q_PROCESSOR_ARM_32)
+#define QT_SSL_SUFFIX "-arm"
+#else
+#define QT_SSL_SUFFIX
+#endif
+
+ tryToLoadOpenSslWin32Library("libssl-" QT_OPENSSL_VERSION QT_SSL_SUFFIX ""_L1,
+ "libcrypto-" QT_OPENSSL_VERSION QT_SSL_SUFFIX ""_L1, result);
+
+#undef QT_SSL_SUFFIX
+ return result;
+}
+#else // !Q_OS_WIN:
+
+struct LoadedOpenSsl {
+ std::unique_ptr<QLibrary> ssl, crypto;
+};
+
+static LoadedOpenSsl loadOpenSsl()
+{
+ LoadedOpenSsl result = { std::make_unique<QLibrary>(), std::make_unique<QLibrary>() };
+
+# if defined(Q_OS_UNIX)
+ QLibrary * const libssl = result.ssl.get();
+ QLibrary * const libcrypto = result.crypto.get();
+
+ // Try to find the libssl library on the system.
+ //
+ // Up until Qt 4.3, this only searched for the "ssl" library at version -1, that
+ // is, libssl.so on most Unix systems. However, the .so file isn't present in
+ // user installations because it's considered a development file.
+ //
+ // The right thing to do is to load the library at the major version we know how
+ // to work with: the SHLIB_VERSION_NUMBER version (macro defined in opensslv.h)
+ //
+ // However, OpenSSL is a well-known case of binary-compatibility breakage. To
+ // avoid such problems, many system integrators and Linux distributions change
+ // the soname of the binary, letting the full version number be the soname. So
+ // we'll find libssl.so.0.9.7, libssl.so.0.9.8, etc. in the system. For that
+ // reason, we will search a few common paths (see findAllLibSsl() above) in hopes
+ // we find one that works.
+ //
+ // If that fails, for OpenSSL 1.0 we also try some fallbacks -- look up
+ // libssl.so with a hardcoded soname. The reason is QTBUG-68156: the binary
+ // builds of Qt happen (at the time of this writing) on RHEL machines,
+ // which change SHLIB_VERSION_NUMBER to a non-portable string. When running
+ // those binaries on the target systems, this code won't pick up
+ // libssl.so.MODIFIED_SHLIB_VERSION_NUMBER because it doesn't exist there.
+ // Given that the only 1.0 supported release (at the time of this writing)
+ // is 1.0.2, with soname "1.0.0", give that a try too. Note that we mandate
+ // OpenSSL >= 1.0.0 with a configure-time check, and OpenSSL has kept binary
+ // compatibility between 1.0.0 and 1.0.2.
+ //
+ // It is important, however, to try the canonical name and the unversioned name
+ // without going through the loop. By not specifying a path, we let the system
+ // dlopen(3) function determine it for us. This will include any DT_RUNPATH or
+ // DT_RPATH tags on our library header as well as other system-specific search
+ // paths. See the man page for dlopen(3) on your system for more information.
+
+#ifdef Q_OS_OPENBSD
+ libcrypto->setLoadHints(QLibrary::ExportExternalSymbolsHint);
+#endif
+
+#if !defined(Q_OS_QNX) // on QNX, the libs are always libssl.so and libcrypto.so
+
+#if defined(OPENSSL_SHLIB_VERSION)
+ // OpenSSL v.3 does not have SLIB_VERSION_NUMBER but has OPENSSL_SHLIB_VERSION.
+ // The comment about OPENSSL_SHLIB_VERSION in opensslv.h is a bit troublesome:
+ // "This is defined in free form."
+ auto shlibVersion = QString("%1"_L1).arg(OPENSSL_SHLIB_VERSION);
+ libssl->setFileNameAndVersion("ssl"_L1, shlibVersion);
+ libcrypto->setFileNameAndVersion("crypto"_L1, shlibVersion);
+#elif defined(SHLIB_VERSION_NUMBER)
+ // first attempt: the canonical name is libssl.so.<SHLIB_VERSION_NUMBER>
+ libssl->setFileNameAndVersion("ssl"_L1, SHLIB_VERSION_NUMBER ""_L1);
+ libcrypto->setFileNameAndVersion("crypto"_L1, SHLIB_VERSION_NUMBER ""_L1);
+#endif // OPENSSL_SHLIB_VERSION
+
+ if (libcrypto->load() && libssl->load()) {
+ // libssl.so.<SHLIB_VERSION_NUMBER> and libcrypto.so.<SHLIB_VERSION_NUMBER> found
+ return result;
+ } else {
+ libssl->unload();
+ libcrypto->unload();
+ }
+#endif // !defined(Q_OS_QNX)
+
+#ifndef Q_OS_DARWIN
+ // second attempt: find the development files libssl.so and libcrypto.so
+ //
+ // disabled on macOS/iOS:
+ // macOS's /usr/lib/libssl.dylib, /usr/lib/libcrypto.dylib will be picked up in the third
+ // attempt, _after_ <bundle>/Contents/Frameworks has been searched.
+ // iOS does not ship a system libssl.dylib, libcrypto.dylib in the first place.
+# if defined(Q_OS_ANDROID)
+ // OpenSSL 1.1.x must be suffixed otherwise it will use the system libcrypto.so libssl.so which on API-21 are OpenSSL 1.0 not 1.1
+ auto openSSLSuffix = [](const QByteArray &defaultSuffix = {}) {
+ auto suffix = qgetenv("ANDROID_OPENSSL_SUFFIX");
+ if (suffix.isEmpty())
+ return defaultSuffix;
+ return suffix;
+ };
+
+ static QString suffix = QString::fromLatin1(openSSLSuffix("_" QT_OPENSSL_VERSION));
+
+ libssl->setFileNameAndVersion("ssl"_L1 + suffix, -1);
+ libcrypto->setFileNameAndVersion("crypto"_L1 + suffix, -1);
+# else
+ libssl->setFileNameAndVersion("ssl"_L1, -1);
+ libcrypto->setFileNameAndVersion("crypto"_L1, -1);
+# endif
+ if (libcrypto->load() && libssl->load()) {
+ // libssl.so.0 and libcrypto.so.0 found
+ return result;
+ } else {
+ libssl->unload();
+ libcrypto->unload();
+ }
+#endif
+
+ // third attempt: loop on the most common library paths and find libssl
+ const QStringList sslList = findAllLibSsl();
+ 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);
+ QString version = fi.completeSuffix();
+
+ for (const QString &ssl : sslList) {
+ if (!ssl.endsWith(version))
+ continue;
+
+ libssl->setFileNameAndVersion(ssl, -1);
+
+ if (libssl->load()) {
+ // libssl.so.x and libcrypto.so.x found
+ return result;
+ } else {
+ libssl->unload();
+ }
+ }
+ }
+ libcrypto->unload();
+ }
+
+ // failed to load anything
+ result = {};
+ return result;
+
+# else
+ // not implemented for this platform yet
+ return result;
+# endif
+}
+#endif
+
+bool q_resolveOpenSslSymbols()
+{
+ static bool symbolsResolved = []() {
+ LoadedOpenSsl libs = loadOpenSsl();
+ if (!libs.ssl || !libs.crypto) {
+ qCWarning(lcTlsBackend, "Failed to load libssl/libcrypto.");
+ return false;
+ }
+
+ RESOLVEFUNC(OPENSSL_init_ssl)
+ 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(OPENSSL_sk_new_null)
+ RESOLVEFUNC(OPENSSL_sk_push)
+ RESOLVEFUNC(OPENSSL_sk_free)
+ RESOLVEFUNC(OPENSSL_sk_num)
+ RESOLVEFUNC(OPENSSL_sk_pop_free)
+ RESOLVEFUNC(OPENSSL_sk_value)
+ RESOLVEFUNC(SSL_CTX_set_options)
+ RESOLVEFUNC(SSL_set_info_callback)
+ RESOLVEFUNC(SSL_alert_type_string)
+ RESOLVEFUNC(SSL_alert_desc_string_long)
+ RESOLVEFUNC(SSL_CTX_get_security_level)
+ RESOLVEFUNC(SSL_CTX_set_security_level)
+#ifdef TLS1_3_VERSION
+ RESOLVEFUNC(SSL_CTX_set_ciphersuites)
+ RESOLVEFUNC(SSL_set_psk_use_session_callback)
+ RESOLVEFUNC(SSL_CTX_sess_set_new_cb)
+ RESOLVEFUNC(SSL_SESSION_is_resumable)
+#endif // TLS 1.3 or OpenSSL > 1.1.1
+
+ RESOLVEFUNC(SSL_get_client_random)
+ RESOLVEFUNC(SSL_SESSION_get_master_key)
+ RESOLVEFUNC(SSL_session_reused)
+ RESOLVEFUNC(SSL_get_session)
+ RESOLVEFUNC(SSL_set_options)
+ RESOLVEFUNC(CRYPTO_get_ex_new_index)
+ RESOLVEFUNC(TLS_method)
+ RESOLVEFUNC(TLS_client_method)
+ RESOLVEFUNC(TLS_server_method)
+ RESOLVEFUNC(X509_up_ref)
+ 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)
+ RESOLVEFUNC(X509_STORE_set_ex_data)
+ RESOLVEFUNC(X509_STORE_get_ex_data)
+ RESOLVEFUNC(CRYPTO_free)
+ RESOLVEFUNC(CRYPTO_memcmp)
+ RESOLVEFUNC(OpenSSL_version_num)
+ RESOLVEFUNC(OpenSSL_version)
+
+ if (!_q_OpenSSL_version || !_q_OpenSSL_version_num) {
+ // Apparently, we were built with OpenSSL 1.1 enabled but are now using
+ // a wrong library.
+ qCWarning(lcTlsBackend, "Incompatible version of OpenSSL");
+ return false;
+ }
+
+#if OPENSSL_VERSION_NUMBER >= 0x30000000
+ if (q_OpenSSL_version_num() < 0x30000000) {
+ qCWarning(lcTlsBackend, "Incompatible version of OpenSSL (built with OpenSSL >= 3.x, runtime version is < 3.x)");
+ return false;
+ }
+#else
+ if (q_OpenSSL_version_num() >= 0x30000000) {
+ qCWarning(lcTlsBackend, "Incompatible version of OpenSSL (built with OpenSSL 1.x, runtime version is >= 3.x)");
+ return false;
+ }
+#endif // OPENSSL_VERSION_NUMBER
+
+ RESOLVEFUNC(SSL_SESSION_get_ticket_lifetime_hint)
+
+#if QT_CONFIG(dtls)
+ RESOLVEFUNC(DTLSv1_listen)
+ RESOLVEFUNC(BIO_ADDR_new)
+ RESOLVEFUNC(BIO_ADDR_free)
+ RESOLVEFUNC(BIO_meth_new)
+ RESOLVEFUNC(BIO_meth_free)
+ RESOLVEFUNC(BIO_meth_set_write)
+ RESOLVEFUNC(BIO_meth_set_read)
+ RESOLVEFUNC(BIO_meth_set_puts)
+ RESOLVEFUNC(BIO_meth_set_ctrl)
+ RESOLVEFUNC(BIO_meth_set_create)
+ RESOLVEFUNC(BIO_meth_set_destroy)
+#endif // dtls
+
+#if QT_CONFIG(ocsp)
+ RESOLVEFUNC(OCSP_SINGLERESP_get0_id)
+ RESOLVEFUNC(d2i_OCSP_RESPONSE)
+ RESOLVEFUNC(OCSP_RESPONSE_free)
+ RESOLVEFUNC(OCSP_response_status)
+ RESOLVEFUNC(OCSP_response_get1_basic)
+ RESOLVEFUNC(OCSP_BASICRESP_free)
+ RESOLVEFUNC(OCSP_basic_verify)
+ RESOLVEFUNC(OCSP_resp_count)
+ RESOLVEFUNC(OCSP_resp_get0)
+ RESOLVEFUNC(OCSP_single_get0_status)
+ RESOLVEFUNC(OCSP_check_validity)
+ RESOLVEFUNC(OCSP_cert_to_id)
+ RESOLVEFUNC(OCSP_id_get0_info)
+ RESOLVEFUNC(OCSP_resp_get0_certs)
+ RESOLVEFUNC(OCSP_basic_sign)
+ RESOLVEFUNC(OCSP_response_create)
+ RESOLVEFUNC(i2d_OCSP_RESPONSE)
+ RESOLVEFUNC(OCSP_basic_add1_status)
+ RESOLVEFUNC(OCSP_BASICRESP_new)
+ RESOLVEFUNC(OCSP_CERTID_free)
+ RESOLVEFUNC(OCSP_cert_to_id)
+ RESOLVEFUNC(OCSP_id_cmp)
+#endif // ocsp
+
+ RESOLVEFUNC(BIO_set_data)
+ RESOLVEFUNC(BIO_get_data)
+ RESOLVEFUNC(BIO_set_init)
+ RESOLVEFUNC(BIO_get_shutdown)
+ RESOLVEFUNC(BIO_set_shutdown)
+ RESOLVEFUNC(ASN1_INTEGER_get)
+ RESOLVEFUNC(ASN1_INTEGER_cmp)
+ RESOLVEFUNC(ASN1_STRING_length)
+ RESOLVEFUNC(ASN1_STRING_to_UTF8)
+ RESOLVEFUNC(ASN1_TIME_to_tm)
+ RESOLVEFUNC(BIO_ctrl)
+ RESOLVEFUNC(BIO_free)
+ RESOLVEFUNC(BIO_new)
+ RESOLVEFUNC(BIO_new_mem_buf)
+ RESOLVEFUNC(BIO_read)
+ RESOLVEFUNC(BIO_s_mem)
+ RESOLVEFUNC(BIO_write)
+ RESOLVEFUNC(BIO_set_flags)
+ RESOLVEFUNC(BIO_clear_flags)
+ RESOLVEFUNC(BIO_set_ex_data)
+ RESOLVEFUNC(BIO_get_ex_data)
+ RESOLVEFUNC(BN_num_bits)
+ RESOLVEFUNC(BN_is_word)
+ RESOLVEFUNC(BN_mod_word)
+ RESOLVEFUNC(ERR_error_string)
+ RESOLVEFUNC(ERR_error_string_n)
+ RESOLVEFUNC(ERR_get_error)
+ RESOLVEFUNC(EVP_CIPHER_CTX_new)
+ RESOLVEFUNC(EVP_CIPHER_CTX_free)
+ RESOLVEFUNC(EVP_CIPHER_CTX_ctrl)
+ RESOLVEFUNC(EVP_CIPHER_CTX_set_key_length)
+ RESOLVEFUNC(EVP_CipherInit)
+ RESOLVEFUNC(EVP_CipherInit_ex)
+ RESOLVEFUNC(EVP_CipherUpdate)
+ RESOLVEFUNC(EVP_CipherFinal)
+ RESOLVEFUNC(EVP_get_digestbyname)
+#ifndef OPENSSL_NO_DES
+ RESOLVEFUNC(EVP_des_cbc)
+ RESOLVEFUNC(EVP_des_ede3_cbc)
+#endif
+#ifndef OPENSSL_NO_RC2
+ RESOLVEFUNC(EVP_rc2_cbc)
+#endif
+#ifndef OPENSSL_NO_AES
+ RESOLVEFUNC(EVP_aes_128_cbc)
+ RESOLVEFUNC(EVP_aes_192_cbc)
+ RESOLVEFUNC(EVP_aes_256_cbc)
+#endif
+ RESOLVEFUNC(EVP_sha1)
+ RESOLVEFUNC(EVP_PKEY_free)
+ RESOLVEFUNC(EVP_PKEY_new)
+ RESOLVEFUNC(EVP_PKEY_type)
+ RESOLVEFUNC(OBJ_nid2sn)
+ RESOLVEFUNC(OBJ_nid2ln)
+ RESOLVEFUNC(OBJ_sn2nid)
+ RESOLVEFUNC(OBJ_ln2nid)
+ RESOLVEFUNC(i2t_ASN1_OBJECT)
+ RESOLVEFUNC(OBJ_obj2txt)
+ RESOLVEFUNC(OBJ_obj2nid)
+ RESOLVEFUNC(PEM_read_bio_PrivateKey)
+ RESOLVEFUNC(PEM_write_bio_PrivateKey)
+ RESOLVEFUNC(PEM_write_bio_PrivateKey_traditional)
+ RESOLVEFUNC(PEM_read_bio_PUBKEY)
+ RESOLVEFUNC(PEM_write_bio_PUBKEY)
+ RESOLVEFUNC(RAND_seed)
+ RESOLVEFUNC(RAND_status)
+ RESOLVEFUNC(RAND_bytes)
+ RESOLVEFUNC(SSL_CIPHER_description)
+ RESOLVEFUNC(SSL_CIPHER_get_bits)
+ RESOLVEFUNC(SSL_get_rbio)
+ RESOLVEFUNC(SSL_CTX_check_private_key)
+ RESOLVEFUNC(SSL_CTX_ctrl)
+ RESOLVEFUNC(SSL_CTX_free)
+ RESOLVEFUNC(SSL_CTX_new)
+ RESOLVEFUNC(SSL_CTX_set_cipher_list)
+ RESOLVEFUNC(SSL_CTX_callback_ctrl)
+ RESOLVEFUNC(SSL_CTX_set_default_verify_paths)
+ RESOLVEFUNC(SSL_CTX_set_verify)
+ RESOLVEFUNC(SSL_CTX_set_verify_depth)
+ RESOLVEFUNC(SSL_CTX_use_certificate)
+ RESOLVEFUNC(SSL_CTX_use_certificate_file)
+ RESOLVEFUNC(SSL_CTX_use_PrivateKey)
+ RESOLVEFUNC(SSL_CTX_use_PrivateKey_file)
+ RESOLVEFUNC(SSL_CTX_get_cert_store);
+ RESOLVEFUNC(SSL_CONF_CTX_new);
+ RESOLVEFUNC(SSL_CONF_CTX_free);
+ RESOLVEFUNC(SSL_CONF_CTX_set_ssl_ctx);
+ RESOLVEFUNC(SSL_CONF_CTX_set_flags);
+ RESOLVEFUNC(SSL_CONF_CTX_finish);
+ RESOLVEFUNC(SSL_CONF_cmd);
+ RESOLVEFUNC(SSL_accept)
+ RESOLVEFUNC(SSL_clear)
+ RESOLVEFUNC(SSL_connect)
+ RESOLVEFUNC(SSL_free)
+ RESOLVEFUNC(SSL_get_ciphers)
+ RESOLVEFUNC(SSL_get_current_cipher)
+ 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(DH_new)
+ RESOLVEFUNC(DH_free)
+ RESOLVEFUNC(DH_check)
+ RESOLVEFUNC(DH_get0_pqg)
+
+ RESOLVEFUNC(d2i_DHparams)
+ RESOLVEFUNC(i2d_DHparams)
+
+ RESOLVEFUNC(PEM_read_bio_DHparams)
+
+ 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(SSL_CTX_use_RSAPrivateKey)
+
+ RESOLVEFUNC(DSA_new)
+ RESOLVEFUNC(DSA_free)
+
+ RESOLVEFUNC(RSA_new)
+ RESOLVEFUNC(RSA_free)
+
+ 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)
+ RESOLVEFUNC(EC_KEY_dup)
+ RESOLVEFUNC(EC_KEY_new_by_curve_name)
+ RESOLVEFUNC(EC_KEY_free)
+
+#endif // OPENSSL_NO_EC
+
+#endif // OPENSSL_NO_DEPRECATED_3_0
+
+ RESOLVEFUNC(SSL_get_verify_result)
+ RESOLVEFUNC(SSL_new)
+ RESOLVEFUNC(SSL_get_SSL_CTX)
+ RESOLVEFUNC(SSL_ctrl)
+ RESOLVEFUNC(SSL_read)
+ RESOLVEFUNC(SSL_set_accept_state)
+ RESOLVEFUNC(SSL_set_bio)
+ RESOLVEFUNC(SSL_set_connect_state)
+ RESOLVEFUNC(SSL_shutdown)
+ RESOLVEFUNC(SSL_in_init)
+ RESOLVEFUNC(SSL_get_shutdown)
+ RESOLVEFUNC(SSL_set_session)
+ RESOLVEFUNC(SSL_SESSION_free)
+ RESOLVEFUNC(SSL_get1_session)
+ RESOLVEFUNC(SSL_get_session)
+ RESOLVEFUNC(SSL_set_ex_data)
+ RESOLVEFUNC(SSL_get_ex_data)
+ RESOLVEFUNC(SSL_get_ex_data_X509_STORE_CTX_idx)
+
+#ifndef OPENSSL_NO_PSK
+ RESOLVEFUNC(SSL_set_psk_client_callback)
+ RESOLVEFUNC(SSL_set_psk_server_callback)
+ RESOLVEFUNC(SSL_CTX_use_psk_identity_hint)
+#endif // !OPENSSL_NO_PSK
+
+ RESOLVEFUNC(SSL_write)
+ RESOLVEFUNC(X509_NAME_entry_count)
+ RESOLVEFUNC(X509_NAME_get_entry)
+ RESOLVEFUNC(X509_NAME_ENTRY_get_data)
+ RESOLVEFUNC(X509_NAME_ENTRY_get_object)
+ RESOLVEFUNC(X509_PUBKEY_get)
+ RESOLVEFUNC(X509_STORE_free)
+ RESOLVEFUNC(X509_STORE_new)
+ RESOLVEFUNC(X509_STORE_add_cert)
+ RESOLVEFUNC(X509_STORE_CTX_free)
+ RESOLVEFUNC(X509_STORE_CTX_init)
+ RESOLVEFUNC(X509_STORE_CTX_new)
+ RESOLVEFUNC(X509_STORE_CTX_set_purpose)
+ RESOLVEFUNC(X509_STORE_CTX_get_error)
+ RESOLVEFUNC(X509_STORE_CTX_get_error_depth)
+ RESOLVEFUNC(X509_STORE_CTX_get_current_cert)
+ RESOLVEFUNC(X509_STORE_CTX_get0_store)
+ RESOLVEFUNC(X509_cmp)
+ RESOLVEFUNC(X509_STORE_CTX_get_ex_data)
+ RESOLVEFUNC(X509_dup)
+ RESOLVEFUNC(X509_print)
+ RESOLVEFUNC(X509_digest)
+ RESOLVEFUNC(X509_EXTENSION_get_object)
+ RESOLVEFUNC(X509_free)
+ RESOLVEFUNC(X509_gmtime_adj)
+ RESOLVEFUNC(ASN1_TIME_free)
+ RESOLVEFUNC(X509_get_ext)
+ RESOLVEFUNC(X509_get_ext_count)
+ RESOLVEFUNC(X509_get_ext_d2i)
+ RESOLVEFUNC(X509V3_EXT_get)
+ RESOLVEFUNC(X509V3_EXT_d2i)
+ RESOLVEFUNC(X509_EXTENSION_get_critical)
+ RESOLVEFUNC(X509_EXTENSION_get_data)
+ RESOLVEFUNC(BASIC_CONSTRAINTS_free)
+ RESOLVEFUNC(AUTHORITY_KEYID_free)
+ RESOLVEFUNC(GENERAL_NAME_free)
+ RESOLVEFUNC(ASN1_STRING_print)
+ RESOLVEFUNC(X509_check_issued)
+ RESOLVEFUNC(X509_get_issuer_name)
+ RESOLVEFUNC(X509_get_subject_name)
+ RESOLVEFUNC(X509_get_serialNumber)
+ RESOLVEFUNC(X509_verify_cert)
+ RESOLVEFUNC(d2i_X509)
+ RESOLVEFUNC(i2d_X509)
+#if OPENSSL_VERSION_MAJOR < 3
+ RESOLVEFUNC(SSL_CTX_load_verify_locations)
+#else
+ RESOLVEFUNC(SSL_CTX_load_verify_dir)
+#endif // OPENSSL_VERSION_MAJOR
+ RESOLVEFUNC(i2d_SSL_SESSION)
+ RESOLVEFUNC(d2i_SSL_SESSION)
+
+#ifndef OPENSSL_NO_NEXTPROTONEG
+ RESOLVEFUNC(SSL_select_next_proto)
+ RESOLVEFUNC(SSL_CTX_set_next_proto_select_cb)
+ RESOLVEFUNC(SSL_get0_next_proto_negotiated)
+ RESOLVEFUNC(SSL_set_alpn_protos)
+ RESOLVEFUNC(SSL_CTX_set_alpn_select_cb)
+ RESOLVEFUNC(SSL_get0_alpn_selected)
+#endif // !OPENSSL_NO_NEXTPROTONEG
+
+#if QT_CONFIG(dtls)
+ RESOLVEFUNC(SSL_CTX_set_cookie_generate_cb)
+ RESOLVEFUNC(SSL_CTX_set_cookie_verify_cb)
+ RESOLVEFUNC(DTLS_server_method)
+ RESOLVEFUNC(DTLS_client_method)
+#endif // dtls
+
+ RESOLVEFUNC(CRYPTO_malloc)
+ RESOLVEFUNC(BN_bin2bn)
+
+#ifndef OPENSSL_NO_EC
+ RESOLVEFUNC(EC_get_builtin_curves)
+#endif // OPENSSL_NO_EC
+
+ RESOLVEFUNC(PKCS12_parse)
+ RESOLVEFUNC(d2i_PKCS12_bio)
+ RESOLVEFUNC(PKCS12_free)
+ return true;
+ }();
+
+ return symbolsResolved;
+}
+#endif // QT_CONFIG(library)
+
+#else // !defined QT_LINKED_OPENSSL
+
+bool q_resolveOpenSslSymbols()
+{
+#ifdef QT_NO_OPENSSL
+ return false;
+#endif
+ return true;
+}
+#endif // !defined QT_LINKED_OPENSSL
+
+QT_END_NAMESPACE
diff --git a/src/plugins/tls/openssl/qsslsocket_openssl_symbols_p.h b/src/plugins/tls/openssl/qsslsocket_openssl_symbols_p.h
new file mode 100644
index 0000000000..a93c110b3f
--- /dev/null
+++ b/src/plugins/tls/openssl/qsslsocket_openssl_symbols_p.h
@@ -0,0 +1,765 @@
+// Copyright (C) 2017 The Qt Company Ltd.
+// Copyright (C) 2014 BlackBerry Limited. All rights reserved.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+/****************************************************************************
+**
+** In addition, as a special exception, the copyright holders listed above give
+** permission to link the code of its release of Qt with the OpenSSL project's
+** "OpenSSL" library (or modified versions of the "OpenSSL" library that use the
+** same license as the original version), and distribute the linked executables.
+**
+** You must comply with the GNU General Public License version 2 in all
+** respects for all of the code used other than the "OpenSSL" code. If you
+** modify this file, you may extend this exception to your version of the file,
+** but you are not obligated to do so. If you do not wish to do so, delete
+** this exception statement from your version of this file.
+**
+****************************************************************************/
+
+#ifndef QSSLSOCKET_OPENSSL_SYMBOLS_P_H
+#define QSSLSOCKET_OPENSSL_SYMBOLS_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 <QtNetwork/private/qtnetworkglobal_p.h>
+
+#include "qopenssl_p.h"
+
+#include <QtCore/qglobal.h>
+
+#if QT_CONFIG(ocsp)
+#include <QtNetwork/private/qocsp_p.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+#define DUMMYARG
+
+#if !defined QT_LINKED_OPENSSL
+// **************** Shared declarations ******************
+// ret func(arg)
+
+# define DEFINEFUNC(ret, func, arg, a, err, funcret) \
+ typedef ret (*_q_PTR_##func)(arg); \
+ static _q_PTR_##func _q_##func = nullptr; \
+ ret q_##func(arg) { \
+ if (Q_UNLIKELY(!_q_##func)) { \
+ qsslSocketUnresolvedSymbolWarning(#func); \
+ err; \
+ } \
+ funcret _q_##func(a); \
+ }
+
+// ret func(arg1, arg2)
+# define DEFINEFUNC2(ret, func, arg1, a, arg2, b, err, funcret) \
+ typedef ret (*_q_PTR_##func)(arg1, arg2); \
+ static _q_PTR_##func _q_##func = nullptr; \
+ ret q_##func(arg1, arg2) { \
+ if (Q_UNLIKELY(!_q_##func)) { \
+ qsslSocketUnresolvedSymbolWarning(#func);\
+ err; \
+ } \
+ funcret _q_##func(a, b); \
+ }
+
+// ret func(arg1, arg2, arg3)
+# define DEFINEFUNC3(ret, func, arg1, a, arg2, b, arg3, c, err, funcret) \
+ typedef ret (*_q_PTR_##func)(arg1, arg2, arg3); \
+ static _q_PTR_##func _q_##func = nullptr; \
+ ret q_##func(arg1, arg2, arg3) { \
+ if (Q_UNLIKELY(!_q_##func)) { \
+ qsslSocketUnresolvedSymbolWarning(#func); \
+ err; \
+ } \
+ funcret _q_##func(a, b, c); \
+ }
+
+// ret func(arg1, arg2, arg3, arg4)
+# define DEFINEFUNC4(ret, func, arg1, a, arg2, b, arg3, c, arg4, d, err, funcret) \
+ typedef ret (*_q_PTR_##func)(arg1, arg2, arg3, arg4); \
+ static _q_PTR_##func _q_##func = nullptr; \
+ ret q_##func(arg1, arg2, arg3, arg4) { \
+ if (Q_UNLIKELY(!_q_##func)) { \
+ qsslSocketUnresolvedSymbolWarning(#func); \
+ err; \
+ } \
+ funcret _q_##func(a, b, c, d); \
+ }
+
+// ret func(arg1, arg2, arg3, arg4, arg5)
+# define DEFINEFUNC5(ret, func, arg1, a, arg2, b, arg3, c, arg4, d, arg5, e, err, funcret) \
+ typedef ret (*_q_PTR_##func)(arg1, arg2, arg3, arg4, arg5); \
+ static _q_PTR_##func _q_##func = nullptr; \
+ ret q_##func(arg1, arg2, arg3, arg4, arg5) { \
+ if (Q_UNLIKELY(!_q_##func)) { \
+ qsslSocketUnresolvedSymbolWarning(#func); \
+ err; \
+ } \
+ funcret _q_##func(a, b, c, d, e); \
+ }
+
+// ret func(arg1, arg2, arg3, arg4, arg6)
+# define DEFINEFUNC6(ret, func, arg1, a, arg2, b, arg3, c, arg4, d, arg5, e, arg6, f, err, funcret) \
+ typedef ret (*_q_PTR_##func)(arg1, arg2, arg3, arg4, arg5, arg6); \
+ static _q_PTR_##func _q_##func = nullptr; \
+ ret q_##func(arg1, arg2, arg3, arg4, arg5, arg6) { \
+ if (Q_UNLIKELY(!_q_##func)) { \
+ qsslSocketUnresolvedSymbolWarning(#func); \
+ err; \
+ } \
+ funcret _q_##func(a, b, c, d, e, f); \
+ }
+
+// ret func(arg1, arg2, arg3, arg4, arg6, arg7)
+# define DEFINEFUNC7(ret, func, arg1, a, arg2, b, arg3, c, arg4, d, arg5, e, arg6, f, arg7, g, err, funcret) \
+ typedef ret (*_q_PTR_##func)(arg1, arg2, arg3, arg4, arg5, arg6, arg7); \
+ static _q_PTR_##func _q_##func = nullptr; \
+ ret q_##func(arg1, arg2, arg3, arg4, arg5, arg6, arg7) { \
+ if (Q_UNLIKELY(!_q_##func)) { \
+ qsslSocketUnresolvedSymbolWarning(#func); \
+ err; \
+ } \
+ funcret _q_##func(a, b, c, d, e, f, g); \
+ }
+
+// ret func(arg1, arg2, arg3, arg4, arg6, arg7, arg8, arg9)
+# define DEFINEFUNC9(ret, func, arg1, a, arg2, b, arg3, c, arg4, d, arg5, e, arg6, f, arg7, g, arg8, h, arg9, i, err, funcret) \
+ typedef ret (*_q_PTR_##func)(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9); \
+ static _q_PTR_##func _q_##func = nullptr; \
+ ret q_##func(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) { \
+ if (Q_UNLIKELY(!_q_##func)) { \
+ qsslSocketUnresolvedSymbolWarning(#func); \
+ err; \
+ } \
+ funcret _q_##func(a, b, c, d, e, f, g, h, i); \
+ }
+// **************** Shared declarations ******************
+
+#else // !defined QT_LINKED_OPENSSL
+
+// **************** Static declarations ******************
+
+// ret func(arg)
+# define DEFINEFUNC(ret, func, arg, a, err, funcret) \
+ ret q_##func(arg) { funcret func(a); }
+
+// ret func(arg1, arg2)
+# define DEFINEFUNC2(ret, func, arg1, a, arg2, b, err, funcret) \
+ ret q_##func(arg1, arg2) { funcret func(a, b); }
+
+// ret func(arg1, arg2, arg3)
+# define DEFINEFUNC3(ret, func, arg1, a, arg2, b, arg3, c, err, funcret) \
+ ret q_##func(arg1, arg2, arg3) { funcret func(a, b, c); }
+
+// ret func(arg1, arg2, arg3, arg4)
+# define DEFINEFUNC4(ret, func, arg1, a, arg2, b, arg3, c, arg4, d, err, funcret) \
+ ret q_##func(arg1, arg2, arg3, arg4) { funcret func(a, b, c, d); }
+
+// ret func(arg1, arg2, arg3, arg4, arg5)
+# define DEFINEFUNC5(ret, func, arg1, a, arg2, b, arg3, c, arg4, d, arg5, e, err, funcret) \
+ ret q_##func(arg1, arg2, arg3, arg4, arg5) { funcret func(a, b, c, d, e); }
+
+// ret func(arg1, arg2, arg3, arg4, arg6)
+# define DEFINEFUNC6(ret, func, arg1, a, arg2, b, arg3, c, arg4, d, arg5, e, arg6, f, err, funcret) \
+ ret q_##func(arg1, arg2, arg3, arg4, arg5, arg6) { funcret func(a, b, c, d, e, f); }
+
+// ret func(arg1, arg2, arg3, arg4, arg6, arg7)
+# define DEFINEFUNC7(ret, func, arg1, a, arg2, b, arg3, c, arg4, d, arg5, e, arg6, f, arg7, g, err, funcret) \
+ ret q_##func(arg1, arg2, arg3, arg4, arg5, arg6, arg7) { funcret func(a, b, c, d, e, f, g); }
+
+// ret func(arg1, arg2, arg3, arg4, arg6, arg7, arg8, arg9)
+# define DEFINEFUNC9(ret, func, arg1, a, arg2, b, arg3, c, arg4, d, arg5, e, arg6, f, arg7, g, arg8, h, arg9, i, err, funcret) \
+ ret q_##func(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) { funcret func(a, b, c, d, e, f, g, h, i); }
+
+// **************** Static declarations ******************
+
+#endif // !defined QT_LINKED_OPENSSL
+#if defined(OPENSSL_VERSION_MAJOR) && OPENSSL_VERSION_MAJOR >= 3
+typedef uint64_t qssloptions;
+#else
+typedef unsigned long qssloptions;
+#endif
+// TODO: the following lines previously were a part of 1.1 - specific header.
+// To reduce the amount of the change, I'm directly copying and pasting the
+// content of the header here. Later, can be better sorted/split into groups,
+// depending on the functionality.
+
+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();
+
+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_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();
+void q_OPENSSL_sk_push(OPENSSL_STACK *st, void *data);
+void q_OPENSSL_sk_free(OPENSSL_STACK *a);
+void * q_OPENSSL_sk_value(OPENSSL_STACK *a, int b);
+int q_SSL_session_reused(SSL *a);
+qssloptions q_SSL_CTX_set_options(SSL_CTX *ctx, qssloptions op);
+int q_OPENSSL_init_ssl(uint64_t opts, const OPENSSL_INIT_SETTINGS *settings);
+size_t q_SSL_get_client_random(SSL *a, unsigned char *out, size_t outlen);
+size_t q_SSL_SESSION_get_master_key(const SSL_SESSION *session, unsigned char *out, size_t outlen);
+int q_CRYPTO_get_ex_new_index(int class_index, long argl, void *argp, CRYPTO_EX_new *new_func, CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func);
+const SSL_METHOD *q_TLS_method();
+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);
+EVP_PKEY *q_X509_get_pubkey(X509 *a);
+void q_X509_STORE_set_verify_cb(X509_STORE *ctx, X509_STORE_CTX_verify_cb verify_cb);
+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);
+
+# define q_SSL_load_error_strings() q_OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS \
+ | OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL)
+
+#define q_SKM_sk_num(st) q_OPENSSL_sk_num((OPENSSL_STACK *)st)
+#define q_SKM_sk_value(type, st,i) (type *)q_OPENSSL_sk_value((OPENSSL_STACK *)st, i)
+
+#define q_OPENSSL_add_all_algorithms_conf() q_OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS \
+ | OPENSSL_INIT_ADD_ALL_DIGESTS \
+ | OPENSSL_INIT_LOAD_CONFIG, NULL)
+#define q_OPENSSL_add_all_algorithms_noconf() q_OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS \
+ | OPENSSL_INIT_ADD_ALL_DIGESTS, NULL)
+
+int q_OPENSSL_init_crypto(uint64_t opts, const OPENSSL_INIT_SETTINGS *settings);
+
+long q_OpenSSL_version_num();
+const char *q_OpenSSL_version(int type);
+
+unsigned long q_SSL_SESSION_get_ticket_lifetime_hint(const SSL_SESSION *session);
+unsigned long q_SSL_set_options(SSL *s, unsigned long op);
+
+#ifdef TLS1_3_VERSION
+int q_SSL_CTX_set_ciphersuites(SSL_CTX *ctx, const char *str);
+
+// The functions below do not really have to be ifdefed like this, but for now
+// they only used in TLS 1.3 handshake (and probably future versions).
+// Plus, 'is resumalbe' is OpenSSL 1.1.1-only (and again we need it for
+// TLS 1.3-specific session management).
+
+extern "C"
+{
+using NewSessionCallback = int (*)(SSL *, SSL_SESSION *);
+}
+
+void q_SSL_CTX_sess_set_new_cb(SSL_CTX *ctx, NewSessionCallback cb);
+int q_SSL_SESSION_is_resumable(const SSL_SESSION *s);
+
+#define q_SSL_CTX_set_session_cache_mode(ctx,m) \
+ q_SSL_CTX_ctrl(ctx,SSL_CTRL_SET_SESS_CACHE_MODE,m,NULL)
+
+#endif
+
+#if QT_CONFIG(dtls)
+// Functions and types required for DTLS support:
+extern "C"
+{
+
+typedef int (*CookieVerifyCallback)(SSL *, const unsigned char *, unsigned);
+typedef int (*DgramWriteCallback) (BIO *, const char *, int);
+typedef int (*DgramReadCallback) (BIO *, char *, int);
+typedef int (*DgramPutsCallback) (BIO *, const char *);
+typedef long (*DgramCtrlCallback) (BIO *, int, long, void *);
+typedef int (*DgramCreateCallback) (BIO *);
+typedef int (*DgramDestroyCallback) (BIO *);
+
+}
+
+int q_DTLSv1_listen(SSL *s, BIO_ADDR *client);
+BIO_ADDR *q_BIO_ADDR_new();
+void q_BIO_ADDR_free(BIO_ADDR *ap);
+
+// API we need for a custom dgram BIO:
+
+BIO_METHOD *q_BIO_meth_new(int type, const char *name);
+void q_BIO_meth_free(BIO_METHOD *biom);
+int q_BIO_meth_set_write(BIO_METHOD *biom, DgramWriteCallback);
+int q_BIO_meth_set_read(BIO_METHOD *biom, DgramReadCallback);
+int q_BIO_meth_set_puts(BIO_METHOD *biom, DgramPutsCallback);
+int q_BIO_meth_set_ctrl(BIO_METHOD *biom, DgramCtrlCallback);
+int q_BIO_meth_set_create(BIO_METHOD *biom, DgramCreateCallback);
+int q_BIO_meth_set_destroy(BIO_METHOD *biom, DgramDestroyCallback);
+
+#endif // dtls
+
+void q_BIO_set_data(BIO *a, void *ptr);
+void *q_BIO_get_data(BIO *a);
+void q_BIO_set_init(BIO *a, int init);
+int q_BIO_get_shutdown(BIO *a);
+void q_BIO_set_shutdown(BIO *a, int shut);
+
+#if QT_CONFIG(ocsp)
+const OCSP_CERTID *q_OCSP_SINGLERESP_get0_id(const OCSP_SINGLERESP *x);
+#endif // ocsp
+
+#define q_SSL_CTX_set_min_proto_version(ctx, version) \
+ q_SSL_CTX_ctrl(ctx, SSL_CTRL_SET_MIN_PROTO_VERSION, version, nullptr)
+
+#define q_SSL_CTX_set_max_proto_version(ctx, version) \
+ q_SSL_CTX_ctrl(ctx, SSL_CTRL_SET_MAX_PROTO_VERSION, version, nullptr)
+
+extern "C" {
+typedef int (*q_SSL_psk_use_session_cb_func_t)(SSL *, const EVP_MD *, const unsigned char **, size_t *,
+ SSL_SESSION **);
+}
+void q_SSL_set_psk_use_session_callback(SSL *s, q_SSL_psk_use_session_cb_func_t);
+// Here the content of the 1.1 header ends.
+
+bool q_resolveOpenSslSymbols();
+long q_ASN1_INTEGER_get(ASN1_INTEGER *a);
+int q_ASN1_INTEGER_cmp(const ASN1_INTEGER *x, const ASN1_INTEGER *y);
+int q_ASN1_STRING_length(ASN1_STRING *a);
+int q_ASN1_STRING_to_UTF8(unsigned char **a, ASN1_STRING *b);
+int q_ASN1_TIME_to_tm(const ASN1_TIME *s, struct tm *tm);
+long q_BIO_ctrl(BIO *a, int b, long c, void *d);
+int q_BIO_free(BIO *a);
+BIO *q_BIO_new_mem_buf(void *a, int b);
+int q_BIO_read(BIO *a, void *b, int c);
+int q_BIO_write(BIO *a, const void *b, int c);
+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);
+
+X509 *q_d2i_X509(X509 **a, const unsigned char **b, long c);
+char *q_ERR_error_string(unsigned long a, char *b);
+void q_ERR_error_string_n(unsigned long e, char *buf, size_t len);
+unsigned long q_ERR_get_error();
+EVP_CIPHER_CTX *q_EVP_CIPHER_CTX_new();
+void q_EVP_CIPHER_CTX_free(EVP_CIPHER_CTX *a);
+int q_EVP_CIPHER_CTX_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr);
+int q_EVP_CIPHER_CTX_set_key_length(EVP_CIPHER_CTX *x, int keylen);
+int q_EVP_CipherInit(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *type, const unsigned char *key, const unsigned char *iv, int enc);
+int q_EVP_CipherInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, ENGINE *impl, const unsigned char *key, const unsigned char *iv, int enc);
+int q_EVP_CipherUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl, const unsigned char *in, int inl);
+int q_EVP_CipherFinal(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl);
+const EVP_MD *q_EVP_get_digestbyname(const char *name);
+
+#ifndef OPENSSL_NO_DES
+const EVP_CIPHER *q_EVP_des_cbc();
+const EVP_CIPHER *q_EVP_des_ede3_cbc();
+#endif // OPENSSL_NO_DES
+
+#ifndef OPENSSL_NO_RC2
+const EVP_CIPHER *q_EVP_rc2_cbc();
+#endif // OPENSSL_NO_RC2
+
+#ifndef OPENSSL_NO_AES
+const EVP_CIPHER *q_EVP_aes_128_cbc();
+const EVP_CIPHER *q_EVP_aes_192_cbc();
+const EVP_CIPHER *q_EVP_aes_256_cbc();
+#endif // OPENSSL_NO_AES
+
+const EVP_MD *q_EVP_sha1();
+
+void q_EVP_PKEY_free(EVP_PKEY *a);
+int q_EVP_PKEY_type(int a);
+EVP_PKEY *q_EVP_PKEY_new();
+int q_i2d_X509(X509 *a, unsigned char **b);
+const char *q_OBJ_nid2sn(int a);
+const char *q_OBJ_nid2ln(int a);
+int q_OBJ_sn2nid(const char *s);
+int q_OBJ_ln2nid(const char *s);
+int q_i2t_ASN1_OBJECT(char *buf, int buf_len, ASN1_OBJECT *obj);
+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);
+
+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);
+int q_PEM_write_bio_PUBKEY(BIO *a, EVP_PKEY *b);
+
+void q_RAND_seed(const void *a, int b);
+int q_RAND_status();
+int q_RAND_bytes(unsigned char *b, int n);
+int q_SSL_accept(SSL *a);
+int q_SSL_clear(SSL *a);
+char *q_SSL_CIPHER_description(const SSL_CIPHER *a, char *b, int c);
+int q_SSL_CIPHER_get_bits(const SSL_CIPHER *a, int *b);
+BIO *q_SSL_get_rbio(const SSL *s);
+int q_SSL_connect(SSL *a);
+int q_SSL_CTX_check_private_key(const SSL_CTX *a);
+long q_SSL_CTX_ctrl(SSL_CTX *a, int b, long c, void *d);
+void q_SSL_CTX_free(SSL_CTX *a);
+SSL_CTX *q_SSL_CTX_new(const SSL_METHOD *a);
+int q_SSL_CTX_set_cipher_list(SSL_CTX *a, const char *b);
+int q_SSL_CTX_set_default_verify_paths(SSL_CTX *a);
+void q_SSL_CTX_set_verify(SSL_CTX *a, int b, int (*c)(int, X509_STORE_CTX *));
+void q_SSL_CTX_set_verify_depth(SSL_CTX *a, int b);
+extern "C" {
+typedef void (*GenericCallbackType)();
+}
+long q_SSL_CTX_callback_ctrl(SSL_CTX *, int, GenericCallbackType);
+int q_SSL_CTX_use_certificate(SSL_CTX *a, X509 *b);
+int q_SSL_CTX_use_certificate_file(SSL_CTX *a, const char *b, int c);
+int q_SSL_CTX_use_PrivateKey(SSL_CTX *a, EVP_PKEY *b);
+int q_SSL_CTX_use_PrivateKey_file(SSL_CTX *a, const char *b, int c);
+X509_STORE *q_SSL_CTX_get_cert_store(const SSL_CTX *a);
+SSL_CONF_CTX *q_SSL_CONF_CTX_new();
+void q_SSL_CONF_CTX_free(SSL_CONF_CTX *a);
+void q_SSL_CONF_CTX_set_ssl_ctx(SSL_CONF_CTX *a, SSL_CTX *b);
+unsigned int q_SSL_CONF_CTX_set_flags(SSL_CONF_CTX *a, unsigned int b);
+int q_SSL_CONF_CTX_finish(SSL_CONF_CTX *a);
+int q_SSL_CONF_cmd(SSL_CONF_CTX *a, const char *b, const char *c);
+void q_SSL_free(SSL *a);
+STACK_OF(SSL_CIPHER) *q_SSL_get_ciphers(const SSL *a);
+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);
+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);
+long q_SSL_ctrl(SSL *ssl,int cmd, long larg, void *parg);
+int q_SSL_read(SSL *a, void *b, int c);
+void q_SSL_set_bio(SSL *a, BIO *b, BIO *c);
+void q_SSL_set_accept_state(SSL *a);
+void q_SSL_set_connect_state(SSL *a);
+int q_SSL_shutdown(SSL *a);
+int q_SSL_in_init(const SSL *s);
+int q_SSL_get_shutdown(const SSL *ssl);
+int q_SSL_set_session(SSL *to, SSL_SESSION *session);
+void q_SSL_SESSION_free(SSL_SESSION *ses);
+SSL_SESSION *q_SSL_get1_session(SSL *ssl);
+SSL_SESSION *q_SSL_get_session(const SSL *ssl);
+int q_SSL_set_ex_data(SSL *ssl, int idx, void *arg);
+void *q_SSL_get_ex_data(const SSL *ssl, int idx);
+#ifndef OPENSSL_NO_PSK
+typedef unsigned int (*q_psk_client_callback_t)(SSL *ssl, const char *hint, char *identity, unsigned int max_identity_len, unsigned char *psk, unsigned int max_psk_len);
+void q_SSL_set_psk_client_callback(SSL *ssl, q_psk_client_callback_t callback);
+typedef unsigned int (*q_psk_server_callback_t)(SSL *ssl, const char *identity, unsigned char *psk, unsigned int max_psk_len);
+void q_SSL_set_psk_server_callback(SSL *ssl, q_psk_server_callback_t callback);
+int q_SSL_CTX_use_psk_identity_hint(SSL_CTX *ctx, const char *hint);
+#endif // !OPENSSL_NO_PSK
+int q_SSL_write(SSL *a, const void *b, int c);
+int q_X509_cmp(X509 *a, X509 *b);
+X509 *q_X509_dup(X509 *a);
+void q_X509_print(BIO *a, X509*b);
+int q_X509_digest(const X509 *x509, const EVP_MD *type, unsigned char *md, unsigned int *len);
+ASN1_OBJECT *q_X509_EXTENSION_get_object(X509_EXTENSION *a);
+void q_X509_free(X509 *a);
+ASN1_TIME *q_X509_gmtime_adj(ASN1_TIME *s, long adj);
+void q_ASN1_TIME_free(ASN1_TIME *t);
+X509_EXTENSION *q_X509_get_ext(X509 *a, int b);
+int q_X509_get_ext_count(X509 *a);
+void *q_X509_get_ext_d2i(X509 *a, int b, int *c, int *d);
+const X509V3_EXT_METHOD *q_X509V3_EXT_get(X509_EXTENSION *a);
+void *q_X509V3_EXT_d2i(X509_EXTENSION *a);
+int q_X509_EXTENSION_get_critical(X509_EXTENSION *a);
+ASN1_OCTET_STRING *q_X509_EXTENSION_get_data(X509_EXTENSION *a);
+void q_BASIC_CONSTRAINTS_free(BASIC_CONSTRAINTS *a);
+void q_AUTHORITY_KEYID_free(AUTHORITY_KEYID *a);
+int q_ASN1_STRING_print(BIO *a, const ASN1_STRING *b);
+int q_X509_check_issued(X509 *a, X509 *b);
+X509_NAME *q_X509_get_issuer_name(X509 *a);
+X509_NAME *q_X509_get_subject_name(X509 *a);
+ASN1_INTEGER *q_X509_get_serialNumber(X509 *a);
+int q_X509_verify_cert(X509_STORE_CTX *ctx);
+int q_X509_NAME_entry_count(X509_NAME *a);
+X509_NAME_ENTRY *q_X509_NAME_get_entry(X509_NAME *a,int b);
+ASN1_STRING *q_X509_NAME_ENTRY_get_data(X509_NAME_ENTRY *a);
+ASN1_OBJECT *q_X509_NAME_ENTRY_get_object(X509_NAME_ENTRY *a);
+EVP_PKEY *q_X509_PUBKEY_get(X509_PUBKEY *a);
+void q_X509_STORE_free(X509_STORE *store);
+X509_STORE *q_X509_STORE_new();
+int q_X509_STORE_add_cert(X509_STORE *ctx, X509 *x);
+void q_X509_STORE_CTX_free(X509_STORE_CTX *storeCtx);
+int q_X509_STORE_CTX_init(X509_STORE_CTX *ctx, X509_STORE *store,
+ X509 *x509, STACK_OF(X509) *chain);
+X509_STORE_CTX *q_X509_STORE_CTX_new();
+int q_X509_STORE_CTX_set_purpose(X509_STORE_CTX *ctx, int purpose);
+int q_X509_STORE_CTX_get_error(X509_STORE_CTX *ctx);
+int q_X509_STORE_CTX_get_error_depth(X509_STORE_CTX *ctx);
+X509 *q_X509_STORE_CTX_get_current_cert(X509_STORE_CTX *ctx);
+X509_STORE *q_X509_STORE_CTX_get0_store(X509_STORE_CTX *ctx);
+
+// Diffie-Hellman support
+#ifndef OPENSSL_NO_DEPRECATED_3_0
+DH *q_DH_new();
+void q_DH_free(DH *dh);
+int q_DH_check(DH *dh, int *codes);
+void q_DH_get0_pqg(const DH *dh, const BIGNUM **p, const BIGNUM **q, const BIGNUM **g);
+
+DH *q_d2i_DHparams(DH **a, const unsigned char **pp, long length);
+int q_i2d_DHparams(DH *a, unsigned char **p);
+
+DH *q_PEM_read_bio_DHparams(BIO *a, DH **b, pem_password_cb *c, void *d);
+#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)
+#define q_SSL_CTX_set_dh_auto(ctx, onoff) q_SSL_CTX_ctrl(ctx,SSL_CTRL_SET_DH_AUTO,onoff,NULL)
+
+#ifndef OPENSSL_NO_EC
+// EC Diffie-Hellman support
+#define q_SSL_CTX_set_tmp_ecdh(ctx, ecdh) q_SSL_CTX_ctrl((ctx), SSL_CTRL_SET_TMP_ECDH, 0, (char *)ecdh)
+
+// EC curves management
+size_t q_EC_get_builtin_curves(EC_builtin_curve *r, size_t nitems);
+int q_EC_curve_nist2nid(const char *name);
+#endif // OPENSSL_NO_EC
+
+#define q_SSL_get_server_tmp_key(ssl, key) q_SSL_ctrl((ssl), SSL_CTRL_GET_SERVER_TMP_KEY, 0, (char *)key)
+
+// PKCS#12 support
+int q_PKCS12_parse(PKCS12 *p12, const char *pass, EVP_PKEY **pkey, X509 **cert, STACK_OF(X509) **ca);
+PKCS12 *q_d2i_PKCS12_bio(BIO *bio, PKCS12 **pkcs12);
+void q_PKCS12_free(PKCS12 *pkcs12);
+
+#define q_BIO_get_mem_data(b, pp) (int)q_BIO_ctrl(b,BIO_CTRL_INFO,0,(char *)pp)
+#define q_BIO_pending(b) (int)q_BIO_ctrl(b,BIO_CTRL_PENDING,0,NULL)
+#define q_SSL_CTX_set_mode(ctx,op) q_SSL_CTX_ctrl((ctx),SSL_CTRL_MODE,(op),NULL)
+#define q_sk_GENERAL_NAME_num(st) q_SKM_sk_num((st))
+#define q_sk_GENERAL_NAME_value(st, i) q_SKM_sk_value(GENERAL_NAME, (st), (i))
+
+void q_GENERAL_NAME_free(GENERAL_NAME *a);
+
+#define q_sk_X509_num(st) q_SKM_sk_num((st))
+#define q_sk_X509_value(st, i) q_SKM_sk_value(X509, (st), (i))
+#define q_sk_SSL_CIPHER_num(st) q_SKM_sk_num((st))
+#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_OpenSSL_add_all_algorithms() q_OPENSSL_add_all_algorithms_conf()
+
+#if OPENSSL_VERSION_MAJOR < 3
+int q_SSL_CTX_load_verify_locations(SSL_CTX *ctx, const char *CAfile, const char *CApath);
+#else
+int q_SSL_CTX_load_verify_dir(SSL_CTX *ctx, const char *CApath);
+#endif // OPENSSL_VERSION_MAJOR
+
+int q_i2d_SSL_SESSION(SSL_SESSION *in, unsigned char **pp);
+SSL_SESSION *q_d2i_SSL_SESSION(SSL_SESSION **a, const unsigned char **pp, long length);
+
+#ifndef OPENSSL_NO_NEXTPROTONEG
+int q_SSL_select_next_proto(unsigned char **out, unsigned char *outlen,
+ const unsigned char *in, unsigned int inlen,
+ const unsigned char *client, unsigned int client_len);
+void q_SSL_CTX_set_next_proto_select_cb(SSL_CTX *s,
+ int (*cb) (SSL *ssl, unsigned char **out,
+ unsigned char *outlen,
+ const unsigned char *in,
+ unsigned int inlen, void *arg),
+ void *arg);
+void q_SSL_get0_next_proto_negotiated(const SSL *s, const unsigned char **data,
+ unsigned *len);
+int q_SSL_set_alpn_protos(SSL *ssl, const unsigned char *protos,
+ unsigned protos_len);
+void q_SSL_CTX_set_alpn_select_cb(SSL_CTX *ctx,
+ int (*cb) (SSL *ssl,
+ const unsigned char **out,
+ unsigned char *outlen,
+ const unsigned char *in,
+ unsigned int inlen,
+ void *arg), void *arg);
+void q_SSL_get0_alpn_selected(const SSL *ssl, const unsigned char **data,
+ unsigned *len);
+#endif // !OPENSSL_NO_NEXTPROTONEG
+
+
+#if QT_CONFIG(dtls)
+
+extern "C"
+{
+typedef int (*CookieGenerateCallback)(SSL *, unsigned char *, unsigned *);
+}
+
+void q_SSL_CTX_set_cookie_generate_cb(SSL_CTX *ctx, CookieGenerateCallback cb);
+void q_SSL_CTX_set_cookie_verify_cb(SSL_CTX *ctx, CookieVerifyCallback cb);
+const SSL_METHOD *q_DTLS_server_method();
+const SSL_METHOD *q_DTLS_client_method();
+
+#endif // dtls
+
+void *q_X509_STORE_CTX_get_ex_data(X509_STORE_CTX *ctx, int idx);
+int q_SSL_get_ex_data_X509_STORE_CTX_idx();
+
+#if QT_CONFIG(dtls)
+#define q_DTLS_set_link_mtu(ssl, mtu) q_SSL_ctrl((ssl), DTLS_CTRL_SET_LINK_MTU, (mtu), nullptr)
+#define q_DTLSv1_get_timeout(ssl, arg) q_SSL_ctrl(ssl, DTLS_CTRL_GET_TIMEOUT, 0, arg)
+#define q_DTLSv1_handle_timeout(ssl) q_SSL_ctrl(ssl, DTLS_CTRL_HANDLE_TIMEOUT, 0, nullptr)
+#endif // dtls
+
+void q_BIO_set_flags(BIO *b, int flags);
+void q_BIO_clear_flags(BIO *b, int flags);
+void *q_BIO_get_ex_data(BIO *b, int idx);
+int q_BIO_set_ex_data(BIO *b, int idx, void *data);
+
+#define q_BIO_set_retry_read(b) q_BIO_set_flags(b, (BIO_FLAGS_READ|BIO_FLAGS_SHOULD_RETRY))
+#define q_BIO_set_retry_write(b) q_BIO_set_flags(b, (BIO_FLAGS_WRITE|BIO_FLAGS_SHOULD_RETRY))
+#define q_BIO_clear_retry_flags(b) q_BIO_clear_flags(b, (BIO_FLAGS_RWS|BIO_FLAGS_SHOULD_RETRY))
+#define q_BIO_set_app_data(s,arg) q_BIO_set_ex_data(s,0,arg)
+#define q_BIO_get_app_data(s) q_BIO_get_ex_data(s,0)
+
+#define q_SSL_set_tlsext_status_type(ssl, type) \
+ q_SSL_ctrl((ssl), SSL_CTRL_SET_TLSEXT_STATUS_REQ_TYPE, (type), nullptr)
+
+#if QT_CONFIG(ocsp)
+
+OCSP_RESPONSE *q_d2i_OCSP_RESPONSE(OCSP_RESPONSE **a, const unsigned char **in, long len);
+int q_i2d_OCSP_RESPONSE(OCSP_RESPONSE *r, unsigned char **ppout);
+OCSP_RESPONSE *q_OCSP_response_create(int status, OCSP_BASICRESP *bs);
+void q_OCSP_RESPONSE_free(OCSP_RESPONSE *rs);
+int q_OCSP_response_status(OCSP_RESPONSE *resp);
+OCSP_BASICRESP *q_OCSP_response_get1_basic(OCSP_RESPONSE *resp);
+OCSP_SINGLERESP *q_OCSP_basic_add1_status(OCSP_BASICRESP *rsp, OCSP_CERTID *cid,
+ int status, int reason, ASN1_TIME *revtime,
+ ASN1_TIME *thisupd, ASN1_TIME *nextupd);
+int q_OCSP_basic_sign(OCSP_BASICRESP *brsp, X509 *signer, EVP_PKEY *key, const EVP_MD *dgst,
+ STACK_OF(X509) *certs, unsigned long flags);
+OCSP_BASICRESP *q_OCSP_BASICRESP_new();
+void q_OCSP_BASICRESP_free(OCSP_BASICRESP *bs);
+int q_OCSP_basic_verify(OCSP_BASICRESP *bs, STACK_OF(X509) *certs, X509_STORE *st, unsigned long flags);
+int q_OCSP_resp_count(OCSP_BASICRESP *bs);
+OCSP_SINGLERESP *q_OCSP_resp_get0(OCSP_BASICRESP *bs, int idx);
+int q_OCSP_single_get0_status(OCSP_SINGLERESP *single, int *reason, ASN1_GENERALIZEDTIME **revtime,
+ ASN1_GENERALIZEDTIME **thisupd, ASN1_GENERALIZEDTIME **nextupd);
+int q_OCSP_check_validity(ASN1_GENERALIZEDTIME *thisupd, ASN1_GENERALIZEDTIME *nextupd, long nsec, long maxsec);
+int q_OCSP_id_get0_info(ASN1_OCTET_STRING **piNameHash, ASN1_OBJECT **pmd, ASN1_OCTET_STRING **pikeyHash,
+ ASN1_INTEGER **pserial, OCSP_CERTID *cid);
+
+const STACK_OF(X509) *q_OCSP_resp_get0_certs(const OCSP_BASICRESP *bs);
+OCSP_CERTID *q_OCSP_cert_to_id(const EVP_MD *dgst, X509 *subject, X509 *issuer);
+void q_OCSP_CERTID_free(OCSP_CERTID *cid);
+int q_OCSP_id_cmp(OCSP_CERTID *a, OCSP_CERTID *b);
+
+#define q_SSL_get_tlsext_status_ocsp_resp(ssl, arg) \
+ q_SSL_ctrl(ssl, SSL_CTRL_GET_TLSEXT_STATUS_REQ_OCSP_RESP, 0, arg)
+
+#define q_SSL_CTX_set_tlsext_status_cb(ssl, cb) \
+ q_SSL_CTX_callback_ctrl(ssl, SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB, GenericCallbackType(cb))
+
+# define q_SSL_set_tlsext_status_ocsp_resp(ssl, arg, arglen) \
+ q_SSL_ctrl(ssl, SSL_CTRL_SET_TLSEXT_STATUS_REQ_OCSP_RESP, arglen, arg)
+
+#endif // ocsp
+
+
+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)
+int q_CRYPTO_memcmp(const void * in_a, const void * in_b, size_t len);
+
+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);
+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_DSA_new();
+void q_DSA_free(DSA *a);
+
+RSA *q_RSA_new();
+void q_RSA_free(RSA *a);
+
+#ifndef OPENSSL_NO_EC
+
+EC_KEY *q_EC_KEY_dup(const EC_KEY *src);
+EC_KEY *q_EC_KEY_new_by_curve_name(int nid);
+void q_EC_KEY_free(EC_KEY *ecdh);
+
+#endif // OPENSSL_NO_EC
+
+int q_SSL_CTX_use_RSAPrivateKey(SSL_CTX *a, RSA *b);
+
+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
new file mode 100644
index 0000000000..57d09a649b
--- /dev/null
+++ b/src/plugins/tls/openssl/qtls_openssl.cpp
@@ -0,0 +1,1860 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qsslsocket_openssl_symbols_p.h"
+#include "qx509_openssl_p.h"
+#include "qtls_openssl_p.h"
+
+#ifdef Q_OS_WIN
+#include "qwindowscarootfetcher_p.h"
+#endif
+
+#include <QtNetwork/private/qsslpresharedkeyauthenticator_p.h>
+#include <QtNetwork/private/qsslcertificate_p.h>
+#include <QtNetwork/private/qocspresponse_p.h>
+#include <QtNetwork/private/qsslsocket_p.h>
+
+#include <QtNetwork/qsslpresharedkeyauthenticator.h>
+
+#include <QtCore/qscopedvaluerollback.h>
+#include <QtCore/qscopeguard.h>
+
+#include <algorithm>
+#include <cstring>
+
+QT_BEGIN_NAMESPACE
+
+using namespace Qt::StringLiterals;
+
+namespace {
+
+QSsl::AlertLevel tlsAlertLevel(int value)
+{
+ using QSsl::AlertLevel;
+
+ if (const char *typeString = q_SSL_alert_type_string(value)) {
+ // Documented to return 'W' for warning, 'F' for fatal,
+ // 'U' for unknown.
+ switch (typeString[0]) {
+ case 'W':
+ return AlertLevel::Warning;
+ case 'F':
+ return AlertLevel::Fatal;
+ default:;
+ }
+ }
+
+ return AlertLevel::Unknown;
+}
+
+QString tlsAlertDescription(int value)
+{
+ QString description = QLatin1StringView(q_SSL_alert_desc_string_long(value));
+ if (!description.size())
+ description = "no description provided"_L1;
+ return description;
+}
+
+QSsl::AlertType tlsAlertType(int value)
+{
+ // In case for some reason openssl gives us a value,
+ // which is not in our enum actually, we leave it to
+ // an application to handle (supposedly they have
+ // if or switch-statements).
+ return QSsl::AlertType(value & 0xff);
+}
+
+#ifdef Q_OS_WIN
+
+QSslCertificate findCertificateToFetch(const QList<QSslError> &tlsErrors, bool checkAIA)
+{
+ QSslCertificate certToFetch;
+
+ for (const auto &tlsError : tlsErrors) {
+ switch (tlsError.error()) {
+ case QSslError::UnableToGetLocalIssuerCertificate: // site presented intermediate cert, but root is unknown
+ case QSslError::SelfSignedCertificateInChain: // site presented a complete chain, but root is unknown
+ certToFetch = tlsError.certificate();
+ break;
+ case QSslError::SelfSignedCertificate:
+ case QSslError::CertificateBlacklisted:
+ //With these errors, we know it will be untrusted so save time by not asking windows
+ return QSslCertificate{};
+ default:
+#ifdef QSSLSOCKET_DEBUG
+ qCDebug(lcTlsBackend) << tlsError.errorString();
+#endif
+ //TODO - this part is strange.
+ break;
+ }
+ }
+
+ if (checkAIA) {
+ const auto extensions = certToFetch.extensions();
+ for (const auto &ext : extensions) {
+ if (ext.oid() == u"1.3.6.1.5.5.7.1.1") // See RFC 4325
+ return certToFetch;
+ }
+ //The only reason we check this extensions is because an application set trusted
+ //CA certificates explicitly, thus technically disabling CA fetch. So, if it's
+ //the case and an intermediate certificate is missing, and no extensions is
+ //present on the leaf certificate - we fail the handshake immediately.
+ return QSslCertificate{};
+ }
+
+ return certToFetch;
+}
+
+#endif // Q_OS_WIN
+
+} // unnamed namespace
+
+namespace QTlsPrivate {
+
+extern "C" {
+
+int q_X509Callback(int ok, X509_STORE_CTX *ctx)
+{
+ if (!ok) {
+ // Store the error and at which depth the error was detected.
+
+ using ErrorListPtr = QList<QSslErrorEntry> *;
+ ErrorListPtr errors = nullptr;
+
+ // Error list is attached to either 'SSL' or 'X509_STORE'.
+ if (X509_STORE *store = q_X509_STORE_CTX_get0_store(ctx)) // We try store first:
+ errors = ErrorListPtr(q_X509_STORE_get_ex_data(store, 0));
+
+ if (!errors) {
+ // Not found on store? Try SSL and its external data then. According to the OpenSSL's
+ // documentation:
+ //
+ // "Whenever a X509_STORE_CTX object is created for the verification of the
+ // peer's certificate during a handshake, a pointer to the SSL object is
+ // stored into the X509_STORE_CTX object to identify the connection affected.
+ // To retrieve this pointer the X509_STORE_CTX_get_ex_data() function can be
+ // used with the correct index."
+ const auto offset = QTlsBackendOpenSSL::s_indexForSSLExtraData
+ + TlsCryptographOpenSSL::errorOffsetInExData;
+ if (SSL *ssl = static_cast<SSL *>(q_X509_STORE_CTX_get_ex_data(
+ ctx, q_SSL_get_ex_data_X509_STORE_CTX_idx()))) {
+
+ // We may be in a renegotiation, check if we are inside a call to SSL_read:
+ const auto tlsOffset = QTlsBackendOpenSSL::s_indexForSSLExtraData
+ + TlsCryptographOpenSSL::socketOffsetInExData;
+ auto tls = static_cast<TlsCryptographOpenSSL *>(q_SSL_get_ex_data(ssl, tlsOffset));
+ Q_ASSERT(tls);
+ if (tls->isInSslRead()) {
+ // We are in a renegotiation, make a note of this for later.
+ // We'll check that the certificate is the same as the one we got during
+ // the initial handshake
+ tls->setRenegotiated(true);
+ return 1;
+ }
+
+ errors = ErrorListPtr(q_SSL_get_ex_data(ssl, offset));
+ }
+ }
+
+ if (!errors) {
+ qCWarning(lcTlsBackend, "Neither X509_STORE, nor SSL contains error list, handshake failure");
+ return 0;
+ }
+
+ errors->append(X509CertificateOpenSSL::errorEntryFromStoreContext(ctx));
+ }
+ // Always return OK to allow verification to continue. We handle the
+ // errors gracefully after collecting all errors, after verification has
+ // completed.
+ return 1;
+}
+
+int q_X509CallbackDirect(int ok, X509_STORE_CTX *ctx)
+{
+ // Passed to SSL_CTX_set_verify()
+ // https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_verify.html
+ // Returns 0 to abort verification, 1 to continue.
+
+ // This is a new, experimental verification callback, reporting
+ // errors immediately and returning 0 or 1 depending on an application
+ // either ignoring or not ignoring verification errors as they come.
+ if (!ctx) {
+ qCWarning(lcTlsBackend, "Invalid store context (nullptr)");
+ return 0;
+ }
+
+ if (!ok) {
+ // "Whenever a X509_STORE_CTX object is created for the verification of the
+ // peer's certificate during a handshake, a pointer to the SSL object is
+ // stored into the X509_STORE_CTX object to identify the connection affected.
+ // To retrieve this pointer the X509_STORE_CTX_get_ex_data() function can be
+ // used with the correct index."
+ SSL *ssl = static_cast<SSL *>(q_X509_STORE_CTX_get_ex_data(ctx, q_SSL_get_ex_data_X509_STORE_CTX_idx()));
+ if (!ssl) {
+ qCWarning(lcTlsBackend, "No external data (SSL) found in X509 store object");
+ return 0;
+ }
+
+ const auto offset = QTlsBackendOpenSSL::s_indexForSSLExtraData
+ + TlsCryptographOpenSSL::socketOffsetInExData;
+ auto crypto = static_cast<TlsCryptographOpenSSL *>(q_SSL_get_ex_data(ssl, offset));
+ if (!crypto) {
+ qCWarning(lcTlsBackend, "No external data (TlsCryptographOpenSSL) found in SSL object");
+ return 0;
+ }
+
+ return crypto->emitErrorFromCallback(ctx);
+ }
+ return 1;
+}
+
+#ifndef OPENSSL_NO_PSK
+static unsigned q_ssl_psk_client_callback(SSL *ssl, const char *hint, char *identity, unsigned max_identity_len,
+ unsigned char *psk, unsigned max_psk_len)
+{
+ auto *tls = static_cast<TlsCryptographOpenSSL *>(q_SSL_get_ex_data(ssl, QTlsBackendOpenSSL::s_indexForSSLExtraData));
+ return tls->pskClientTlsCallback(hint, identity, max_identity_len, psk, max_psk_len);
+}
+
+static unsigned int q_ssl_psk_server_callback(SSL *ssl, const char *identity, unsigned char *psk,
+ unsigned int max_psk_len)
+{
+ auto *tls = static_cast<TlsCryptographOpenSSL *>(q_SSL_get_ex_data(ssl, QTlsBackendOpenSSL::s_indexForSSLExtraData));
+ Q_ASSERT(tls);
+ return tls->pskServerTlsCallback(identity, psk, max_psk_len);
+}
+
+#ifdef TLS1_3_VERSION
+static unsigned q_ssl_psk_restore_client(SSL *ssl, const char *hint, char *identity, unsigned max_identity_len,
+ unsigned char *psk, unsigned max_psk_len)
+{
+ Q_UNUSED(hint);
+ Q_UNUSED(identity);
+ Q_UNUSED(max_identity_len);
+ Q_UNUSED(psk);
+ Q_UNUSED(max_psk_len);
+
+#ifdef QT_DEBUG
+ auto tls = static_cast<TlsCryptographOpenSSL *>(q_SSL_get_ex_data(ssl, QTlsBackendOpenSSL::s_indexForSSLExtraData));
+ Q_ASSERT(tls);
+ 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 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(md);
+ Q_UNUSED(id);
+ Q_UNUSED(idlen);
+ Q_UNUSED(sess);
+
+#ifdef QT_DEBUG
+ auto *tls = static_cast<TlsCryptographOpenSSL *>(q_SSL_get_ex_data(ssl, QTlsBackendOpenSSL::s_indexForSSLExtraData));
+ Q_ASSERT(tls);
+ Q_ASSERT(tls->d);
+ Q_ASSERT(tls->d->tlsMode() == QSslSocket::SslClientMode);
+#endif
+
+ // Temporarily rebind the psk because it will be called next. The function will restore it.
+ q_SSL_set_psk_client_callback(ssl, &q_ssl_psk_restore_client);
+
+ return 1; // need to return 1 or else "the connection setup fails."
+}
+
+int q_ssl_sess_set_new_cb(SSL *ssl, SSL_SESSION *session)
+{
+ if (!ssl) {
+ qCWarning(lcTlsBackend, "Invalid SSL (nullptr)");
+ return 0;
+ }
+ if (!session) {
+ qCWarning(lcTlsBackend, "Invalid SSL_SESSION (nullptr)");
+ return 0;
+ }
+
+ auto *tls = static_cast<TlsCryptographOpenSSL *>(q_SSL_get_ex_data(ssl, QTlsBackendOpenSSL::s_indexForSSLExtraData));
+ Q_ASSERT(tls);
+ return tls->handleNewSessionTicket(ssl);
+}
+#endif // TLS1_3_VERSION
+
+#endif // !OPENSSL_NO_PSK
+
+#if QT_CONFIG(ocsp)
+
+int qt_OCSP_status_server_callback(SSL *ssl, void *ocspRequest)
+{
+ Q_UNUSED(ocspRequest);
+ if (!ssl)
+ return SSL_TLSEXT_ERR_ALERT_FATAL;
+
+ auto crypto = static_cast<TlsCryptographOpenSSL *>(q_SSL_get_ex_data(ssl, QTlsBackendOpenSSL::s_indexForSSLExtraData));
+ if (!crypto)
+ return SSL_TLSEXT_ERR_ALERT_FATAL;
+
+ Q_ASSERT(crypto->d);
+ Q_ASSERT(crypto->d->tlsMode() == QSslSocket::SslServerMode);
+ const QByteArray &response = crypto->ocspResponseDer;
+ Q_ASSERT(response.size());
+
+ unsigned char *derCopy = static_cast<unsigned char *>(q_OPENSSL_malloc(size_t(response.size())));
+ if (!derCopy)
+ return SSL_TLSEXT_ERR_ALERT_FATAL;
+
+ std::copy(response.data(), response.data() + response.size(), derCopy);
+ // We don't check the return value: internally OpenSSL simply assigns the
+ // pointer (it assumes it now owns this memory btw!) and the length.
+ q_SSL_set_tlsext_status_ocsp_resp(ssl, derCopy, response.size());
+
+ return SSL_TLSEXT_ERR_OK;
+}
+
+#endif // ocsp
+
+void qt_AlertInfoCallback(const SSL *connection, int from, int value)
+{
+ // Passed to SSL_set_info_callback()
+ // https://www.openssl.org/docs/man1.1.1/man3/SSL_set_info_callback.html
+
+ if (!connection) {
+#ifdef QSSLSOCKET_DEBUG
+ qCWarning(lcTlsBackend, "Invalid 'connection' parameter (nullptr)");
+#endif // QSSLSOCKET_DEBUG
+ return;
+ }
+
+ const auto offset = QTlsBackendOpenSSL::s_indexForSSLExtraData
+ + TlsCryptographOpenSSL::socketOffsetInExData;
+ auto crypto = static_cast<TlsCryptographOpenSSL *>(q_SSL_get_ex_data(connection, offset));
+ if (!crypto) {
+ // SSL_set_ex_data can fail:
+#ifdef QSSLSOCKET_DEBUG
+ qCWarning(lcTlsBackend, "No external data (socket backend) found for parameter 'connection'");
+#endif // QSSLSOCKET_DEBUG
+ return;
+ }
+
+ if (!(from & SSL_CB_ALERT)) {
+ // We only want to know about alerts (at least for now).
+ return;
+ }
+
+ if (from & SSL_CB_WRITE)
+ crypto->alertMessageSent(value);
+ else
+ crypto->alertMessageReceived(value);
+}
+
+} // extern "C"
+
+#if QT_CONFIG(ocsp)
+namespace {
+
+QSslError::SslError qt_OCSP_response_status_to_SslError(long code)
+{
+ switch (code) {
+ case OCSP_RESPONSE_STATUS_MALFORMEDREQUEST:
+ return QSslError::OcspMalformedRequest;
+ case OCSP_RESPONSE_STATUS_INTERNALERROR:
+ return QSslError::OcspInternalError;
+ case OCSP_RESPONSE_STATUS_TRYLATER:
+ return QSslError::OcspTryLater;
+ case OCSP_RESPONSE_STATUS_SIGREQUIRED:
+ return QSslError::OcspSigRequred;
+ case OCSP_RESPONSE_STATUS_UNAUTHORIZED:
+ return QSslError::OcspUnauthorized;
+ case OCSP_RESPONSE_STATUS_SUCCESSFUL:
+ default:
+ return {};
+ }
+ Q_UNREACHABLE();
+}
+
+QOcspRevocationReason qt_OCSP_revocation_reason(int reason)
+{
+ switch (reason) {
+ case OCSP_REVOKED_STATUS_NOSTATUS:
+ return QOcspRevocationReason::None;
+ case OCSP_REVOKED_STATUS_UNSPECIFIED:
+ return QOcspRevocationReason::Unspecified;
+ case OCSP_REVOKED_STATUS_KEYCOMPROMISE:
+ return QOcspRevocationReason::KeyCompromise;
+ case OCSP_REVOKED_STATUS_CACOMPROMISE:
+ return QOcspRevocationReason::CACompromise;
+ case OCSP_REVOKED_STATUS_AFFILIATIONCHANGED:
+ return QOcspRevocationReason::AffiliationChanged;
+ case OCSP_REVOKED_STATUS_SUPERSEDED:
+ return QOcspRevocationReason::Superseded;
+ case OCSP_REVOKED_STATUS_CESSATIONOFOPERATION:
+ return QOcspRevocationReason::CessationOfOperation;
+ case OCSP_REVOKED_STATUS_CERTIFICATEHOLD:
+ return QOcspRevocationReason::CertificateHold;
+ case OCSP_REVOKED_STATUS_REMOVEFROMCRL:
+ return QOcspRevocationReason::RemoveFromCRL;
+ default:
+ return QOcspRevocationReason::None;
+ }
+
+ Q_UNREACHABLE();
+}
+
+bool qt_OCSP_certificate_match(OCSP_SINGLERESP *singleResponse, X509 *peerCert, X509 *issuer)
+{
+ // OCSP_basic_verify does verify that the responder is legit, the response is
+ // correctly signed, CertID is correct. But it does not know which certificate
+ // we were presented with by our peer, so it does not check if it's a response
+ // for our peer's certificate.
+ Q_ASSERT(singleResponse && peerCert && issuer);
+
+ const OCSP_CERTID *certId = q_OCSP_SINGLERESP_get0_id(singleResponse); // Does not increment refcount.
+ if (!certId) {
+ qCWarning(lcTlsBackend, "A SingleResponse without CertID");
+ return false;
+ }
+
+ ASN1_OBJECT *md = nullptr;
+ ASN1_INTEGER *reportedSerialNumber = nullptr;
+ const int result = q_OCSP_id_get0_info(nullptr, &md, nullptr, &reportedSerialNumber, const_cast<OCSP_CERTID *>(certId));
+ if (result != 1 || !md || !reportedSerialNumber) {
+ qCWarning(lcTlsBackend, "Failed to extract a hash and serial number from CertID structure");
+ return false;
+ }
+
+ if (!q_X509_get_serialNumber(peerCert)) {
+ // Is this possible at all? But we have to check this,
+ // ASN1_INTEGER_cmp (called from OCSP_id_cmp) dereferences
+ // without any checks at all.
+ qCWarning(lcTlsBackend, "No serial number in peer's ceritificate");
+ return false;
+ }
+
+ const int nid = q_OBJ_obj2nid(md);
+ if (nid == NID_undef) {
+ qCWarning(lcTlsBackend, "Unknown hash algorithm in CertID");
+ return false;
+ }
+
+ const EVP_MD *digest = q_EVP_get_digestbynid(nid); // Does not increment refcount.
+ if (!digest) {
+ qCWarning(lcTlsBackend) << "No digest for nid" << nid;
+ return false;
+ }
+
+ OCSP_CERTID *recreatedId = q_OCSP_cert_to_id(digest, peerCert, issuer);
+ if (!recreatedId) {
+ qCWarning(lcTlsBackend, "Failed to re-create CertID");
+ return false;
+ }
+ const QSharedPointer<OCSP_CERTID> guard(recreatedId, q_OCSP_CERTID_free);
+
+ if (q_OCSP_id_cmp(const_cast<OCSP_CERTID *>(certId), recreatedId)) {
+ qCDebug(lcTlsBackend, "Certificate ID mismatch");
+ return false;
+ }
+ // Bingo!
+ return true;
+}
+
+} // unnamed namespace
+#endif // ocsp
+
+TlsCryptographOpenSSL::~TlsCryptographOpenSSL()
+{
+ destroySslContext();
+}
+
+void TlsCryptographOpenSSL::init(QSslSocket *qObj, QSslSocketPrivate *dObj)
+{
+ Q_ASSERT(qObj);
+ Q_ASSERT(dObj);
+ q = qObj;
+ d = dObj;
+
+ ocspResponses.clear();
+ ocspResponseDer.clear();
+
+ systemOrSslErrorDetected = false;
+ handshakeInterrupted = false;
+
+ fetchAuthorityInformation = false;
+ caToFetch.reset();
+}
+
+void TlsCryptographOpenSSL::checkSettingSslContext(std::shared_ptr<QSslContext> tlsContext)
+{
+ if (!sslContextPointer)
+ sslContextPointer = std::move(tlsContext);
+}
+
+std::shared_ptr<QSslContext> TlsCryptographOpenSSL::sslContext() const
+{
+ return sslContextPointer;
+}
+
+QList<QSslError> TlsCryptographOpenSSL::tlsErrors() const
+{
+ return sslErrors;
+}
+
+void TlsCryptographOpenSSL::startClientEncryption()
+{
+ if (!initSslContext()) {
+ Q_ASSERT(d);
+ setErrorAndEmit(d, QAbstractSocket::SslInternalError,
+ QSslSocket::tr("Unable to init SSL Context: %1").arg(QTlsBackendOpenSSL::getErrorsFromOpenSsl()));
+ return;
+ }
+
+ // Start connecting. This will place outgoing data in the BIO, so we
+ // follow up with calling transmit().
+ startHandshake();
+ transmit();
+}
+
+void TlsCryptographOpenSSL::startServerEncryption()
+{
+ if (!initSslContext()) {
+ Q_ASSERT(d);
+ setErrorAndEmit(d, QAbstractSocket::SslInternalError,
+ QSslSocket::tr("Unable to init SSL Context: %1").arg(QTlsBackendOpenSSL::getErrorsFromOpenSsl()));
+ return;
+ }
+
+ // Start connecting. This will place outgoing data in the BIO, so we
+ // follow up with calling transmit().
+ startHandshake();
+ transmit();
+}
+
+bool TlsCryptographOpenSSL::startHandshake()
+{
+ // Check if the connection has been established. Get all errors from the
+ // verification stage.
+ Q_ASSERT(q);
+ Q_ASSERT(d);
+
+ using ScopedBool = QScopedValueRollback<bool>;
+
+ if (inSetAndEmitError)
+ return false;
+
+ const auto mode = d->tlsMode();
+
+ pendingFatalAlert = false;
+ errorsReportedFromCallback = false;
+ QList<QSslErrorEntry> lastErrors;
+ q_SSL_set_ex_data(ssl, QTlsBackendOpenSSL::s_indexForSSLExtraData + errorOffsetInExData, &lastErrors);
+
+ // SSL_set_ex_data can fail, but see the callback's code - we handle this there.
+ q_SSL_set_ex_data(ssl, QTlsBackendOpenSSL::s_indexForSSLExtraData + socketOffsetInExData, this);
+ q_SSL_set_info_callback(ssl, qt_AlertInfoCallback);
+
+ int result = (mode == QSslSocket::SslClientMode) ? q_SSL_connect(ssl) : q_SSL_accept(ssl);
+ q_SSL_set_ex_data(ssl, QTlsBackendOpenSSL::s_indexForSSLExtraData + errorOffsetInExData, nullptr);
+ // Note, unlike errors as external data on SSL object, we do not unset
+ // a callback/ex-data if alert notifications are enabled: an alert can
+ // arrive after the handshake, for example, this happens when the server
+ // does not find a ClientCert or does not like it.
+
+ if (!lastErrors.isEmpty() || errorsReportedFromCallback)
+ storePeerCertificates();
+
+ // storePeerCertificate() if called above - would update the
+ // configuration with peer's certificates.
+ auto configuration = q->sslConfiguration();
+ if (!errorsReportedFromCallback) {
+ const auto &peerCertificateChain = configuration.peerCertificateChain();
+ for (const auto &currentError : std::as_const(lastErrors)) {
+ emit q->peerVerifyError(QTlsPrivate::X509CertificateOpenSSL::openSSLErrorToQSslError(currentError.code,
+ peerCertificateChain.value(currentError.depth)));
+ if (q->state() != QAbstractSocket::ConnectedState)
+ break;
+ }
+ }
+
+ errorList << lastErrors;
+
+ // Connection aborted during handshake phase.
+ if (q->state() != QAbstractSocket::ConnectedState)
+ return false;
+
+ // Check if we're encrypted or not.
+ if (result <= 0) {
+ switch (q_SSL_get_error(ssl, result)) {
+ case SSL_ERROR_WANT_READ:
+ case SSL_ERROR_WANT_WRITE:
+ // The handshake is not yet complete.
+ break;
+ default:
+ QString errorString = QTlsBackendOpenSSL::msgErrorsDuringHandshake();
+#ifdef QSSLSOCKET_DEBUG
+ qCDebug(lcTlsBackend) << "TlsCryptographOpenSSL::startHandshake: error!" << errorString;
+#endif
+ {
+ const ScopedBool bg(inSetAndEmitError, true);
+ setErrorAndEmit(d, QAbstractSocket::SslHandshakeFailedError, errorString);
+ if (pendingFatalAlert) {
+ trySendFatalAlert();
+ pendingFatalAlert = false;
+ }
+ }
+ q->abort();
+ }
+ return false;
+ }
+
+ // store peer certificate chain
+ storePeerCertificates();
+
+ // Start translating errors.
+ QList<QSslError> errors;
+
+ // Note, the storePeerCerificates() probably updated the configuration at this point.
+ configuration = q->sslConfiguration();
+ // Check the whole chain for blacklisting (including root, as we check for subjectInfo and issuer)
+ const auto &peerCertificateChain = configuration.peerCertificateChain();
+ for (const QSslCertificate &cert : peerCertificateChain) {
+ if (QSslCertificatePrivate::isBlacklisted(cert)) {
+ QSslError error(QSslError::CertificateBlacklisted, cert);
+ errors << error;
+ emit q->peerVerifyError(error);
+ if (q->state() != QAbstractSocket::ConnectedState)
+ return false;
+ }
+ }
+
+ const bool doVerifyPeer = configuration.peerVerifyMode() == QSslSocket::VerifyPeer
+ || (configuration.peerVerifyMode() == QSslSocket::AutoVerifyPeer
+ && mode == QSslSocket::SslClientMode);
+
+#if QT_CONFIG(ocsp)
+ // For now it's always QSslSocket::SslClientMode - initSslContext() will bail out early,
+ // if it's enabled in QSslSocket::SslServerMode. This can change.
+ if (!configuration.peerCertificate().isNull() && configuration.ocspStaplingEnabled() && doVerifyPeer) {
+ if (!checkOcspStatus()) {
+ if (ocspErrors.isEmpty()) {
+ {
+ const ScopedBool bg(inSetAndEmitError, true);
+ setErrorAndEmit(d, QAbstractSocket::SslHandshakeFailedError, ocspErrorDescription);
+ }
+ q->abort();
+ return false;
+ }
+
+ for (const QSslError &error : ocspErrors) {
+ errors << error;
+ emit q->peerVerifyError(error);
+ if (q->state() != QAbstractSocket::ConnectedState)
+ return false;
+ }
+ }
+ }
+#endif // ocsp
+
+ // Check the peer certificate itself. First try the subject's common name
+ // (CN) as a wildcard, then try all alternate subject name DNS entries the
+ // same way.
+ if (!configuration.peerCertificate().isNull()) {
+ // but only if we're a client connecting to a server
+ // if we're the server, don't check CN
+ const auto verificationPeerName = d->verificationName();
+ if (mode == QSslSocket::SslClientMode) {
+ QString peerName = (verificationPeerName.isEmpty () ? q->peerName() : verificationPeerName);
+
+ if (!isMatchingHostname(configuration.peerCertificate(), peerName)) {
+ // No matches in common names or alternate names.
+ QSslError error(QSslError::HostNameMismatch, configuration.peerCertificate());
+ errors << error;
+ emit q->peerVerifyError(error);
+ if (q->state() != QAbstractSocket::ConnectedState)
+ return false;
+ }
+ }
+ } else {
+ // No peer certificate presented. Report as error if the socket
+ // expected one.
+ if (doVerifyPeer) {
+ QSslError error(QSslError::NoPeerCertificate);
+ errors << error;
+ emit q->peerVerifyError(error);
+ if (q->state() != QAbstractSocket::ConnectedState)
+ return false;
+ }
+ }
+
+ // Translate errors from the error list into QSslErrors.
+ errors.reserve(errors.size() + errorList.size());
+ for (const auto &error : std::as_const(errorList))
+ errors << X509CertificateOpenSSL::openSSLErrorToQSslError(error.code, peerCertificateChain.value(error.depth));
+
+ if (!errors.isEmpty()) {
+ sslErrors = errors;
+#ifdef Q_OS_WIN
+ const bool fetchEnabled = QSslSocketPrivate::rootCertOnDemandLoadingSupported()
+ && d->isRootsOnDemandAllowed();
+ // !fetchEnabled is a special case scenario, when we potentially have a missing
+ // intermediate certificate and a recoverable chain, but on demand cert loading
+ // was disabled by setCaCertificates call. For this scenario we check if "Authority
+ // Information Access" is present - wincrypt can deal with such certificates.
+ QSslCertificate certToFetch;
+ if (doVerifyPeer && !d->verifyErrorsHaveBeenIgnored())
+ certToFetch = findCertificateToFetch(sslErrors, !fetchEnabled);
+
+ //Skip this if not using system CAs, or if the SSL errors are configured in advance to be ignorable
+ if (!certToFetch.isNull()) {
+ fetchAuthorityInformation = !fetchEnabled;
+ //Windows desktop versions starting from vista ship with minimal set of roots and download on demand
+ //from the windows update server CA roots that are trusted by MS. It also can fetch a missing intermediate
+ //in case "Authority Information Access" extension is present.
+ //
+ //However, this is only transparent if using WinINET - we have to trigger it
+ //ourselves.
+ fetchCaRootForCert(certToFetch);
+ return false;
+ }
+#endif // Q_OS_WIN
+ if (!checkSslErrors())
+ return false;
+ // A slot, attached to sslErrors signal can call
+ // abort/close/disconnetFromHost/etc; no need to
+ // continue handshake then.
+ if (q->state() != QAbstractSocket::ConnectedState)
+ return false;
+ } else {
+ sslErrors.clear();
+ }
+
+ continueHandshake();
+ return true;
+}
+
+void TlsCryptographOpenSSL::enableHandshakeContinuation()
+{
+ handshakeInterrupted = false;
+}
+
+void TlsCryptographOpenSSL::cancelCAFetch()
+{
+ fetchAuthorityInformation = false;
+ caToFetch.reset();
+}
+
+void TlsCryptographOpenSSL::continueHandshake()
+{
+ Q_ASSERT(q);
+ Q_ASSERT(d);
+
+ auto *plainSocket = d->plainTcpSocket();
+ Q_ASSERT(plainSocket);
+
+ const auto mode = d->tlsMode();
+
+ // if we have a max read buffer size, reset the plain socket's to match
+ if (const auto maxSize = d->maxReadBufferSize())
+ plainSocket->setReadBufferSize(maxSize);
+
+ if (q_SSL_session_reused(ssl))
+ QTlsBackend::setPeerSessionShared(d, true);
+
+#ifdef QT_DECRYPT_SSL_TRAFFIC
+ if (q_SSL_get_session(ssl)) {
+ size_t master_key_len = q_SSL_SESSION_get_master_key(q_SSL_get_session(ssl), nullptr, 0);
+ size_t client_random_len = q_SSL_get_client_random(ssl, nullptr, 0);
+ QByteArray masterKey(int(master_key_len), Qt::Uninitialized); // Will not overflow
+ QByteArray clientRandom(int(client_random_len), Qt::Uninitialized); // Will not overflow
+
+ q_SSL_SESSION_get_master_key(q_SSL_get_session(ssl),
+ reinterpret_cast<unsigned char*>(masterKey.data()),
+ masterKey.size());
+ q_SSL_get_client_random(ssl, reinterpret_cast<unsigned char *>(clientRandom.data()),
+ clientRandom.size());
+
+ QByteArray debugLineClientRandom("CLIENT_RANDOM ");
+ debugLineClientRandom.append(clientRandom.toHex().toUpper());
+ debugLineClientRandom.append(" ");
+ debugLineClientRandom.append(masterKey.toHex().toUpper());
+ debugLineClientRandom.append("\n");
+
+ QString sslKeyFile = QDir::tempPath() + "/qt-ssl-keys"_L1;
+ QFile file(sslKeyFile);
+ if (!file.open(QIODevice::Append))
+ qCWarning(lcTlsBackend) << "could not open file" << sslKeyFile << "for appending";
+ if (!file.write(debugLineClientRandom))
+ qCWarning(lcTlsBackend) << "could not write to file" << sslKeyFile;
+ file.close();
+ } else {
+ qCWarning(lcTlsBackend, "could not decrypt SSL traffic");
+ }
+#endif // QT_DECRYPT_SSL_TRAFFIC
+
+ const auto &configuration = q->sslConfiguration();
+ // Cache this SSL session inside the QSslContext
+ if (!(configuration.testSslOption(QSsl::SslOptionDisableSessionSharing))) {
+ if (!sslContextPointer->cacheSession(ssl)) {
+ sslContextPointer.reset(); // we could not cache the session
+ } else {
+ // Cache the session for permanent usage as well
+ if (!(configuration.testSslOption(QSsl::SslOptionDisableSessionPersistence))) {
+ if (!sslContextPointer->sessionASN1().isEmpty())
+ QTlsBackend::setSessionAsn1(d, sslContextPointer->sessionASN1());
+ QTlsBackend::setSessionLifetimeHint(d, sslContextPointer->sessionTicketLifeTimeHint());
+ }
+ }
+ }
+
+#if !defined(OPENSSL_NO_NEXTPROTONEG)
+
+ QTlsBackend::setAlpnStatus(d, sslContextPointer->npnContext().status);
+ if (sslContextPointer->npnContext().status == QSslConfiguration::NextProtocolNegotiationUnsupported) {
+ // we could not agree -> be conservative and use HTTP/1.1
+ // T.P.: I have to admit, this is a really strange notion of 'conservative',
+ // given the protocol-neutral nature of ALPN/NPN.
+ QTlsBackend::setNegotiatedProtocol(d, QByteArrayLiteral("http/1.1"));
+ } else {
+ const unsigned char *proto = nullptr;
+ unsigned int proto_len = 0;
+
+ q_SSL_get0_alpn_selected(ssl, &proto, &proto_len);
+ if (proto_len && mode == QSslSocket::SslClientMode) {
+ // Client does not have a callback that sets it ...
+ QTlsBackend::setAlpnStatus(d, QSslConfiguration::NextProtocolNegotiationNegotiated);
+ }
+
+ if (!proto_len) { // Test if NPN was more lucky ...
+ q_SSL_get0_next_proto_negotiated(ssl, &proto, &proto_len);
+ }
+
+ if (proto_len)
+ QTlsBackend::setNegotiatedProtocol(d, QByteArray(reinterpret_cast<const char *>(proto), proto_len));
+ else
+ QTlsBackend::setNegotiatedProtocol(d,{});
+ }
+#endif // !defined(OPENSSL_NO_NEXTPROTONEG)
+
+ if (mode == QSslSocket::SslClientMode) {
+ EVP_PKEY *key;
+ if (q_SSL_get_server_tmp_key(ssl, &key))
+ QTlsBackend::setEphemeralKey(d, QSslKey(key, QSsl::PublicKey));
+ }
+
+ d->setEncrypted(true);
+ emit q->encrypted();
+ if (d->isAutoStartingHandshake() && d->isPendingClose()) {
+ d->setPendingClose(false);
+ q->disconnectFromHost();
+ }
+}
+
+void TlsCryptographOpenSSL::transmit()
+{
+ Q_ASSERT(q);
+ Q_ASSERT(d);
+
+ using ScopedBool = QScopedValueRollback<bool>;
+
+ if (inSetAndEmitError)
+ return;
+
+ // If we don't have any SSL context, don't bother transmitting.
+ if (!ssl)
+ return;
+
+ auto &writeBuffer = d->tlsWriteBuffer();
+ auto &buffer = d->tlsBuffer();
+ auto *plainSocket = d->plainTcpSocket();
+ Q_ASSERT(plainSocket);
+ bool &emittedBytesWritten = d->tlsEmittedBytesWritten();
+
+ bool transmitting;
+ do {
+ transmitting = false;
+
+ // If the connection is secure, we can transfer data from the write
+ // buffer (in plain text) to the write BIO through SSL_write.
+ if (q->isEncrypted() && !writeBuffer.isEmpty()) {
+ qint64 totalBytesWritten = 0;
+ int nextDataBlockSize;
+ while ((nextDataBlockSize = writeBuffer.nextDataBlockSize()) > 0) {
+ int writtenBytes = q_SSL_write(ssl, writeBuffer.readPointer(), nextDataBlockSize);
+ if (writtenBytes <= 0) {
+ int error = q_SSL_get_error(ssl, writtenBytes);
+ //write can result in a want_write_error - not an error - continue transmitting
+ if (error == SSL_ERROR_WANT_WRITE) {
+ transmitting = true;
+ break;
+ } else if (error == SSL_ERROR_WANT_READ) {
+ //write can result in a want_read error, possibly due to renegotiation - not an error - stop transmitting
+ transmitting = false;
+ break;
+ } else {
+ // ### Better error handling.
+ const ScopedBool bg(inSetAndEmitError, true);
+ setErrorAndEmit(d, QAbstractSocket::SslInternalError,
+ QSslSocket::tr("Unable to write data: %1").arg(
+ QTlsBackendOpenSSL::getErrorsFromOpenSsl()));
+ return;
+ }
+ }
+#ifdef QSSLSOCKET_DEBUG
+ qCDebug(lcTlsBackend) << "TlsCryptographOpenSSL::transmit: encrypted" << writtenBytes << "bytes";
+#endif
+ writeBuffer.free(writtenBytes);
+ totalBytesWritten += writtenBytes;
+
+ if (writtenBytes < nextDataBlockSize) {
+ // break out of the writing loop and try again after we had read
+ transmitting = true;
+ break;
+ }
+ }
+
+ if (totalBytesWritten > 0) {
+ // Don't emit bytesWritten() recursively.
+ if (!emittedBytesWritten) {
+ emittedBytesWritten = true;
+ emit q->bytesWritten(totalBytesWritten);
+ emittedBytesWritten = false;
+ }
+ emit q->channelBytesWritten(0, totalBytesWritten);
+ }
+ }
+
+ // Check if we've got any data to be written to the socket.
+ QVarLengthArray<char, 4096> data;
+ int pendingBytes;
+ while (plainSocket->isValid() && (pendingBytes = q_BIO_pending(writeBio)) > 0
+ && plainSocket->openMode() != QIODevice::NotOpen) {
+ // Read encrypted data from the write BIO into a buffer.
+ data.resize(pendingBytes);
+ int encryptedBytesRead = q_BIO_read(writeBio, data.data(), pendingBytes);
+
+ // Write encrypted data from the buffer to the socket.
+ qint64 actualWritten = plainSocket->write(data.constData(), encryptedBytesRead);
+#ifdef QSSLSOCKET_DEBUG
+ qCDebug(lcTlsBackend) << "TlsCryptographOpenSSL::transmit: wrote" << encryptedBytesRead
+ << "encrypted bytes to the socket" << actualWritten << "actual.";
+#endif
+ if (actualWritten < 0) {
+ //plain socket write fails if it was in the pending close state.
+ const ScopedBool bg(inSetAndEmitError, true);
+ setErrorAndEmit(d, plainSocket->error(), plainSocket->errorString());
+ return;
+ }
+ transmitting = true;
+ }
+
+ // Check if we've got any data to be read from the socket.
+ if (!q->isEncrypted() || !d->maxReadBufferSize() || buffer.size() < d->maxReadBufferSize())
+ while ((pendingBytes = plainSocket->bytesAvailable()) > 0) {
+ // Read encrypted data from the socket into a buffer.
+ data.resize(pendingBytes);
+ // just peek() here because q_BIO_write could write less data than expected
+ int encryptedBytesRead = plainSocket->peek(data.data(), pendingBytes);
+
+#ifdef QSSLSOCKET_DEBUG
+ qCDebug(lcTlsBackend) << "TlsCryptographOpenSSL::transmit: read" << encryptedBytesRead << "encrypted bytes from the socket";
+#endif
+ // Write encrypted data from the buffer into the read BIO.
+ int writtenToBio = q_BIO_write(readBio, data.constData(), encryptedBytesRead);
+
+ // Throw away the results.
+ if (writtenToBio > 0) {
+ plainSocket->skip(writtenToBio);
+ } else {
+ // ### Better error handling.
+ const ScopedBool bg(inSetAndEmitError, true);
+ setErrorAndEmit(d, QAbstractSocket::SslInternalError,
+ QSslSocket::tr("Unable to decrypt data: %1")
+ .arg(QTlsBackendOpenSSL::getErrorsFromOpenSsl()));
+ return;
+ }
+
+ transmitting = true;
+ }
+
+ // If the connection isn't secured yet, this is the time to retry the
+ // connect / accept.
+ if (!q->isEncrypted()) {
+#ifdef QSSLSOCKET_DEBUG
+ qCDebug(lcTlsBackend) << "TlsCryptographOpenSSL::transmit: testing encryption";
+#endif
+ if (startHandshake()) {
+#ifdef QSSLSOCKET_DEBUG
+ qCDebug(lcTlsBackend) << "TlsCryptographOpenSSL::transmit: encryption established";
+#endif
+ d->setEncrypted(true);
+ transmitting = true;
+ } else if (plainSocket->state() != QAbstractSocket::ConnectedState) {
+#ifdef QSSLSOCKET_DEBUG
+ qCDebug(lcTlsBackend) << "TlsCryptographOpenSSL::transmit: connection lost";
+#endif
+ break;
+ } else if (d->isPaused()) {
+ // just wait until the user continues
+ return;
+ } else {
+#ifdef QSSLSOCKET_DEBUG
+ qCDebug(lcTlsBackend) << "TlsCryptographOpenSSL::transmit: encryption not done yet";
+#endif
+ }
+ }
+
+ // If the request is small and the remote host closes the transmission
+ // after sending, there's a chance that startHandshake() will already
+ // have triggered a shutdown.
+ if (!ssl)
+ continue;
+
+ // We always read everything from the SSL decryption buffers, even if
+ // we have a readBufferMaxSize. There's no point in leaving data there
+ // just so that readBuffer.size() == readBufferMaxSize.
+ int readBytes = 0;
+ const int bytesToRead = 4096;
+ do {
+ if (q->readChannelCount() == 0) {
+ // The read buffer is deallocated, don't try resize or write to it.
+ break;
+ }
+ // Don't use SSL_pending(). It's very unreliable.
+ inSslRead = true;
+ readBytes = q_SSL_read(ssl, buffer.reserve(bytesToRead), bytesToRead);
+ inSslRead = false;
+ if (renegotiated) {
+ renegotiated = false;
+ X509 *x509 = q_SSL_get_peer_certificate(ssl);
+ const auto peerCertificate =
+ QTlsPrivate::X509CertificateOpenSSL::certificateFromX509(x509);
+ // Fail the renegotiate if the certificate has changed, else: continue.
+ if (peerCertificate != q->peerCertificate()) {
+ const ScopedBool bg(inSetAndEmitError, true);
+ setErrorAndEmit(
+ d, QAbstractSocket::RemoteHostClosedError,
+ QSslSocket::tr(
+ "TLS certificate unexpectedly changed during renegotiation!"));
+ q->abort();
+ return;
+ }
+ }
+ if (readBytes > 0) {
+#ifdef QSSLSOCKET_DEBUG
+ qCDebug(lcTlsBackend) << "TlsCryptographOpenSSL::transmit: decrypted" << readBytes << "bytes";
+#endif
+ buffer.chop(bytesToRead - readBytes);
+
+ if (bool *readyReadEmittedPointer = d->readyReadPointer())
+ *readyReadEmittedPointer = true;
+ emit q->readyRead();
+ emit q->channelReadyRead(0);
+ transmitting = true;
+ continue;
+ }
+ buffer.chop(bytesToRead);
+
+ // Error.
+ switch (q_SSL_get_error(ssl, readBytes)) {
+ case SSL_ERROR_WANT_READ:
+ case SSL_ERROR_WANT_WRITE:
+ // Out of data.
+ break;
+ case SSL_ERROR_ZERO_RETURN:
+ // The remote host closed the connection.
+#ifdef QSSLSOCKET_DEBUG
+ qCDebug(lcTlsBackend) << "TlsCryptographOpenSSL::transmit: remote disconnect";
+#endif
+ shutdown = true; // the other side shut down, make sure we do not send shutdown ourselves
+ {
+ const ScopedBool bg(inSetAndEmitError, true);
+ setErrorAndEmit(d, QAbstractSocket::RemoteHostClosedError,
+ QSslSocket::tr("The TLS/SSL connection has been closed"));
+ }
+ return;
+ case SSL_ERROR_SYSCALL: // some IO error
+ case SSL_ERROR_SSL: // error in the SSL library
+ // we do not know exactly what the error is, nor whether we can recover from it,
+ // so just return to prevent an endless loop in the outer "while" statement
+ systemOrSslErrorDetected = true;
+ {
+ const ScopedBool bg(inSetAndEmitError, true);
+ setErrorAndEmit(d, QAbstractSocket::SslInternalError,
+ QSslSocket::tr("Error while reading: %1")
+ .arg(QTlsBackendOpenSSL::getErrorsFromOpenSsl()));
+ }
+ return;
+ default:
+ // SSL_ERROR_WANT_CONNECT, SSL_ERROR_WANT_ACCEPT: can only happen with a
+ // BIO_s_connect() or BIO_s_accept(), which we do not call.
+ // SSL_ERROR_WANT_X509_LOOKUP: can only happen with a
+ // SSL_CTX_set_client_cert_cb(), which we do not call.
+ // So this default case should never be triggered.
+ {
+ const ScopedBool bg(inSetAndEmitError, true);
+ setErrorAndEmit(d, QAbstractSocket::SslInternalError,
+ QSslSocket::tr("Error while reading: %1")
+ .arg(QTlsBackendOpenSSL::getErrorsFromOpenSsl()));
+ }
+ break;
+ }
+ } while (ssl && readBytes > 0);
+ } while (ssl && transmitting);
+}
+
+void TlsCryptographOpenSSL::disconnectFromHost()
+{
+ if (ssl) {
+ if (!shutdown && !q_SSL_in_init(ssl) && !systemOrSslErrorDetected) {
+ if (q_SSL_shutdown(ssl) != 1) {
+ // Some error may be queued, clear it.
+ QTlsBackendOpenSSL::clearErrorQueue();
+ }
+ shutdown = true;
+ transmit();
+ }
+ }
+ Q_ASSERT(d);
+ auto *plainSocket = d->plainTcpSocket();
+ Q_ASSERT(plainSocket);
+ plainSocket->disconnectFromHost();
+}
+
+void TlsCryptographOpenSSL::disconnected()
+{
+ Q_ASSERT(d);
+ auto *plainSocket = d->plainTcpSocket();
+ Q_ASSERT(plainSocket);
+ d->setEncrypted(false);
+
+ if (plainSocket->bytesAvailable() <= 0) {
+ destroySslContext();
+ } else {
+ // Move all bytes into the plain buffer.
+ const qint64 tmpReadBufferMaxSize = d->maxReadBufferSize();
+ // Reset temporarily, so the plain socket buffer is completely drained:
+ d->setMaxReadBufferSize(0);
+ transmit();
+ d->setMaxReadBufferSize(tmpReadBufferMaxSize);
+ }
+ //if there is still buffered data in the plain socket, don't destroy the ssl context yet.
+ //it will be destroyed when the socket is deleted.
+}
+
+QSslCipher TlsCryptographOpenSSL::sessionCipher() const
+{
+ if (!ssl)
+ return {};
+
+ const SSL_CIPHER *sessionCipher = q_SSL_get_current_cipher(ssl);
+ return sessionCipher ? QTlsBackendOpenSSL::qt_OpenSSL_cipher_to_QSslCipher(sessionCipher) : QSslCipher{};
+}
+
+QSsl::SslProtocol TlsCryptographOpenSSL::sessionProtocol() const
+{
+ if (!ssl)
+ return QSsl::UnknownProtocol;
+
+ 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:
+ return QSsl::TlsV1_3;
+ }
+
+ return QSsl::UnknownProtocol;
+}
+
+QList<QOcspResponse> TlsCryptographOpenSSL::ocsps() const
+{
+ return ocspResponses;
+}
+
+bool TlsCryptographOpenSSL::checkSslErrors()
+{
+ Q_ASSERT(q);
+ Q_ASSERT(d);
+
+ if (sslErrors.isEmpty())
+ return true;
+
+ emit q->sslErrors(sslErrors);
+
+ const auto vfyMode = q->peerVerifyMode();
+ const auto mode = d->tlsMode();
+
+ bool doVerifyPeer = vfyMode == QSslSocket::VerifyPeer || (vfyMode == QSslSocket::AutoVerifyPeer
+ && mode == QSslSocket::SslClientMode);
+ bool doEmitSslError = !d->verifyErrorsHaveBeenIgnored();
+ // check whether we need to emit an SSL handshake error
+ if (doVerifyPeer && doEmitSslError) {
+ if (q->pauseMode() & QAbstractSocket::PauseOnSslErrors) {
+ QSslSocketPrivate::pauseSocketNotifiers(q);
+ d->setPaused(true);
+ } else {
+ setErrorAndEmit(d, QAbstractSocket::SslHandshakeFailedError, sslErrors.constFirst().errorString());
+ auto *plainSocket = d->plainTcpSocket();
+ Q_ASSERT(plainSocket);
+ plainSocket->disconnectFromHost();
+ }
+ return false;
+ }
+ return true;
+}
+
+int TlsCryptographOpenSSL::handleNewSessionTicket(SSL *connection)
+{
+ // If we return 1, this means we own the session, but we don't.
+ // 0 would tell OpenSSL to deref (but they still have it in the
+ // internal cache).
+ Q_ASSERT(connection);
+
+ Q_ASSERT(q);
+ Q_ASSERT(d);
+
+ if (q->sslConfiguration().testSslOption(QSsl::SslOptionDisableSessionPersistence)) {
+ // We silently ignore, do nothing, remove from cache.
+ return 0;
+ }
+
+ SSL_SESSION *currentSession = q_SSL_get_session(connection);
+ if (!currentSession) {
+ qCWarning(lcTlsBackend,
+ "New session ticket callback, the session is invalid (nullptr)");
+ return 0;
+ }
+
+ if (q_SSL_version(connection) < 0x304) {
+ // We only rely on this mechanics with TLS >= 1.3
+ return 0;
+ }
+
+#ifdef TLS1_3_VERSION
+ if (!q_SSL_SESSION_is_resumable(currentSession)) {
+ qCDebug(lcTlsBackend, "New session ticket, but the session is non-resumable");
+ return 0;
+ }
+#endif // TLS1_3_VERSION
+
+ const int sessionSize = q_i2d_SSL_SESSION(currentSession, nullptr);
+ if (sessionSize <= 0) {
+ qCWarning(lcTlsBackend, "could not store persistent version of SSL session");
+ return 0;
+ }
+
+ // We have somewhat perverse naming, it's not a ticket, it's a session.
+ QByteArray sessionTicket(sessionSize, 0);
+ auto data = reinterpret_cast<unsigned char *>(sessionTicket.data());
+ if (!q_i2d_SSL_SESSION(currentSession, &data)) {
+ qCWarning(lcTlsBackend, "could not store persistent version of SSL session");
+ return 0;
+ }
+
+ QTlsBackend::setSessionAsn1(d, sessionTicket);
+ QTlsBackend::setSessionLifetimeHint(d, q_SSL_SESSION_get_ticket_lifetime_hint(currentSession));
+
+ emit q->newSessionTicketReceived();
+ return 0;
+}
+
+void TlsCryptographOpenSSL::alertMessageSent(int value)
+{
+ Q_ASSERT(q);
+ Q_ASSERT(d);
+
+ const auto level = tlsAlertLevel(value);
+ if (level == QSsl::AlertLevel::Fatal && !q->isEncrypted()) {
+ // Note, this logic is handshake-time only:
+ pendingFatalAlert = true;
+ }
+
+ emit q->alertSent(level, tlsAlertType(value), tlsAlertDescription(value));
+
+}
+
+void TlsCryptographOpenSSL::alertMessageReceived(int value)
+{
+ Q_ASSERT(q);
+
+ emit q->alertReceived(tlsAlertLevel(value), tlsAlertType(value), tlsAlertDescription(value));
+}
+
+int TlsCryptographOpenSSL::emitErrorFromCallback(X509_STORE_CTX *ctx)
+{
+ // Returns 0 to abort verification, 1 to continue despite error (as
+ // OpenSSL expects from the verification callback).
+ Q_ASSERT(q);
+ Q_ASSERT(ctx);
+
+ using ScopedBool = QScopedValueRollback<bool>;
+ // While we are not setting, we are emitting and in general -
+ // we want to prevent accidental recursive startHandshake()
+ // calls:
+ const ScopedBool bg(inSetAndEmitError, true);
+
+ X509 *x509 = q_X509_STORE_CTX_get_current_cert(ctx);
+ if (!x509) {
+ qCWarning(lcTlsBackend, "Could not obtain the certificate (that failed to verify)");
+ return 0;
+ }
+
+ const QSslCertificate certificate = QTlsPrivate::X509CertificateOpenSSL::certificateFromX509(x509);
+ const auto errorAndDepth = QTlsPrivate::X509CertificateOpenSSL::errorEntryFromStoreContext(ctx);
+ const QSslError tlsError = QTlsPrivate::X509CertificateOpenSSL::openSSLErrorToQSslError(errorAndDepth.code, certificate);
+
+ errorsReportedFromCallback = true;
+ handshakeInterrupted = true;
+ emit q->handshakeInterruptedOnError(tlsError);
+
+ // Conveniently so, we also can access 'lastErrors' external data set
+ // in startHandshake, we store it for the case an application later
+ // wants to check errors (ignored or not):
+ const auto offset = QTlsBackendOpenSSL::s_indexForSSLExtraData
+ + TlsCryptographOpenSSL::errorOffsetInExData;
+ if (auto errorList = static_cast<QList<QSslErrorEntry> *>(q_SSL_get_ex_data(ssl, offset)))
+ errorList->append(errorAndDepth);
+
+ // An application is expected to ignore this error (by calling ignoreSslErrors)
+ // in its directly connected slot:
+ return !handshakeInterrupted;
+}
+
+void TlsCryptographOpenSSL::trySendFatalAlert()
+{
+ Q_ASSERT(pendingFatalAlert);
+ Q_ASSERT(d);
+
+ auto *plainSocket = d->plainTcpSocket();
+
+ pendingFatalAlert = false;
+ QVarLengthArray<char, 4096> data;
+ int pendingBytes = 0;
+ while (plainSocket->isValid() && (pendingBytes = q_BIO_pending(writeBio)) > 0
+ && plainSocket->openMode() != QIODevice::NotOpen) {
+ // Read encrypted data from the write BIO into a buffer.
+ data.resize(pendingBytes);
+ const int bioReadBytes = q_BIO_read(writeBio, data.data(), pendingBytes);
+
+ // Write encrypted data from the buffer to the socket.
+ qint64 actualWritten = plainSocket->write(data.constData(), bioReadBytes);
+ if (actualWritten < 0)
+ return;
+ plainSocket->flush();
+ }
+}
+
+bool TlsCryptographOpenSSL::initSslContext()
+{
+ Q_ASSERT(q);
+ Q_ASSERT(d);
+
+ // If no external context was set (e.g. by QHttpNetworkConnection) we will
+ // create a new one.
+ const auto mode = d->tlsMode();
+ const auto configuration = q->sslConfiguration();
+ if (!sslContextPointer)
+ sslContextPointer = QSslContext::sharedFromConfiguration(mode, configuration, d->isRootsOnDemandAllowed());
+
+ if (sslContextPointer->error() != QSslError::NoError) {
+ setErrorAndEmit(d, QAbstractSocket::SslInvalidUserDataError, sslContextPointer->errorString());
+ sslContextPointer.reset();
+ return false;
+ }
+
+ // Create and initialize SSL session
+ if (!(ssl = sslContextPointer->createSsl())) {
+ setErrorAndEmit(d, QAbstractSocket::SslInternalError,
+ QSslSocket::tr("Error creating SSL session, %1").arg(QTlsBackendOpenSSL::getErrorsFromOpenSsl()));
+ return false;
+ }
+
+ if (configuration.protocol() != QSsl::UnknownProtocol && mode == QSslSocket::SslClientMode) {
+ const auto verificationPeerName = d->verificationName();
+ // Set server hostname on TLS extension. RFC4366 section 3.1 requires it in ACE format.
+ QString tlsHostName = verificationPeerName.isEmpty() ? q->peerName() : verificationPeerName;
+ if (tlsHostName.isEmpty())
+ tlsHostName = d->tlsHostName();
+ QByteArray ace = QUrl::toAce(tlsHostName);
+ // only send the SNI header if the URL is valid and not an IP
+ if (!ace.isEmpty()
+ && !QHostAddress().setAddress(tlsHostName)
+ && !(configuration.testSslOption(QSsl::SslOptionDisableServerNameIndication))) {
+ // We don't send the trailing dot from the host header if present see
+ // https://tools.ietf.org/html/rfc6066#section-3
+ if (ace.endsWith('.'))
+ ace.chop(1);
+ if (!q_SSL_ctrl(ssl, SSL_CTRL_SET_TLSEXT_HOSTNAME, TLSEXT_NAMETYPE_host_name, ace.data()))
+ qCWarning(lcTlsBackend, "could not set SSL_CTRL_SET_TLSEXT_HOSTNAME, Server Name Indication disabled");
+ }
+ }
+
+ // Clear the session.
+ errorList.clear();
+
+ // Initialize memory BIOs for encryption and decryption.
+ readBio = q_BIO_new(q_BIO_s_mem());
+ writeBio = q_BIO_new(q_BIO_s_mem());
+ if (!readBio || !writeBio) {
+ setErrorAndEmit(d, QAbstractSocket::SslInternalError,
+ QSslSocket::tr("Error creating SSL session: %1").arg(QTlsBackendOpenSSL::getErrorsFromOpenSsl()));
+ if (readBio)
+ q_BIO_free(readBio);
+ if (writeBio)
+ q_BIO_free(writeBio);
+ return false;
+ }
+
+ // Assign the bios.
+ q_SSL_set_bio(ssl, readBio, writeBio);
+
+ if (mode == QSslSocket::SslClientMode)
+ q_SSL_set_connect_state(ssl);
+ else
+ q_SSL_set_accept_state(ssl);
+
+ q_SSL_set_ex_data(ssl, QTlsBackendOpenSSL::s_indexForSSLExtraData, this);
+
+#ifndef OPENSSL_NO_PSK
+ // Set the client callback for PSK
+ if (mode == QSslSocket::SslClientMode)
+ q_SSL_set_psk_client_callback(ssl, &q_ssl_psk_client_callback);
+ else if (mode == QSslSocket::SslServerMode)
+ q_SSL_set_psk_server_callback(ssl, &q_ssl_psk_server_callback);
+
+#if OPENSSL_VERSION_NUMBER >= 0x10101006L
+ // Set the client callback for TLSv1.3 PSK
+ if (mode == QSslSocket::SslClientMode
+ && QSslSocket::sslLibraryBuildVersionNumber() >= 0x10101006L) {
+ q_SSL_set_psk_use_session_callback(ssl, &q_ssl_psk_use_session_callback);
+ }
+#endif // openssl version >= 0x10101006L
+
+#endif // OPENSSL_NO_PSK
+
+#if QT_CONFIG(ocsp)
+ if (configuration.ocspStaplingEnabled()) {
+ if (mode == QSslSocket::SslServerMode) {
+ setErrorAndEmit(d, QAbstractSocket::SslInvalidUserDataError,
+ QSslSocket::tr("Server-side QSslSocket does not support OCSP stapling"));
+ return false;
+ }
+ if (q_SSL_set_tlsext_status_type(ssl, TLSEXT_STATUSTYPE_ocsp) != 1) {
+ setErrorAndEmit(d, QAbstractSocket::SslInternalError,
+ QSslSocket::tr("Failed to enable OCSP stapling"));
+ return false;
+ }
+ }
+
+ ocspResponseDer.clear();
+ const auto backendConfig = configuration.backendConfiguration();
+ auto responsePos = backendConfig.find("Qt-OCSP-response");
+ if (responsePos != backendConfig.end()) {
+ // This is our private, undocumented 'API' we use for the auto-testing of
+ // OCSP-stapling. It must be a der-encoded OCSP response, presumably set
+ // by tst_QOcsp.
+ const QVariant data(responsePos.value());
+ if (data.canConvert<QByteArray>())
+ ocspResponseDer = data.toByteArray();
+ }
+
+ if (ocspResponseDer.size()) {
+ if (mode != QSslSocket::SslServerMode) {
+ setErrorAndEmit(d, QAbstractSocket::SslInvalidUserDataError,
+ QSslSocket::tr("Client-side sockets do not send OCSP responses"));
+ return false;
+ }
+ }
+#endif // ocsp
+
+ return true;
+}
+
+void TlsCryptographOpenSSL::destroySslContext()
+{
+ if (ssl) {
+ if (!q_SSL_in_init(ssl) && !systemOrSslErrorDetected) {
+ // We do not send a shutdown alert here. Just mark the session as
+ // resumable for qhttpnetworkconnection's "optimization", otherwise
+ // OpenSSL won't start a session resumption.
+ if (q_SSL_shutdown(ssl) != 1) {
+ // Some error may be queued, clear it.
+ const auto errors = QTlsBackendOpenSSL::getErrorsFromOpenSsl();
+ Q_UNUSED(errors);
+ }
+ }
+ q_SSL_free(ssl);
+ ssl = nullptr;
+ }
+ sslContextPointer.reset();
+}
+
+void TlsCryptographOpenSSL::storePeerCertificates()
+{
+ Q_ASSERT(d);
+
+ // Store the peer certificate and chain. For clients, the peer certificate
+ // chain includes the peer certificate; for servers, it doesn't. Both the
+ // peer certificate and the chain may be empty if the peer didn't present
+ // any certificate.
+ X509 *x509 = q_SSL_get_peer_certificate(ssl);
+
+ const auto peerCertificate = QTlsPrivate::X509CertificateOpenSSL::certificateFromX509(x509);
+ QTlsBackend::storePeerCertificate(d, peerCertificate);
+ q_X509_free(x509);
+ auto peerCertificateChain = q->peerCertificateChain();
+ if (peerCertificateChain.isEmpty()) {
+ peerCertificateChain = QTlsPrivate::X509CertificateOpenSSL::stackOfX509ToQSslCertificates(q_SSL_get_peer_cert_chain(ssl));
+ if (!peerCertificate.isNull() && d->tlsMode() == QSslSocket::SslServerMode)
+ peerCertificateChain.prepend(peerCertificate);
+ QTlsBackend::storePeerCertificateChain(d, peerCertificateChain);
+ }
+}
+
+#if QT_CONFIG(ocsp)
+
+bool TlsCryptographOpenSSL::checkOcspStatus()
+{
+ Q_ASSERT(ssl);
+ Q_ASSERT(d);
+
+ const auto &configuration = q->sslConfiguration();
+ Q_ASSERT(d->tlsMode() == QSslSocket::SslClientMode); // See initSslContext() for SslServerMode
+ Q_ASSERT(configuration.peerVerifyMode() != QSslSocket::VerifyNone);
+
+ const auto clearErrorQueue = qScopeGuard([] {
+ QTlsBackendOpenSSL::logAndClearErrorQueue();
+ });
+
+ ocspResponses.clear();
+ ocspErrorDescription.clear();
+ ocspErrors.clear();
+
+ const unsigned char *responseData = nullptr;
+ const long responseLength = q_SSL_get_tlsext_status_ocsp_resp(ssl, &responseData);
+ if (responseLength <= 0 || !responseData) {
+ ocspErrors.push_back(QSslError(QSslError::OcspNoResponseFound));
+ return false;
+ }
+
+ OCSP_RESPONSE *response = q_d2i_OCSP_RESPONSE(nullptr, &responseData, responseLength);
+ if (!response) {
+ // Treat this as a fatal SslHandshakeError.
+ ocspErrorDescription = QSslSocket::tr("Failed to decode OCSP response");
+ return false;
+ }
+ const QSharedPointer<OCSP_RESPONSE> responseGuard(response, q_OCSP_RESPONSE_free);
+
+ const int ocspStatus = q_OCSP_response_status(response);
+ if (ocspStatus != OCSP_RESPONSE_STATUS_SUCCESSFUL) {
+ // It's not a definitive response, it's an error message (not signed by the responder).
+ ocspErrors.push_back(QSslError(qt_OCSP_response_status_to_SslError(ocspStatus)));
+ return false;
+ }
+
+ OCSP_BASICRESP *basicResponse = q_OCSP_response_get1_basic(response);
+ if (!basicResponse) {
+ // SslHandshakeError.
+ ocspErrorDescription = QSslSocket::tr("Failed to extract basic OCSP response");
+ return false;
+ }
+ const QSharedPointer<OCSP_BASICRESP> basicResponseGuard(basicResponse, q_OCSP_BASICRESP_free);
+
+ SSL_CTX *ctx = q_SSL_get_SSL_CTX(ssl); // Does not increment refcount.
+ Q_ASSERT(ctx);
+ X509_STORE *store = q_SSL_CTX_get_cert_store(ctx); // Does not increment refcount.
+ if (!store) {
+ // SslHandshakeError.
+ ocspErrorDescription = QSslSocket::tr("No certificate verification store, cannot verify OCSP response");
+ return false;
+ }
+
+ STACK_OF(X509) *peerChain = q_SSL_get_peer_cert_chain(ssl); // Does not increment refcount.
+ X509 *peerX509 = q_SSL_get_peer_certificate(ssl);
+ Q_ASSERT(peerChain || peerX509);
+ const QSharedPointer<X509> peerX509Guard(peerX509, q_X509_free);
+ // OCSP_basic_verify with 0 as verificationFlags:
+ //
+ // 0) Tries to find the OCSP responder's certificate in either peerChain
+ // or basicResponse->certs. If not found, verification fails.
+ // 1) It checks the signature using the responder's public key.
+ // 2) Then it tries to validate the responder's cert (building a chain
+ // etc.)
+ // 3) It checks CertID in response.
+ // 4) Ensures the responder is authorized to sign the status respond.
+ //
+ // Note, OpenSSL prior to 1.0.2b would only use bs->certs to
+ // verify the responder's chain (see their commit 4ba9a4265bd).
+ // Working this around - is too much fuss for ancient versions we
+ // are dropping quite soon anyway.
+ const unsigned long verificationFlags = 0;
+ const int success = q_OCSP_basic_verify(basicResponse, peerChain, store, verificationFlags);
+ if (success <= 0)
+ ocspErrors.push_back(QSslError(QSslError::OcspResponseCannotBeTrusted));
+
+ if (q_OCSP_resp_count(basicResponse) != 1) {
+ ocspErrors.push_back(QSslError(QSslError::OcspMalformedResponse));
+ return false;
+ }
+
+ OCSP_SINGLERESP *singleResponse = q_OCSP_resp_get0(basicResponse, 0);
+ if (!singleResponse) {
+ ocspErrors.clear();
+ // A fatal problem -> SslHandshakeError.
+ ocspErrorDescription = QSslSocket::tr("Failed to decode a SingleResponse from OCSP status response");
+ return false;
+ }
+
+ // Let's make sure the response is for the correct certificate - we
+ // can re-create this CertID using our peer's certificate and its
+ // issuer's public key.
+ ocspResponses.push_back(QOcspResponse());
+ QOcspResponsePrivate *dResponse = ocspResponses.back().d.data();
+ dResponse->subjectCert = configuration.peerCertificate();
+ bool matchFound = false;
+ if (dResponse->subjectCert.isSelfSigned()) {
+ dResponse->signerCert = configuration.peerCertificate();
+ matchFound = qt_OCSP_certificate_match(singleResponse, peerX509, peerX509);
+ } else {
+ const STACK_OF(X509) *certs = q_SSL_get_peer_cert_chain(ssl);
+ if (!certs) // Oh, what a cataclysm! Last try:
+ certs = q_OCSP_resp_get0_certs(basicResponse);
+ if (certs) {
+ // It could be the first certificate in 'certs' is our peer's
+ // certificate. Since it was not captured by the 'self-signed' branch
+ // above, the CertID will not match and we'll just iterate on to the
+ // next certificate. So we start from 0, not 1.
+ for (int i = 0, e = q_sk_X509_num(certs); i < e; ++i) {
+ X509 *issuer = q_sk_X509_value(certs, i);
+ matchFound = qt_OCSP_certificate_match(singleResponse, peerX509, issuer);
+ if (matchFound) {
+ if (q_X509_check_issued(issuer, peerX509) == X509_V_OK) {
+ dResponse->signerCert = QTlsPrivate::X509CertificateOpenSSL::certificateFromX509(issuer);
+ break;
+ }
+ matchFound = false;
+ }
+ }
+ }
+ }
+
+ if (!matchFound) {
+ dResponse->signerCert.clear();
+ ocspErrors.push_back({QSslError::OcspResponseCertIdUnknown, configuration.peerCertificate()});
+ }
+
+ // Check if the response is valid time-wise:
+ ASN1_GENERALIZEDTIME *revTime = nullptr;
+ ASN1_GENERALIZEDTIME *thisUpdate = nullptr;
+ ASN1_GENERALIZEDTIME *nextUpdate = nullptr;
+ int reason;
+ const int certStatus = q_OCSP_single_get0_status(singleResponse, &reason, &revTime, &thisUpdate, &nextUpdate);
+ if (!thisUpdate) {
+ // This is unexpected, treat as SslHandshakeError, OCSP_check_validity assumes this pointer
+ // to be != nullptr.
+ ocspErrors.clear();
+ ocspResponses.clear();
+ ocspErrorDescription = QSslSocket::tr("Failed to extract 'this update time' from the SingleResponse");
+ return false;
+ }
+
+ // OCSP_check_validity(this, next, nsec, maxsec) does this check:
+ // this <= now <= next. They allow some freedom to account
+ // for delays/time inaccuracy.
+ // this > now + nsec ? -> NOT_YET_VALID
+ // if maxsec >= 0:
+ // now - maxsec > this ? -> TOO_OLD
+ // now - nsec > next ? -> EXPIRED
+ // next < this ? -> NEXT_BEFORE_THIS
+ // OK.
+ if (!q_OCSP_check_validity(thisUpdate, nextUpdate, 60, -1))
+ ocspErrors.push_back({QSslError::OcspResponseExpired, configuration.peerCertificate()});
+
+ // And finally, the status:
+ switch (certStatus) {
+ case V_OCSP_CERTSTATUS_GOOD:
+ // This certificate was not found among the revoked ones.
+ dResponse->certificateStatus = QOcspCertificateStatus::Good;
+ break;
+ case V_OCSP_CERTSTATUS_REVOKED:
+ dResponse->certificateStatus = QOcspCertificateStatus::Revoked;
+ dResponse->revocationReason = qt_OCSP_revocation_reason(reason);
+ ocspErrors.push_back({QSslError::CertificateRevoked, configuration.peerCertificate()});
+ break;
+ case V_OCSP_CERTSTATUS_UNKNOWN:
+ dResponse->certificateStatus = QOcspCertificateStatus::Unknown;
+ ocspErrors.push_back({QSslError::OcspStatusUnknown, configuration.peerCertificate()});
+ }
+
+ return !ocspErrors.size();
+}
+
+#endif // QT_CONFIG(ocsp)
+
+
+unsigned TlsCryptographOpenSSL::pskClientTlsCallback(const char *hint, char *identity,
+ unsigned max_identity_len,
+ unsigned char *psk, unsigned max_psk_len)
+{
+ Q_ASSERT(q);
+
+ QSslPreSharedKeyAuthenticator authenticator;
+ // Fill in some read-only fields (for the user)
+ const int hintLength = hint ? int(std::strlen(hint)) : 0;
+ QTlsBackend::setupClientPskAuth(&authenticator, hint, hintLength, max_identity_len, max_psk_len);
+ // Let the client provide the remaining bits...
+ emit q->preSharedKeyAuthenticationRequired(&authenticator);
+
+ // No PSK set? Return now to make the handshake fail
+ if (authenticator.preSharedKey().isEmpty())
+ return 0;
+
+ // Copy data back into OpenSSL
+ const int identityLength = qMin(authenticator.identity().size(), authenticator.maximumIdentityLength());
+ std::memcpy(identity, authenticator.identity().constData(), identityLength);
+ identity[identityLength] = 0;
+
+ const int pskLength = qMin(authenticator.preSharedKey().size(), authenticator.maximumPreSharedKeyLength());
+ std::memcpy(psk, authenticator.preSharedKey().constData(), pskLength);
+ return pskLength;
+}
+
+unsigned TlsCryptographOpenSSL::pskServerTlsCallback(const char *identity, unsigned char *psk,
+ unsigned max_psk_len)
+{
+ Q_ASSERT(q);
+
+ QSslPreSharedKeyAuthenticator authenticator;
+
+ // Fill in some read-only fields (for the user)
+ QTlsBackend::setupServerPskAuth(&authenticator, identity, q->sslConfiguration().preSharedKeyIdentityHint(),
+ max_psk_len);
+ emit q->preSharedKeyAuthenticationRequired(&authenticator);
+
+ // No PSK set? Return now to make the handshake fail
+ if (authenticator.preSharedKey().isEmpty())
+ return 0;
+
+ // Copy data back into OpenSSL
+ const int pskLength = qMin(authenticator.preSharedKey().size(), authenticator.maximumPreSharedKeyLength());
+ std::memcpy(psk, authenticator.preSharedKey().constData(), pskLength);
+ return pskLength;
+}
+
+bool TlsCryptographOpenSSL::isInSslRead() const
+{
+ return inSslRead;
+}
+
+void TlsCryptographOpenSSL::setRenegotiated(bool renegotiated)
+{
+ this->renegotiated = renegotiated;
+}
+
+#ifdef Q_OS_WIN
+
+void TlsCryptographOpenSSL::fetchCaRootForCert(const QSslCertificate &cert)
+{
+ Q_ASSERT(d);
+ Q_ASSERT(q);
+
+ //The root certificate is downloaded from windows update, which blocks for 15 seconds in the worst case
+ //so the request is done in a worker thread.
+ QList<QSslCertificate> customRoots;
+ if (fetchAuthorityInformation)
+ customRoots = q->sslConfiguration().caCertificates();
+
+ //Remember we are fetching and what we are fetching:
+ caToFetch = cert;
+
+ QWindowsCaRootFetcher *fetcher = new QWindowsCaRootFetcher(cert, d->tlsMode(), customRoots,
+ q->peerVerifyName());
+ connect(fetcher, &QWindowsCaRootFetcher::finished, this, &TlsCryptographOpenSSL::caRootLoaded,
+ Qt::QueuedConnection);
+ QMetaObject::invokeMethod(fetcher, "start", Qt::QueuedConnection);
+ QSslSocketPrivate::pauseSocketNotifiers(q);
+ d->setPaused(true);
+}
+
+void TlsCryptographOpenSSL::caRootLoaded(QSslCertificate cert, QSslCertificate trustedRoot)
+{
+ if (caToFetch != cert) {
+ //Ooops, something from the previous connection attempt, ignore!
+ return;
+ }
+
+ Q_ASSERT(d);
+ Q_ASSERT(q);
+
+ //Done, fetched already:
+ caToFetch.reset();
+
+ if (fetchAuthorityInformation) {
+ if (!q->sslConfiguration().caCertificates().contains(trustedRoot))
+ trustedRoot = QSslCertificate{};
+ fetchAuthorityInformation = false;
+ }
+
+ if (!trustedRoot.isNull() && !trustedRoot.isBlacklisted()) {
+ if (QSslSocketPrivate::rootCertOnDemandLoadingSupported()) {
+ //Add the new root cert to default cert list for use by future sockets
+ auto defaultConfig = QSslConfiguration::defaultConfiguration();
+ defaultConfig.addCaCertificate(trustedRoot);
+ QSslConfiguration::setDefaultConfiguration(defaultConfig);
+ }
+ //Add the new root cert to this socket for future connections
+ QTlsBackend::addTustedRoot(d, trustedRoot);
+ //Remove the broken chain ssl errors (as chain is verified by windows)
+ for (int i=sslErrors.count() - 1; i >= 0; --i) {
+ if (sslErrors.at(i).certificate() == cert) {
+ switch (sslErrors.at(i).error()) {
+ case QSslError::UnableToGetLocalIssuerCertificate:
+ case QSslError::CertificateUntrusted:
+ case QSslError::UnableToVerifyFirstCertificate:
+ case QSslError::SelfSignedCertificateInChain:
+ // error can be ignored if OS says the chain is trusted
+ sslErrors.removeAt(i);
+ break;
+ default:
+ // error cannot be ignored
+ break;
+ }
+ }
+ }
+ }
+
+ auto *plainSocket = d->plainTcpSocket();
+ Q_ASSERT(plainSocket);
+ // Continue with remaining errors
+ if (plainSocket)
+ plainSocket->resume();
+ d->setPaused(false);
+ if (checkSslErrors() && ssl) {
+ bool willClose = (d->isAutoStartingHandshake() && d->isPendingClose());
+ continueHandshake();
+ if (!willClose)
+ transmit();
+ }
+}
+
+#endif // Q_OS_WIN
+
+} // namespace QTlsPrivate
+
+QT_END_NAMESPACE
diff --git a/src/plugins/tls/openssl/qtls_openssl_p.h b/src/plugins/tls/openssl/qtls_openssl_p.h
new file mode 100644
index 0000000000..65d21a395b
--- /dev/null
+++ b/src/plugins/tls/openssl/qtls_openssl_p.h
@@ -0,0 +1,140 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QTLS_OPENSSL_P_H
+#define QTLS_OPENSSL_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 <QtNetwork/private/qtnetworkglobal_p.h>
+
+#include "qtlsbackend_openssl_p.h"
+#include "qsslcontext_openssl_p.h"
+#include "qopenssl_p.h"
+
+#include <QtNetwork/qsslcertificate.h>
+#include <QtNetwork/qocspresponse.h>
+
+#include <QtCore/qsharedpointer.h>
+#include <QtCore/qbytearray.h>
+#include <QtCore/qglobal.h>
+#include <QtCore/qlist.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QTlsPrivate {
+
+class TlsCryptographOpenSSL : public TlsCryptograph
+{
+public:
+ enum ExDataOffset {
+ errorOffsetInExData = 1,
+ socketOffsetInExData = 2
+ };
+
+ ~TlsCryptographOpenSSL();
+
+ void init(QSslSocket *qObj, QSslSocketPrivate *dObj) override;
+ void checkSettingSslContext(std::shared_ptr<QSslContext> tlsContext) override;
+ std::shared_ptr<QSslContext> sslContext() const override;
+
+ QList<QSslError> tlsErrors() const override;
+
+ void startClientEncryption() override;
+ void startServerEncryption() override;
+ bool startHandshake();
+ void enableHandshakeContinuation() override;
+ void cancelCAFetch() override;
+ void continueHandshake() override;
+ void transmit() override;
+ void disconnectFromHost() override;
+ void disconnected() override;
+ QSslCipher sessionCipher() const override;
+ QSsl::SslProtocol sessionProtocol() const override;
+ QList<QOcspResponse> ocsps() const override;
+
+ bool checkSslErrors();
+ int handleNewSessionTicket(SSL *connection);
+
+ void alertMessageSent(int encoded);
+ void alertMessageReceived(int encoded);
+
+ int emitErrorFromCallback(X509_STORE_CTX *ctx);
+ void trySendFatalAlert();
+
+#if QT_CONFIG(ocsp)
+ bool checkOcspStatus();
+#endif
+
+ QSslSocket *q = nullptr;
+ QSslSocketPrivate *d = nullptr;
+
+ void storePeerCertificates();
+
+ unsigned pskClientTlsCallback(const char *hint, char *identity, unsigned max_identity_len,
+ unsigned char *psk, unsigned max_psk_len);
+ unsigned pskServerTlsCallback(const char *identity, unsigned char *psk,
+ unsigned max_psk_len);
+
+ bool isInSslRead() const;
+ void setRenegotiated(bool renegotiated);
+
+#ifdef Q_OS_WIN
+ void fetchCaRootForCert(const QSslCertificate &cert);
+ void caRootLoaded(QSslCertificate certificate, QSslCertificate trustedRoot);
+#endif
+
+ QByteArray ocspResponseDer;
+private:
+ // TLSTODO: names were preserved, to make comparison
+ // easier (see qsslsocket_openssl.cpp, while it exists).
+ bool initSslContext();
+ void destroySslContext();
+
+ std::shared_ptr<QSslContext> sslContextPointer;
+ SSL *ssl = nullptr; // TLSTODO: RAII.
+
+ QList<QSslErrorEntry> errorList;
+ QList<QSslError> sslErrors;
+
+ BIO *readBio = nullptr;
+ BIO *writeBio = nullptr;
+
+ QList<QOcspResponse> ocspResponses;
+
+ // This description will go to setErrorAndEmit(SslHandshakeError, ocspErrorDescription)
+ QString ocspErrorDescription;
+ // These will go to sslErrors()
+ QList<QSslError> ocspErrors;
+
+ bool systemOrSslErrorDetected = false;
+ bool handshakeInterrupted = false;
+
+ bool fetchAuthorityInformation = false;
+ std::optional<QSslCertificate> caToFetch;
+
+ bool inSetAndEmitError = false;
+ bool pendingFatalAlert = false;
+ bool errorsReportedFromCallback = false;
+
+ bool shutdown = false;
+
+ bool inSslRead = false;
+ bool renegotiated = false;
+};
+
+} // namespace QTlsPrivate
+
+QT_END_NAMESPACE
+
+#endif // QTLS_OPENSSL_P_H
+
diff --git a/src/plugins/tls/openssl/qtlsbackend_openssl.cpp b/src/plugins/tls/openssl/qtlsbackend_openssl.cpp
new file mode 100644
index 0000000000..d73515724b
--- /dev/null
+++ b/src/plugins/tls/openssl/qtlsbackend_openssl.cpp
@@ -0,0 +1,611 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qsslsocket_openssl_symbols_p.h"
+#include "qtlsbackend_openssl_p.h"
+#include "qtlskey_openssl_p.h"
+#include "qx509_openssl_p.h"
+#include "qtls_openssl_p.h"
+
+#if QT_CONFIG(dtls)
+#include "qdtls_openssl_p.h"
+#endif // QT_CONFIG(dtls)
+
+#include <QtNetwork/private/qsslcipher_p.h>
+
+#include <QtNetwork/qsslcipher.h>
+#include <QtNetwork/qssl.h>
+
+#include <QtCore/qdir.h>
+#include <QtCore/qdirlisting.h>
+#include <QtCore/qlist.h>
+#include <QtCore/qmutex.h>
+#include <QtCore/qscopeguard.h>
+#include <QtCore/qset.h>
+
+#include "qopenssl_p.h"
+
+#include <algorithm>
+
+QT_BEGIN_NAMESPACE
+
+using namespace Qt::StringLiterals;
+
+#if defined(Q_OS_WIN) || defined(Q_OS_MACOS)
+constexpr auto DefaultWarningLevel = QtCriticalMsg;
+#else
+constexpr auto DefaultWarningLevel = QtDebugMsg;
+#endif
+
+Q_LOGGING_CATEGORY(lcTlsBackend, "qt.tlsbackend.ossl", DefaultWarningLevel);
+
+static void q_loadCiphersForConnection(SSL *connection, QList<QSslCipher> &ciphers,
+ QList<QSslCipher> &defaultCiphers)
+{
+ Q_ASSERT(connection);
+
+ STACK_OF(SSL_CIPHER) *supportedCiphers = q_SSL_get_ciphers(connection);
+ for (int i = 0; i < q_sk_SSL_CIPHER_num(supportedCiphers); ++i) {
+ if (SSL_CIPHER *cipher = q_sk_SSL_CIPHER_value(supportedCiphers, i)) {
+ const auto ciph = QTlsBackendOpenSSL::qt_OpenSSL_cipher_to_QSslCipher(cipher);
+ if (!ciph.isNull()) {
+ // Unconditionally exclude ADH and AECDH ciphers since they offer no MITM protection
+ if (!ciph.name().toLower().startsWith("adh"_L1) &&
+ !ciph.name().toLower().startsWith("exp-adh"_L1) &&
+ !ciph.name().toLower().startsWith("aecdh"_L1)) {
+ ciphers << ciph;
+
+ if (ciph.usedBits() >= 128)
+ defaultCiphers << ciph;
+ }
+ }
+ }
+ }
+}
+
+int QTlsBackendOpenSSL::s_indexForSSLExtraData = -1;
+
+QString QTlsBackendOpenSSL::getErrorsFromOpenSsl()
+{
+ QString errorString;
+ char buf[256] = {}; // OpenSSL docs claim both 120 and 256; use the larger.
+ unsigned long errNum;
+ while ((errNum = q_ERR_get_error())) {
+ if (!errorString.isEmpty())
+ errorString.append(", "_L1);
+ q_ERR_error_string_n(errNum, buf, sizeof buf);
+ errorString.append(QLatin1StringView(buf)); // error is ascii according to man ERR_error_string
+ }
+ return errorString;
+}
+
+void QTlsBackendOpenSSL::logAndClearErrorQueue()
+{
+ const auto errors = getErrorsFromOpenSsl();
+ if (errors.size())
+ qCWarning(lcTlsBackend) << "Discarding errors:" << errors;
+}
+
+void QTlsBackendOpenSSL::clearErrorQueue()
+{
+ while (q_ERR_get_error())
+ ;
+}
+
+bool QTlsBackendOpenSSL::ensureLibraryLoaded()
+{
+ static bool libraryLoaded = []() {
+ if (!q_resolveOpenSslSymbols())
+ return false;
+
+ // Initialize OpenSSL.
+ if (q_OPENSSL_init_ssl(0, nullptr) != 1)
+ return false;
+
+ if (q_OpenSSL_version_num() < 0x10101000L) {
+ qCWarning(lcTlsBackend, "QSslSocket: OpenSSL >= 1.1.1 is required; %s was found instead", q_OpenSSL_version(OPENSSL_VERSION));
+ return false;
+ }
+
+ q_SSL_load_error_strings();
+ q_OpenSSL_add_all_algorithms();
+
+ s_indexForSSLExtraData = q_CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_SSL, 0L, nullptr, nullptr,
+ nullptr, nullptr);
+
+ // Initialize OpenSSL's random seed.
+ if (!q_RAND_status()) {
+ qWarning("Random number generator not seeded, disabling SSL support");
+ return false;
+ }
+
+ return true;
+ }();
+
+ return libraryLoaded;
+}
+
+QString QTlsBackendOpenSSL::backendName() const
+{
+ return builtinBackendNames[nameIndexOpenSSL];
+}
+
+bool QTlsBackendOpenSSL::isValid() const
+{
+ return ensureLibraryLoaded();
+}
+
+long QTlsBackendOpenSSL::tlsLibraryVersionNumber() const
+{
+ return q_OpenSSL_version_num();
+}
+
+QString QTlsBackendOpenSSL::tlsLibraryVersionString() const
+{
+ const char *versionString = q_OpenSSL_version(OPENSSL_VERSION);
+ if (!versionString)
+ return QString();
+
+ return QString::fromLatin1(versionString);
+}
+
+long QTlsBackendOpenSSL::tlsLibraryBuildVersionNumber() const
+{
+ return OPENSSL_VERSION_NUMBER;
+}
+
+QString QTlsBackendOpenSSL::tlsLibraryBuildVersionString() const
+{
+ // Using QStringLiteral to store the version string as unicode and
+ // avoid false positives from Google searching the playstore for old
+ // SSL versions. See QTBUG-46265
+ return QStringLiteral(OPENSSL_VERSION_TEXT);
+}
+
+void QTlsBackendOpenSSL::ensureInitialized() const
+{
+ // Old qsslsocket_openssl calls supportsSsl() (which means
+ // library found and symbols resolved, this already assured
+ // by the fact we end up in this function (isValid() returned
+ // true for the backend, see its code). The qsslsocket_openssl
+ // proceedes with loading certificate, ciphers and elliptic
+ // curves.
+ ensureCiphersAndCertsLoaded();
+}
+
+void QTlsBackendOpenSSL::ensureCiphersAndCertsLoaded() const
+{
+ Q_CONSTINIT static bool initializationStarted = false;
+ Q_CONSTINIT static QAtomicInt initialized = Q_BASIC_ATOMIC_INITIALIZER(0);
+ Q_CONSTINIT static QRecursiveMutex initMutex;
+
+ if (initialized.loadAcquire())
+ return;
+
+ const QMutexLocker locker(&initMutex);
+
+ if (initializationStarted || initialized.loadAcquire())
+ return;
+
+ // Indicate that the initialization has already started in the current
+ // thread in case of recursive calls. The atomic variable cannot be used
+ // for this because it is checked without holding the init mutex.
+ initializationStarted = true;
+
+ auto guard = qScopeGuard([] { initialized.storeRelease(1); });
+
+ resetDefaultCiphers();
+ resetDefaultEllipticCurves();
+
+#if QT_CONFIG(library)
+ //load symbols needed to receive certificates from system store
+#if defined(Q_OS_QNX)
+ 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)
+ const QList<QByteArray> dirs = QSslSocketPrivate::unixRootCertDirectories();
+ const QStringList symLinkFilter{
+ u"[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]"_s};
+ for (const auto &dir : dirs) {
+ QDirListing dirList(QString::fromLatin1(dir), symLinkFilter, QDir::Files);
+ if (dirList.cbegin() != dirList.cend()) { // Not empty
+ QSslSocketPrivate::setRootCertOnDemandLoadingSupported(true);
+ break;
+ }
+ }
+#endif
+#endif // QT_CONFIG(library)
+ // if on-demand loading was not enabled, load the certs now
+ if (!QSslSocketPrivate::rootCertOnDemandLoadingSupported())
+ setDefaultCaCertificates(systemCaCertificates());
+#ifdef Q_OS_WIN
+ //Enabled for fetching additional root certs from windows update on windows.
+ //This flag is set false by setDefaultCaCertificates() indicating the app uses
+ //its own cert bundle rather than the system one.
+ //Same logic that disables the unix on demand cert loading.
+ //Unlike unix, we do preload the certificates from the cert store.
+ QSslSocketPrivate::setRootCertOnDemandLoadingSupported(true);
+#endif
+}
+
+void QTlsBackendOpenSSL::resetDefaultCiphers()
+{
+ SSL_CTX *myCtx = q_SSL_CTX_new(q_TLS_client_method());
+ // Note, we assert, not just silently return/bail out early:
+ // this should never happen and problems with OpenSSL's initialization
+ // must be caught before this (see supportsSsl()).
+ Q_ASSERT(myCtx);
+ SSL *mySsl = q_SSL_new(myCtx);
+ Q_ASSERT(mySsl);
+
+ QList<QSslCipher> ciphers;
+ QList<QSslCipher> defaultCiphers;
+
+ q_loadCiphersForConnection(mySsl, ciphers, defaultCiphers);
+
+ q_SSL_CTX_free(myCtx);
+ q_SSL_free(mySsl);
+
+ setDefaultSupportedCiphers(ciphers);
+ setDefaultCiphers(defaultCiphers);
+
+#if QT_CONFIG(dtls)
+ ciphers.clear();
+ defaultCiphers.clear();
+ myCtx = q_SSL_CTX_new(q_DTLS_client_method());
+ if (myCtx) {
+ mySsl = q_SSL_new(myCtx);
+ if (mySsl) {
+ q_loadCiphersForConnection(mySsl, ciphers, defaultCiphers);
+ setDefaultDtlsCiphers(defaultCiphers);
+ q_SSL_free(mySsl);
+ }
+ q_SSL_CTX_free(myCtx);
+ }
+#endif // dtls
+}
+
+QList<QSsl::SslProtocol> QTlsBackendOpenSSL::supportedProtocols() const
+{
+ QList<QSsl::SslProtocol> protocols;
+
+ 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;
+
+#ifdef TLS1_3_VERSION
+ protocols << QSsl::TlsV1_3;
+ protocols << QSsl::TlsV1_3OrLater;
+#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
+
+ return protocols;
+}
+
+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;
+ features << QSsl::SupportedFeature::Alerts;
+
+ return features;
+}
+
+QList<QSsl::ImplementedClass> QTlsBackendOpenSSL::implementedClasses() const
+{
+ QList<QSsl::ImplementedClass> classes;
+
+ classes << QSsl::ImplementedClass::Key;
+ classes << QSsl::ImplementedClass::Certificate;
+ classes << QSsl::ImplementedClass::Socket;
+#if QT_CONFIG(dtls)
+ classes << QSsl::ImplementedClass::Dtls;
+ classes << QSsl::ImplementedClass::DtlsCookie;
+#endif
+ classes << QSsl::ImplementedClass::EllipticCurve;
+ classes << QSsl::ImplementedClass::DiffieHellman;
+
+ return classes;
+}
+
+QTlsPrivate::TlsKey *QTlsBackendOpenSSL::createKey() const
+{
+ return new QTlsPrivate::TlsKeyOpenSSL;
+}
+
+QTlsPrivate::X509Certificate *QTlsBackendOpenSSL::createCertificate() const
+{
+ return new QTlsPrivate::X509CertificateOpenSSL;
+}
+
+namespace QTlsPrivate {
+
+#ifdef Q_OS_ANDROID
+QList<QByteArray> fetchSslCertificateData();
+#endif
+
+QList<QSslCertificate> systemCaCertificates();
+
+#ifndef Q_OS_DARWIN
+QList<QSslCertificate> systemCaCertificates()
+{
+#ifdef QSSLSOCKET_DEBUG
+ QElapsedTimer timer;
+ timer.start();
+#endif
+ QList<QSslCertificate> systemCerts;
+#if defined(Q_OS_WIN)
+ HCERTSTORE hSystemStore;
+ hSystemStore =
+ CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0,
+ CERT_STORE_READONLY_FLAG | CERT_SYSTEM_STORE_CURRENT_USER, L"ROOT");
+ if (hSystemStore) {
+ PCCERT_CONTEXT pc = nullptr;
+ while (1) {
+ pc = CertFindCertificateInStore(hSystemStore, X509_ASN_ENCODING, 0, CERT_FIND_ANY, nullptr, pc);
+ if (!pc)
+ break;
+ QByteArray der(reinterpret_cast<const char *>(pc->pbCertEncoded),
+ static_cast<int>(pc->cbCertEncoded));
+ QSslCertificate cert(der, QSsl::Der);
+ systemCerts.append(cert);
+ }
+ CertCloseStore(hSystemStore, 0);
+ }
+#elif defined(Q_OS_ANDROID)
+ const QList<QByteArray> certData = fetchSslCertificateData();
+ for (auto certDatum : certData)
+ systemCerts.append(QSslCertificate::fromData(certDatum, QSsl::Der));
+#elif defined(Q_OS_UNIX)
+ {
+ 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(QLatin1StringView(directory));
+ for (const auto &dirEntry : QDirListing(currentDir)) {
+ // use canonical path here to not load the same certificate twice if symlinked
+ certFiles.insert(dirEntry.canonicalFilePath());
+ }
+ }
+ for (const QString& file : std::as_const(certFiles))
+ systemCerts.append(QSslCertificate::fromPath(file, QSsl::Pem));
+ }
+#endif // platform
+#ifdef QSSLSOCKET_DEBUG
+ qCDebug(lcTlsBackend) << "systemCaCertificates retrieval time " << timer.elapsed() << "ms";
+ qCDebug(lcTlsBackend) << "imported " << systemCerts.count() << " certificates";
+#endif
+
+ return systemCerts;
+}
+#endif // !Q_OS_DARWIN
+} // namespace QTlsPrivate
+
+QList<QSslCertificate> QTlsBackendOpenSSL::systemCaCertificates() const
+{
+ return QTlsPrivate::systemCaCertificates();
+}
+
+QTlsPrivate::DtlsCookieVerifier *QTlsBackendOpenSSL::createDtlsCookieVerifier() const
+{
+#if QT_CONFIG(dtls)
+ return new QDtlsClientVerifierOpenSSL;
+#else
+ qCWarning(lcTlsBackend, "Feature 'dtls' is disabled, cannot verify DTLS cookies");
+ return nullptr;
+#endif // QT_CONFIG(dtls)
+}
+
+QTlsPrivate::TlsCryptograph *QTlsBackendOpenSSL::createTlsCryptograph() const
+{
+ return new QTlsPrivate::TlsCryptographOpenSSL;
+}
+
+QTlsPrivate::DtlsCryptograph *QTlsBackendOpenSSL::createDtlsCryptograph(QDtls *q, int mode) const
+{
+#if QT_CONFIG(dtls)
+ return new QDtlsPrivateOpenSSL(q, QSslSocket::SslMode(mode));
+#else
+ Q_UNUSED(q);
+ Q_UNUSED(mode);
+ qCWarning(lcTlsBackend, "Feature 'dtls' is disabled, cannot encrypt UDP datagrams");
+ return nullptr;
+#endif // QT_CONFIG(dtls)
+}
+
+QTlsPrivate::X509ChainVerifyPtr QTlsBackendOpenSSL::X509Verifier() const
+{
+ return QTlsPrivate::X509CertificateOpenSSL::verify;
+}
+
+QTlsPrivate::X509PemReaderPtr QTlsBackendOpenSSL::X509PemReader() const
+{
+ return QTlsPrivate::X509CertificateOpenSSL::certificatesFromPem;
+}
+
+QTlsPrivate::X509DerReaderPtr QTlsBackendOpenSSL::X509DerReader() const
+{
+ return QTlsPrivate::X509CertificateOpenSSL::certificatesFromDer;
+}
+
+QTlsPrivate::X509Pkcs12ReaderPtr QTlsBackendOpenSSL::X509Pkcs12Reader() const
+{
+ return QTlsPrivate::X509CertificateOpenSSL::importPkcs12;
+}
+
+QList<int> QTlsBackendOpenSSL::ellipticCurvesIds() const
+{
+ QList<int> ids;
+
+#ifndef OPENSSL_NO_EC
+ const size_t curveCount = q_EC_get_builtin_curves(nullptr, 0);
+ QVarLengthArray<EC_builtin_curve> builtinCurves(static_cast<int>(curveCount));
+
+ if (q_EC_get_builtin_curves(builtinCurves.data(), curveCount) == curveCount) {
+ ids.reserve(curveCount);
+ for (const auto &ec : builtinCurves)
+ ids.push_back(ec.nid);
+ }
+#endif // OPENSSL_NO_EC
+
+ return ids;
+}
+
+ int QTlsBackendOpenSSL::curveIdFromShortName(const QString &name) const
+ {
+ int nid = 0;
+ if (name.isEmpty())
+ return nid;
+
+ ensureInitialized(); // TLSTODO: check if it's needed!
+#ifndef OPENSSL_NO_EC
+ const QByteArray curveNameLatin1 = name.toLatin1();
+ nid = q_OBJ_sn2nid(curveNameLatin1.data());
+
+ if (nid == 0)
+ nid = q_EC_curve_nist2nid(curveNameLatin1.data());
+#endif // !OPENSSL_NO_EC
+
+ return nid;
+ }
+
+ int QTlsBackendOpenSSL::curveIdFromLongName(const QString &name) const
+ {
+ int nid = 0;
+ if (name.isEmpty())
+ return nid;
+
+ ensureInitialized();
+
+#ifndef OPENSSL_NO_EC
+ const QByteArray curveNameLatin1 = name.toLatin1();
+ nid = q_OBJ_ln2nid(curveNameLatin1.data());
+#endif
+
+ return nid;
+ }
+
+ QString QTlsBackendOpenSSL::shortNameForId(int id) const
+ {
+ QString result;
+
+#ifndef OPENSSL_NO_EC
+ if (id != 0)
+ result = QString::fromLatin1(q_OBJ_nid2sn(id));
+#endif
+
+ return result;
+ }
+
+QString QTlsBackendOpenSSL::longNameForId(int id) const
+{
+ QString result;
+
+#ifndef OPENSSL_NO_EC
+ if (id != 0)
+ result = QString::fromLatin1(q_OBJ_nid2ln(id));
+#endif
+
+ return result;
+}
+
+// NIDs of named curves allowed in TLS as per RFCs 4492 and 7027,
+// see also https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-8
+static const int tlsNamedCurveNIDs[] = {
+ // RFC 4492
+ NID_sect163k1,
+ NID_sect163r1,
+ NID_sect163r2,
+ NID_sect193r1,
+ NID_sect193r2,
+ NID_sect233k1,
+ NID_sect233r1,
+ NID_sect239k1,
+ NID_sect283k1,
+ NID_sect283r1,
+ NID_sect409k1,
+ NID_sect409r1,
+ NID_sect571k1,
+ NID_sect571r1,
+
+ NID_secp160k1,
+ NID_secp160r1,
+ NID_secp160r2,
+ NID_secp192k1,
+ NID_X9_62_prime192v1, // secp192r1
+ NID_secp224k1,
+ NID_secp224r1,
+ NID_secp256k1,
+ NID_X9_62_prime256v1, // secp256r1
+ NID_secp384r1,
+ NID_secp521r1,
+
+ // RFC 7027
+ NID_brainpoolP256r1,
+ NID_brainpoolP384r1,
+ NID_brainpoolP512r1
+};
+
+const size_t tlsNamedCurveNIDCount = sizeof(tlsNamedCurveNIDs) / sizeof(tlsNamedCurveNIDs[0]);
+
+bool QTlsBackendOpenSSL::isTlsNamedCurve(int id) const
+{
+ const int *const tlsNamedCurveNIDsEnd = tlsNamedCurveNIDs + tlsNamedCurveNIDCount;
+ return std::find(tlsNamedCurveNIDs, tlsNamedCurveNIDsEnd, id) != tlsNamedCurveNIDsEnd;
+}
+
+QString QTlsBackendOpenSSL::msgErrorsDuringHandshake()
+{
+ return QSslSocket::tr("Error during SSL handshake: %1").arg(getErrorsFromOpenSsl());
+}
+
+QSslCipher QTlsBackendOpenSSL::qt_OpenSSL_cipher_to_QSslCipher(const SSL_CIPHER *cipher)
+{
+ Q_ASSERT(cipher);
+ char buf [256] = {};
+ const QString desc = QString::fromLatin1(q_SSL_CIPHER_description(cipher, buf, sizeof(buf)));
+ int supportedBits = 0;
+ const int bits = q_SSL_CIPHER_get_bits(cipher, &supportedBits);
+ return createCiphersuite(desc, bits, supportedBits);
+}
+
+void QTlsBackendOpenSSL::forceAutotestSecurityLevel()
+{
+ QSslContext::forceAutoTestSecurityLevel();
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qtlsbackend_openssl_p.cpp"
diff --git a/src/plugins/tls/openssl/qtlsbackend_openssl_p.h b/src/plugins/tls/openssl/qtlsbackend_openssl_p.h
new file mode 100644
index 0000000000..b9f1f95df0
--- /dev/null
+++ b/src/plugins/tls/openssl/qtlsbackend_openssl_p.h
@@ -0,0 +1,104 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QTLSBACKEND_OPENSSL_P_H
+#define QTLSBACKEND_OPENSSL_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 <QtNetwork/private/qtnetworkglobal_p.h>
+
+#include <QtNetwork/qssldiffiehellmanparameters.h>
+#include <QtNetwork/qsslcertificate.h>
+
+#include <QtNetwork/private/qtlsbackend_p.h>
+
+#include <QtCore/qglobal.h>
+#include <QtCore/qlist.h>
+
+#include <openssl/ssl.h>
+
+QT_BEGIN_NAMESPACE
+
+class QTlsBackendOpenSSL final : public QTlsBackend
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID QTlsBackend_iid)
+ Q_INTERFACES(QTlsBackend)
+
+public:
+
+ static QString getErrorsFromOpenSsl();
+ static void logAndClearErrorQueue();
+ static void clearErrorQueue();
+
+ // Index used in SSL_get_ex_data to get the matching TlsCryptographerOpenSSL:
+ static int s_indexForSSLExtraData;
+
+ static QString msgErrorsDuringHandshake();
+ static QSslCipher qt_OpenSSL_cipher_to_QSslCipher(const SSL_CIPHER *cipher);
+private:
+ static bool ensureLibraryLoaded();
+ QString backendName() const override;
+ bool isValid() const override;
+ long tlsLibraryVersionNumber() const override;
+ QString tlsLibraryVersionString() const override;
+ long tlsLibraryBuildVersionNumber() const override;
+ QString tlsLibraryBuildVersionString() const override;
+
+ void ensureInitialized() const override;
+ void ensureCiphersAndCertsLoaded() const;
+ static void resetDefaultCiphers();
+
+ QList<QSsl::SslProtocol> supportedProtocols() const override;
+ QList<QSsl::SupportedFeature> supportedFeatures() const override;
+ QList<QSsl::ImplementedClass> implementedClasses() const override;
+
+ // QSslKey:
+ QTlsPrivate::TlsKey *createKey() const override;
+
+ // QSslCertificate:
+ QTlsPrivate::X509Certificate *createCertificate() const override;
+ QList<QSslCertificate> systemCaCertificates() const override;
+
+ QTlsPrivate::TlsCryptograph *createTlsCryptograph() const override;
+ QTlsPrivate::DtlsCookieVerifier *createDtlsCookieVerifier() const override;
+ QTlsPrivate::DtlsCryptograph *createDtlsCryptograph(QDtls *q, int mode) const override;
+
+ QTlsPrivate::X509ChainVerifyPtr X509Verifier() const override;
+ QTlsPrivate::X509PemReaderPtr X509PemReader() const override;
+ QTlsPrivate::X509DerReaderPtr X509DerReader() const override;
+ QTlsPrivate::X509Pkcs12ReaderPtr X509Pkcs12Reader() const override;
+
+ // Elliptic curves:
+ QList<int> ellipticCurvesIds() const override;
+ int curveIdFromShortName(const QString &name) const override;
+ int curveIdFromLongName(const QString &name) const override;
+ QString shortNameForId(int cid) const override;
+ QString longNameForId(int cid) const override;
+ bool isTlsNamedCurve(int cid) const override;
+
+ // DH parameters:
+ using DHParams = QSslDiffieHellmanParameters;
+ int dhParametersFromDer(const QByteArray &derData, QByteArray *data) const override;
+ int dhParametersFromPem(const QByteArray &pemData, QByteArray *data) const override;
+
+ 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
new file mode 100644
index 0000000000..294fc2ffcd
--- /dev/null
+++ b/src/plugins/tls/openssl/qtlskey_openssl.cpp
@@ -0,0 +1,541 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qsslsocket_openssl_symbols_p.h"
+#include "qtlsbackend_openssl_p.h"
+#include "qtlskey_openssl_p.h"
+
+#include <QtNetwork/private/qsslkey_p.h>
+
+#include <QtNetwork/qsslsocket.h>
+
+#include <QtCore/qscopeguard.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QTlsPrivate {
+
+void TlsKeyOpenSSL::decodeDer(QSsl::KeyType type, QSsl::KeyAlgorithm algorithm, const QByteArray &der,
+ const QByteArray &passPhrase, bool deepClear)
+{
+ if (der.isEmpty())
+ return;
+
+ keyType = type;
+ keyAlgorithm = algorithm;
+
+ QMap<QByteArray, QByteArray> headers;
+ const auto pem = pemFromDer(der, headers);
+
+ decodePem(type, algorithm, pem, passPhrase, deepClear);
+}
+
+void TlsKeyOpenSSL::decodePem(KeyType type, KeyAlgorithm algorithm, const QByteArray &pem,
+ const QByteArray &passPhrase, bool deepClear)
+{
+ if (pem.isEmpty())
+ return;
+
+ keyType = type;
+ keyAlgorithm = algorithm;
+
+ clear(deepClear);
+
+ BIO *bio = q_BIO_new_mem_buf(const_cast<char *>(pem.data()), pem.size());
+ if (!bio)
+ return;
+
+ const auto bioRaii = qScopeGuard([bio]{q_BIO_free(bio);});
+
+ 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)
+ : q_PEM_read_bio_RSAPrivateKey(bio, &rsa, nullptr, phrase);
+ if (rsa && rsa == result)
+ keyIsNull = false;
+ } else if (algorithm == QSsl::Dsa) {
+ DSA *result = (type == QSsl::PublicKey)
+ ? q_PEM_read_bio_DSA_PUBKEY(bio, &dsa, nullptr, phrase)
+ : q_PEM_read_bio_DSAPrivateKey(bio, &dsa, nullptr, phrase);
+ if (dsa && dsa == result)
+ keyIsNull = false;
+ } else if (algorithm == QSsl::Dh) {
+ EVP_PKEY *result = (type == QSsl::PublicKey)
+ ? q_PEM_read_bio_PUBKEY(bio, nullptr, nullptr, phrase)
+ : q_PEM_read_bio_PrivateKey(bio, nullptr, nullptr, phrase);
+ if (result)
+ dh = q_EVP_PKEY_get1_DH(result);
+ if (dh)
+ keyIsNull = false;
+ q_EVP_PKEY_free(result);
+#ifndef OPENSSL_NO_EC
+ } else if (algorithm == QSsl::Ec) {
+ EC_KEY *result = (type == QSsl::PublicKey)
+ ? q_PEM_read_bio_EC_PUBKEY(bio, &ec, nullptr, phrase)
+ : q_PEM_read_bio_ECPrivateKey(bio, &ec, nullptr, phrase);
+ if (ec && ec == result)
+ keyIsNull = false;
+#endif // OPENSSL_NO_EC
+ }
+
+#endif // OPENSSL_NO_DEPRECATED_3_0
+}
+
+QByteArray TlsKeyOpenSSL::derFromPem(const QByteArray &pem, QMap<QByteArray, QByteArray> *headers) const
+{
+ QByteArray header = pemHeader();
+ QByteArray footer = pemFooter();
+
+ QByteArray der(pem);
+
+ int headerIndex = der.indexOf(header);
+ int footerIndex = der.indexOf(footer, headerIndex + header.size());
+ if (type() != QSsl::PublicKey) {
+ if (headerIndex == -1 || footerIndex == -1) {
+ header = pkcs8Header(true);
+ footer = pkcs8Footer(true);
+ headerIndex = der.indexOf(header);
+ footerIndex = der.indexOf(footer, headerIndex + header.size());
+ }
+ if (headerIndex == -1 || footerIndex == -1) {
+ header = pkcs8Header(false);
+ footer = pkcs8Footer(false);
+ headerIndex = der.indexOf(header);
+ footerIndex = der.indexOf(footer, headerIndex + header.size());
+ }
+ }
+ if (headerIndex == -1 || footerIndex == -1)
+ return QByteArray();
+
+ der = der.mid(headerIndex + header.size(), footerIndex - (headerIndex + header.size()));
+
+ if (der.contains("Proc-Type:")) {
+ // taken from QHttpNetworkReplyPrivate::parseHeader
+ int i = 0;
+ while (i < der.size()) {
+ int j = der.indexOf(':', i); // field-name
+ if (j == -1)
+ break;
+ const QByteArray field = der.mid(i, j - i).trimmed();
+ j++;
+ // any number of LWS is allowed before and after the value
+ QByteArray value;
+ do {
+ i = der.indexOf('\n', j);
+ if (i == -1)
+ break;
+ if (!value.isEmpty())
+ value += ' ';
+ // check if we have CRLF or only LF
+ bool hasCR = (i && der[i-1] == '\r');
+ int length = i -(hasCR ? 1: 0) - j;
+ value += der.mid(j, length).trimmed();
+ j = ++i;
+ } while (i < der.size() && (der.at(i) == ' ' || der.at(i) == '\t'));
+ if (i == -1)
+ break; // something is wrong
+
+ headers->insert(field, value);
+ }
+ der = der.mid(i);
+ }
+
+ return QByteArray::fromBase64(der); // ignores newlines
+}
+
+void TlsKeyOpenSSL::clear(bool deep)
+{
+ keyIsNull = true;
+
+#ifndef OPENSSL_NO_DEPRECATED_3_0
+ if (algorithm() == QSsl::Rsa && rsa) {
+ if (deep)
+ q_RSA_free(rsa);
+ rsa = nullptr;
+ }
+ if (algorithm() == QSsl::Dsa && dsa) {
+ if (deep)
+ q_DSA_free(dsa);
+ dsa = nullptr;
+ }
+ if (algorithm() == QSsl::Dh && dh) {
+ if (deep)
+ q_DH_free(dh);
+ dh = nullptr;
+ }
+#ifndef OPENSSL_NO_EC
+ if (algorithm() == QSsl::Ec && ec) {
+ if (deep)
+ q_EC_KEY_free(ec);
+ 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
+{
+ 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:
+ return Qt::HANDLE(dsa);
+ case QSsl::Dh:
+ return Qt::HANDLE(dh);
+#ifndef OPENSSL_NO_EC
+ case QSsl::Ec:
+ return Qt::HANDLE(ec);
+#endif
+ 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(genericKey);
+#endif
+}
+
+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);
+ case QSsl::Dsa:
+ return q_DSA_bits(dsa);
+ case QSsl::Dh:
+ return q_DH_bits(dh);
+#ifndef OPENSSL_NO_EC
+ case QSsl::Ec:
+ return q_EC_GROUP_get_degree(q_EC_KEY_get0_group(ec));
+#endif
+ 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
+{
+ if (!QSslSocket::supportsSsl() || isNull() || algorithm() == QSsl::Opaque)
+ return {};
+
+ const EVP_CIPHER *cipher = nullptr;
+ if (type() == QSsl::PrivateKey && !passPhrase.isEmpty()) {
+#ifndef OPENSSL_NO_DES
+ cipher = q_EVP_des_ede3_cbc();
+#else
+ return {};
+#endif
+ }
+
+ BIO *bio = q_BIO_new(q_BIO_s_mem());
+ if (!bio)
+ return {};
+
+ const auto bioRaii = qScopeGuard([bio]{q_BIO_free(bio);});
+
+#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 (!write_pubkey(RSA, rsa))
+ fail = true;
+ } else if (!write_privatekey(RSA, rsa)) {
+ fail = true;
+ }
+ } else if (algorithm() == QSsl::Dsa) {
+ if (type() == QSsl::PublicKey) {
+ 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
+#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)) {
+ fail = true;
+ }
+#ifndef OPENSSL_NO_EC
+ } else if (algorithm() == QSsl::Ec) {
+ if (type() == QSsl::PublicKey) {
+ if (!write_pubkey(EC, ec))
+ fail = true;
+ } else {
+ if (!write_privatekey(EC, ec))
+ fail = true;
+ }
+#endif
+ } else {
+ fail = true;
+ }
+
+ QByteArray pem;
+ if (!fail) {
+ char *data = nullptr;
+ const long size = q_BIO_get_mem_data(bio, &data);
+ if (size > 0 && data)
+ pem = QByteArray(data, size);
+ } else {
+ QTlsBackendOpenSSL::logAndClearErrorQueue();
+ }
+
+ return pem;
+}
+
+void TlsKeyOpenSSL::fromHandle(Qt::HANDLE handle, QSsl::KeyType expectedType)
+{
+ EVP_PKEY *evpKey = reinterpret_cast<EVP_PKEY *>(handle);
+ if (!evpKey || !fromEVP_PKEY(evpKey)) {
+ opaque = evpKey;
+ keyAlgorithm = QSsl::Opaque;
+ } else {
+ q_EVP_PKEY_free(evpKey);
+ }
+
+ keyType = expectedType;
+ keyIsNull = !opaque;
+}
+
+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;
+ get_key(rsa, RSA);
+ return true;
+ case EVP_PKEY_DSA:
+ keyIsNull = false;
+ keyAlgorithm = QSsl::Dsa;
+ keyType = QSsl::PrivateKey;
+ get_key(dsa, DSA);
+ return true;
+ case EVP_PKEY_DH:
+ keyIsNull = false;
+ keyAlgorithm = QSsl::Dh;
+ keyType = QSsl::PrivateKey;
+ get_key(dh, DH);
+ return true;
+#ifndef OPENSSL_NO_EC
+ case EVP_PKEY_EC:
+ keyIsNull = false;
+ keyAlgorithm = QSsl::Ec;
+ keyType = QSsl::PrivateKey;
+ get_key(ec, EC_KEY);
+ return true;
+#endif
+ default:;
+ // Unknown key type. This could be handled as opaque, but then
+ // we'd eventually leak memory since we wouldn't be able to free
+ // the underlying EVP_PKEY structure. For now, we won't support
+ // this.
+ }
+
+ return false;
+}
+
+QByteArray doCrypt(QSslKeyPrivate::Cipher cipher, const QByteArray &data,
+ const QByteArray &key, const QByteArray &iv, bool enc)
+{
+ const EVP_CIPHER *type = nullptr;
+ int i = 0, len = 0;
+
+ switch (cipher) {
+ case Cipher::DesCbc:
+#ifndef OPENSSL_NO_DES
+ type = q_EVP_des_cbc();
+#endif
+ break;
+ case Cipher::DesEde3Cbc:
+#ifndef OPENSSL_NO_DES
+ type = q_EVP_des_ede3_cbc();
+#endif
+ break;
+ case Cipher::Rc2Cbc:
+#ifndef OPENSSL_NO_RC2
+ type = q_EVP_rc2_cbc();
+#endif
+ break;
+ case Cipher::Aes128Cbc:
+ type = q_EVP_aes_128_cbc();
+ break;
+ case Cipher::Aes192Cbc:
+ type = q_EVP_aes_192_cbc();
+ break;
+ case Cipher::Aes256Cbc:
+ type = q_EVP_aes_256_cbc();
+ break;
+ }
+
+ if (type == nullptr)
+ return {};
+
+ QByteArray output;
+ output.resize(data.size() + EVP_MAX_BLOCK_LENGTH);
+
+ EVP_CIPHER_CTX *ctx = q_EVP_CIPHER_CTX_new();
+ q_EVP_CIPHER_CTX_reset(ctx);
+ 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);
+
+ q_EVP_CipherInit_ex(ctx, nullptr, nullptr,
+ reinterpret_cast<const unsigned char *>(key.constData()),
+ reinterpret_cast<const unsigned char *>(iv.constData()),
+ enc);
+ q_EVP_CipherUpdate(ctx,
+ reinterpret_cast<unsigned char *>(output.data()), &len,
+ reinterpret_cast<const unsigned char *>(data.constData()), data.size());
+ q_EVP_CipherFinal(ctx,
+ reinterpret_cast<unsigned char *>(output.data()) + len, &i);
+ len += i;
+
+ q_EVP_CIPHER_CTX_reset(ctx);
+ q_EVP_CIPHER_CTX_free(ctx);
+
+ return output.left(len);
+}
+
+QByteArray TlsKeyOpenSSL::decrypt(Cipher cipher, const QByteArray &data,
+ const QByteArray &key, const QByteArray &iv) const
+{
+ return doCrypt(cipher, data, key, iv, false);
+}
+
+QByteArray TlsKeyOpenSSL::encrypt(Cipher cipher, const QByteArray &data,
+ const QByteArray &key, const QByteArray &iv) const
+{
+ return doCrypt(cipher, data, key, iv, true);
+}
+
+TlsKeyOpenSSL *TlsKeyOpenSSL::publicKeyFromX509(X509 *x)
+{
+ TlsKeyOpenSSL *tlsKey = new TlsKeyOpenSSL;
+ std::unique_ptr<TlsKeyOpenSSL> keyRaii(tlsKey);
+
+ 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) {
+ get_pubkey(rsa, RSA);
+ tlsKey->keyAlgorithm = QSsl::Rsa;
+ tlsKey->keyIsNull = false;
+ } else if (keyType == EVP_PKEY_DSA) {
+ get_pubkey(dsa, DSA);
+ tlsKey->keyAlgorithm = QSsl::Dsa;
+ tlsKey->keyIsNull = false;
+#ifndef OPENSSL_NO_EC
+ } else if (keyType == EVP_PKEY_EC) {
+ get_pubkey(ec, EC_KEY);
+ tlsKey->keyAlgorithm = QSsl::Ec;
+ tlsKey->keyIsNull = false;
+#endif
+ } else if (keyType == EVP_PKEY_DH) {
+ // DH unsupported (key is null)
+ } else {
+ // error? (key is null)
+ }
+
+#ifndef OPENSSL_NO_DEPRECATED_3_0
+ q_EVP_PKEY_free(pkey);
+#endif
+
+ return keyRaii.release();
+}
+
+} // namespace QTlsPrivate
+
+QT_END_NAMESPACE
diff --git a/src/plugins/tls/openssl/qtlskey_openssl_p.h b/src/plugins/tls/openssl/qtlskey_openssl_p.h
new file mode 100644
index 0000000000..4ee16ffc29
--- /dev/null
+++ b/src/plugins/tls/openssl/qtlskey_openssl_p.h
@@ -0,0 +1,100 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QTLSKEY_OPENSSL_H
+#define QTLSKEY_OPENSSL_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 <QtNetwork/private/qtnetworkglobal_p.h>
+
+#include "../shared/qtlskey_base_p.h"
+
+#include <QtNetwork/private/qtlsbackend_p.h>
+#include <QtNetwork/private/qsslkey_p.h>
+
+#include <QtNetwork/qssl.h>
+
+#include <QtCore/qbytearray.h>
+#include <QtCore/qglobal.h>
+
+#include <openssl/rsa.h>
+#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);
+
+namespace QTlsPrivate {
+
+class TlsKeyOpenSSL final : public TlsKeyBase
+{
+public:
+ TlsKeyOpenSSL()
+ : opaque(nullptr)
+ {
+ clear(false);
+ }
+ ~TlsKeyOpenSSL()
+ {
+ clear(true);
+ }
+
+ void decodeDer(KeyType type, KeyAlgorithm algorithm, const QByteArray &der,
+ const QByteArray &passPhrase, bool deepClear) override;
+ void decodePem(KeyType type, KeyAlgorithm algorithm, const QByteArray &pem,
+ const QByteArray &passPhrase, bool deepClear) override;
+
+ QByteArray toPem(const QByteArray &passPhrase) const override;
+ QByteArray derFromPem(const QByteArray &pem, QMap<QByteArray, QByteArray> *headers) const override;
+
+ void fromHandle(Qt::HANDLE opaque, KeyType expectedType) override;
+
+ void clear(bool deep) override;
+ Qt::HANDLE handle() const override;
+ int length() const override;
+
+ QByteArray decrypt(Cipher cipher, const QByteArray &data,
+ const QByteArray &key, const QByteArray &iv) const override;
+ QByteArray encrypt(Cipher cipher, const QByteArray &data,
+ const QByteArray &key, const QByteArray &iv) const override;
+
+ static TlsKeyOpenSSL *publicKeyFromX509(X509 *x);
+
+ union {
+ EVP_PKEY *opaque;
+ RSA *rsa;
+ DSA *dsa;
+ DH *dh;
+#ifndef OPENSSL_NO_EC
+ EC_KEY *ec;
+#endif
+ EVP_PKEY *genericKey;
+ };
+
+ bool fromEVP_PKEY(EVP_PKEY *pkey);
+};
+
+} // namespace QTlsPrivate
+
+QT_END_NAMESPACE
+
+#endif // QTLSKEY_OPENSSL_H
diff --git a/src/plugins/tls/openssl/qwindowscarootfetcher.cpp b/src/plugins/tls/openssl/qwindowscarootfetcher.cpp
new file mode 100644
index 0000000000..a18aae0b71
--- /dev/null
+++ b/src/plugins/tls/openssl/qwindowscarootfetcher.cpp
@@ -0,0 +1,249 @@
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qwindowscarootfetcher_p.h"
+#include "qx509_openssl_p.h"
+#include "qopenssl_p.h"
+
+#include <QtCore/QThread>
+#include <QtGlobal>
+
+#include <QtCore/qscopeguard.h>
+
+#ifdef QSSLSOCKET_DEBUG
+#include <QtNetwork/private/qtlsbackend_p.h> // for debug categories
+#include <QtCore/QElapsedTimer>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+class QWindowsCaRootFetcherThread : public QThread
+{
+public:
+ QWindowsCaRootFetcherThread()
+ {
+ qRegisterMetaType<QSslCertificate>();
+ setObjectName(QStringLiteral("QWindowsCaRootFetcher"));
+ start();
+ }
+ ~QWindowsCaRootFetcherThread()
+ {
+ quit();
+ wait(15500); // worst case, a running request can block for 15 seconds
+ }
+};
+
+Q_GLOBAL_STATIC(QWindowsCaRootFetcherThread, windowsCaRootFetcherThread);
+
+namespace {
+
+const QList<QSslCertificate> buildVerifiedChain(const QList<QSslCertificate> &caCertificates,
+ PCCERT_CHAIN_CONTEXT chainContext,
+ const QString &peerVerifyName)
+{
+ // We ended up here because OpenSSL verification failed to
+ // build a chain, with intermediate certificate missing
+ // but "Authority Information Access" extension present.
+ // Also, apparently the normal CA fetching path was disabled
+ // by setting custom CA certificates. We convert wincrypt's
+ // structures in QSslCertificate and give OpenSSL the second
+ // chance to verify the now (apparently) complete chain.
+ // In addition, wincrypt gives us a benefit of some checks
+ // we don't have in OpenSSL back-end.
+ Q_ASSERT(chainContext);
+
+ if (!chainContext->cChain)
+ return {};
+
+ QList<QSslCertificate> verifiedChain;
+
+ CERT_SIMPLE_CHAIN *chain = chainContext->rgpChain[chainContext->cChain - 1];
+ if (!chain)
+ return {};
+
+ if (chain->TrustStatus.dwErrorStatus & CERT_TRUST_IS_PARTIAL_CHAIN)
+ return {}; // No need to mess with OpenSSL (the chain is still incomplete).
+
+ for (DWORD i = 0; i < chain->cElement; ++i) {
+ CERT_CHAIN_ELEMENT *element = chain->rgpElement[i];
+ QSslCertificate cert(QByteArray(reinterpret_cast<const char*>(element->pCertContext->pbCertEncoded),
+ int(element->pCertContext->cbCertEncoded)), QSsl::Der);
+
+ if (cert.isBlacklisted())
+ return {};
+
+ if (element->TrustStatus.dwErrorStatus & CERT_TRUST_IS_REVOKED) // Good to know!
+ return {};
+
+ if (element->TrustStatus.dwErrorStatus & CERT_TRUST_IS_NOT_SIGNATURE_VALID)
+ return {};
+
+ verifiedChain.append(cert);
+ }
+
+ // We rely on OpenSSL's ability to find other problems.
+ const auto tlsErrors = QTlsPrivate::X509CertificateOpenSSL::verify(caCertificates, verifiedChain, peerVerifyName);
+ if (tlsErrors.size())
+ verifiedChain.clear();
+
+ return verifiedChain;
+}
+
+} // unnamed namespace
+
+QWindowsCaRootFetcher::QWindowsCaRootFetcher(const QSslCertificate &certificate, QSslSocket::SslMode sslMode,
+ const QList<QSslCertificate> &caCertificates, const QString &hostName)
+ : cert(certificate), mode(sslMode), explicitlyTrustedCAs(caCertificates), peerVerifyName(hostName)
+{
+ moveToThread(windowsCaRootFetcherThread());
+}
+
+QWindowsCaRootFetcher::~QWindowsCaRootFetcher()
+{
+}
+
+void QWindowsCaRootFetcher::start()
+{
+ QByteArray der = cert.toDer();
+ PCCERT_CONTEXT wincert = CertCreateCertificateContext(X509_ASN_ENCODING, (const BYTE *)der.constData(), der.length());
+ if (!wincert) {
+#ifdef QSSLSOCKET_DEBUG
+ qCDebug(lcTlsBackend, "QWindowsCaRootFetcher failed to convert certificate to windows form");
+#endif
+ emit finished(cert, QSslCertificate());
+ deleteLater();
+ return;
+ }
+
+ CERT_CHAIN_PARA parameters;
+ memset(&parameters, 0, sizeof(parameters));
+ parameters.cbSize = sizeof(parameters);
+ // set key usage constraint
+ parameters.RequestedUsage.dwType = USAGE_MATCH_TYPE_AND;
+ parameters.RequestedUsage.Usage.cUsageIdentifier = 1;
+ LPSTR oid = (LPSTR)(mode == QSslSocket::SslClientMode ? szOID_PKIX_KP_SERVER_AUTH : szOID_PKIX_KP_CLIENT_AUTH);
+ parameters.RequestedUsage.Usage.rgpszUsageIdentifier = &oid;
+
+#ifdef QSSLSOCKET_DEBUG
+ QElapsedTimer stopwatch;
+ stopwatch.start();
+#endif
+ PCCERT_CHAIN_CONTEXT chain;
+ auto additionalStore = createAdditionalStore();
+ BOOL result = CertGetCertificateChain(
+ nullptr, //default engine
+ wincert,
+ nullptr, //current date/time
+ additionalStore.get(), //default store (nullptr) or CAs an application trusts
+ &parameters,
+ 0, //default dwFlags
+ nullptr, //reserved
+ &chain);
+#ifdef QSSLSOCKET_DEBUG
+ qCDebug(lcSsl) << "QWindowsCaRootFetcher" << stopwatch.elapsed() << "ms to get chain";
+#endif
+
+ QSslCertificate trustedRoot;
+ if (result) {
+#ifdef QSSLSOCKET_DEBUG
+ qCDebug(lcSsl) << "QWindowsCaRootFetcher - examining windows chains";
+ if (chain->TrustStatus.dwErrorStatus == CERT_TRUST_NO_ERROR)
+ qCDebug(lcSsl) << " - TRUSTED";
+ else
+ qCDebug(lcSsl) << " - NOT TRUSTED" << chain->TrustStatus.dwErrorStatus;
+ if (chain->TrustStatus.dwInfoStatus & CERT_TRUST_IS_SELF_SIGNED)
+ qCDebug(lcSsl) << " - SELF SIGNED";
+ qCDebug(lcSsl) << "QWindowsCaRootFetcher - dumping simple chains";
+ for (unsigned int i = 0; i < chain->cChain; i++) {
+ if (chain->rgpChain[i]->TrustStatus.dwErrorStatus == CERT_TRUST_NO_ERROR)
+ qCDebug(lcSsl) << " - TRUSTED SIMPLE CHAIN" << i;
+ else
+ qCDebug(lcSsl) << " - UNTRUSTED SIMPLE CHAIN" << i << "reason:" << chain->rgpChain[i]->TrustStatus.dwErrorStatus;
+ for (unsigned int j = 0; j < chain->rgpChain[i]->cElement; j++) {
+ QSslCertificate foundCert(QByteArray((const char *)chain->rgpChain[i]->rgpElement[j]->pCertContext->pbCertEncoded
+ , chain->rgpChain[i]->rgpElement[j]->pCertContext->cbCertEncoded), QSsl::Der);
+ qCDebug(lcSsl) << " - " << foundCert;
+ }
+ }
+ qCDebug(lcSsl) << " - and" << chain->cLowerQualityChainContext << "low quality chains"; //expect 0, we haven't asked for them
+#endif
+
+ //based on http://msdn.microsoft.com/en-us/library/windows/desktop/aa377182%28v=vs.85%29.aspx
+ //about the final chain rgpChain[cChain-1] which must begin with a trusted root to be valid
+ if (chain->TrustStatus.dwErrorStatus == CERT_TRUST_NO_ERROR
+ && chain->cChain > 0) {
+ const PCERT_SIMPLE_CHAIN finalChain = chain->rgpChain[chain->cChain - 1];
+ // http://msdn.microsoft.com/en-us/library/windows/desktop/aa377544%28v=vs.85%29.aspx
+ // rgpElement[0] is the end certificate chain element. rgpElement[cElement-1] is the self-signed "root" certificate element.
+ if (finalChain->TrustStatus.dwErrorStatus == CERT_TRUST_NO_ERROR
+ && finalChain->cElement > 0) {
+ trustedRoot = QSslCertificate(QByteArray((const char *)finalChain->rgpElement[finalChain->cElement - 1]->pCertContext->pbCertEncoded
+ , finalChain->rgpElement[finalChain->cElement - 1]->pCertContext->cbCertEncoded), QSsl::Der);
+ }
+ } else if (explicitlyTrustedCAs.size()) {
+ // Setting custom CA in configuration, and those CAs are not trusted by MS.
+#if QT_CONFIG(openssl)
+ const auto verifiedChain = buildVerifiedChain(explicitlyTrustedCAs, chain, peerVerifyName);
+ if (verifiedChain.size())
+ trustedRoot = verifiedChain.last();
+#else
+ //It's only OpenSSL code-path that can trigger such a fetch.
+ Q_UNREACHABLE();
+#endif
+ }
+ CertFreeCertificateChain(chain);
+ }
+ CertFreeCertificateContext(wincert);
+
+ emit finished(cert, trustedRoot);
+ deleteLater();
+}
+
+QHCertStorePointer QWindowsCaRootFetcher::createAdditionalStore() const
+{
+ QHCertStorePointer customStore;
+ if (explicitlyTrustedCAs.isEmpty())
+ return customStore;
+
+ if (HCERTSTORE rawPtr = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, 0, nullptr)) {
+ customStore.reset(rawPtr);
+
+ unsigned rootsAdded = 0;
+ for (const QSslCertificate &caCert : explicitlyTrustedCAs) {
+ const auto der = caCert.toDer();
+ PCCERT_CONTEXT winCert = CertCreateCertificateContext(X509_ASN_ENCODING,
+ reinterpret_cast<const BYTE *>(der.data()),
+ DWORD(der.length()));
+ if (!winCert) {
+#if defined(QSSLSOCKET_DEBUG)
+ qCWarning(lcSsl) << "CA fetcher, failed to convert QSslCertificate"
+ << "to the native representation";
+#endif // QSSLSOCKET_DEBUG
+ continue;
+ }
+ const auto deleter = qScopeGuard([winCert](){
+ CertFreeCertificateContext(winCert);
+ });
+ if (CertAddCertificateContextToStore(customStore.get(), winCert, CERT_STORE_ADD_ALWAYS, nullptr))
+ ++rootsAdded;
+#if defined(QSSLSOCKET_DEBUG)
+ else //Why assert? With flags we're using and winCert check - should not happen!
+ Q_ASSERT("CertAddCertificateContextToStore() failed");
+#endif // QSSLSOCKET_DEBUG
+ }
+ if (!rootsAdded) //Useless store, no cert was added.
+ customStore.reset();
+#if defined(QSSLSOCKET_DEBUG)
+ } else {
+
+ qCWarning(lcSsl) << "CA fetcher, failed to create a custom"
+ << "store for explicitly trusted CA certificate";
+#endif // QSSLSOCKET_DEBUG
+ }
+
+ return customStore;
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qwindowscarootfetcher_p.cpp"
diff --git a/src/plugins/tls/openssl/qwindowscarootfetcher_p.h b/src/plugins/tls/openssl/qwindowscarootfetcher_p.h
new file mode 100644
index 0000000000..715fd19945
--- /dev/null
+++ b/src/plugins/tls/openssl/qwindowscarootfetcher_p.h
@@ -0,0 +1,59 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QWINDOWSCAROOTFETCHER_P_H
+#define QWINDOWSCAROOTFETCHER_P_H
+
+#include <QtNetwork/private/qtnetworkglobal_p.h>
+
+#include <QtNetwork/qsslcertificate.h>
+#include <QtNetwork/qsslsocket.h>
+
+#include <QtCore/QtGlobal>
+#include <QtCore/QObject>
+
+#include "../shared/qwincrypt_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.
+//
+
+QT_BEGIN_NAMESPACE
+
+class QWindowsCaRootFetcher : public QObject
+{
+ Q_OBJECT
+public:
+ QWindowsCaRootFetcher(const QSslCertificate &certificate, QSslSocket::SslMode sslMode,
+ const QList<QSslCertificate> &caCertificates = {},
+ const QString &hostName = {});
+ ~QWindowsCaRootFetcher();
+public slots:
+ void start();
+signals:
+ void finished(QSslCertificate brokenChain, QSslCertificate caroot);
+private:
+ QHCertStorePointer createAdditionalStore() const;
+
+ QSslCertificate cert;
+ QSslSocket::SslMode mode;
+ // In case the application set CA certificates in the configuration,
+ // in the past we did not load missing certs. But this disables
+ // recoverable case when a certificate has Authority Information Access
+ // extension. So we try to fetch in this scenario also, but in case
+ // explicitly trusted root was not in a system store, we'll do
+ // additional checks, thus we need 'peerVerifyName':
+ QList<QSslCertificate> explicitlyTrustedCAs;
+ QString peerVerifyName;
+};
+
+QT_END_NAMESPACE
+
+#endif // QWINDOWSCAROOTFETCHER_P_H
diff --git a/src/plugins/tls/openssl/qx509_openssl.cpp b/src/plugins/tls/openssl/qx509_openssl.cpp
new file mode 100644
index 0000000000..0cd3749f88
--- /dev/null
+++ b/src/plugins/tls/openssl/qx509_openssl.cpp
@@ -0,0 +1,947 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qsslsocket_openssl_symbols_p.h"
+#include "qtlsbackend_openssl_p.h"
+#include "qtlskey_openssl_p.h"
+#include "qx509_openssl_p.h"
+#include "qtls_openssl_p.h"
+
+#include <QtNetwork/private/qsslcertificate_p.h>
+
+#include <QtNetwork/qsslsocket.h>
+#include <QtNetwork/qhostaddress.h>
+
+#include <QtCore/qendian.h>
+#include <QtCore/qdatetime.h>
+#include <QtCore/qhash.h>
+#include <QtCore/qiodevice.h>
+#include <QtCore/qscopeguard.h>
+#include <QtCore/qtimezone.h>
+#include <QtCore/qvarlengtharray.h>
+
+QT_BEGIN_NAMESPACE
+
+using namespace Qt::StringLiterals;
+
+namespace QTlsPrivate {
+
+namespace {
+
+QByteArray asn1ObjectId(ASN1_OBJECT *object)
+{
+ if (!object)
+ return {};
+
+ char buf[80] = {}; // The openssl docs a buffer length of 80 should be more than enough
+ q_OBJ_obj2txt(buf, sizeof(buf), object, 1); // the 1 says always use the oid not the long name
+
+ return QByteArray(buf);
+}
+
+QByteArray asn1ObjectName(ASN1_OBJECT *object)
+{
+ if (!object)
+ return {};
+
+ const int nid = q_OBJ_obj2nid(object);
+ if (nid != NID_undef)
+ return QByteArray(q_OBJ_nid2sn(nid));
+
+ return asn1ObjectId(object);
+}
+
+QMultiMap<QByteArray, QString> mapFromX509Name(X509_NAME *name)
+{
+ if (!name)
+ return {};
+
+ QMultiMap<QByteArray, QString> info;
+ for (int i = 0; i < q_X509_NAME_entry_count(name); ++i) {
+ X509_NAME_ENTRY *e = q_X509_NAME_get_entry(name, i);
+
+ QByteArray name = asn1ObjectName(q_X509_NAME_ENTRY_get_object(e));
+ unsigned char *data = nullptr;
+ int size = q_ASN1_STRING_to_UTF8(&data, q_X509_NAME_ENTRY_get_data(e));
+ info.insert(name, QString::fromUtf8((char*)data, size));
+ q_CRYPTO_free(data, nullptr, 0);
+ }
+
+ return info;
+}
+
+QDateTime dateTimeFromASN1(const ASN1_TIME *aTime)
+{
+ QDateTime result;
+ tm lTime;
+
+ if (q_ASN1_TIME_to_tm(aTime, &lTime)) {
+ QDate resDate(lTime.tm_year + 1900, lTime.tm_mon + 1, lTime.tm_mday);
+ QTime resTime(lTime.tm_hour, lTime.tm_min, lTime.tm_sec);
+ result = QDateTime(resDate, resTime, QTimeZone::UTC);
+ }
+
+ return result;
+}
+
+
+#define BEGINCERTSTRING "-----BEGIN CERTIFICATE-----"
+#define ENDCERTSTRING "-----END CERTIFICATE-----"
+
+QByteArray x509ToQByteArray(X509 *x509, QSsl::EncodingFormat format)
+{
+ Q_ASSERT(x509);
+
+ // Use i2d_X509 to convert the X509 to an array.
+ const int length = q_i2d_X509(x509, nullptr);
+ if (length <= 0) {
+ QTlsBackendOpenSSL::logAndClearErrorQueue();
+ return {};
+ }
+
+ QByteArray array;
+ array.resize(length);
+
+ char *data = array.data();
+ char **dataP = &data;
+ unsigned char **dataPu = (unsigned char **)dataP;
+ if (q_i2d_X509(x509, dataPu) < 0)
+ return QByteArray();
+
+ if (format == QSsl::Der)
+ return array;
+
+ // Convert to Base64 - wrap at 64 characters.
+ array = array.toBase64();
+ QByteArray tmp;
+ for (int i = 0; i <= array.size() - 64; i += 64) {
+ tmp += QByteArray::fromRawData(array.data() + i, 64);
+ tmp += '\n';
+ }
+ if (int remainder = array.size() % 64) {
+ tmp += QByteArray::fromRawData(array.data() + array.size() - remainder, remainder);
+ tmp += '\n';
+ }
+
+ return BEGINCERTSTRING "\n" + tmp + ENDCERTSTRING "\n";
+}
+
+QString x509ToText(X509 *x509)
+{
+ Q_ASSERT(x509);
+
+ QByteArray result;
+ BIO *bio = q_BIO_new(q_BIO_s_mem());
+ if (!bio)
+ return QString();
+ const auto bioRaii = qScopeGuard([bio]{q_BIO_free(bio);});
+
+ q_X509_print(bio, x509);
+
+ QVarLengthArray<char, 16384> data;
+ int count = q_BIO_read(bio, data.data(), 16384);
+ if ( count > 0 )
+ result = QByteArray( data.data(), count );
+
+ return QString::fromLatin1(result);
+}
+
+QVariant x509UnknownExtensionToValue(X509_EXTENSION *ext)
+{
+ // Get the extension specific method object if available
+ // 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.
+ Q_ASSERT(ext);
+
+ X509V3_EXT_METHOD *meth = const_cast<X509V3_EXT_METHOD *>(q_X509V3_EXT_get(ext));
+ if (!meth) {
+ ASN1_OCTET_STRING *value = q_X509_EXTENSION_get_data(ext);
+ Q_ASSERT(value);
+ QByteArray result( reinterpret_cast<const char *>(q_ASN1_STRING_get0_data(value)),
+ q_ASN1_STRING_length(value));
+ return result;
+ }
+
+ 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) {
+ 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;
+ bool isMap = false;
+
+ for (int j = 0; j < q_SKM_sk_num(val); j++) {
+ CONF_VALUE *nval = q_SKM_sk_value(CONF_VALUE, val, j);
+ if (nval->name && nval->value) {
+ isMap = true;
+ map[QString::fromUtf8(nval->name)] = QString::fromUtf8(nval->value);
+ } else if (nval->name) {
+ list << QString::fromUtf8(nval->name);
+ } else if (nval->value) {
+ list << QString::fromUtf8(nval->value);
+ }
+ }
+
+ if (isMap)
+ return map;
+ else
+ return list;
+ } 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) {
+ QByteArray result;
+
+ BIO *bio = q_BIO_new(q_BIO_s_mem());
+ if (!bio)
+ return result;
+
+ meth->i2r(meth, ext_internal, bio, 0);
+
+ char *bio_buffer;
+ long bio_size = q_BIO_get_mem_data(bio, &bio_buffer);
+ result = QByteArray(bio_buffer, bio_size);
+
+ q_BIO_free(bio);
+ return result;
+ }
+
+ return QVariant();
+}
+
+/*
+ * Convert extensions to a variant. The naming of the keys of the map are
+ * taken from RFC 5280, however we decided the capitalisation in the RFC
+ * was too silly for the real world.
+ */
+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:
+ {
+ BASIC_CONSTRAINTS *basic = reinterpret_cast<BASIC_CONSTRAINTS *>(q_X509V3_EXT_d2i(ext));
+ if (!basic)
+ return {};
+ QVariantMap result;
+ result["ca"_L1] = basic->ca ? true : false;
+ if (basic->pathlen)
+ result["pathLenConstraint"_L1] = (qlonglong)q_ASN1_INTEGER_get(basic->pathlen);
+
+ q_BASIC_CONSTRAINTS_free(basic);
+ return result;
+ }
+ break;
+ case NID_info_access:
+ {
+ AUTHORITY_INFO_ACCESS *info = reinterpret_cast<AUTHORITY_INFO_ACCESS *>(q_X509V3_EXT_d2i(ext));
+ if (!info)
+ return {};
+ QVariantMap result;
+ for (int i=0; i < q_SKM_sk_num(info); i++) {
+ ACCESS_DESCRIPTION *ad = q_SKM_sk_value(ACCESS_DESCRIPTION, info, i);
+
+ GENERAL_NAME *name = ad->location;
+ if (name->type == GEN_URI) {
+ int len = q_ASN1_STRING_length(name->d.uniformResourceIdentifier);
+ if (len < 0 || len >= 8192) {
+ // broken name
+ continue;
+ }
+
+ const char *uriStr = reinterpret_cast<const char *>(q_ASN1_STRING_get0_data(name->d.uniformResourceIdentifier));
+ const QString uri = QString::fromUtf8(uriStr, len);
+
+ result[QString::fromUtf8(asn1ObjectName(ad->method))] = uri;
+ } else {
+ qCWarning(lcTlsBackend) << "Strange location type" << name->type;
+ }
+ }
+
+ q_AUTHORITY_INFO_ACCESS_free(info);
+ return result;
+ }
+ break;
+ case NID_subject_key_identifier:
+ {
+ ext_internal = q_X509V3_EXT_d2i(ext);
+ if (!ext_internal)
+ return {};
+
+ hexString = meth->i2s(meth, ext_internal);
+ return QVariant(QString::fromUtf8(hexString));
+ }
+ break;
+ case NID_authority_key_identifier:
+ {
+ AUTHORITY_KEYID *auth_key = reinterpret_cast<AUTHORITY_KEYID *>(q_X509V3_EXT_d2i(ext));
+ if (!auth_key)
+ return {};
+ QVariantMap result;
+
+ // keyid
+ if (auth_key->keyid) {
+ QByteArray keyid(reinterpret_cast<const char *>(auth_key->keyid->data),
+ auth_key->keyid->length);
+ result["keyid"_L1] = keyid.toHex();
+ }
+
+ // issuer
+ // TODO: GENERAL_NAMES
+
+ // serial
+ if (auth_key->serial)
+ result["serial"_L1] = (qlonglong)q_ASN1_INTEGER_get(auth_key->serial);
+
+ q_AUTHORITY_KEYID_free(auth_key);
+ return result;
+ }
+ break;
+ }
+
+ return {};
+}
+
+} // Unnamed namespace
+
+extern "C" int qt_X509Callback(int ok, X509_STORE_CTX *ctx)
+{
+ if (!ok) {
+ // Store the error and at which depth the error was detected.
+ using ErrorListPtr = QList<QSslErrorEntry> *;
+ ErrorListPtr errors = nullptr;
+
+ // Error list is attached to either 'SSL' or 'X509_STORE'.
+ if (X509_STORE *store = q_X509_STORE_CTX_get0_store(ctx)) // We try store first:
+ errors = ErrorListPtr(q_X509_STORE_get_ex_data(store, 0));
+
+ if (!errors) {
+ // Not found on store? Try SSL and its external data then. According to the OpenSSL's
+ // documentation:
+ //
+ // "Whenever a X509_STORE_CTX object is created for the verification of the
+ // peer's certificate during a handshake, a pointer to the SSL object is
+ // stored into the X509_STORE_CTX object to identify the connection affected.
+ // To retrieve this pointer the X509_STORE_CTX_get_ex_data() function can be
+ // used with the correct index."
+
+ // TLSTODO: verification callback has to change as soon as TlsCryptographer is in place.
+ // This is a temporary solution for now to ease the transition.
+ const auto offset = QTlsBackendOpenSSL::s_indexForSSLExtraData
+ + TlsCryptographOpenSSL::errorOffsetInExData;
+ if (SSL *ssl = static_cast<SSL *>(q_X509_STORE_CTX_get_ex_data(ctx, q_SSL_get_ex_data_X509_STORE_CTX_idx())))
+ errors = ErrorListPtr(q_SSL_get_ex_data(ssl, offset));
+ }
+
+ if (!errors) {
+ qCWarning(lcTlsBackend, "Neither X509_STORE, nor SSL contains error list, verification failed");
+ return 0;
+ }
+
+ errors->append(X509CertificateOpenSSL::errorEntryFromStoreContext(ctx));
+ }
+ // Always return OK to allow verification to continue. We handle the
+ // errors gracefully after collecting all errors, after verification has
+ // completed.
+ return 1;
+}
+
+X509CertificateOpenSSL::X509CertificateOpenSSL() = default;
+
+X509CertificateOpenSSL::~X509CertificateOpenSSL()
+{
+ if (x509)
+ q_X509_free(x509);
+}
+
+bool X509CertificateOpenSSL::isEqual(const X509Certificate &rhs) const
+{
+ //TLSTODO: to make it safe I'll check the backend type later.
+ const auto &other = static_cast<const X509CertificateOpenSSL &>(rhs);
+ if (x509 && other.x509) {
+ const int ret = q_X509_cmp(x509, other.x509);
+ if (ret >= -1 && ret <= 1)
+ return ret == 0;
+ QTlsBackendOpenSSL::logAndClearErrorQueue();
+ }
+
+ return false;
+}
+
+bool X509CertificateOpenSSL::isSelfSigned() const
+{
+ if (!x509)
+ return false;
+
+ return q_X509_check_issued(x509, x509) == X509_V_OK;
+}
+
+QMultiMap<QSsl::AlternativeNameEntryType, QString>
+X509CertificateOpenSSL::subjectAlternativeNames() const
+{
+ QMultiMap<QSsl::AlternativeNameEntryType, QString> result;
+
+ if (!x509)
+ return result;
+
+ auto *altNames = static_cast<STACK_OF(GENERAL_NAME) *>(q_X509_get_ext_d2i(x509, NID_subject_alt_name,
+ nullptr, nullptr));
+ if (!altNames)
+ return result;
+
+ auto altName = [](ASN1_IA5STRING *ia5, int len) {
+ const char *altNameStr = reinterpret_cast<const char *>(q_ASN1_STRING_get0_data(ia5));
+ return QString::fromLatin1(altNameStr, len);
+ };
+
+ for (int i = 0; i < q_sk_GENERAL_NAME_num(altNames); ++i) {
+ const GENERAL_NAME *genName = q_sk_GENERAL_NAME_value(altNames, i);
+ if (genName->type != GEN_DNS && genName->type != GEN_EMAIL && genName->type != GEN_IPADD)
+ continue;
+
+ const int len = q_ASN1_STRING_length(genName->d.ia5);
+ if (len < 0 || len >= 8192) {
+ // broken name
+ continue;
+ }
+
+ switch (genName->type) {
+ case GEN_DNS:
+ result.insert(QSsl::DnsEntry, altName(genName->d.ia5, len));
+ break;
+ case GEN_EMAIL:
+ result.insert(QSsl::EmailEntry, altName(genName->d.ia5, len));
+ break;
+ case GEN_IPADD: {
+ QHostAddress ipAddress;
+ switch (len) {
+ case 4: // IPv4
+ ipAddress = QHostAddress(qFromBigEndian(*reinterpret_cast<quint32 *>(genName->d.iPAddress->data)));
+ break;
+ case 16: // IPv6
+ ipAddress = QHostAddress(reinterpret_cast<quint8 *>(genName->d.iPAddress->data));
+ break;
+ default: // Unknown IP address format
+ break;
+ }
+ if (!ipAddress.isNull())
+ result.insert(QSsl::IpAddressEntry, ipAddress.toString());
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ q_OPENSSL_sk_pop_free((OPENSSL_STACK*)altNames, reinterpret_cast<void(*)(void*)>(q_GENERAL_NAME_free));
+
+ return result;
+}
+
+TlsKey *X509CertificateOpenSSL::publicKey() const
+{
+ if (!x509)
+ return {};
+
+ return TlsKeyOpenSSL::publicKeyFromX509(x509);
+}
+
+QByteArray X509CertificateOpenSSL::toPem() const
+{
+ if (!x509)
+ return {};
+
+ return x509ToQByteArray(x509, QSsl::Pem);
+}
+
+QByteArray X509CertificateOpenSSL::toDer() const
+{
+ if (!x509)
+ return {};
+
+ return x509ToQByteArray(x509, QSsl::Der);
+
+}
+QString X509CertificateOpenSSL::toText() const
+{
+ if (!x509)
+ return {};
+
+ return x509ToText(x509);
+}
+
+Qt::HANDLE X509CertificateOpenSSL::handle() const
+{
+ return Qt::HANDLE(x509);
+}
+
+size_t X509CertificateOpenSSL::hash(size_t seed) const noexcept
+{
+ if (x509) {
+ const EVP_MD *sha1 = q_EVP_sha1();
+ unsigned int len = 0;
+ unsigned char md[EVP_MAX_MD_SIZE];
+ q_X509_digest(x509, sha1, md, &len);
+ return qHashBits(md, len, seed);
+ }
+
+ return seed;
+}
+
+QSslCertificate X509CertificateOpenSSL::certificateFromX509(X509 *x509)
+{
+ QSslCertificate certificate;
+
+ auto *backend = QTlsBackend::backend<X509CertificateOpenSSL>(certificate);
+ if (!backend || !x509)
+ return certificate;
+
+ ASN1_TIME *nbef = q_X509_getm_notBefore(x509);
+ if (nbef)
+ backend->notValidBefore = dateTimeFromASN1(nbef);
+
+ ASN1_TIME *naft = q_X509_getm_notAfter(x509);
+ if (naft)
+ backend->notValidAfter = dateTimeFromASN1(naft);
+
+ backend->null = false;
+ backend->x509 = q_X509_dup(x509);
+
+ backend->issuerInfoEntries = mapFromX509Name(q_X509_get_issuer_name(x509));
+ backend->subjectInfoEntries = mapFromX509Name(q_X509_get_subject_name(x509));
+ backend->versionString = QByteArray::number(qlonglong(q_X509_get_version(x509)) + 1);
+
+ if (ASN1_INTEGER *serialNumber = q_X509_get_serialNumber(x509)) {
+ QByteArray hexString;
+ hexString.reserve(serialNumber->length * 3);
+ for (int a = 0; a < serialNumber->length; ++a) {
+ hexString += QByteArray::number(serialNumber->data[a], 16).rightJustified(2, '0');
+ hexString += ':';
+ }
+ hexString.chop(1);
+ backend->serialNumberString = hexString;
+ }
+
+ backend->parseExtensions();
+
+ return certificate;
+}
+
+QList<QSslCertificate> X509CertificateOpenSSL::stackOfX509ToQSslCertificates(STACK_OF(X509) *x509)
+{
+ if (!x509)
+ return {};
+
+ QList<QSslCertificate> certificates;
+ for (int i = 0; i < q_sk_X509_num(x509); ++i) {
+ if (X509 *entry = q_sk_X509_value(x509, i))
+ certificates << certificateFromX509(entry);
+ }
+
+ return certificates;
+}
+
+QSslErrorEntry X509CertificateOpenSSL::errorEntryFromStoreContext(X509_STORE_CTX *ctx)
+{
+ Q_ASSERT(ctx);
+
+ return {q_X509_STORE_CTX_get_error(ctx), q_X509_STORE_CTX_get_error_depth(ctx)};
+}
+
+QList<QSslError> X509CertificateOpenSSL::verify(const QList<QSslCertificate> &chain,
+ const QString &hostName)
+{
+ // This was previously QSslSocketPrivate::verify().
+ auto roots = QSslConfiguration::defaultConfiguration().caCertificates();
+#ifndef Q_OS_WIN
+ // On Windows, system CA certificates are already set as default ones.
+ // No need to add them again (and again) and also, if the default configuration
+ // has its own set of CAs, this probably should not be amended by the ones
+ // from the 'ROOT' store, since it's not what an application chose to trust.
+ if (QSslSocketPrivate::rootCertOnDemandLoadingSupported())
+ roots.append(QSslSocketPrivate::systemCaCertificates());
+#endif // Q_OS_WIN
+ return verify(roots, chain, hostName);
+}
+
+QList<QSslError> X509CertificateOpenSSL::verify(const QList<QSslCertificate> &caCertificates,
+ const QList<QSslCertificate> &certificateChain,
+ const QString &hostName)
+{
+ // This was previously QSslSocketPrivate::verify().
+ if (certificateChain.size() <= 0)
+ return {QSslError(QSslError::UnspecifiedError)};
+
+ QList<QSslError> errors;
+ X509_STORE *certStore = q_X509_STORE_new();
+ if (!certStore) {
+ qCWarning(lcTlsBackend) << "Unable to create certificate store";
+ errors << QSslError(QSslError::UnspecifiedError);
+ return errors;
+ }
+ const std::unique_ptr<X509_STORE, decltype(&q_X509_STORE_free)> storeGuard(certStore, q_X509_STORE_free);
+
+ const QDateTime now = QDateTime::currentDateTimeUtc();
+ for (const QSslCertificate &caCertificate : caCertificates) {
+ // From https://www.openssl.org/docs/ssl/SSL_CTX_load_verify_locations.html:
+ //
+ // If several CA certificates matching the name, key identifier, and
+ // serial number condition are available, only the first one will be
+ // examined. This may lead to unexpected results if the same CA
+ // certificate is available with different expiration dates. If a
+ // ``certificate expired'' verification error occurs, no other
+ // certificate will be searched. Make sure to not have expired
+ // certificates mixed with valid ones.
+ //
+ // See also: QSslContext::sharedFromConfiguration()
+ if (caCertificate.expiryDate() >= now) {
+ q_X509_STORE_add_cert(certStore, reinterpret_cast<X509 *>(caCertificate.handle()));
+ }
+ }
+
+ QList<QSslErrorEntry> lastErrors;
+ if (!q_X509_STORE_set_ex_data(certStore, 0, &lastErrors)) {
+ qCWarning(lcTlsBackend) << "Unable to attach external data (error list) to a store";
+ errors << QSslError(QSslError::UnspecifiedError);
+ return errors;
+ }
+
+ // Register a custom callback to get all verification errors.
+ q_X509_STORE_set_verify_cb(certStore, qt_X509Callback);
+
+ // Build the chain of intermediate certificates
+ STACK_OF(X509) *intermediates = nullptr;
+ if (certificateChain.size() > 1) {
+ intermediates = (STACK_OF(X509) *) q_OPENSSL_sk_new_null();
+
+ if (!intermediates) {
+ errors << QSslError(QSslError::UnspecifiedError);
+ return errors;
+ }
+
+ bool first = true;
+ for (const QSslCertificate &cert : certificateChain) {
+ if (first) {
+ first = false;
+ continue;
+ }
+
+ q_OPENSSL_sk_push((OPENSSL_STACK *)intermediates, reinterpret_cast<X509 *>(cert.handle()));
+ }
+ }
+
+ X509_STORE_CTX *storeContext = q_X509_STORE_CTX_new();
+ if (!storeContext) {
+ errors << QSslError(QSslError::UnspecifiedError);
+ return errors;
+ }
+ std::unique_ptr<X509_STORE_CTX, decltype(&q_X509_STORE_CTX_free)> ctxGuard(storeContext, q_X509_STORE_CTX_free);
+
+ if (!q_X509_STORE_CTX_init(storeContext, certStore, reinterpret_cast<X509 *>(certificateChain[0].handle()), intermediates)) {
+ errors << QSslError(QSslError::UnspecifiedError);
+ return errors;
+ }
+
+ // Now we can actually perform the verification of the chain we have built.
+ // We ignore the result of this function since we process errors via the
+ // callback.
+ (void) q_X509_verify_cert(storeContext);
+ ctxGuard.reset();
+ q_OPENSSL_sk_free((OPENSSL_STACK *)intermediates);
+
+ // Now process the errors
+
+ if (certificateChain[0].isBlacklisted())
+ errors << QSslError(QSslError::CertificateBlacklisted, certificateChain[0]);
+
+ // Check the certificate name against the hostname if one was specified
+ if (!hostName.isEmpty() && !TlsCryptograph::isMatchingHostname(certificateChain[0], hostName)) {
+ // No matches in common names or alternate names.
+ QSslError error(QSslError::HostNameMismatch, certificateChain[0]);
+ errors << error;
+ }
+
+ // Translate errors from the error list into QSslErrors.
+ errors.reserve(errors.size() + lastErrors.size());
+ for (const auto &error : std::as_const(lastErrors))
+ errors << openSSLErrorToQSslError(error.code, certificateChain.value(error.depth));
+
+ return errors;
+}
+
+QList<QSslCertificate> X509CertificateOpenSSL::certificatesFromPem(const QByteArray &pem, int count)
+{
+ QList<QSslCertificate> certificates;
+
+ int offset = 0;
+ while (count == -1 || certificates.size() < count) {
+ int startPos = pem.indexOf(BEGINCERTSTRING, offset);
+ if (startPos == -1)
+ break;
+ startPos += sizeof(BEGINCERTSTRING) - 1;
+ if (!matchLineFeed(pem, &startPos))
+ break;
+
+ int endPos = pem.indexOf(ENDCERTSTRING, startPos);
+ if (endPos == -1)
+ break;
+
+ offset = endPos + sizeof(ENDCERTSTRING) - 1;
+ if (offset < pem.size() && !matchLineFeed(pem, &offset))
+ break;
+
+ QByteArray decoded = QByteArray::fromBase64(
+ QByteArray::fromRawData(pem.data() + startPos, endPos - startPos));
+ const unsigned char *data = (const unsigned char *)decoded.data();
+
+ if (X509 *x509 = q_d2i_X509(nullptr, &data, decoded.size())) {
+ certificates << certificateFromX509(x509);
+ q_X509_free(x509);
+ }
+ }
+
+ return certificates;
+}
+
+QList<QSslCertificate> X509CertificateOpenSSL::certificatesFromDer(const QByteArray &der, int count)
+{
+ QList<QSslCertificate> certificates;
+
+ const unsigned char *data = (const unsigned char *)der.data();
+ int size = der.size();
+
+ while (size > 0 && (count == -1 || certificates.size() < count)) {
+ if (X509 *x509 = q_d2i_X509(nullptr, &data, size)) {
+ certificates << certificateFromX509(x509);
+ q_X509_free(x509);
+ } else {
+ break;
+ }
+ size -= ((const char *)data - der.data());
+ }
+
+ return certificates;
+}
+
+bool X509CertificateOpenSSL::importPkcs12(QIODevice *device, QSslKey *key, QSslCertificate *cert,
+ QList<QSslCertificate> *caCertificates,
+ const QByteArray &passPhrase)
+{
+ // These are required
+ Q_ASSERT(device);
+ Q_ASSERT(key);
+ Q_ASSERT(cert);
+
+ // Read the file into a BIO
+ QByteArray pkcs12data = device->readAll();
+ if (pkcs12data.size() == 0)
+ return false;
+
+ BIO *bio = q_BIO_new_mem_buf(const_cast<char *>(pkcs12data.constData()), pkcs12data.size());
+ if (!bio) {
+ qCWarning(lcTlsBackend, "BIO_new_mem_buf returned null");
+ return false;
+ }
+ const auto bioRaii = qScopeGuard([bio]{q_BIO_free(bio);});
+
+ // Create the PKCS#12 object
+ PKCS12 *p12 = q_d2i_PKCS12_bio(bio, nullptr);
+ if (!p12) {
+ qCWarning(lcTlsBackend, "Unable to read PKCS#12 structure, %s",
+ q_ERR_error_string(q_ERR_get_error(), nullptr));
+ return false;
+ }
+ const auto p12Raii = qScopeGuard([p12]{q_PKCS12_free(p12);});
+
+ // Extract the data
+ EVP_PKEY *pkey = nullptr;
+ X509 *x509 = nullptr;
+ STACK_OF(X509) *ca = nullptr;
+
+ if (!q_PKCS12_parse(p12, passPhrase.constData(), &pkey, &x509, &ca)) {
+ qCWarning(lcTlsBackend, "Unable to parse PKCS#12 structure, %s",
+ q_ERR_error_string(q_ERR_get_error(), nullptr));
+ return false;
+ }
+
+ const auto x509Raii = qScopeGuard([x509]{q_X509_free(x509);});
+ const auto keyRaii = qScopeGuard([pkey]{q_EVP_PKEY_free(pkey);});
+ const auto caRaii = qScopeGuard([ca] {
+ q_OPENSSL_sk_pop_free(reinterpret_cast<OPENSSL_STACK *>(ca),
+ reinterpret_cast<void (*)(void *)>(q_X509_free));
+ });
+
+ // Convert to Qt types
+ auto *tlsKey = QTlsBackend::backend<TlsKeyOpenSSL>(*key);
+ if (!tlsKey || !tlsKey->fromEVP_PKEY(pkey)) {
+ qCWarning(lcTlsBackend, "Unable to convert private key");
+ return false;
+ }
+
+ *cert = certificateFromX509(x509);
+
+ if (caCertificates)
+ *caCertificates = stackOfX509ToQSslCertificates(ca);
+
+ return true;
+}
+
+QSslError X509CertificateOpenSSL::openSSLErrorToQSslError(int errorCode, const QSslCertificate &cert)
+{
+ QSslError error;
+ switch (errorCode) {
+ case X509_V_OK:
+ // X509_V_OK is also reported if the peer had no certificate.
+ break;
+ case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
+ error = QSslError(QSslError::UnableToGetIssuerCertificate, cert); break;
+ case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE:
+ error = QSslError(QSslError::UnableToDecryptCertificateSignature, cert); break;
+ case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY:
+ error = QSslError(QSslError::UnableToDecodeIssuerPublicKey, cert); break;
+ case X509_V_ERR_CERT_SIGNATURE_FAILURE:
+ error = QSslError(QSslError::CertificateSignatureFailed, cert); break;
+ case X509_V_ERR_CERT_NOT_YET_VALID:
+ error = QSslError(QSslError::CertificateNotYetValid, cert); break;
+ case X509_V_ERR_CERT_HAS_EXPIRED:
+ error = QSslError(QSslError::CertificateExpired, cert); break;
+ case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
+ error = QSslError(QSslError::InvalidNotBeforeField, cert); break;
+ case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
+ error = QSslError(QSslError::InvalidNotAfterField, cert); break;
+ case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
+ error = QSslError(QSslError::SelfSignedCertificate, cert); break;
+ case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
+ error = QSslError(QSslError::SelfSignedCertificateInChain, cert); break;
+ case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
+ error = QSslError(QSslError::UnableToGetLocalIssuerCertificate, cert); break;
+ case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE:
+ error = QSslError(QSslError::UnableToVerifyFirstCertificate, cert); break;
+ case X509_V_ERR_CERT_REVOKED:
+ error = QSslError(QSslError::CertificateRevoked, cert); break;
+ case X509_V_ERR_INVALID_CA:
+ error = QSslError(QSslError::InvalidCaCertificate, cert); break;
+ case X509_V_ERR_PATH_LENGTH_EXCEEDED:
+ error = QSslError(QSslError::PathLengthExceeded, cert); break;
+ case X509_V_ERR_INVALID_PURPOSE:
+ error = QSslError(QSslError::InvalidPurpose, cert); break;
+ case X509_V_ERR_CERT_UNTRUSTED:
+ error = QSslError(QSslError::CertificateUntrusted, cert); break;
+ case X509_V_ERR_CERT_REJECTED:
+ error = QSslError(QSslError::CertificateRejected, cert); break;
+ default:
+ error = QSslError(QSslError::UnspecifiedError, cert); break;
+ }
+ return error;
+}
+
+void X509CertificateOpenSSL::parseExtensions()
+{
+ extensions.clear();
+
+ if (!x509)
+ return;
+
+ int count = q_X509_get_ext_count(x509);
+ if (count <= 0)
+ return;
+
+ extensions.reserve(count);
+
+ for (int i = 0; i < count; i++) {
+ X509_EXTENSION *ext = q_X509_get_ext(x509, i);
+ if (!ext) {
+ qCWarning(lcTlsBackend) << "Invalid (nullptr) extension at index" << i;
+ continue;
+ }
+
+ extensions << convertExtension(ext);
+ }
+
+ // Converting an extension may result in an error(s), clean them up:
+ QTlsBackendOpenSSL::clearErrorQueue();
+}
+
+X509CertificateBase::X509CertificateExtension X509CertificateOpenSSL::convertExtension(X509_EXTENSION *ext)
+{
+ Q_ASSERT(ext);
+
+ X509CertificateExtension result;
+
+ ASN1_OBJECT *obj = q_X509_EXTENSION_get_object(ext);
+ if (!obj)
+ return result;
+
+ result.oid = QString::fromUtf8(asn1ObjectId(obj));
+ result.name = QString::fromUtf8(asn1ObjectName(obj));
+
+ result.critical = bool(q_X509_EXTENSION_get_critical(ext));
+
+ // Lets see if we have custom support for this one
+ QVariant extensionValue = x509ExtensionToValue(ext);
+ if (extensionValue.isValid()) {
+ result.value = extensionValue;
+ result.supported = true;
+ return result;
+ }
+
+ extensionValue = x509UnknownExtensionToValue(ext);
+ if (extensionValue.isValid())
+ result.value = extensionValue;
+
+ result.supported = false;
+
+ return result;
+}
+
+} // namespace QTlsPrivate
+
+QT_END_NAMESPACE
diff --git a/src/plugins/tls/openssl/qx509_openssl_p.h b/src/plugins/tls/openssl/qx509_openssl_p.h
new file mode 100644
index 0000000000..3b2e06f343
--- /dev/null
+++ b/src/plugins/tls/openssl/qx509_openssl_p.h
@@ -0,0 +1,88 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QX509_OPENSSL_P_H
+#define QX509_OPENSSL_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 <QtNetwork/private/qtnetworkglobal_p.h>
+
+#include "../shared/qx509_base_p.h"
+
+#include <QtNetwork/private/qtlsbackend_p.h>
+
+#include <QtCore/qvariant.h>
+#include <QtCore/qglobal.h>
+#include <QtCore/qstring.h>
+
+#include "qopenssl_p.h"
+
+#include <algorithm>
+
+QT_BEGIN_NAMESPACE
+
+namespace QTlsPrivate {
+
+class X509CertificateOpenSSL final : public X509CertificateBase
+{
+public:
+ X509CertificateOpenSSL();
+ ~X509CertificateOpenSSL();
+
+ // TLSTODO: in future may become movable/copyable (ref-counted based
+ // OpenSSL's X509 implementation).
+
+ bool isEqual(const X509Certificate &rhs) const override;
+ bool isSelfSigned() const override;
+ QMultiMap<QSsl::AlternativeNameEntryType, QString> subjectAlternativeNames() const override;
+ TlsKey *publicKey() const override;
+
+ QByteArray toPem() const override;
+ QByteArray toDer() const override;
+ QString toText() const override;
+ Qt::HANDLE handle() const override;
+
+ size_t hash(size_t seed) const noexcept override;
+
+ static QSslCertificate certificateFromX509(X509 *x);
+ static QList<QSslCertificate> stackOfX509ToQSslCertificates(STACK_OF(X509) *x509);
+ static QSslErrorEntry errorEntryFromStoreContext(X509_STORE_CTX *ctx);
+
+ static QList<QSslError> verify(const QList<QSslCertificate> &chain, const QString &hostName);
+ static QList<QSslError> verify(const QList<QSslCertificate> &caCertificates,
+ const QList<QSslCertificate> &certificateChain,
+ const QString &hostName);
+
+ static QList<QSslCertificate> certificatesFromPem(const QByteArray &pem, int count);
+ static QList<QSslCertificate> certificatesFromDer(const QByteArray &der, int count);
+ static bool importPkcs12(QIODevice *device, QSslKey *key, QSslCertificate *cert,
+ QList<QSslCertificate> *caCertificates,
+ const QByteArray &passPhrase);
+
+ static QSslError openSSLErrorToQSslError(int errorCode, const QSslCertificate &cert);
+private:
+ void parseExtensions();
+ static X509CertificateExtension convertExtension(X509_EXTENSION *ext);
+
+ X509 *x509 = nullptr;
+
+ Q_DISABLE_COPY_MOVE(X509CertificateOpenSSL)
+};
+
+extern "C" int qt_X509Callback(int ok, X509_STORE_CTX *ctx);
+
+} // namespace QTlsPrivate
+
+QT_END_NAMESPACE
+
+#endif // QX509_OPENSSL_P_H
diff --git a/src/plugins/tls/schannel/CMakeLists.txt b/src/plugins/tls/schannel/CMakeLists.txt
new file mode 100644
index 0000000000..a7f7fcd99f
--- /dev/null
+++ b/src/plugins/tls/schannel/CMakeLists.txt
@@ -0,0 +1,34 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+qt_internal_add_plugin(QSchannelBackendPlugin
+ OUTPUT_NAME qschannelbackend
+ CLASS_NAME QSchannelBackend
+ PLUGIN_TYPE tls
+ DEFAULT_IF WIN32
+ SOURCES
+ ../shared/qtlskey_base_p.h
+ ../shared/qtlskey_base.cpp
+ ../shared/qtlskey_generic_p.h
+ ../shared/qtlskey_generic.cpp
+ ../shared/qx509_base_p.h
+ ../shared/qx509_base.cpp
+ ../shared/qx509_generic_p.h
+ ../shared/qx509_generic.cpp
+ ../shared/qsslsocket_qt.cpp
+ ../shared/qwincrypt_p.h
+ ../shared/qasn1element_p.h
+ ../shared/qasn1element.cpp
+ qtls_schannel.cpp qtls_schannel_p.h
+ qtlsbackend_schannel_p.h
+ qtlskey_schannel.cpp qtlskey_schannel_p.h
+ qx509_schannel.cpp qx509_schannel_p.h
+ LIBRARIES
+ Qt::NetworkPrivate
+ crypt32
+ secur32
+ bcrypt
+ ncrypt
+ DEFINES
+ QT_NO_CAST_FROM_ASCII
+)
diff --git a/src/plugins/tls/schannel/qtls_schannel.cpp b/src/plugins/tls/schannel/qtls_schannel.cpp
new file mode 100644
index 0000000000..a244a90ebc
--- /dev/null
+++ b/src/plugins/tls/schannel/qtls_schannel.cpp
@@ -0,0 +1,2640 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+// #define QSSLSOCKET_DEBUG
+
+#include "qtlsbackend_schannel_p.h"
+#include "qtlskey_schannel_p.h"
+#include "qx509_schannel_p.h"
+#include "qtls_schannel_p.h"
+
+#include <QtNetwork/private/qsslcertificate_p.h>
+#include <QtNetwork/private/qsslcipher_p.h>
+#include <QtNetwork/private/qssl_p.h>
+
+#include <QtNetwork/qsslcertificate.h>
+#include <QtNetwork/qsslcertificateextension.h>
+#include <QtNetwork/qsslsocket.h>
+
+#include <QtCore/qscopeguard.h>
+#include <QtCore/qoperatingsystemversion.h>
+#include <QtCore/qregularexpression.h>
+#include <QtCore/qdatastream.h>
+#include <QtCore/qmutex.h>
+
+#define SECURITY_WIN32
+#include <security.h>
+#include <schnlsp.h>
+
+#if NTDDI_VERSION >= NTDDI_WINBLUE && defined(SECBUFFER_APPLICATION_PROTOCOLS)
+// ALPN = Application Layer Protocol Negotiation
+#define SUPPORTS_ALPN 1
+#endif
+
+// Not defined in MinGW
+#ifndef SECBUFFER_ALERT
+#define SECBUFFER_ALERT 17
+#endif
+#ifndef SECPKG_ATTR_APPLICATION_PROTOCOL
+#define SECPKG_ATTR_APPLICATION_PROTOCOL 35
+#endif
+
+// Another missing MinGW define
+#ifndef SEC_E_APPLICATION_PROTOCOL_MISMATCH
+#define SEC_E_APPLICATION_PROTOCOL_MISMATCH _HRESULT_TYPEDEF_(0x80090367L)
+#endif
+
+// Also not defined in MinGW.......
+#ifndef SP_PROT_TLS1_SERVER
+#define SP_PROT_TLS1_SERVER 0x00000040
+#endif
+#ifndef SP_PROT_TLS1_CLIENT
+#define SP_PROT_TLS1_CLIENT 0x00000080
+#endif
+#ifndef SP_PROT_TLS1_0_SERVER
+#define SP_PROT_TLS1_0_SERVER SP_PROT_TLS1_SERVER
+#endif
+#ifndef SP_PROT_TLS1_0_CLIENT
+#define SP_PROT_TLS1_0_CLIENT SP_PROT_TLS1_CLIENT
+#endif
+#ifndef SP_PROT_TLS1_0
+#define SP_PROT_TLS1_0 (SP_PROT_TLS1_0_CLIENT | SP_PROT_TLS1_0_SERVER)
+#endif
+#ifndef SP_PROT_TLS1_1_SERVER
+#define SP_PROT_TLS1_1_SERVER 0x00000100
+#endif
+#ifndef SP_PROT_TLS1_1_CLIENT
+#define SP_PROT_TLS1_1_CLIENT 0x00000200
+#endif
+#ifndef SP_PROT_TLS1_1
+#define SP_PROT_TLS1_1 (SP_PROT_TLS1_1_CLIENT | SP_PROT_TLS1_1_SERVER)
+#endif
+#ifndef SP_PROT_TLS1_2_SERVER
+#define SP_PROT_TLS1_2_SERVER 0x00000400
+#endif
+#ifndef SP_PROT_TLS1_2_CLIENT
+#define SP_PROT_TLS1_2_CLIENT 0x00000800
+#endif
+#ifndef SP_PROT_TLS1_2
+#define SP_PROT_TLS1_2 (SP_PROT_TLS1_2_CLIENT | SP_PROT_TLS1_2_SERVER)
+#endif
+#ifndef SP_PROT_TLS1_3_SERVER
+#define SP_PROT_TLS1_3_SERVER 0x00001000
+#endif
+#ifndef SP_PROT_TLS1_3_CLIENT
+#define SP_PROT_TLS1_3_CLIENT 0x00002000
+#endif
+#ifndef SP_PROT_TLS1_3
+#define SP_PROT_TLS1_3 (SP_PROT_TLS1_3_CLIENT | SP_PROT_TLS1_3_SERVER)
+#endif
+#ifndef BCRYPT_ECDH_ALGORITHM
+#define BCRYPT_ECDH_ALGORITHM L"ECDH"
+#endif
+#ifndef BCRYPT_ECDSA_ALGORITHM
+#define BCRYPT_ECDSA_ALGORITHM L"ECDSA"
+#endif
+
+/*
+ @future!:
+
+ - Transmitting intermediate certificates
+ - Look for a way to avoid putting intermediate certificates in the certificate store
+ - No documentation on how to send the chain
+ - A stackoverflow question on this from 3 years ago implies schannel only sends intermediate
+ certificates if it's "in the system or user certificate store".
+ - https://stackoverflow.com/q/30156584/2493610
+ - This can be done by users, but we shouldn't add any and all local intermediate
+ certs to the stores automatically.
+ - PSK support
+ - Was added in Windows 10 (it seems), documentation at time of writing is sparse/non-existent.
+ - Specifically about how to supply credentials when they're requested.
+ - Or how to recognize that they're requested in the first place.
+ - Skip certificate verification.
+ - Check if "PSK-only" is still required to do PSK _at all_ (all-around bad solution).
+ - Check if SEC_I_INCOMPLETE_CREDENTIALS is still returned for both "missing certificate" and
+ "missing PSK" when calling InitializeSecurityContext in "performHandshake".
+
+ Low priority:
+ - Possibly make RAII wrappers for SecBuffer (which I commonly create QScopeGuards for)
+
+*/
+
+QT_BEGIN_NAMESPACE
+
+using namespace Qt::StringLiterals;
+
+Q_LOGGING_CATEGORY(lcTlsBackendSchannel, "qt.tlsbackend.schannel");
+
+// Defined in qsslsocket_qt.cpp.
+QByteArray _q_makePkcs12(const QList<QSslCertificate> &certs, const QSslKey &key,
+ const QString &passPhrase);
+
+namespace {
+bool supportsTls13();
+}
+
+namespace QTlsPrivate {
+
+QList<QSslCipher> defaultCiphers();
+
+struct SchannelCipherInfo {
+ const char *openSslCipherSuite;
+ const char *schannelCipherSuite;
+ const char *keyExchangeMethod;
+ const char *authenticationMethod;
+ const char *encryptionMethod;
+ int encryptionBits;
+ const char *hashMethod;
+ QList<QSsl::SslProtocol> protocols;
+};
+
+// The list of supported ciphers according to
+// https://learn.microsoft.com/en-us/windows/win32/secauthn/tls-cipher-suites-in-windows-server-2022
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
+std::array<SchannelCipherInfo, 44> schannelCipherInfo = {{
+ {"TLS_AES_256_GCM_SHA384", "TLS_AES_256_GCM_SHA384", "", "", "AES", 256, "SHA384", {QSsl::TlsV1_3}},
+ {"TLS_AES_128_GCM_SHA256", "TLS_AES_128_GCM_SHA256", "", "", "AES", 128, "SHA256", {QSsl::TlsV1_3}},
+ {"ECDHE-ECDSA-AES256-GCM-SHA384", "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", "ECDH", "ECDSA", "AES", 256, "SHA384", {QSsl::TlsV1_2}},
+ {"ECDHE-ECDSA-AES128-GCM-SHA256", "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", "ECDH", "ECDSA", "AES", 128, "SHA256", {QSsl::TlsV1_2}},
+ {"ECDHE-RSA-AES256-GCM-SHA384", "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", "ECDH", "RSA", "AES", 256, "SHA384", {QSsl::TlsV1_2}},
+ {"ECDHE-RSA-AES128-GCM-SHA256", "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", "ECDH", "RSA", "AES", 128, "SHA256", {QSsl::TlsV1_2}},
+ {"DHE-RSA-AES256-GCM-SHA384", "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", "DH", "RSA", "AES", 256, "SHA384", {QSsl::TlsV1_2}},
+ {"DHE-RSA-AES128-GCM-SHA256", "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", "DH", "RSA", "AES", 128, "SHA256", {QSsl::TlsV1_2}},
+ {"ECDHE-ECDSA-AES256-SHA384", "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384", "ECDH", "ECDSA", "AES", 256, "SHA384", {QSsl::TlsV1_2}},
+ {"ECDHE-ECDSA-AES128-SHA256", "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", "ECDH", "ECDSA", "AES", 128, "SHA256", {QSsl::TlsV1_2}},
+ {"ECDHE-RSA-AES256-SHA384", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384", "ECDH", "RSA", "AES", 256, "SHA384", {QSsl::TlsV1_2}},
+ {"ECDHE-RSA-AES128-SHA256", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", "ECDH", "RSA", "AES", 128, "SHA256", {QSsl::TlsV1_2}},
+ {"ECDHE-ECDSA-AES256-SHA", "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", "ECDH", "ECDSA", "AES", 256, "SHA1", {QSsl::TlsV1_2, QSsl::TlsV1_1, QSsl::TlsV1_0}},
+ {"ECDHE-ECDSA-AES128-SHA", "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", "ECDH", "ECDSA", "AES", 128, "SHA1", {QSsl::TlsV1_2, QSsl::TlsV1_1, QSsl::TlsV1_0}},
+ {"ECDHE-RSA-AES256-SHA", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", "ECDH", "RSA", "AES", 256, "SHA1", {QSsl::TlsV1_2, QSsl::TlsV1_1, QSsl::TlsV1_0}},
+ {"ECDHE-RSA-AES128-SHA", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", "ECDH", "RSA", "AES", 128, "SHA1", {QSsl::TlsV1_2, QSsl::TlsV1_1, QSsl::TlsV1_0}},
+ {"AES256-GCM-SHA384", "TLS_RSA_WITH_AES_256_GCM_SHA384", "RSA", "RSA", "AES", 256, "SHA384", {QSsl::TlsV1_2}},
+ {"AES128-GCM-SHA256", "TLS_RSA_WITH_AES_128_GCM_SHA256", "RSA", "RSA", "AES", 128, "SHA256", {QSsl::TlsV1_2}},
+ {"AES256-SHA256", "TLS_RSA_WITH_AES_256_CBC_SHA256", "RSA", "RSA", "AES", 256, "SHA256", {QSsl::TlsV1_2}},
+ {"AES128-SHA256", "TLS_RSA_WITH_AES_128_CBC_SHA256", "RSA", "RSA", "AES", 128, "SHA256", {QSsl::TlsV1_2}},
+ {"AES256-SHA", "TLS_RSA_WITH_AES_256_CBC_SHA", "RSA", "RSA", "AES", 256, "SHA1", {QSsl::TlsV1_2, QSsl::TlsV1_1, QSsl::TlsV1_0}},
+ {"AES128-SHA", "TLS_RSA_WITH_AES_128_CBC_SHA", "RSA", "RSA", "AES", 128, "SHA1", {QSsl::TlsV1_2, QSsl::TlsV1_1, QSsl::TlsV1_0}},
+ {"DES-CBC3-SHA", "TLS_RSA_WITH_3DES_EDE_CBC_SHA", "RSA", "RSA", "3DES", 168, "SHA1", {QSsl::TlsV1_2, QSsl::TlsV1_1, QSsl::TlsV1_0}},
+ {"NULL-SHA256", "TLS_RSA_WITH_NULL_SHA256", "RSA", "RSA", "", 0, "SHA256", {QSsl::TlsV1_2}},
+ {"NULL-SHA", "TLS_RSA_WITH_NULL_SHA", "RSA", "RSA", "", 0, "SHA1", {QSsl::TlsV1_2, QSsl::TlsV1_1, QSsl::TlsV1_0}},
+
+ // the following cipher suites are not enabled by default in schannel provider
+ {"TLS_CHACHA20_POLY1305_SHA256", "TLS_CHACHA20_POLY1305_SHA256", "", "", "CHACHA20_POLY1305", 0, "", {QSsl::TlsV1_3}},
+ {"DHE-RSA-AES256-SHA", "TLS_DHE_RSA_WITH_AES_256_CBC_SHA", "DH", "RSA", "AES", 256, "SHA1", {QSsl::TlsV1_2, QSsl::TlsV1_1, QSsl::TlsV1_0}},
+ {"DHE-RSA-AES128-SHA", "TLS_DHE_RSA_WITH_AES_128_CBC_SHA", "DH", "RSA", "AES", 128, "SHA1", {QSsl::TlsV1_2, QSsl::TlsV1_1, QSsl::TlsV1_0}},
+ {"DHE-DSS-AES256-SHA256", "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256", "DH", "DSA", "AES", 256, "SHA256", {QSsl::TlsV1_2}},
+ {"DHE-DSS-AES128-SHA256", "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256", "DH", "DSA", "AES", 128, "SHA256", {QSsl::TlsV1_2}},
+ {"DHE-DSS-AES256-SHA", "TLS_DHE_DSS_WITH_AES_256_CBC_SHA", "DH", "DSA", "AES", 256, "SHA1", {QSsl::TlsV1_2, QSsl::TlsV1_1, QSsl::TlsV1_0}},
+ {"DHE-DSS-AES128-SHA", "TLS_DHE_DSS_WITH_AES_128_CBC_SHA", "DH", "DSA", "AES", 128, "SHA1", {QSsl::TlsV1_2, QSsl::TlsV1_1, QSsl::TlsV1_0}},
+ {"EDH-DSS-DES-CBC3-SHA", "TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA", "DH", "DSA", "3DES", 168, "SHA1", {QSsl::TlsV1_2, QSsl::TlsV1_1, QSsl::TlsV1_0}},
+ {"RC4-SHA", "TLS_RSA_WITH_RC4_128_SHA", "RSA", "RSA", "RC4", 128, "SHA1", {QSsl::TlsV1_2, QSsl::TlsV1_1, QSsl::TlsV1_0}},
+ {"RC4-MD5", "TLS_RSA_WITH_RC4_128_MD5", "RSA", "RSA", "RC4", 128, "MD5", {QSsl::TlsV1_2, QSsl::TlsV1_1, QSsl::TlsV1_0}},
+ {"DES-CBC-SHA", "TLS_RSA_WITH_DES_CBC_SHA", "RSA", "RSA", "DES", 56, "SHA1", {QSsl::TlsV1_2, QSsl::TlsV1_1, QSsl::TlsV1_0}},
+ {"EDH-DSS-DES-CBC-SHA", "TLS_DHE_DSS_WITH_DES_CBC_SHA", "DH", "DSA", "DES", 56, "SHA1", {QSsl::TlsV1_2, QSsl::TlsV1_1, QSsl::TlsV1_0}},
+ {"NULL-MD5", "TLS_RSA_WITH_NULL_MD5", "RSA", "RSA", "", 0, "MD5", {QSsl::TlsV1_2, QSsl::TlsV1_1, QSsl::TlsV1_0}},
+
+ // PSK cipher suites
+ {"PSK-AES256-GCM-SHA384", "TLS_PSK_WITH_AES_256_GCM_SHA384", "PSK", "", "AES", 256, "SHA384", {QSsl::TlsV1_2}},
+ {"PSK-AES128-GCM-SHA256", "TLS_PSK_WITH_AES_128_GCM_SHA256", "PSK", "", "AES", 128, "SHA256", {QSsl::TlsV1_2}},
+ {"PSK-AES256-CBC-SHA384", "TLS_PSK_WITH_AES_256_CBC_SHA384", "PSK", "", "AES", 256, "SHA384", {QSsl::TlsV1_2}},
+ {"PSK-AES128-CBC-SHA256", "TLS_PSK_WITH_AES_128_CBC_SHA256", "PSK", "", "AES", 128, "SHA256", {QSsl::TlsV1_2}},
+ {"PSK-NULL-SHA384", "TLS_PSK_WITH_NULL_SHA384", "PSK", "", "", 0, "SHA384", {QSsl::TlsV1_2}},
+ {"PSK-NULL-SHA256", "TLS_PSK_WITH_NULL_SHA256", "PSK", "", "", 0, "SHA256", {QSsl::TlsV1_2}},
+}};
+QT_WARNING_POP
+
+const SchannelCipherInfo *cipherInfoByOpenSslName(const QString &name)
+{
+ for (const auto &cipherInfo : schannelCipherInfo) {
+ if (name == QLatin1StringView(cipherInfo.openSslCipherSuite))
+ return &cipherInfo;
+ }
+
+ return nullptr;
+}
+
+UNICODE_STRING cbcChainingMode = {
+ sizeof(BCRYPT_CHAIN_MODE_CBC) - 2,
+ sizeof(BCRYPT_CHAIN_MODE_CBC),
+ const_cast<PWSTR>(BCRYPT_CHAIN_MODE_CBC)
+};
+
+UNICODE_STRING gcmChainingMode = {
+ sizeof(BCRYPT_CHAIN_MODE_GCM) - 2,
+ sizeof(BCRYPT_CHAIN_MODE_GCM),
+ const_cast<PWSTR>(BCRYPT_CHAIN_MODE_GCM)
+};
+
+/**
+ Determines which algorithms are not used by the requested ciphers to build
+ up a black list that can be passed to SCH_CREDENTIALS.
+ */
+QList<CRYPTO_SETTINGS> cryptoSettingsForCiphers(const QList<QSslCipher> &ciphers)
+{
+ static const QList<QSslCipher> defaultCipherList = defaultCiphers();
+
+ if (defaultCipherList == ciphers) {
+ // the ciphers have not been restricted for this session, so no black listing needed
+ return {};
+ }
+
+ QList<const SchannelCipherInfo*> cipherInfo;
+
+ for (const auto &cipher : ciphers) {
+ if (cipher.isNull())
+ continue;
+
+ const auto *info = cipherInfoByOpenSslName(cipher.name());
+ if (!cipherInfo.contains(info))
+ cipherInfo.append(info);
+ }
+
+ QList<CRYPTO_SETTINGS> cryptoSettings;
+
+ const auto assignUnicodeString = [](UNICODE_STRING &unicodeString, const wchar_t *characters) {
+ unicodeString.Length = static_cast<USHORT>(wcslen(characters) * sizeof(WCHAR));
+ unicodeString.MaximumLength = unicodeString.Length + sizeof(UNICODE_NULL);
+ unicodeString.Buffer = const_cast<wchar_t*>(characters);
+ };
+
+ // black list of key exchange algorithms
+ const auto allKeyExchangeAlgorithms = {BCRYPT_RSA_ALGORITHM,
+ BCRYPT_ECDH_ALGORITHM,
+ BCRYPT_DH_ALGORITHM};
+
+ for (const auto &algorithm : allKeyExchangeAlgorithms) {
+ const auto method = QStringView(algorithm);
+
+ const auto usesMethod = [method](const SchannelCipherInfo *info) {
+ return QLatin1StringView(info->keyExchangeMethod) == method;
+ };
+
+ const bool exclude = std::none_of(cipherInfo.cbegin(), cipherInfo.cend(), usesMethod);
+
+ if (exclude) {
+ CRYPTO_SETTINGS settings = {};
+ settings.eAlgorithmUsage = TlsParametersCngAlgUsageKeyExchange;
+ assignUnicodeString(settings.strCngAlgId, algorithm);
+ cryptoSettings.append(settings);
+ }
+ }
+
+ // black list of authentication algorithms
+ const auto allAuthenticationAlgorithms = {BCRYPT_RSA_ALGORITHM,
+ BCRYPT_DSA_ALGORITHM,
+ BCRYPT_ECDSA_ALGORITHM,
+ BCRYPT_DH_ALGORITHM};
+
+ for (const auto &algorithm : allAuthenticationAlgorithms) {
+ const auto method = QStringView(algorithm);
+
+ const auto usesMethod = [method](const SchannelCipherInfo *info) {
+ return QLatin1StringView(info->authenticationMethod) == method;
+ };
+
+ const bool exclude = std::none_of(cipherInfo.begin(), cipherInfo.end(), usesMethod);
+
+ if (exclude) {
+ CRYPTO_SETTINGS settings = {};
+ settings.eAlgorithmUsage = TlsParametersCngAlgUsageSignature;
+ assignUnicodeString(settings.strCngAlgId, algorithm);
+ cryptoSettings.append(settings);
+ }
+ }
+
+
+ // black list of encryption algorithms
+ const auto allEncryptionAlgorithms = {BCRYPT_AES_ALGORITHM,
+ BCRYPT_RC4_ALGORITHM,
+ BCRYPT_DES_ALGORITHM,
+ BCRYPT_3DES_ALGORITHM};
+
+ for (const auto &algorithm : allEncryptionAlgorithms) {
+ const auto method = QStringView(algorithm);
+
+ if (method == QLatin1StringView("AES")) {
+ bool uses128Bit = false;
+ bool uses256Bit = false;
+ bool usesGcm = false;
+ bool usesCbc = false;
+ for (const auto *info : cipherInfo) {
+ if (QLatin1StringView(info->encryptionMethod) == method) {
+ uses128Bit = uses128Bit || (info->encryptionBits == 128);
+ uses256Bit = uses256Bit || (info->encryptionBits == 256);
+ usesGcm = usesGcm ||
+ QLatin1StringView(info->schannelCipherSuite).contains("_GCM_"_L1);
+ usesCbc = usesCbc ||
+ QLatin1StringView(info->schannelCipherSuite).contains("_CBC_"_L1);
+ }
+ }
+
+ CRYPTO_SETTINGS settings = {};
+ settings.eAlgorithmUsage = TlsParametersCngAlgUsageCipher;
+ assignUnicodeString(settings.strCngAlgId, algorithm);
+
+ if (usesGcm && !usesCbc) {
+ settings.cChainingModes = 1;
+ settings.rgstrChainingModes = &cbcChainingMode;
+ } else if (!usesGcm && usesCbc) {
+ settings.cChainingModes = 1;
+ settings.rgstrChainingModes = &gcmChainingMode;
+ }
+
+ if (!uses128Bit && uses256Bit) {
+ settings.dwMinBitLength = 256;
+ cryptoSettings.append(settings);
+ } else if (uses128Bit && !uses256Bit) {
+ settings.dwMaxBitLength = 128;
+ cryptoSettings.append(settings);
+ } else if (!uses128Bit && !uses256Bit) {
+ cryptoSettings.append(settings);
+ }
+ } else {
+ const auto usesMethod = [method](const SchannelCipherInfo *info) {
+ return QLatin1StringView(info->encryptionMethod) == method;
+ };
+
+ const bool exclude = std::none_of(cipherInfo.begin(), cipherInfo.end(), usesMethod);
+
+ if (exclude) {
+ CRYPTO_SETTINGS settings = {};
+ settings.eAlgorithmUsage = TlsParametersCngAlgUsageCipher;
+ assignUnicodeString(settings.strCngAlgId, algorithm);
+ cryptoSettings.append(settings);
+ }
+ }
+ }
+
+ // black list of hash algorithms
+ const auto allHashAlgorithms = {BCRYPT_MD5_ALGORITHM,
+ BCRYPT_SHA1_ALGORITHM,
+ BCRYPT_SHA256_ALGORITHM,
+ BCRYPT_SHA384_ALGORITHM};
+
+ for (const auto &algorithm : allHashAlgorithms) {
+ const auto method = QStringView(algorithm);
+
+ const auto usesMethod = [method](const SchannelCipherInfo *info) {
+ return QLatin1StringView(info->hashMethod) == method;
+ };
+
+ const bool exclude = std::none_of(cipherInfo.begin(), cipherInfo.end(), usesMethod);
+
+ if (exclude) {
+ CRYPTO_SETTINGS settings = {};
+ settings.eAlgorithmUsage = TlsParametersCngAlgUsageDigest;
+ assignUnicodeString(settings.strCngAlgId, algorithm);
+ cryptoSettings.append(settings);
+ }
+ }
+
+ return cryptoSettings;
+}
+
+QList<QSslCipher> ciphersByName(QStringView schannelSuiteName)
+{
+ QList<QSslCipher> ciphers;
+
+ for (const auto &cipher : schannelCipherInfo) {
+ if (QLatin1StringView(cipher.schannelCipherSuite) == schannelSuiteName) {
+ for (const auto &protocol : cipher.protocols) {
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
+ const QString protocolName = (
+ protocol == QSsl::TlsV1_0 ? QStringLiteral("TLSv1.0") :
+ protocol == QSsl::TlsV1_1 ? QStringLiteral("TLSv1.1") :
+ protocol == QSsl::TlsV1_2 ? QStringLiteral("TLSv1.2") :
+ protocol == QSsl::TlsV1_3 ? QStringLiteral("TLSv1.3") :
+ QString());
+QT_WARNING_POP
+
+ ciphers.append(QTlsBackend::createCiphersuite(QLatin1StringView(cipher.openSslCipherSuite),
+ QLatin1StringView(cipher.keyExchangeMethod),
+ QLatin1StringView(cipher.encryptionMethod),
+ QLatin1StringView(cipher.authenticationMethod),
+ cipher.encryptionBits,
+ protocol, protocolName));
+ }
+ }
+ }
+
+ return ciphers;
+}
+
+QList<QSslCipher> defaultCiphers()
+{
+ ULONG contextFunctionsCount = {};
+ PCRYPT_CONTEXT_FUNCTIONS contextFunctions = {};
+
+ const auto status = BCryptEnumContextFunctions(CRYPT_LOCAL, L"SSL", NCRYPT_SCHANNEL_INTERFACE,
+ &contextFunctionsCount, &contextFunctions);
+ if (!NT_SUCCESS(status)) {
+ qCWarning(lcTlsBackendSchannel, "Failed to enumerate ciphers");
+ return {};
+ }
+
+ const bool supportsV13 = supportsTls13();
+
+ QList<QSslCipher> ciphers;
+
+ for (ULONG index = 0; index < contextFunctions->cFunctions; ++index) {
+ const auto suiteName = QStringView(contextFunctions->rgpszFunctions[index]);
+
+ const QList<QSslCipher> allCiphers = ciphersByName(suiteName);
+
+ for (const auto &cipher : allCiphers) {
+ if (!supportsV13 && (cipher.protocol() == QSsl::TlsV1_3))
+ continue;
+
+ ciphers.append(cipher);
+ }
+ }
+
+ BCryptFreeBuffer(contextFunctions);
+
+ return ciphers;
+}
+
+bool containsTls13Cipher(const QList<QSslCipher> &ciphers)
+{
+ return std::any_of(ciphers.cbegin(), ciphers.cend(),
+ [](const QSslCipher &cipher) { return cipher.protocol() == QSsl::TlsV1_3; });
+}
+
+} // namespace QTlsPrivate
+
+bool QSchannelBackend::s_loadedCiphersAndCerts = false;
+Q_GLOBAL_STATIC(QRecursiveMutex, qt_schannel_mutex)
+
+long QSchannelBackend::tlsLibraryVersionNumber() const
+{
+ const auto os = QOperatingSystemVersion::current();
+ return (os.majorVersion() << 24) | ((os.minorVersion() & 0xFF) << 16) | (os.microVersion() & 0xFFFF);
+}
+
+QString QSchannelBackend::tlsLibraryVersionString() const
+{
+ const auto os = QOperatingSystemVersion::current();
+ return "Secure Channel, %1 %2.%3.%4"_L1
+ .arg(os.name(),
+ QString::number(os.majorVersion()),
+ QString::number(os.minorVersion()),
+ QString::number(os.microVersion()));
+}
+
+long QSchannelBackend::tlsLibraryBuildVersionNumber() const
+{
+ return NTDDI_VERSION;
+}
+
+QString QSchannelBackend::tlsLibraryBuildVersionString() const
+{
+ return "Secure Channel (NTDDI: 0x%1)"_L1
+ .arg(QString::number(NTDDI_VERSION, 16).toUpper());
+}
+
+void QSchannelBackend::ensureInitialized() const
+{
+ ensureInitializedImplementation();
+}
+
+void QSchannelBackend::ensureInitializedImplementation()
+{
+ const QMutexLocker<QRecursiveMutex> locker(qt_schannel_mutex);
+ if (s_loadedCiphersAndCerts)
+ return;
+ s_loadedCiphersAndCerts = true;
+
+ setDefaultCaCertificates(systemCaCertificatesImplementation());
+ // setDefaultCaCertificates sets it to false, re-enable it:
+ QSslSocketPrivate::setRootCertOnDemandLoadingSupported(true);
+
+ resetDefaultCiphers();
+}
+
+void QSchannelBackend::resetDefaultCiphers()
+{
+ setDefaultSupportedCiphers(QTlsPrivate::defaultCiphers());
+ setDefaultCiphers(QTlsPrivate::defaultCiphers());
+}
+
+QString QSchannelBackend::backendName() const
+{
+ return builtinBackendNames[nameIndexSchannel];
+}
+
+QList<QSsl::SslProtocol> QSchannelBackend::supportedProtocols() const
+{
+ QList<QSsl::SslProtocol> protocols;
+
+ 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;
+
+ if (supportsTls13()) {
+ protocols << QSsl::TlsV1_3;
+ protocols << QSsl::TlsV1_3OrLater;
+ }
+
+ return protocols;
+}
+
+QList<QSsl::SupportedFeature> QSchannelBackend::supportedFeatures() const
+{
+ QList<QSsl::SupportedFeature> features;
+
+#ifdef SUPPORTS_ALPN
+ features << QSsl::SupportedFeature::ClientSideAlpn;
+ features << QSsl::SupportedFeature::ServerSideAlpn;
+#endif
+
+ return features;
+}
+
+QList<QSsl::ImplementedClass> QSchannelBackend::implementedClasses() const
+{
+ QList<QSsl::ImplementedClass> classes;
+
+ classes << QSsl::ImplementedClass::Socket;
+ classes << QSsl::ImplementedClass::Certificate;
+ classes << QSsl::ImplementedClass::Key;
+
+ return classes;
+}
+
+QTlsPrivate::TlsKey *QSchannelBackend::createKey() const
+{
+ return new QTlsPrivate::TlsKeySchannel;
+}
+
+QTlsPrivate::X509Certificate *QSchannelBackend::createCertificate() const
+{
+ return new QTlsPrivate::X509CertificateSchannel;
+}
+
+QList<QSslCertificate> QSchannelBackend::systemCaCertificates() const
+{
+ return systemCaCertificatesImplementation();
+}
+
+QTlsPrivate::TlsCryptograph *QSchannelBackend::createTlsCryptograph() const
+{
+ return new QTlsPrivate::TlsCryptographSchannel;
+}
+
+QList<QSslCertificate> QSchannelBackend::systemCaCertificatesImplementation()
+{
+ // Similar to non-Darwin version found in qtlsbackend_openssl.cpp,
+ // QTlsPrivate::systemCaCertificates function.
+ QList<QSslCertificate> systemCerts;
+
+ auto hSystemStore = QHCertStorePointer(
+ CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0,
+ CERT_STORE_READONLY_FLAG | CERT_SYSTEM_STORE_CURRENT_USER, L"ROOT"));
+
+ if (hSystemStore) {
+ PCCERT_CONTEXT pc = nullptr;
+ while ((pc = CertFindCertificateInStore(hSystemStore.get(), X509_ASN_ENCODING, 0,
+ CERT_FIND_ANY, nullptr, pc))) {
+ systemCerts.append(QTlsPrivate::X509CertificateSchannel::QSslCertificate_from_CERT_CONTEXT(pc));
+ }
+ }
+ return systemCerts;
+}
+
+QTlsPrivate::X509PemReaderPtr QSchannelBackend::X509PemReader() const
+{
+ return QTlsPrivate::X509CertificateGeneric::certificatesFromPem;
+}
+
+QTlsPrivate::X509DerReaderPtr QSchannelBackend::X509DerReader() const
+{
+ return QTlsPrivate::X509CertificateGeneric::certificatesFromDer;
+}
+
+QTlsPrivate::X509Pkcs12ReaderPtr QSchannelBackend::X509Pkcs12Reader() const
+{
+ return QTlsPrivate::X509CertificateSchannel::importPkcs12;
+}
+
+namespace {
+
+SecBuffer createSecBuffer(void *ptr, unsigned long length, unsigned long bufferType)
+{
+ return SecBuffer{ length, bufferType, ptr };
+}
+
+SecBuffer createSecBuffer(QByteArray &buffer, unsigned long bufferType)
+{
+ return createSecBuffer(buffer.data(), static_cast<unsigned long>(buffer.length()), bufferType);
+}
+
+QString schannelErrorToString(qint32 status)
+{
+ switch (status) {
+ case SEC_E_INSUFFICIENT_MEMORY:
+ return QSslSocket::tr("Insufficient memory");
+ case SEC_E_INTERNAL_ERROR:
+ return QSslSocket::tr("Internal error");
+ case SEC_E_INVALID_HANDLE:
+ return QSslSocket::tr("An internal handle was invalid");
+ case SEC_E_INVALID_TOKEN:
+ return QSslSocket::tr("An internal token was invalid");
+ case SEC_E_LOGON_DENIED:
+ // According to the link below we get this error when Schannel receives TLS1_ALERT_ACCESS_DENIED
+ // https://docs.microsoft.com/en-us/windows/desktop/secauthn/schannel-error-codes-for-tls-and-ssl-alerts
+ return QSslSocket::tr("Access denied");
+ case SEC_E_NO_AUTHENTICATING_AUTHORITY:
+ return QSslSocket::tr("No authority could be contacted for authorization");
+ case SEC_E_NO_CREDENTIALS:
+ return QSslSocket::tr("No credentials");
+ case SEC_E_TARGET_UNKNOWN:
+ return QSslSocket::tr("The target is unknown or unreachable");
+ case SEC_E_UNSUPPORTED_FUNCTION:
+ return QSslSocket::tr("An unsupported function was requested");
+ case SEC_E_WRONG_PRINCIPAL:
+ // SNI error
+ return QSslSocket::tr("The hostname provided does not match the one received from the peer");
+ case SEC_E_APPLICATION_PROTOCOL_MISMATCH:
+ return QSslSocket::tr("No common protocol exists between the client and the server");
+ case SEC_E_ILLEGAL_MESSAGE:
+ return QSslSocket::tr("Unexpected or badly-formatted message received");
+ case SEC_E_ENCRYPT_FAILURE:
+ return QSslSocket::tr("The data could not be encrypted");
+ case SEC_E_ALGORITHM_MISMATCH:
+ return QSslSocket::tr("No cipher suites in common");
+ case SEC_E_UNKNOWN_CREDENTIALS:
+ // This can mean "invalid argument" in some cases...
+ return QSslSocket::tr("The credentials were not recognized / Invalid argument");
+ case SEC_E_MESSAGE_ALTERED:
+ // According to the Internet it also triggers for messages that are out of order.
+ // https://microsoft.public.platformsdk.security.narkive.com/4JAvlMvD/help-please-schannel-security-contexts-and-decryptmessage
+ return QSslSocket::tr("The message was tampered with, damaged or out of sequence.");
+ case SEC_E_OUT_OF_SEQUENCE:
+ return QSslSocket::tr("A message was received out of sequence.");
+ case SEC_E_CONTEXT_EXPIRED:
+ return QSslSocket::tr("The TLS/SSL connection has been closed");
+ default:
+ return QSslSocket::tr("Unknown error occurred: %1").arg(status);
+ }
+}
+
+bool supportsTls13()
+{
+ static bool supported = []() {
+ const auto current = QOperatingSystemVersion::current();
+ // 20221 just happens to be the preview version I run on my laptop where I tested TLS 1.3.
+ const auto minimum =
+ QOperatingSystemVersion(QOperatingSystemVersion::Windows, 10, 0, 20221);
+ return current >= minimum;
+ }();
+
+ return supported;
+}
+
+DWORD toSchannelProtocol(QSsl::SslProtocol protocol)
+{
+ DWORD protocols = SP_PROT_NONE;
+ switch (protocol) {
+ case QSsl::UnknownProtocol:
+ return DWORD(-1);
+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 DWORD(-1); // Not supported at the moment (@future)
+ case QSsl::AnyProtocol:
+ protocols = SP_PROT_TLS1_0 | SP_PROT_TLS1_1 | SP_PROT_TLS1_2;
+ 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;
+ case QSsl::TlsV1_3:
+ if (supportsTls13())
+ protocols = SP_PROT_TLS1_3;
+ else
+ protocols = DWORD(-1);
+ break;
+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
+ protocols = SP_PROT_TLS1_0;
+ Q_FALLTHROUGH();
+ 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();
+ case QSsl::TlsV1_3OrLater:
+ if (supportsTls13())
+ protocols |= SP_PROT_TLS1_3;
+ else if (protocol == QSsl::TlsV1_3OrLater)
+ protocols = DWORD(-1); // if TlsV1_3OrLater was specifically chosen we should fail
+ break;
+ }
+ return protocols;
+}
+
+// In the new API that descended down upon us we are not asked which protocols we want
+// but rather which protocols we don't want. So now we have this function to disable
+// anything that is not enabled.
+DWORD negatedSchannelProtocols(DWORD wantedProtocols)
+{
+ DWORD protocols = SP_PROT_ALL; // all protocols
+ protocols &= ~wantedProtocols; // minus the one(s) we want
+ return protocols;
+}
+
+/*!
+ \internal
+ Used when converting the established session's \a protocol back to
+ Qt's own SslProtocol type.
+
+ Only one protocol should be passed in at a time.
+*/
+QSsl::SslProtocol toQtSslProtocol(DWORD protocol)
+{
+#define MAP_PROTOCOL(sp_protocol, q_protocol) \
+ if (protocol & sp_protocol) { \
+ Q_ASSERT(!(protocol & ~sp_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
+ Q_UNREACHABLE();
+ return QSsl::UnknownProtocol;
+}
+
+/*!
+ \internal
+ Used by verifyCertContext to check if a client cert is used by a server or vice versa.
+*/
+bool netscapeWrongCertType(const QList<QSslCertificateExtension> &extensions, bool isClient)
+{
+ const auto netscapeIt = std::find_if(
+ extensions.cbegin(), extensions.cend(),
+ [](const QSslCertificateExtension &extension) {
+ return extension.oid() == u"2.16.840.1.113730.1.1";
+ });
+ if (netscapeIt != extensions.cend()) {
+ const QByteArray netscapeCertTypeByte = netscapeIt->value().toByteArray();
+ int netscapeCertType = 0;
+ QDataStream dataStream(netscapeCertTypeByte);
+ dataStream >> netscapeCertType;
+ if (dataStream.status() != QDataStream::Status::Ok)
+ return true;
+ const int expectedPeerCertType = isClient ? NETSCAPE_SSL_SERVER_AUTH_CERT_TYPE
+ : NETSCAPE_SSL_CLIENT_AUTH_CERT_TYPE;
+ if ((netscapeCertType & expectedPeerCertType) == 0)
+ return true;
+ }
+ return false;
+}
+
+/*!
+ \internal
+ Used by verifyCertContext to check the basicConstraints certificate
+ extension to see if the certificate is a certificate authority.
+ Returns false if the certificate does not have the basicConstraints
+ extension or if it is not a certificate authority.
+*/
+bool isCertificateAuthority(const QList<QSslCertificateExtension> &extensions)
+{
+ auto it = std::find_if(extensions.cbegin(), extensions.cend(),
+ [](const QSslCertificateExtension &extension) {
+ return extension.name() == "basicConstraints"_L1;
+ });
+ if (it != extensions.cend()) {
+ QVariantMap basicConstraints = it->value().toMap();
+ return basicConstraints.value("ca"_L1, false).toBool();
+ }
+ return false;
+}
+
+/*!
+ \internal
+ Returns true if the attributes we requested from the context/handshake have
+ been given.
+*/
+bool matchesContextRequirements(DWORD attributes, DWORD requirements,
+ QSslSocket::PeerVerifyMode verifyMode,
+ bool isClient)
+{
+#ifdef QSSLSOCKET_DEBUG
+#define DEBUG_WARN(message) qCWarning(lcTlsBackendSchannel, message)
+#else
+#define DEBUG_WARN(message)
+#endif
+
+#define CHECK_ATTRIBUTE(attributeName) \
+ do { \
+ const DWORD req##attributeName = isClient ? ISC_REQ_##attributeName : ASC_REQ_##attributeName; \
+ const DWORD ret##attributeName = isClient ? ISC_RET_##attributeName : ASC_RET_##attributeName; \
+ if (!(requirements & req##attributeName) != !(attributes & ret##attributeName)) { \
+ DEBUG_WARN("Missing attribute \"" #attributeName "\""); \
+ return false; \
+ } \
+ } while (false)
+
+ CHECK_ATTRIBUTE(CONFIDENTIALITY);
+ CHECK_ATTRIBUTE(REPLAY_DETECT);
+ CHECK_ATTRIBUTE(SEQUENCE_DETECT);
+ CHECK_ATTRIBUTE(STREAM);
+ if (verifyMode == QSslSocket::PeerVerifyMode::VerifyPeer)
+ CHECK_ATTRIBUTE(MUTUAL_AUTH);
+
+ // This one is manual because there is no server / ASC_ version
+ if (isClient) {
+ const auto reqManualCredValidation = ISC_REQ_MANUAL_CRED_VALIDATION;
+ const auto retManualCredValidation = ISC_RET_MANUAL_CRED_VALIDATION;
+ if (!(requirements & reqManualCredValidation) != !(attributes & retManualCredValidation)) {
+ DEBUG_WARN("Missing attribute \"MANUAL_CRED_VALIDATION\"");
+ return false;
+ }
+ }
+
+ return true;
+#undef CHECK_ATTRIBUTE
+#undef DEBUG_WARN
+}
+
+template<typename Required, typename Actual>
+Required const_reinterpret_cast(Actual *p)
+{
+ return Required(p);
+}
+
+#ifdef SUPPORTS_ALPN
+QByteArray createAlpnString(const QByteArrayList &nextAllowedProtocols)
+{
+ QByteArray alpnString;
+ if (!nextAllowedProtocols.isEmpty()) {
+ const QByteArray names = [&nextAllowedProtocols]() {
+ QByteArray protocolString;
+ for (QByteArray proto : nextAllowedProtocols) {
+ if (proto.size() > 255) {
+ qCWarning(lcTlsBackendSchannel)
+ << "TLS ALPN extension" << proto << "is too long and will be ignored.";
+ continue;
+ } else if (proto.isEmpty()) {
+ continue;
+ }
+ protocolString += char(proto.length()) + proto;
+ }
+ return protocolString;
+ }();
+ if (names.isEmpty())
+ return alpnString;
+
+ const quint16 namesSize = names.size();
+ const quint32 alpnId = SecApplicationProtocolNegotiationExt_ALPN;
+ const quint32 totalSize = sizeof(alpnId) + sizeof(namesSize) + namesSize;
+ alpnString = QByteArray::fromRawData(reinterpret_cast<const char *>(&totalSize), sizeof(totalSize))
+ + QByteArray::fromRawData(reinterpret_cast<const char *>(&alpnId), sizeof(alpnId))
+ + QByteArray::fromRawData(reinterpret_cast<const char *>(&namesSize), sizeof(namesSize))
+ + names;
+ }
+ return alpnString;
+}
+#endif // SUPPORTS_ALPN
+
+qint64 readToBuffer(QByteArray &buffer, QTcpSocket *plainSocket)
+{
+ Q_ASSERT(plainSocket);
+ static const qint64 shrinkCutoff = 1024 * 12;
+ static const qint64 defaultRead = 1024 * 16;
+ qint64 bytesRead = 0;
+
+ const auto toRead = std::min(defaultRead, plainSocket->bytesAvailable());
+ if (toRead > 0) {
+ const auto bufferSize = buffer.size();
+ buffer.reserve(bufferSize + toRead); // avoid growth strategy kicking in
+ buffer.resize(bufferSize + toRead);
+ bytesRead = plainSocket->read(buffer.data() + bufferSize, toRead);
+ buffer.resize(bufferSize + bytesRead);
+ // In case of excessive memory usage we shrink:
+ if (buffer.size() < shrinkCutoff && buffer.capacity() > defaultRead)
+ buffer.shrink_to_fit();
+ }
+
+ return bytesRead;
+}
+
+void retainExtraData(QByteArray &buffer, const SecBuffer &secBuffer)
+{
+ Q_ASSERT(secBuffer.BufferType == SECBUFFER_EXTRA);
+ if (int(secBuffer.cbBuffer) >= buffer.size())
+ return;
+
+#ifdef QSSLSOCKET_DEBUG
+ 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);
+}
+
+qint64 checkIncompleteData(const SecBuffer &secBuffer)
+{
+ if (secBuffer.BufferType == SECBUFFER_MISSING) {
+#ifdef QSSLSOCKET_DEBUG
+ qCDebug(lcTlsBackendSchannel, "Need %lu more bytes.", secBuffer.cbBuffer);
+#endif
+ return secBuffer.cbBuffer;
+}
+ return 0;
+}
+
+DWORD defaultCredsFlag()
+{
+ return qEnvironmentVariableIsSet("QT_SCH_DEFAULT_CREDS") ? 0 : SCH_CRED_NO_DEFAULT_CREDS;
+}
+} // anonymous namespace
+
+
+namespace QTlsPrivate {
+
+TlsCryptographSchannel::TlsCryptographSchannel()
+{
+ SecInvalidateHandle(&credentialHandle);
+ SecInvalidateHandle(&contextHandle);
+ QSchannelBackend::ensureInitializedImplementation();
+}
+
+TlsCryptographSchannel::~TlsCryptographSchannel()
+{
+ closeCertificateStores();
+ deallocateContext();
+ freeCredentialsHandle();
+ CertFreeCertificateContext(localCertContext);
+}
+
+void TlsCryptographSchannel::init(QSslSocket *qObj, QSslSocketPrivate *dObj)
+{
+ Q_ASSERT(qObj);
+ Q_ASSERT(dObj);
+
+ q = qObj;
+ d = dObj;
+
+ reset();
+}
+
+bool TlsCryptographSchannel::sendToken(void *token, unsigned long tokenLength, bool emitError)
+{
+ if (tokenLength == 0)
+ return true;
+
+ Q_ASSERT(d);
+ auto *plainSocket = d->plainTcpSocket();
+ Q_ASSERT(plainSocket);
+ if (plainSocket->state() == QAbstractSocket::UnconnectedState || !plainSocket->isValid()
+ || !plainSocket->isOpen()) {
+ return false;
+ }
+
+ const qint64 written = plainSocket->write(static_cast<const char *>(token), tokenLength);
+ if (written != qint64(tokenLength)) {
+ // Failed to write/buffer everything or an error occurred
+ if (emitError)
+ setErrorAndEmit(d, plainSocket->error(), plainSocket->errorString());
+ return false;
+ }
+ return true;
+}
+
+QString TlsCryptographSchannel::targetName() const
+{
+ // Used for SNI extension
+ Q_ASSERT(q);
+ Q_ASSERT(d);
+
+ const auto verificationPeerName = d->verificationName();
+ return verificationPeerName.isEmpty() ? q->peerName() : verificationPeerName;
+}
+
+ULONG TlsCryptographSchannel::getContextRequirements()
+{
+ Q_ASSERT(d);
+ Q_ASSERT(q);
+
+ const bool isClient = d->tlsMode() == QSslSocket::SslClientMode;
+ ULONG req = 0;
+
+ req |= ISC_REQ_ALLOCATE_MEMORY; // Allocate memory for buffers automatically
+ req |= ISC_REQ_CONFIDENTIALITY; // Encrypt messages
+ req |= ISC_REQ_REPLAY_DETECT; // Detect replayed messages
+ req |= ISC_REQ_SEQUENCE_DETECT; // Detect out of sequence messages
+ req |= ISC_REQ_STREAM; // Support a stream-oriented connection
+
+ if (isClient) {
+ req |= ISC_REQ_MANUAL_CRED_VALIDATION; // Manually validate certificate
+ } else {
+ switch (q->peerVerifyMode()) {
+ case QSslSocket::PeerVerifyMode::VerifyNone:
+ // There doesn't seem to be a way to ask for an optional client cert :-(
+ case QSslSocket::PeerVerifyMode::AutoVerifyPeer:
+ case QSslSocket::PeerVerifyMode::QueryPeer:
+ break;
+ case QSslSocket::PeerVerifyMode::VerifyPeer:
+ req |= ISC_REQ_MUTUAL_AUTH;
+ break;
+ }
+ }
+
+ return req;
+}
+
+bool TlsCryptographSchannel::acquireCredentialsHandle()
+{
+ Q_ASSERT(d);
+ Q_ASSERT(q);
+ const auto &configuration = q->sslConfiguration();
+
+ Q_ASSERT(schannelState == SchannelState::InitializeHandshake);
+
+ const bool isClient = d->tlsMode() == QSslSocket::SslClientMode;
+ DWORD protocols = toSchannelProtocol(configuration.protocol());
+ if (protocols == DWORD(-1)) {
+ setErrorAndEmit(d, QAbstractSocket::SslInvalidUserDataError,
+ QSslSocket::tr("Invalid protocol chosen"));
+ return false;
+ }
+
+ const CERT_CHAIN_CONTEXT *chainContext = nullptr;
+ auto freeCertChain = qScopeGuard([&chainContext]() {
+ if (chainContext)
+ CertFreeCertificateChain(chainContext);
+ });
+
+ DWORD certsCount = 0;
+ // Set up our certificate stores before trying to use one...
+ initializeCertificateStores();
+
+ // Check if user has specified a certificate chain but it could not be loaded.
+ // This happens if there was something wrong with the certificate chain or there was no private
+ // key.
+ if (!configuration.localCertificateChain().isEmpty() && !localCertificateStore)
+ return true; // 'true' because "tst_QSslSocket::setEmptyKey" expects us to not disconnect
+
+ if (localCertificateStore != nullptr) {
+ CERT_CHAIN_FIND_BY_ISSUER_PARA findParam;
+ ZeroMemory(&findParam, sizeof(findParam));
+ findParam.cbSize = sizeof(findParam);
+ findParam.pszUsageIdentifier = isClient ? szOID_PKIX_KP_CLIENT_AUTH : szOID_PKIX_KP_SERVER_AUTH;
+
+ // There should only be one chain in our store, so.. we grab that one.
+ chainContext = CertFindChainInStore(localCertificateStore.get(),
+ X509_ASN_ENCODING,
+ 0,
+ CERT_CHAIN_FIND_BY_ISSUER,
+ &findParam,
+ nullptr);
+ if (!chainContext) {
+ const QString message = isClient
+ ? QSslSocket::tr("The certificate provided cannot be used for a client.")
+ : QSslSocket::tr("The certificate provided cannot be used for a server.");
+ setErrorAndEmit(d, QAbstractSocket::SocketError::SslInvalidUserDataError, message);
+ return false;
+ }
+ Q_ASSERT(chainContext->cChain == 1);
+ Q_ASSERT(chainContext->rgpChain[0]);
+ Q_ASSERT(chainContext->rgpChain[0]->cbSize >= 1);
+ Q_ASSERT(chainContext->rgpChain[0]->rgpElement[0]);
+ Q_ASSERT(!localCertContext);
+ localCertContext = CertDuplicateCertificateContext(chainContext->rgpChain[0]
+ ->rgpElement[0]
+ ->pCertContext);
+ certsCount = 1;
+ Q_ASSERT(localCertContext);
+ }
+
+ const QList<QSslCipher> ciphers = configuration.ciphers();
+ if (!ciphers.isEmpty() && !containsTls13Cipher(ciphers))
+ protocols &= ~SP_PROT_TLS1_3;
+
+ QList<CRYPTO_SETTINGS> cryptoSettings;
+ if (!ciphers.isEmpty())
+ cryptoSettings = cryptoSettingsForCiphers(ciphers);
+
+ TLS_PARAMETERS tlsParameters = {
+ 0,
+ nullptr,
+ negatedSchannelProtocols(protocols), // what protocols to disable
+ static_cast<DWORD>(cryptoSettings.size()),
+ (cryptoSettings.isEmpty() ? nullptr : cryptoSettings.data()),
+ 0
+ };
+
+ SCH_CREDENTIALS credentials = {
+ SCH_CREDENTIALS_VERSION,
+ 0,
+ certsCount,
+ &localCertContext,
+ nullptr,
+ 0,
+ nullptr,
+ 0,
+ SCH_CRED_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT | defaultCredsFlag(),
+ 1,
+ &tlsParameters
+ };
+
+ TimeStamp expiration{};
+ auto status = AcquireCredentialsHandle(nullptr, // pszPrincipal (unused)
+ const_cast<wchar_t *>(UNISP_NAME), // pszPackage
+ isClient ? SECPKG_CRED_OUTBOUND : SECPKG_CRED_INBOUND, // fCredentialUse
+ nullptr, // pvLogonID (unused)
+ &credentials, // pAuthData
+ nullptr, // pGetKeyFn (unused)
+ nullptr, // pvGetKeyArgument (unused)
+ &credentialHandle, // phCredential
+ &expiration // ptsExpir
+ );
+
+ if (status != SEC_E_OK) {
+ setErrorAndEmit(d, QAbstractSocket::SslInternalError, schannelErrorToString(status));
+ return false;
+ }
+ return true;
+}
+
+void TlsCryptographSchannel::deallocateContext()
+{
+ if (SecIsValidHandle(&contextHandle)) {
+ DeleteSecurityContext(&contextHandle);
+ SecInvalidateHandle(&contextHandle);
+ }
+}
+
+void TlsCryptographSchannel::freeCredentialsHandle()
+{
+ if (SecIsValidHandle(&credentialHandle)) {
+ FreeCredentialsHandle(&credentialHandle);
+ SecInvalidateHandle(&credentialHandle);
+ }
+}
+
+void TlsCryptographSchannel::closeCertificateStores()
+{
+ localCertificateStore.reset();
+ peerCertificateStore.reset();
+ caCertificateStore.reset();
+}
+
+bool TlsCryptographSchannel::createContext()
+{
+ Q_ASSERT(q);
+ Q_ASSERT(d);
+
+ Q_ASSERT(SecIsValidHandle(&credentialHandle));
+ Q_ASSERT(schannelState == SchannelState::InitializeHandshake);
+ Q_ASSERT(d->tlsMode() == QSslSocket::SslClientMode);
+ ULONG contextReq = getContextRequirements();
+
+ SecBuffer outBuffers[3];
+ outBuffers[0] = createSecBuffer(nullptr, 0, SECBUFFER_TOKEN);
+ outBuffers[1] = createSecBuffer(nullptr, 0, SECBUFFER_ALERT);
+ outBuffers[2] = createSecBuffer(nullptr, 0, SECBUFFER_EMPTY);
+ auto freeBuffers = qScopeGuard([&outBuffers]() {
+ for (auto i = 0ull; i < ARRAYSIZE(outBuffers); i++) {
+ if (outBuffers[i].pvBuffer)
+ FreeContextBuffer(outBuffers[i].pvBuffer);
+ }
+ });
+ SecBufferDesc outputBufferDesc{
+ SECBUFFER_VERSION,
+ ARRAYSIZE(outBuffers),
+ outBuffers
+ };
+
+ TimeStamp expiry;
+
+ SecBufferDesc alpnBufferDesc;
+ bool useAlpn = false;
+#ifdef SUPPORTS_ALPN
+ QTlsBackend::setAlpnStatus(d, QSslConfiguration::NextProtocolNegotiationNone);
+ QByteArray alpnString = createAlpnString(q->sslConfiguration().allowedNextProtocols());
+ useAlpn = !alpnString.isEmpty();
+ SecBuffer alpnBuffers[1];
+ alpnBuffers[0] = createSecBuffer(alpnString, SECBUFFER_APPLICATION_PROTOCOLS);
+ alpnBufferDesc = {
+ SECBUFFER_VERSION,
+ ARRAYSIZE(alpnBuffers),
+ alpnBuffers
+ };
+#endif
+
+ auto status = InitializeSecurityContext(&credentialHandle, // phCredential
+ nullptr, // phContext
+ const_reinterpret_cast<SEC_WCHAR *>(targetName().utf16()), // pszTargetName
+ contextReq, // fContextReq
+ 0, // Reserved1
+ 0, // TargetDataRep (unused)
+ useAlpn ? &alpnBufferDesc : nullptr, // pInput
+ 0, // Reserved2
+ &contextHandle, // phNewContext
+ &outputBufferDesc, // pOutput
+ &contextAttributes, // pfContextAttr
+ &expiry // ptsExpiry
+ );
+
+ // This is the first call to InitializeSecurityContext, so theoretically "CONTINUE_NEEDED"
+ // should be the only non-error return-code here.
+ if (status != SEC_I_CONTINUE_NEEDED) {
+ setErrorAndEmit(d, QAbstractSocket::SslInternalError,
+ QSslSocket::tr("Error creating SSL context (%1)").arg(schannelErrorToString(status)));
+ return false;
+ }
+
+ if (!sendToken(outBuffers[0].pvBuffer, outBuffers[0].cbBuffer))
+ return false;
+ schannelState = SchannelState::PerformHandshake;
+ return true;
+}
+
+bool TlsCryptographSchannel::acceptContext()
+{
+ Q_ASSERT(d);
+ Q_ASSERT(q);
+
+ auto *plainSocket = d->plainTcpSocket();
+ Q_ASSERT(plainSocket);
+
+ Q_ASSERT(SecIsValidHandle(&credentialHandle));
+ Q_ASSERT(schannelState == SchannelState::InitializeHandshake);
+ Q_ASSERT(d->tlsMode() == QSslSocket::SslServerMode);
+ ULONG contextReq = getContextRequirements();
+
+ if (missingData > plainSocket->bytesAvailable())
+ return true;
+
+ missingData = 0;
+ readToBuffer(intermediateBuffer, plainSocket);
+ if (intermediateBuffer.isEmpty())
+ return true; // definitely need more data..
+
+ SecBuffer inBuffers[2];
+ inBuffers[0] = createSecBuffer(intermediateBuffer, SECBUFFER_TOKEN);
+
+#ifdef SUPPORTS_ALPN
+ QTlsBackend::setAlpnStatus(d, QSslConfiguration::NextProtocolNegotiationNone);
+ // The string must be alive when we call AcceptSecurityContext
+ QByteArray alpnString = createAlpnString(q->sslConfiguration().allowedNextProtocols());
+ if (!alpnString.isEmpty()) {
+ inBuffers[1] = createSecBuffer(alpnString, SECBUFFER_APPLICATION_PROTOCOLS);
+ } else
+#endif
+ {
+ inBuffers[1] = createSecBuffer(nullptr, 0, SECBUFFER_EMPTY);
+ }
+
+ SecBufferDesc inputBufferDesc{
+ SECBUFFER_VERSION,
+ ARRAYSIZE(inBuffers),
+ inBuffers
+ };
+
+ SecBuffer outBuffers[3];
+ outBuffers[0] = createSecBuffer(nullptr, 0, SECBUFFER_TOKEN);
+ outBuffers[1] = createSecBuffer(nullptr, 0, SECBUFFER_ALERT);
+ outBuffers[2] = createSecBuffer(nullptr, 0, SECBUFFER_EMPTY);
+ auto freeBuffers = qScopeGuard([&outBuffers]() {
+ for (auto i = 0ull; i < ARRAYSIZE(outBuffers); i++) {
+ if (outBuffers[i].pvBuffer)
+ FreeContextBuffer(outBuffers[i].pvBuffer);
+ }
+ });
+ SecBufferDesc outputBufferDesc{
+ SECBUFFER_VERSION,
+ ARRAYSIZE(outBuffers),
+ outBuffers
+ };
+
+ TimeStamp expiry;
+ auto status = AcceptSecurityContext(
+ &credentialHandle, // phCredential
+ nullptr, // phContext
+ &inputBufferDesc, // pInput
+ contextReq, // fContextReq
+ 0, // TargetDataRep (unused)
+ &contextHandle, // phNewContext
+ &outputBufferDesc, // pOutput
+ &contextAttributes, // pfContextAttr
+ &expiry // ptsTimeStamp
+ );
+
+ if (status == SEC_E_INCOMPLETE_MESSAGE) {
+ // Need more data
+ missingData = checkIncompleteData(outBuffers[0]);
+ return true;
+ }
+
+ if (inBuffers[1].BufferType == SECBUFFER_EXTRA) {
+ // https://docs.microsoft.com/en-us/windows/desktop/secauthn/extra-buffers-returned-by-schannel
+ // inBuffers[1].cbBuffer indicates the amount of bytes _NOT_ processed, the rest need to
+ // be stored.
+ retainExtraData(intermediateBuffer, inBuffers[1]);
+ } else { /* No 'extra' data, message not incomplete */
+ intermediateBuffer.resize(0);
+ }
+
+ if (status != SEC_I_CONTINUE_NEEDED) {
+ setErrorAndEmit(d, QAbstractSocket::SslHandshakeFailedError,
+ QSslSocket::tr("Error creating SSL context (%1)").arg(schannelErrorToString(status)));
+ return false;
+ }
+ if (!sendToken(outBuffers[0].pvBuffer, outBuffers[0].cbBuffer))
+ return false;
+ schannelState = SchannelState::PerformHandshake;
+ return true;
+}
+
+bool TlsCryptographSchannel::performHandshake()
+{
+ Q_ASSERT(d);
+ auto *plainSocket = d->plainTcpSocket();
+ Q_ASSERT(plainSocket);
+
+ if (plainSocket->state() == QAbstractSocket::UnconnectedState || !plainSocket->isValid()
+ || !plainSocket->isOpen()) {
+ setErrorAndEmit(d, QAbstractSocket::RemoteHostClosedError,
+ QSslSocket::tr("The TLS/SSL connection has been closed"));
+ return false;
+ }
+ Q_ASSERT(SecIsValidHandle(&credentialHandle));
+ Q_ASSERT(SecIsValidHandle(&contextHandle));
+ Q_ASSERT(schannelState == SchannelState::PerformHandshake);
+
+#ifdef QSSLSOCKET_DEBUG
+ qCDebug(lcTlsBackendSchannel, "Bytes available from socket: %lld",
+ plainSocket->bytesAvailable());
+ qCDebug(lcTlsBackendSchannel, "intermediateBuffer size: %d", intermediateBuffer.size());
+#endif
+
+ if (missingData > plainSocket->bytesAvailable())
+ return true;
+
+ missingData = 0;
+ readToBuffer(intermediateBuffer, plainSocket);
+ if (intermediateBuffer.isEmpty())
+ return true; // no data, will fail
+
+ SecBuffer outBuffers[3] = {};
+ const auto freeOutBuffers = [&outBuffers]() {
+ for (auto i = 0ull; i < ARRAYSIZE(outBuffers); i++) {
+ if (outBuffers[i].pvBuffer)
+ FreeContextBuffer(outBuffers[i].pvBuffer);
+ }
+ };
+ const auto outBuffersGuard = qScopeGuard(freeOutBuffers);
+ // For this call to InitializeSecurityContext we may need to call it twice.
+ // In some cases us not having a certificate isn't actually an error, but just a request.
+ // With Schannel, to ignore this warning, we need to call InitializeSecurityContext again
+ // when we get SEC_I_INCOMPLETE_CREDENTIALS! As far as I can tell it's not documented anywhere.
+ // https://stackoverflow.com/a/47479968/2493610
+ SECURITY_STATUS status;
+ short attempts = 2;
+ do {
+ SecBuffer inputBuffers[2];
+ inputBuffers[0] = createSecBuffer(intermediateBuffer, SECBUFFER_TOKEN);
+ inputBuffers[1] = createSecBuffer(nullptr, 0, SECBUFFER_EMPTY);
+ SecBufferDesc inputBufferDesc{
+ SECBUFFER_VERSION,
+ ARRAYSIZE(inputBuffers),
+ inputBuffers
+ };
+
+ freeOutBuffers(); // free buffers from any previous attempt
+ outBuffers[0] = createSecBuffer(nullptr, 0, SECBUFFER_TOKEN);
+ outBuffers[1] = createSecBuffer(nullptr, 0, SECBUFFER_ALERT);
+ outBuffers[2] = createSecBuffer(nullptr, 0, SECBUFFER_EMPTY);
+ SecBufferDesc outputBufferDesc{
+ SECBUFFER_VERSION,
+ ARRAYSIZE(outBuffers),
+ outBuffers
+ };
+
+ ULONG contextReq = getContextRequirements();
+ TimeStamp expiry;
+ status = InitializeSecurityContext(
+ &credentialHandle, // phCredential
+ &contextHandle, // phContext
+ const_reinterpret_cast<SEC_WCHAR *>(targetName().utf16()), // pszTargetName
+ contextReq, // fContextReq
+ 0, // Reserved1
+ 0, // TargetDataRep (unused)
+ &inputBufferDesc, // pInput
+ 0, // Reserved2
+ nullptr, // phNewContext (we already have one)
+ &outputBufferDesc, // pOutput
+ &contextAttributes, // pfContextAttr
+ &expiry // ptsExpiry
+ );
+
+ if (inputBuffers[1].BufferType == SECBUFFER_EXTRA) {
+ // https://docs.microsoft.com/en-us/windows/desktop/secauthn/extra-buffers-returned-by-schannel
+ // inputBuffers[1].cbBuffer indicates the amount of bytes _NOT_ processed, the rest need
+ // to be stored.
+ retainExtraData(intermediateBuffer, inputBuffers[1]);
+ } else if (status != SEC_E_INCOMPLETE_MESSAGE) {
+ // Clear the buffer if we weren't asked for more data
+ intermediateBuffer.resize(0);
+ }
+
+ --attempts;
+ } while (status == SEC_I_INCOMPLETE_CREDENTIALS && attempts > 0);
+
+ switch (status) {
+ case SEC_E_OK:
+ // Need to transmit a final token in the handshake if 'cbBuffer' is non-zero.
+ if (!sendToken(outBuffers[0].pvBuffer, outBuffers[0].cbBuffer))
+ return false;
+ schannelState = SchannelState::VerifyHandshake;
+ return true;
+ case SEC_I_CONTINUE_NEEDED:
+ if (!sendToken(outBuffers[0].pvBuffer, outBuffers[0].cbBuffer))
+ return false;
+ // Must call InitializeSecurityContext again later (done through continueHandshake)
+ return true;
+ case SEC_I_INCOMPLETE_CREDENTIALS:
+ // Schannel takes care of picking certificate to send (other than the one we can specify),
+ // so if we get here then that means we don't have a certificate the server accepts.
+ setErrorAndEmit(d, QAbstractSocket::SslHandshakeFailedError,
+ QSslSocket::tr("Server did not accept any certificate we could present."));
+ return false;
+ case SEC_I_CONTEXT_EXPIRED:
+ // "The message sender has finished using the connection and has initiated a shutdown."
+ if (outBuffers[0].BufferType == SECBUFFER_TOKEN) {
+ if (!sendToken(outBuffers[0].pvBuffer, outBuffers[0].cbBuffer))
+ return false;
+ }
+ if (!shutdown) { // we did not initiate this
+ setErrorAndEmit(d, QAbstractSocket::RemoteHostClosedError,
+ QSslSocket::tr("The TLS/SSL connection has been closed"));
+ }
+ return true;
+ case SEC_E_INCOMPLETE_MESSAGE:
+ // Simply incomplete, wait for more data
+ missingData = checkIncompleteData(outBuffers[0]);
+ return true;
+ case SEC_E_ALGORITHM_MISMATCH:
+ setErrorAndEmit(d, QAbstractSocket::SslHandshakeFailedError,
+ QSslSocket::tr("Algorithm mismatch"));
+ shutdown = true; // skip sending the "Shutdown" alert
+ return false;
+ }
+
+ // Note: We can get here if the connection is using TLS 1.2 and the server certificate uses
+ // MD5, which is not allowed in Schannel. This causes an "invalid token" error during handshake.
+ // (If you came here investigating an error: md5 is insecure, update your certificate)
+ setErrorAndEmit(d, QAbstractSocket::SslHandshakeFailedError,
+ QSslSocket::tr("Handshake failed: %1").arg(schannelErrorToString(status)));
+ return false;
+}
+
+bool TlsCryptographSchannel::verifyHandshake()
+{
+ Q_ASSERT(d);
+ Q_ASSERT(q);
+ const auto &configuration = q->sslConfiguration();
+
+ sslErrors.clear();
+
+ const bool isClient = d->tlsMode() == QSslSocket::SslClientMode;
+#define CHECK_STATUS(status) \
+ if (status != SEC_E_OK) { \
+ setErrorAndEmit(d, QAbstractSocket::SslInternalError, \
+ QSslSocket::tr("Failed to query the TLS context: %1") \
+ .arg(schannelErrorToString(status))); \
+ return false; \
+ }
+
+ // Everything is set up, now make sure there's nothing wrong and query some attributes...
+ if (!matchesContextRequirements(contextAttributes, getContextRequirements(),
+ configuration.peerVerifyMode(), isClient)) {
+ setErrorAndEmit(d, QAbstractSocket::SslHandshakeFailedError,
+ QSslSocket::tr("Did not get the required attributes for the connection."));
+ return false;
+ }
+
+ // Get stream sizes (to know the max size of a message and the size of the header and trailer)
+ auto status = QueryContextAttributes(&contextHandle,
+ SECPKG_ATTR_STREAM_SIZES,
+ &streamSizes);
+ CHECK_STATUS(status);
+
+ // Get session cipher info
+ status = QueryContextAttributes(&contextHandle,
+ SECPKG_ATTR_CIPHER_INFO,
+ &cipherInfo);
+ CHECK_STATUS(status);
+
+ status = QueryContextAttributes(&contextHandle,
+ SECPKG_ATTR_CONNECTION_INFO,
+ &connectionInfo);
+ CHECK_STATUS(status);
+
+#ifdef SUPPORTS_ALPN
+ const auto allowedProtos = configuration.allowedNextProtocols();
+ if (!allowedProtos.isEmpty()) {
+ SecPkgContext_ApplicationProtocol alpn;
+ status = QueryContextAttributes(&contextHandle,
+ SECPKG_ATTR_APPLICATION_PROTOCOL,
+ &alpn);
+ CHECK_STATUS(status);
+ if (alpn.ProtoNegoStatus == SecApplicationProtocolNegotiationStatus_Success) {
+ QByteArray negotiatedProto = QByteArray((const char *)alpn.ProtocolId,
+ alpn.ProtocolIdSize);
+ if (!allowedProtos.contains(negotiatedProto)) {
+ setErrorAndEmit(d, QAbstractSocket::SslHandshakeFailedError,
+ QSslSocket::tr("Unwanted protocol was negotiated"));
+ return false;
+ }
+ QTlsBackend::setNegotiatedProtocol(d, negotiatedProto);
+ QTlsBackend::setAlpnStatus(d, QSslConfiguration::NextProtocolNegotiationNegotiated);
+ } else {
+ QTlsBackend::setNegotiatedProtocol(d, {});
+ QTlsBackend::setAlpnStatus(d, QSslConfiguration::NextProtocolNegotiationUnsupported);
+ }
+ }
+#endif // supports ALPN
+
+#undef CHECK_STATUS
+
+ // Verify certificate
+ CERT_CONTEXT *certificateContext = nullptr;
+ auto freeCertificate = qScopeGuard([&certificateContext]() {
+ if (certificateContext)
+ CertFreeCertificateContext(certificateContext);
+ });
+ status = QueryContextAttributes(&contextHandle,
+ SECPKG_ATTR_REMOTE_CERT_CONTEXT,
+ &certificateContext);
+
+ // QueryPeer can (currently) not work in Schannel since Schannel itself doesn't have a way to
+ // ask for a certificate and then still be OK if it's not received.
+ // To work around this we don't request a certificate at all for QueryPeer.
+ // For servers AutoVerifyPeer is supposed to be treated the same as QueryPeer.
+ // This means that servers using Schannel will only request client certificate for "VerifyPeer".
+ if ((!isClient && configuration.peerVerifyMode() == QSslSocket::PeerVerifyMode::VerifyPeer)
+ || (isClient && configuration.peerVerifyMode() != QSslSocket::PeerVerifyMode::VerifyNone
+ && configuration.peerVerifyMode() != QSslSocket::PeerVerifyMode::QueryPeer)) {
+ if (status != SEC_E_OK) {
+#ifdef QSSLSOCKET_DEBUG
+ qCDebug(lcTlsBackendSchannel) << "Couldn't retrieve peer certificate, status:"
+ << schannelErrorToString(status);
+#endif
+ const QSslError error{ QSslError::NoPeerCertificate };
+ sslErrors += error;
+ emit q->peerVerifyError(error);
+ if (q->state() != QAbstractSocket::ConnectedState)
+ return false;
+ }
+ }
+
+ // verifyCertContext returns false if the user disconnected while it was checking errors.
+ if (certificateContext && !verifyCertContext(certificateContext))
+ return false;
+
+ if (!checkSslErrors() || q->state() != QAbstractSocket::ConnectedState) {
+#ifdef QSSLSOCKET_DEBUG
+ 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;
+ }
+
+ schannelState = SchannelState::Done;
+ return true;
+}
+
+bool TlsCryptographSchannel::renegotiate()
+{
+ Q_ASSERT(d);
+
+ SecBuffer outBuffers[3];
+ outBuffers[0] = createSecBuffer(nullptr, 0, SECBUFFER_TOKEN);
+ outBuffers[1] = createSecBuffer(nullptr, 0, SECBUFFER_ALERT);
+ outBuffers[2] = createSecBuffer(nullptr, 0, SECBUFFER_EMPTY);
+ auto freeBuffers = qScopeGuard([&outBuffers]() {
+ for (auto i = 0ull; i < ARRAYSIZE(outBuffers); i++) {
+ if (outBuffers[i].pvBuffer)
+ FreeContextBuffer(outBuffers[i].pvBuffer);
+ }
+ });
+ SecBufferDesc outputBufferDesc{
+ SECBUFFER_VERSION,
+ ARRAYSIZE(outBuffers),
+ outBuffers
+ };
+
+ ULONG contextReq = getContextRequirements();
+ TimeStamp expiry;
+ SECURITY_STATUS status;
+ if (d->tlsMode() == QSslSocket::SslClientMode) {
+ status = InitializeSecurityContext(&credentialHandle, // phCredential
+ &contextHandle, // phContext
+ const_reinterpret_cast<SEC_WCHAR *>(targetName().utf16()), // pszTargetName
+ contextReq, // fContextReq
+ 0, // Reserved1
+ 0, // TargetDataRep (unused)
+ nullptr, // pInput (nullptr for renegotiate)
+ 0, // Reserved2
+ nullptr, // phNewContext (we already have one)
+ &outputBufferDesc, // pOutput
+ &contextAttributes, // pfContextAttr
+ &expiry // ptsExpiry
+ );
+ } else {
+ status = AcceptSecurityContext(
+ &credentialHandle, // phCredential
+ &contextHandle, // phContext
+ nullptr, // pInput
+ contextReq, // fContextReq
+ 0, // TargetDataRep (unused)
+ nullptr, // phNewContext
+ &outputBufferDesc, // pOutput
+ &contextAttributes, // pfContextAttr,
+ &expiry // ptsTimeStamp
+ );
+ }
+ if (status == SEC_I_CONTINUE_NEEDED) {
+ schannelState = SchannelState::PerformHandshake;
+ return sendToken(outBuffers[0].pvBuffer, outBuffers[0].cbBuffer);
+ } else if (status == SEC_E_OK) {
+ schannelState = SchannelState::PerformHandshake;
+ return true;
+ }
+ setErrorAndEmit(d, QAbstractSocket::SslHandshakeFailedError,
+ QSslSocket::tr("Renegotiation was unsuccessful: %1").arg(schannelErrorToString(status)));
+ return false;
+}
+
+/*!
+ \internal
+ reset the state in preparation for reuse of socket
+*/
+void TlsCryptographSchannel::reset()
+{
+ Q_ASSERT(d);
+
+ closeCertificateStores(); // certificate stores could've changed
+ deallocateContext();
+ freeCredentialsHandle(); // in case we already had one (@future: session resumption requires re-use)
+
+ cipherInfo = {};
+ connectionInfo = {};
+ streamSizes = {};
+
+ CertFreeCertificateContext(localCertContext);
+ localCertContext = nullptr;
+
+ contextAttributes = 0;
+ intermediateBuffer.clear();
+ schannelState = SchannelState::InitializeHandshake;
+
+
+ d->setEncrypted(false);
+ shutdown = false;
+ renegotiating = false;
+
+ missingData = 0;
+}
+
+void TlsCryptographSchannel::startClientEncryption()
+{
+ Q_ASSERT(q);
+
+ if (q->isEncrypted())
+ return; // let's not mess up the connection...
+ reset();
+ continueHandshake();
+}
+
+void TlsCryptographSchannel::startServerEncryption()
+{
+ Q_ASSERT(q);
+
+ if (q->isEncrypted())
+ return; // let's not mess up the connection...
+ reset();
+ continueHandshake();
+}
+
+void TlsCryptographSchannel::transmit()
+{
+ Q_ASSERT(q);
+ Q_ASSERT(d);
+ auto *plainSocket = d->plainTcpSocket();
+ Q_ASSERT(plainSocket);
+
+ if (d->tlsMode() == QSslSocket::UnencryptedMode)
+ return; // This function should not have been called
+
+ // Can happen if called through QSslSocket::abort->QSslSocket::close->QSslSocket::flush->here
+ if (plainSocket->state() == QAbstractSocket::UnconnectedState || !plainSocket->isValid()
+ || !plainSocket->isOpen()) {
+ return;
+ }
+
+ if (schannelState != SchannelState::Done) {
+ continueHandshake();
+ return;
+ }
+
+ auto &writeBuffer = d->tlsWriteBuffer();
+ auto &buffer = d->tlsBuffer();
+ if (q->isEncrypted()) { // encrypt data in writeBuffer and write it to plainSocket
+ qint64 totalBytesWritten = 0;
+ qint64 writeBufferSize;
+ while ((writeBufferSize = writeBuffer.size()) > 0) {
+ const int headerSize = int(streamSizes.cbHeader);
+ const int trailerSize = int(streamSizes.cbTrailer);
+ // Try to read 'cbMaximumMessage' bytes from buffer before encrypting.
+ const int size = int(std::min(writeBufferSize, qint64(streamSizes.cbMaximumMessage)));
+ QByteArray fullMessage(headerSize + trailerSize + size, Qt::Uninitialized);
+ {
+ // Use peek() here instead of read() so we don't lose data if encryption fails.
+ qint64 copied = writeBuffer.peek(fullMessage.data() + headerSize, size);
+ Q_ASSERT(copied == size);
+ }
+
+ SecBuffer inputBuffers[4]{
+ createSecBuffer(fullMessage.data(), headerSize, SECBUFFER_STREAM_HEADER),
+ createSecBuffer(fullMessage.data() + headerSize, size, SECBUFFER_DATA),
+ createSecBuffer(fullMessage.data() + headerSize + size, trailerSize, SECBUFFER_STREAM_TRAILER),
+ createSecBuffer(nullptr, 0, SECBUFFER_EMPTY)
+ };
+ SecBufferDesc message{
+ SECBUFFER_VERSION,
+ ARRAYSIZE(inputBuffers),
+ inputBuffers
+ };
+ auto status = EncryptMessage(&contextHandle, 0, &message, 0);
+ if (status != SEC_E_OK) {
+ setErrorAndEmit(d, QAbstractSocket::SslInternalError,
+ QSslSocket::tr("Schannel failed to encrypt data: %1")
+ .arg(schannelErrorToString(status)));
+ return;
+ }
+ // Data was encrypted successfully, so we free() what we peek()ed earlier
+ writeBuffer.free(size);
+
+ // The trailer's size is not final, so resize fullMessage to not send trailing junk
+ fullMessage.resize(inputBuffers[0].cbBuffer + inputBuffers[1].cbBuffer + inputBuffers[2].cbBuffer);
+ const qint64 bytesWritten = plainSocket->write(fullMessage);
+#ifdef QSSLSOCKET_DEBUG
+ qCDebug(lcTlsBackendSchannel, "Wrote %lld of total %d bytes", bytesWritten,
+ fullMessage.length());
+#endif
+ if (bytesWritten >= 0) {
+ totalBytesWritten += bytesWritten;
+ } else {
+ setErrorAndEmit(d, plainSocket->error(), plainSocket->errorString());
+ return;
+ }
+ }
+
+ if (totalBytesWritten > 0) {
+ // Don't emit bytesWritten() recursively.
+ bool &emittedBytesWritten = d->tlsEmittedBytesWritten();
+ if (!emittedBytesWritten) {
+ emittedBytesWritten = true;
+ emit q->bytesWritten(totalBytesWritten);
+ emittedBytesWritten = false;
+ }
+ emit q->channelBytesWritten(0, totalBytesWritten);
+ }
+ }
+
+ int totalRead = 0;
+ bool hadIncompleteData = false;
+ const auto readBufferMaxSize = d->maxReadBufferSize();
+ while (!readBufferMaxSize || buffer.size() < readBufferMaxSize) {
+ if (missingData > plainSocket->bytesAvailable()
+ && (!readBufferMaxSize || readBufferMaxSize >= missingData)) {
+#ifdef QSSLSOCKET_DEBUG
+ qCDebug(lcTlsBackendSchannel, "We're still missing %lld bytes, will check later.",
+ missingData);
+#endif
+ break;
+ }
+
+ missingData = 0;
+ const qint64 bytesRead = readToBuffer(intermediateBuffer, plainSocket);
+#ifdef QSSLSOCKET_DEBUG
+ qCDebug(lcTlsBackendSchannel, "Read %lld encrypted bytes from the socket", bytesRead);
+#endif
+ if (intermediateBuffer.length() == 0 || (hadIncompleteData && bytesRead == 0)) {
+#ifdef QSSLSOCKET_DEBUG
+ qCDebug(lcTlsBackendSchannel,
+ hadIncompleteData ? "No new data received, leaving loop!"
+ : "Nothing to decrypt, leaving loop!");
+#endif
+ break;
+ }
+ hadIncompleteData = false;
+#ifdef QSSLSOCKET_DEBUG
+ qCDebug(lcTlsBackendSchannel, "Total amount of bytes to decrypt: %d",
+ intermediateBuffer.length());
+#endif
+
+ SecBuffer dataBuffer[4]{
+ createSecBuffer(intermediateBuffer, SECBUFFER_DATA),
+ createSecBuffer(nullptr, 0, SECBUFFER_EMPTY),
+ createSecBuffer(nullptr, 0, SECBUFFER_EMPTY),
+ createSecBuffer(nullptr, 0, SECBUFFER_EMPTY)
+ };
+ SecBufferDesc message{
+ SECBUFFER_VERSION,
+ ARRAYSIZE(dataBuffer),
+ dataBuffer
+ };
+ auto status = DecryptMessage(&contextHandle, &message, 0, nullptr);
+ if (status == SEC_E_OK || status == SEC_I_RENEGOTIATE || status == SEC_I_CONTEXT_EXPIRED) {
+ // There can still be 0 output even if it succeeds, this is fine
+ if (dataBuffer[1].cbBuffer > 0) {
+ // It is always decrypted in-place.
+ // But [0] is the STREAM_HEADER, [1] is the DATA and [2] is the STREAM_TRAILER.
+ // The pointers in all of those still point into 'intermediateBuffer'.
+ buffer.append(static_cast<char *>(dataBuffer[1].pvBuffer),
+ dataBuffer[1].cbBuffer);
+ totalRead += dataBuffer[1].cbBuffer;
+#ifdef QSSLSOCKET_DEBUG
+ qCDebug(lcTlsBackendSchannel, "Decrypted %lu bytes. New read buffer size: %d",
+ dataBuffer[1].cbBuffer, buffer.size());
+#endif
+ }
+ if (dataBuffer[3].BufferType == SECBUFFER_EXTRA) {
+ // https://docs.microsoft.com/en-us/windows/desktop/secauthn/extra-buffers-returned-by-schannel
+ // dataBuffer[3].cbBuffer indicates the amount of bytes _NOT_ processed,
+ // the rest need to be stored.
+ retainExtraData(intermediateBuffer, dataBuffer[3]);
+ } else {
+ intermediateBuffer.resize(0);
+ }
+ }
+
+ if (status == SEC_E_INCOMPLETE_MESSAGE) {
+ missingData = checkIncompleteData(dataBuffer[0]);
+#ifdef QSSLSOCKET_DEBUG
+ 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(lcTlsBackendSchannel, "The internal SSPI handle is invalid!");
+ Q_UNREACHABLE();
+ } else if (status == SEC_E_INVALID_TOKEN) {
+ // Supposedly we have an invalid token, it's under-documented what
+ // this means, so to be safe we disconnect.
+ shutdown = true;
+ disconnectFromHost();
+ setErrorAndEmit(d, QAbstractSocket::SslInternalError, schannelErrorToString(status));
+ break;
+ } else if (status == SEC_E_MESSAGE_ALTERED) {
+ // The message has been altered, disconnect now.
+ shutdown = true; // skips sending the shutdown alert
+ disconnectFromHost();
+ setErrorAndEmit(d, QAbstractSocket::SslInternalError,
+ schannelErrorToString(status));
+ break;
+ } else if (status == SEC_E_OUT_OF_SEQUENCE) {
+ // @todo: I don't know if this one is actually "fatal"..
+ // This path might never be hit as it seems this is for connection-oriented connections,
+ // while SEC_E_MESSAGE_ALTERED is for stream-oriented ones (what we use).
+ shutdown = true; // skips sending the shutdown alert
+ disconnectFromHost();
+ setErrorAndEmit(d, QAbstractSocket::SslInternalError,
+ schannelErrorToString(status));
+ break;
+ } else if (status == SEC_I_CONTEXT_EXPIRED) {
+ // 'remote' has initiated a shutdown
+ disconnectFromHost();
+ break;
+ } else if (status == SEC_I_RENEGOTIATE) {
+ // 'remote' wants to renegotiate
+#ifdef QSSLSOCKET_DEBUG
+ qCDebug(lcTlsBackendSchannel, "The peer wants to renegotiate.");
+#endif
+ schannelState = SchannelState::Renegotiate;
+ renegotiating = true;
+
+ // We need to call 'continueHandshake' or else there's no guarantee it ever gets called
+ continueHandshake();
+ break;
+ }
+ }
+
+ if (totalRead) {
+ if (bool *readyReadEmittedPointer = d->readyReadPointer())
+ *readyReadEmittedPointer = true;
+ emit q->readyRead();
+ emit q->channelReadyRead(0);
+ }
+}
+
+void TlsCryptographSchannel::sendShutdown()
+{
+ Q_ASSERT(d);
+
+ const bool isClient = d->tlsMode() == QSslSocket::SslClientMode;
+ DWORD shutdownToken = SCHANNEL_SHUTDOWN;
+ SecBuffer buffer = createSecBuffer(&shutdownToken, sizeof(DWORD), SECBUFFER_TOKEN);
+ SecBufferDesc token{
+ SECBUFFER_VERSION,
+ 1,
+ &buffer
+ };
+ auto status = ApplyControlToken(&contextHandle, &token);
+
+ if (status != SEC_E_OK) {
+#ifdef QSSLSOCKET_DEBUG
+ qCDebug(lcTlsBackendSchannel)
+ << "Failed to apply shutdown control token:" << schannelErrorToString(status);
+#endif
+ return;
+ }
+
+ SecBuffer outBuffers[3];
+ outBuffers[0] = createSecBuffer(nullptr, 0, SECBUFFER_TOKEN);
+ outBuffers[1] = createSecBuffer(nullptr, 0, SECBUFFER_ALERT);
+ outBuffers[2] = createSecBuffer(nullptr, 0, SECBUFFER_EMPTY);
+ auto freeBuffers = qScopeGuard([&outBuffers]() {
+ for (auto i = 0ull; i < ARRAYSIZE(outBuffers); i++) {
+ if (outBuffers[i].pvBuffer)
+ FreeContextBuffer(outBuffers[i].pvBuffer);
+ }
+ });
+ SecBufferDesc outputBufferDesc{
+ SECBUFFER_VERSION,
+ ARRAYSIZE(outBuffers),
+ outBuffers
+ };
+
+ ULONG contextReq = getContextRequirements();
+ TimeStamp expiry;
+ if (isClient) {
+ status = InitializeSecurityContext(&credentialHandle, // phCredential
+ &contextHandle, // phContext
+ const_reinterpret_cast<SEC_WCHAR *>(targetName().utf16()), // pszTargetName
+ contextReq, // fContextReq
+ 0, // Reserved1
+ 0, // TargetDataRep (unused)
+ nullptr, // pInput
+ 0, // Reserved2
+ nullptr, // phNewContext (we already have one)
+ &outputBufferDesc, // pOutput
+ &contextAttributes, // pfContextAttr
+ &expiry // ptsExpiry
+ );
+ } else {
+ status = AcceptSecurityContext(
+ &credentialHandle, // phCredential
+ &contextHandle, // phContext
+ nullptr, // pInput
+ contextReq, // fContextReq
+ 0, // TargetDataRep (unused)
+ nullptr, // phNewContext
+ &outputBufferDesc, // pOutput
+ &contextAttributes, // pfContextAttr,
+ &expiry // ptsTimeStamp
+ );
+ }
+ if (status == SEC_E_OK || status == SEC_I_CONTEXT_EXPIRED) {
+ if (!sendToken(outBuffers[0].pvBuffer, outBuffers[0].cbBuffer, false)) {
+ // We failed to send the shutdown message, but it's not that important since we're
+ // shutting down anyway.
+ return;
+ }
+ } else {
+#ifdef QSSLSOCKET_DEBUG
+ qCDebug(lcTlsBackendSchannel)
+ << "Failed to initialize shutdown:" << schannelErrorToString(status);
+#endif
+ }
+}
+
+void TlsCryptographSchannel::disconnectFromHost()
+{
+ Q_ASSERT(q);
+ Q_ASSERT(d);
+ auto *plainSocket = d->plainTcpSocket();
+ Q_ASSERT(plainSocket);
+
+ if (SecIsValidHandle(&contextHandle)) {
+ if (!shutdown) {
+ shutdown = true;
+ if (plainSocket->state() != QAbstractSocket::UnconnectedState && q->isEncrypted()) {
+ sendShutdown();
+ transmit();
+ }
+ }
+ }
+ plainSocket->disconnectFromHost();
+}
+
+void TlsCryptographSchannel::disconnected()
+{
+ Q_ASSERT(d);
+ auto *plainSocket = d->plainTcpSocket();
+ Q_ASSERT(plainSocket);
+ d->setEncrypted(false);
+
+ shutdown = true;
+ if (plainSocket->bytesAvailable() > 0 || hasUndecryptedData()) {
+ // Read as much as possible because this is likely our last chance
+ qint64 tempMax = d->maxReadBufferSize();
+ d->setMaxReadBufferSize(0); // Unlimited
+ transmit();
+ d->setMaxReadBufferSize(tempMax);
+ // Since there were bytes still available we don't want to deallocate
+ // our context yet. It will happen later, when the socket is re-used or
+ // destroyed.
+ } else {
+ deallocateContext();
+ freeCredentialsHandle();
+ }
+}
+
+QSslCipher TlsCryptographSchannel::sessionCipher() const
+{
+ Q_ASSERT(q);
+
+ if (!q->isEncrypted())
+ return {};
+
+ const auto sessionProtocol = toQtSslProtocol(connectionInfo.dwProtocol);
+
+ const auto ciphers = ciphersByName(QStringView(cipherInfo.szCipherSuite));
+ for (const auto& cipher : ciphers) {
+ if (cipher.protocol() == sessionProtocol)
+ return cipher;
+ }
+
+ return {};
+}
+
+QSsl::SslProtocol TlsCryptographSchannel::sessionProtocol() const
+{
+ if (!q->isEncrypted())
+ return QSsl::SslProtocol::UnknownProtocol;
+ return toQtSslProtocol(connectionInfo.dwProtocol);
+}
+
+void TlsCryptographSchannel::continueHandshake()
+{
+ Q_ASSERT(q);
+ Q_ASSERT(d);
+ auto *plainSocket = d->plainTcpSocket();
+ Q_ASSERT(plainSocket);
+
+ const bool isServer = d->tlsMode() == QSslSocket::SslServerMode;
+ switch (schannelState) {
+ case SchannelState::InitializeHandshake:
+ if (!SecIsValidHandle(&credentialHandle) && !acquireCredentialsHandle()) {
+ disconnectFromHost();
+ return;
+ }
+ if (!SecIsValidHandle(&credentialHandle)) // Needed to support tst_QSslSocket::setEmptyKey
+ return;
+ if (!SecIsValidHandle(&contextHandle) && !(isServer ? acceptContext() : createContext())) {
+ disconnectFromHost();
+ return;
+ }
+ if (schannelState != SchannelState::PerformHandshake)
+ break;
+ Q_FALLTHROUGH();
+ case SchannelState::PerformHandshake:
+ if (!performHandshake()) {
+ disconnectFromHost();
+ return;
+ }
+ if (schannelState != SchannelState::VerifyHandshake)
+ break;
+ Q_FALLTHROUGH();
+ case SchannelState::VerifyHandshake:
+ // if we're in shutdown or renegotiating then we might not need to verify
+ // (since we already did)
+ if (!verifyHandshake()) {
+ shutdown = true; // Skip sending shutdown alert
+ q->abort(); // We don't want to send buffered data
+ disconnectFromHost();
+ return;
+ }
+ if (schannelState != SchannelState::Done)
+ break;
+ Q_FALLTHROUGH();
+ case SchannelState::Done:
+ // connectionEncrypted is already true if we come here from a renegotiation
+ if (!q->isEncrypted()) {
+ d->setEncrypted(true); // all is done
+ emit q->encrypted();
+ }
+ renegotiating = false;
+ if (d->isPendingClose()) {
+ d->setPendingClose(false);
+ disconnectFromHost();
+ } else {
+ transmit();
+ }
+ break;
+ case SchannelState::Renegotiate:
+ if (!renegotiate()) {
+ disconnectFromHost();
+ return;
+ } else if (intermediateBuffer.size() || plainSocket->bytesAvailable()) {
+ continueHandshake();
+ }
+ break;
+ }
+}
+
+QList<QSslError> TlsCryptographSchannel::tlsErrors() const
+{
+ return sslErrors;
+}
+
+/*
+ Copied from qsslsocket_mac.cpp, which was copied from qsslsocket_openssl.cpp
+*/
+bool TlsCryptographSchannel::checkSslErrors()
+{
+ if (sslErrors.isEmpty())
+ return true;
+
+ Q_ASSERT(q);
+ Q_ASSERT(d);
+ const auto &configuration = q->sslConfiguration();
+ auto *plainSocket = d->plainTcpSocket();
+
+ emit q->sslErrors(sslErrors);
+
+ const bool doVerifyPeer = configuration.peerVerifyMode() == QSslSocket::VerifyPeer
+ || (configuration.peerVerifyMode() == QSslSocket::AutoVerifyPeer
+ && d->tlsMode() == QSslSocket::SslClientMode);
+ const bool doEmitSslError = !d->verifyErrorsHaveBeenIgnored();
+ // check whether we need to emit an SSL handshake error
+ if (doVerifyPeer && doEmitSslError) {
+ if (q->pauseMode() & QAbstractSocket::PauseOnSslErrors) {
+ QSslSocketPrivate::pauseSocketNotifiers(q);
+ d->setPaused(true);
+ } else {
+ setErrorAndEmit(d, QAbstractSocket::SslHandshakeFailedError,
+ sslErrors.constFirst().errorString());
+ plainSocket->disconnectFromHost();
+ }
+ return false;
+ }
+
+ return true;
+}
+
+void TlsCryptographSchannel::initializeCertificateStores()
+{
+ //// helper function which turns a chain into a certificate store
+ Q_ASSERT(d);
+ Q_ASSERT(q);
+ const auto &configuration = q->sslConfiguration();
+
+ auto createStoreFromCertificateChain = [](const QList<QSslCertificate> certChain, const QSslKey &privateKey) {
+ const wchar_t *passphrase = L"";
+ // Need to embed the private key in the certificate
+ QByteArray pkcs12 = _q_makePkcs12(certChain,
+ privateKey,
+ QString::fromWCharArray(passphrase, 0));
+ CRYPT_DATA_BLOB pfxBlob;
+ pfxBlob.cbData = DWORD(pkcs12.length());
+ pfxBlob.pbData = reinterpret_cast<unsigned char *>(pkcs12.data());
+ return QHCertStorePointer(PFXImportCertStore(&pfxBlob, passphrase, 0));
+ };
+
+ if (!configuration.localCertificateChain().isEmpty()) {
+ if (configuration.privateKey().isNull()) {
+ setErrorAndEmit(d, QAbstractSocket::SslInvalidUserDataError,
+ QSslSocket::tr("Cannot provide a certificate with no key"));
+ return;
+ }
+ if (localCertificateStore == nullptr) {
+ localCertificateStore = createStoreFromCertificateChain(configuration.localCertificateChain(),
+ configuration.privateKey());
+ if (localCertificateStore == nullptr)
+ qCWarning(lcTlsBackendSchannel, "Failed to load certificate chain!");
+ }
+ }
+
+ if (!configuration.caCertificates().isEmpty() && !caCertificateStore) {
+ caCertificateStore = createStoreFromCertificateChain(configuration.caCertificates(),
+ {}); // No private key for the CA certs
+ }
+}
+
+bool TlsCryptographSchannel::verifyCertContext(CERT_CONTEXT *certContext)
+{
+ Q_ASSERT(certContext);
+ Q_ASSERT(q);
+ Q_ASSERT(d);
+
+ const bool isClient = d->tlsMode() == QSslSocket::SslClientMode;
+
+ // Create a collection of stores so we can pass in multiple stores as additional locations to
+ // search for the certificate chain
+ auto tempCertCollection = QHCertStorePointer(CertOpenStore(CERT_STORE_PROV_COLLECTION,
+ X509_ASN_ENCODING,
+ 0,
+ CERT_STORE_CREATE_NEW_FLAG,
+ nullptr));
+ if (!tempCertCollection) {
+#ifdef QSSLSOCKET_DEBUG
+ qCWarning(lcTlsBackendSchannel, "Failed to create certificate store collection!");
+#endif
+ return false;
+ }
+
+ if (rootCertOnDemandLoadingAllowed()) {
+ // @future(maybe): following the OpenSSL backend these certificates should be added into
+ // the Ca list, not just included during verification.
+ // That being said, it's not trivial to add the root certificates (if and only if they
+ // came from the system root store). And I don't see this mentioned in our documentation.
+ auto rootStore = QHCertStorePointer(
+ CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0,
+ CERT_STORE_READONLY_FLAG | CERT_SYSTEM_STORE_CURRENT_USER, L"ROOT"));
+
+ if (!rootStore) {
+#ifdef QSSLSOCKET_DEBUG
+ 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(lcTlsBackendSchannel,
+ "Failed to add the system root CA certificate store to the certificate store "
+ "collection!");
+#endif
+ return false;
+ }
+ }
+ if (caCertificateStore) {
+ if (!CertAddStoreToCollection(tempCertCollection.get(), caCertificateStore.get(), 0, 1)) {
+#ifdef QSSLSOCKET_DEBUG
+ qCWarning(lcTlsBackendSchannel,
+ "Failed to add the user's CA certificate store to the certificate store "
+ "collection!");
+#endif
+ return false;
+ }
+ }
+
+ if (!CertAddStoreToCollection(tempCertCollection.get(), certContext->hCertStore, 0, 0)) {
+#ifdef QSSLSOCKET_DEBUG
+ qCWarning(lcTlsBackendSchannel,
+ "Failed to add certificate's origin store to the certificate store collection!");
+#endif
+ return false;
+ }
+
+ CERT_CHAIN_PARA parameters;
+ ZeroMemory(&parameters, sizeof(parameters));
+ parameters.cbSize = sizeof(CERT_CHAIN_PARA);
+ parameters.RequestedUsage.dwType = USAGE_MATCH_TYPE_AND;
+ parameters.RequestedUsage.Usage.cUsageIdentifier = 1;
+ LPSTR oid = LPSTR(isClient ? szOID_PKIX_KP_SERVER_AUTH
+ : szOID_PKIX_KP_CLIENT_AUTH);
+ parameters.RequestedUsage.Usage.rgpszUsageIdentifier = &oid;
+
+ QTlsBackend::clearPeerCertificates(d);
+ const CERT_CHAIN_CONTEXT *chainContext = nullptr;
+ auto freeCertChain = qScopeGuard([&chainContext]() {
+ if (chainContext)
+ CertFreeCertificateChain(chainContext);
+ });
+ BOOL status = CertGetCertificateChain(nullptr, // hChainEngine, default
+ certContext, // pCertContext
+ nullptr, // pTime, 'now'
+ tempCertCollection.get(), // hAdditionalStore, additional cert store
+ &parameters, // pChainPara
+ CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT, // dwFlags
+ nullptr, // reserved
+ &chainContext // ppChainContext
+ );
+ if (status == FALSE || !chainContext || chainContext->cChain == 0) {
+ QSslError error(QSslError::UnableToVerifyFirstCertificate);
+ sslErrors += error;
+ emit q->peerVerifyError(error);
+ return q->state() == QAbstractSocket::ConnectedState;
+ }
+
+ // Helper-function to get a QSslCertificate given a CERT_CHAIN_ELEMENT
+ static auto getCertificateFromChainElement = [](CERT_CHAIN_ELEMENT *element) {
+ if (!element)
+ return QSslCertificate();
+
+ const CERT_CONTEXT *certContext = element->pCertContext;
+ return QTlsPrivate::X509CertificateSchannel::QSslCertificate_from_CERT_CONTEXT(certContext);
+ };
+
+ // Pick a chain to use as the certificate chain, if multiple are available:
+ // According to https://docs.microsoft.com/en-gb/windows/desktop/api/wincrypt/ns-wincrypt-_cert_chain_context
+ // this seems to be the best way to get a trusted chain.
+ CERT_SIMPLE_CHAIN *chain = chainContext->rgpChain[chainContext->cChain - 1];
+
+ if (chain->TrustStatus.dwErrorStatus & CERT_TRUST_IS_PARTIAL_CHAIN) {
+ auto error = QSslError(QSslError::SslError::UnableToGetIssuerCertificate,
+ getCertificateFromChainElement(chain->rgpElement[chain->cElement - 1]));
+ sslErrors += error;
+ emit q->peerVerifyError(error);
+ if (q->state() != QAbstractSocket::ConnectedState)
+ return false;
+ }
+ if (chain->TrustStatus.dwErrorStatus & CERT_TRUST_INVALID_BASIC_CONSTRAINTS) {
+ // @Note: This is actually one of two errors:
+ // "either the certificate cannot be used to issue other certificates, or the chain path length has been exceeded."
+ // But here we are checking the chain's status, so we assume the "issuing" error cannot occur here.
+ auto error = QSslError(QSslError::PathLengthExceeded);
+ sslErrors += error;
+ emit q->peerVerifyError(error);
+ if (q->state() != QAbstractSocket::ConnectedState)
+ return false;
+ }
+ static const DWORD leftoverCertChainErrorMask = CERT_TRUST_IS_CYCLIC | CERT_TRUST_INVALID_EXTENSION
+ | CERT_TRUST_INVALID_POLICY_CONSTRAINTS | CERT_TRUST_INVALID_NAME_CONSTRAINTS
+ | CERT_TRUST_CTL_IS_NOT_TIME_VALID | CERT_TRUST_CTL_IS_NOT_SIGNATURE_VALID
+ | CERT_TRUST_CTL_IS_NOT_VALID_FOR_USAGE;
+ if (chain->TrustStatus.dwErrorStatus & leftoverCertChainErrorMask) {
+ auto error = QSslError(QSslError::SslError::UnspecifiedError);
+ sslErrors += error;
+ emit q->peerVerifyError(error);
+ if (q->state() != QAbstractSocket::ConnectedState)
+ return false;
+ }
+
+ DWORD verifyDepth = chain->cElement;
+ if (q->peerVerifyDepth() > 0 && DWORD(q->peerVerifyDepth()) < verifyDepth)
+ verifyDepth = DWORD(q->peerVerifyDepth());
+
+ const auto &caCertificates = q->sslConfiguration().caCertificates();
+
+ if (!rootCertOnDemandLoadingAllowed()
+ && !(chain->TrustStatus.dwErrorStatus & CERT_TRUST_IS_PARTIAL_CHAIN)
+ && (q->peerVerifyMode() == QSslSocket::VerifyPeer
+ || (isClient && q->peerVerifyMode() == QSslSocket::AutoVerifyPeer))) {
+ // When verifying a peer Windows "helpfully" builds a chain that
+ // may include roots from the system store. But we don't want that if
+ // the user has set their own CA certificates.
+ // Since Windows claims this is not a partial chain the root is included
+ // and we have to check that it is one of our configured CAs.
+ CERT_CHAIN_ELEMENT *element = chain->rgpElement[chain->cElement - 1];
+ QSslCertificate certificate = getCertificateFromChainElement(element);
+ if (!caCertificates.contains(certificate)) {
+ auto error = QSslError(QSslError::CertificateUntrusted, certificate);
+ sslErrors += error;
+ emit q->peerVerifyError(error);
+ if (q->state() != QAbstractSocket::ConnectedState)
+ return false;
+ }
+ }
+
+ QList<QSslCertificate> peerCertificateChain;
+ for (DWORD i = 0; i < verifyDepth; i++) {
+ CERT_CHAIN_ELEMENT *element = chain->rgpElement[i];
+ QSslCertificate certificate = getCertificateFromChainElement(element);
+ if (certificate.isNull()) {
+ const auto &previousCert = !peerCertificateChain.isEmpty() ? peerCertificateChain.last()
+ : QSslCertificate();
+ auto error = QSslError(QSslError::SslError::UnableToGetIssuerCertificate, previousCert);
+ sslErrors += error;
+ emit q->peerVerifyError(error);
+ if (previousCert.isNull() || q->state() != QAbstractSocket::ConnectedState)
+ return false;
+ }
+ const QList<QSslCertificateExtension> extensions = certificate.extensions();
+
+#ifdef QSSLSOCKET_DEBUG
+ 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);
+ QTlsBackend::storePeerCertificateChain(d, peerCertificateChain);
+
+ if (certificate.isBlacklisted()) {
+ const auto error = QSslError(QSslError::CertificateBlacklisted, certificate);
+ sslErrors += error;
+ emit q->peerVerifyError(error);
+ if (q->state() != QAbstractSocket::ConnectedState)
+ return false;
+ }
+
+ LONG result = CertVerifyTimeValidity(nullptr /*== now */, element->pCertContext->pCertInfo);
+ if (result != 0) {
+ auto error = QSslError(result == -1 ? QSslError::CertificateNotYetValid
+ : QSslError::CertificateExpired,
+ certificate);
+ sslErrors += error;
+ emit q->peerVerifyError(error);
+ if (q->state() != QAbstractSocket::ConnectedState)
+ return false;
+ }
+
+ //// Errors
+ if (element->TrustStatus.dwErrorStatus & CERT_TRUST_IS_NOT_TIME_VALID) {
+ // handled right above
+ Q_ASSERT(!sslErrors.isEmpty());
+ }
+ if (element->TrustStatus.dwErrorStatus & CERT_TRUST_IS_REVOKED) {
+ auto error = QSslError(QSslError::CertificateRevoked, certificate);
+ sslErrors += error;
+ emit q->peerVerifyError(error);
+ if (q->state() != QAbstractSocket::ConnectedState)
+ return false;
+ }
+ if (element->TrustStatus.dwErrorStatus & CERT_TRUST_IS_NOT_SIGNATURE_VALID) {
+ auto error = QSslError(QSslError::CertificateSignatureFailed, certificate);
+ sslErrors += error;
+ emit q->peerVerifyError(error);
+ if (q->state() != QAbstractSocket::ConnectedState)
+ return false;
+ }
+
+ // While netscape shouldn't be relevant now it defined an extension which is
+ // still in use. Schannel does not check this automatically, so we do it here.
+ // It is used to differentiate between client and server certificates.
+ if (netscapeWrongCertType(extensions, isClient))
+ element->TrustStatus.dwErrorStatus |= CERT_TRUST_IS_NOT_VALID_FOR_USAGE;
+
+ if (element->TrustStatus.dwErrorStatus & CERT_TRUST_IS_NOT_VALID_FOR_USAGE) {
+ auto error = QSslError(QSslError::InvalidPurpose, certificate);
+ sslErrors += error;
+ emit q->peerVerifyError(error);
+ if (q->state() != QAbstractSocket::ConnectedState)
+ return false;
+ }
+ if (element->TrustStatus.dwErrorStatus & CERT_TRUST_IS_UNTRUSTED_ROOT) {
+ // Override this error if we have the certificate inside our trusted CAs list.
+ const bool isTrustedRoot = caCertificates.contains(certificate);
+ if (!isTrustedRoot) {
+ auto error = QSslError(QSslError::CertificateUntrusted, certificate);
+ sslErrors += error;
+ emit q->peerVerifyError(error);
+ if (q->state() != QAbstractSocket::ConnectedState)
+ return false;
+ }
+ }
+ static const DWORD certRevocationCheckUnavailableError = CERT_TRUST_IS_OFFLINE_REVOCATION
+ | CERT_TRUST_REVOCATION_STATUS_UNKNOWN;
+ if (element->TrustStatus.dwErrorStatus & certRevocationCheckUnavailableError) {
+ // @future(maybe): Do something with this
+ }
+
+ // Dumping ground of errors that don't fit our specific errors
+ static const DWORD leftoverCertErrorMask = CERT_TRUST_IS_CYCLIC
+ | CERT_TRUST_INVALID_EXTENSION | CERT_TRUST_INVALID_NAME_CONSTRAINTS
+ | CERT_TRUST_INVALID_POLICY_CONSTRAINTS
+ | CERT_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT
+ | CERT_TRUST_HAS_NOT_SUPPORTED_CRITICAL_EXT
+ | CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT
+ | CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT
+ | CERT_TRUST_HAS_NOT_SUPPORTED_NAME_CONSTRAINT;
+ if (element->TrustStatus.dwErrorStatus & leftoverCertErrorMask) {
+ auto error = QSslError(QSslError::UnspecifiedError, certificate);
+ sslErrors += error;
+ emit q->peerVerifyError(error);
+ if (q->state() != QAbstractSocket::ConnectedState)
+ return false;
+ }
+ if (element->TrustStatus.dwErrorStatus & CERT_TRUST_INVALID_BASIC_CONSTRAINTS) {
+ auto it = std::find_if(extensions.cbegin(), extensions.cend(),
+ [](const QSslCertificateExtension &extension) {
+ return extension.name() == "basicConstraints"_L1;
+ });
+ if (it != extensions.cend()) {
+ // @Note: This is actually one of two errors:
+ // "either the certificate cannot be used to issue other certificates,
+ // or the chain path length has been exceeded."
+ QVariantMap basicConstraints = it->value().toMap();
+ QSslError error;
+ if (i > 0 && !basicConstraints.value("ca"_L1, false).toBool())
+ error = QSslError(QSslError::InvalidPurpose, certificate);
+ else
+ error = QSslError(QSslError::PathLengthExceeded, certificate);
+ sslErrors += error;
+ emit q->peerVerifyError(error);
+ if (q->state() != QAbstractSocket::ConnectedState)
+ return false;
+ }
+ }
+ if (element->TrustStatus.dwErrorStatus & CERT_TRUST_IS_EXPLICIT_DISTRUST) {
+ auto error = QSslError(QSslError::CertificateBlacklisted, certificate);
+ sslErrors += error;
+ emit q->peerVerifyError(error);
+ if (q->state() != QAbstractSocket::ConnectedState)
+ return false;
+ }
+
+ if (element->TrustStatus.dwInfoStatus & CERT_TRUST_IS_SELF_SIGNED) {
+ // If it's self-signed *and* a CA then we can assume it's a root CA certificate
+ // and we can ignore the "self-signed" note:
+ // We check the basicConstraints certificate extension when possible, but this didn't
+ // exist for version 1, so we can only guess in that case
+ const bool isRootCertificateAuthority = isCertificateAuthority(extensions)
+ || certificate.version() == "1";
+
+ // Root certificate tends to be signed by themselves, so ignore self-signed status.
+ if (!isRootCertificateAuthority) {
+ auto error = QSslError(QSslError::SelfSignedCertificate, certificate);
+ sslErrors += error;
+ emit q->peerVerifyError(error);
+ if (q->state() != QAbstractSocket::ConnectedState)
+ return false;
+ }
+ }
+ }
+
+ if (!peerCertificateChain.isEmpty())
+ QTlsBackend::storePeerCertificate(d, peerCertificateChain.constFirst());
+
+ const auto &configuration = q->sslConfiguration(); // Probably, updated by QTlsBackend::storePeerCertificate etc.
+ // @Note: Somewhat copied from qsslsocket_mac.cpp
+ const bool doVerifyPeer = q->peerVerifyMode() == QSslSocket::VerifyPeer
+ || (q->peerVerifyMode() == QSslSocket::AutoVerifyPeer
+ && d->tlsMode() == QSslSocket::SslClientMode);
+ // Check the peer certificate itself. First try the subject's common name
+ // (CN) as a wildcard, then try all alternate subject name DNS entries the
+ // same way.
+ if (!configuration.peerCertificate().isNull()) {
+ // but only if we're a client connecting to a server
+ // if we're the server, don't check CN
+ if (d->tlsMode() == QSslSocket::SslClientMode) {
+ const auto verificationPeerName = d->verificationName();
+ const QString peerName(verificationPeerName.isEmpty() ? q->peerName() : verificationPeerName);
+ if (!isMatchingHostname(configuration.peerCertificate(), peerName)) {
+ // No matches in common names or alternate names.
+ const QSslError error(QSslError::HostNameMismatch, configuration.peerCertificate());
+ sslErrors += error;
+ emit q->peerVerifyError(error);
+ if (q->state() != QAbstractSocket::ConnectedState)
+ return false;
+ }
+ }
+ } else if (doVerifyPeer) {
+ // No peer certificate presented. Report as error if the socket
+ // expected one.
+ const QSslError error(QSslError::NoPeerCertificate);
+ sslErrors += error;
+ emit q->peerVerifyError(error);
+ if (q->state() != QAbstractSocket::ConnectedState)
+ return false;
+ }
+
+ return true;
+}
+
+bool TlsCryptographSchannel::rootCertOnDemandLoadingAllowed()
+{
+ Q_ASSERT(d);
+ return d->isRootsOnDemandAllowed() && QSslSocketPrivate::rootCertOnDemandLoadingSupported();
+}
+
+} // namespace QTlsPrivate
+
+QT_END_NAMESPACE
diff --git a/src/plugins/tls/schannel/qtls_schannel_p.h b/src/plugins/tls/schannel/qtls_schannel_p.h
new file mode 100644
index 0000000000..fab8777249
--- /dev/null
+++ b/src/plugins/tls/schannel/qtls_schannel_p.h
@@ -0,0 +1,123 @@
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QTLS_SCHANNEL_P_H
+#define QTLS_SCHANNEL_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 <QtNetwork/private/qtnetworkglobal_p.h>
+
+QT_REQUIRE_CONFIG(schannel);
+
+#include "../shared/qwincrypt_p.h"
+
+#include "qtlsbackend_schannel_p.h"
+
+#include <QtNetwork/private/qsslsocket_p.h>
+
+#define SECURITY_WIN32
+#define SCHANNEL_USE_BLACKLISTS 1
+#include <winternl.h> // needed for UNICODE defines
+#include <security.h>
+#include <schnlsp.h>
+#undef SCHANNEL_USE_BLACKLISTS
+#undef SECURITY_WIN32
+
+QT_BEGIN_NAMESPACE
+
+namespace QTlsPrivate {
+
+class TlsCryptographSchannel final : public TlsCryptograph
+{
+ Q_DISABLE_COPY_MOVE(TlsCryptographSchannel)
+public:
+ TlsCryptographSchannel();
+ ~TlsCryptographSchannel();
+
+ void init(QSslSocket *q, QSslSocketPrivate *d) override;
+
+ void startClientEncryption() override;
+ void startServerEncryption() override;
+ void transmit() override;
+ void disconnectFromHost() override;
+ void disconnected() override;
+ QSslCipher sessionCipher() const override;
+ QSsl::SslProtocol sessionProtocol() const override;
+ void continueHandshake() override;
+ QList<QSslError> tlsErrors() const override;
+
+private:
+ enum class SchannelState {
+ InitializeHandshake, // create and transmit context (client)/accept context (server)
+ PerformHandshake, // get token back, process it
+ VerifyHandshake, // Verify that things are OK
+ Done, // Connection encrypted!
+ Renegotiate // Renegotiating!
+ } schannelState = SchannelState::InitializeHandshake;
+
+ void reset();
+ bool acquireCredentialsHandle();
+ ULONG getContextRequirements();
+ bool createContext(); // for clients
+ bool acceptContext(); // for server
+ bool performHandshake();
+ bool verifyHandshake();
+ bool renegotiate();
+
+ bool sendToken(void *token, unsigned long tokenLength, bool emitError = true);
+ QString targetName() const;
+
+ bool checkSslErrors();
+ void deallocateContext();
+ void freeCredentialsHandle();
+ void closeCertificateStores();
+ void sendShutdown();
+
+ void initializeCertificateStores();
+ bool verifyCertContext(CERT_CONTEXT *certContext);
+
+ bool rootCertOnDemandLoadingAllowed();
+
+ bool hasUndecryptedData() const override { return intermediateBuffer.size() > 0; }
+
+ QSslSocket *q = nullptr;
+ QSslSocketPrivate *d = nullptr;
+
+ SecPkgContext_CipherInfo cipherInfo = {};
+ SecPkgContext_ConnectionInfo connectionInfo = {};
+ SecPkgContext_StreamSizes streamSizes = {};
+
+ CredHandle credentialHandle; // Initialized in ctor
+ CtxtHandle contextHandle; // Initialized in ctor
+
+ QByteArray intermediateBuffer; // data which is left-over or incomplete
+
+ QHCertStorePointer localCertificateStore = nullptr;
+ QHCertStorePointer peerCertificateStore = nullptr;
+ QHCertStorePointer caCertificateStore = nullptr;
+
+ const CERT_CONTEXT *localCertContext = nullptr;
+
+ ULONG contextAttributes = 0;
+ qint64 missingData = 0;
+
+ bool renegotiating = false;
+ bool shutdown = false;
+ QList<QSslError> sslErrors;
+};
+
+} // namespace QTlsPrivate
+
+QT_END_NAMESPACE
+
+#endif // QTLS_SCHANNEL_P_H
diff --git a/src/plugins/tls/schannel/qtlsbackend_schannel_p.h b/src/plugins/tls/schannel/qtlsbackend_schannel_p.h
new file mode 100644
index 0000000000..7c2d675e79
--- /dev/null
+++ b/src/plugins/tls/schannel/qtlsbackend_schannel_p.h
@@ -0,0 +1,71 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QTLSBACKEND_ST_P_H
+#define QTLSBACKEND_ST_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 <private/qtnetworkglobal_p.h>
+
+#include <QtNetwork/private/qtlsbackend_p.h>
+
+#include <QtCore/qglobal.h>
+
+
+QT_BEGIN_NAMESPACE
+
+class QSchannelBackend : public QTlsBackend
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID QTlsBackend_iid)
+ Q_INTERFACES(QTlsBackend)
+
+public:
+ static void ensureInitializedImplementation();
+
+private:
+ long tlsLibraryVersionNumber() const override;
+ QString tlsLibraryVersionString() const override;
+ long tlsLibraryBuildVersionNumber() const override;
+ QString tlsLibraryBuildVersionString() const override;
+ void ensureInitialized() const override;
+
+ static void resetDefaultCiphers();
+
+ QString backendName() const override;
+ QList<QSsl::SslProtocol> supportedProtocols() const override;
+ QList<QSsl::SupportedFeature> supportedFeatures() const override;
+ QList<QSsl::ImplementedClass> implementedClasses() const override;
+
+ QTlsPrivate::TlsKey *createKey() const override;
+ QTlsPrivate::X509Certificate *createCertificate() const override;
+
+ QTlsPrivate::TlsCryptograph * createTlsCryptograph() const override;
+
+ QList<QSslCertificate> systemCaCertificates() const override;
+ static QList<QSslCertificate> systemCaCertificatesImplementation();
+
+ QTlsPrivate::X509PemReaderPtr X509PemReader() const override;
+ QTlsPrivate::X509DerReaderPtr X509DerReader() const override;
+ QTlsPrivate::X509Pkcs12ReaderPtr X509Pkcs12Reader() const override;
+
+ 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
new file mode 100644
index 0000000000..eb0a2371ab
--- /dev/null
+++ b/src/plugins/tls/schannel/qtlskey_schannel.cpp
@@ -0,0 +1,157 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <QtNetwork/private/qssl_p.h>
+
+#include "qtlsbackend_schannel_p.h"
+#include "qtlskey_schannel_p.h"
+
+#include "../shared/qwincrypt_p.h"
+
+#include <QtNetwork/private/qtlsbackend_p.h>
+#include <QtNetwork/private/qsslkey_p.h>
+
+#include <QtNetwork/qsslkey.h>
+
+#include <QtCore/qscopeguard.h>
+#include <QtCore/qbytearray.h>
+#include <QtCore/qvarlengtharray.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace {
+const wchar_t *getName(QSslKeyPrivate::Cipher cipher)
+{
+ switch (cipher) {
+ case QTlsPrivate::Cipher::DesCbc:
+ return BCRYPT_DES_ALGORITHM;
+ case QTlsPrivate::Cipher::DesEde3Cbc:
+ return BCRYPT_3DES_ALGORITHM;
+ case QTlsPrivate::Cipher::Rc2Cbc:
+ return BCRYPT_RC2_ALGORITHM;
+ case QTlsPrivate::Cipher::Aes128Cbc:
+ case QTlsPrivate::Cipher::Aes192Cbc:
+ case QTlsPrivate::Cipher::Aes256Cbc:
+ return BCRYPT_AES_ALGORITHM;
+ }
+ Q_UNREACHABLE();
+}
+
+BCRYPT_ALG_HANDLE getHandle(QSslKeyPrivate::Cipher cipher)
+{
+ BCRYPT_ALG_HANDLE handle;
+ NTSTATUS status = BCryptOpenAlgorithmProvider(
+ &handle, // phAlgorithm
+ getName(cipher), // pszAlgId
+ nullptr, // pszImplementation
+ 0 // dwFlags
+ );
+ if (status < 0) {
+ qCWarning(lcTlsBackendSchannel, "Failed to open algorithm handle (%ld)!", status);
+ return nullptr;
+ }
+
+ return handle;
+}
+
+BCRYPT_KEY_HANDLE generateSymmetricKey(BCRYPT_ALG_HANDLE handle,
+ const QByteArray &key)
+{
+ BCRYPT_KEY_HANDLE keyHandle;
+ NTSTATUS status = BCryptGenerateSymmetricKey(
+ handle, // hAlgorithm
+ &keyHandle, // phKey
+ nullptr, // pbKeyObject (can ignore)
+ 0, // cbKeyObject (also ignoring)
+ reinterpret_cast<unsigned char *>(const_cast<char *>(key.data())), // pbSecret
+ ULONG(key.length()), // cbSecret
+ 0 // dwFlags
+ );
+ if (status < 0) {
+ qCWarning(lcTlsBackendSchannel, "Failed to generate symmetric key (%ld)!", status);
+ return nullptr;
+ }
+
+ status = BCryptSetProperty(
+ keyHandle, // hObject
+ BCRYPT_CHAINING_MODE, // pszProperty
+ reinterpret_cast<UCHAR *>(const_cast<wchar_t *>(BCRYPT_CHAIN_MODE_CBC)), // pbInput
+ ARRAYSIZE(BCRYPT_CHAIN_MODE_CBC), // cbInput
+ 0 // dwFlags
+ );
+ if (status < 0) {
+ BCryptDestroyKey(keyHandle);
+ qCWarning(lcTlsBackendSchannel, "Failed to change the symmetric key's chaining mode (%ld)!",
+ status);
+ return nullptr;
+ }
+ return keyHandle;
+}
+
+QByteArray doCrypt(QSslKeyPrivate::Cipher cipher, const QByteArray &data, const QByteArray &key,
+ const QByteArray &iv, bool encrypt)
+{
+ BCRYPT_ALG_HANDLE handle = getHandle(cipher);
+ if (!handle)
+ return {};
+ auto handleDealloc = qScopeGuard([&handle]() {
+ BCryptCloseAlgorithmProvider(handle, 0);
+ });
+
+ BCRYPT_KEY_HANDLE keyHandle = generateSymmetricKey(handle, key);
+ if (!keyHandle)
+ return {};
+ auto keyHandleDealloc = qScopeGuard([&keyHandle]() {
+ BCryptDestroyKey(keyHandle);
+ });
+
+ QByteArray ivCopy = iv; // This gets modified, so we take a copy
+
+ ULONG sizeNeeded = 0;
+ QVarLengthArray<unsigned char> output;
+ auto cryptFunction = encrypt ? BCryptEncrypt : BCryptDecrypt;
+ for (int i = 0; i < 2; i++) {
+ output.resize(int(sizeNeeded));
+ auto input = reinterpret_cast<unsigned char *>(const_cast<char *>(data.data()));
+ // Need to call it twice because the first iteration lets us know the size needed.
+ NTSTATUS status = cryptFunction(
+ keyHandle, // hKey
+ input, // pbInput
+ ULONG(data.length()), // cbInput
+ nullptr, // pPaddingInfo
+ reinterpret_cast<unsigned char *>(ivCopy.data()), // pbIV
+ ULONG(ivCopy.length()), // cbIV
+ sizeNeeded ? output.data() : nullptr, // pbOutput
+ ULONG(output.length()), // cbOutput
+ &sizeNeeded, // pcbResult
+ BCRYPT_BLOCK_PADDING // dwFlags
+ );
+ if (status < 0) {
+ qCWarning(lcTlsBackendSchannel, "%s failed (%ld)!", encrypt ? "Encrypt" : "Decrypt",
+ status);
+ return {};
+ }
+ }
+
+ return QByteArray(reinterpret_cast<const char *>(output.constData()), int(sizeNeeded));
+}
+} // anonymous namespace
+
+namespace QTlsPrivate {
+
+QByteArray TlsKeySchannel::decrypt(Cipher cipher, const QByteArray &data, const QByteArray &key,
+ const QByteArray &iv) const
+{
+ return doCrypt(cipher, data, key, iv, false);
+}
+
+QByteArray TlsKeySchannel::encrypt(Cipher cipher, const QByteArray &data, const QByteArray &key,
+ const QByteArray &iv) const
+{
+ return doCrypt(cipher, data, key, iv, true);
+}
+
+} // namespace QTlsPrivate
+
+QT_END_NAMESPACE
+
diff --git a/src/plugins/tls/schannel/qtlskey_schannel_p.h b/src/plugins/tls/schannel/qtlskey_schannel_p.h
new file mode 100644
index 0000000000..14d146dfd7
--- /dev/null
+++ b/src/plugins/tls/schannel/qtlskey_schannel_p.h
@@ -0,0 +1,46 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QTLSKEY_SCHANNEL_P_H
+#define QTLSKEY_SCHANNEL_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 <QtNetwork/private/qtnetworkglobal_p.h>
+
+#include "../shared/qtlskey_generic_p.h"
+
+#include <QtCore/qglobal.h>
+
+QT_REQUIRE_CONFIG(ssl);
+
+QT_BEGIN_NAMESPACE
+
+namespace QTlsPrivate {
+
+class TlsKeySchannel final : public TlsKeyGeneric
+{
+public:
+ using TlsKeyGeneric::TlsKeyGeneric;
+
+ QByteArray decrypt(Cipher cipher, const QByteArray &data, const QByteArray &key,
+ const QByteArray &iv) const override;
+ QByteArray encrypt(Cipher cipher, const QByteArray &data, const QByteArray &key,
+ const QByteArray &iv) const override;
+};
+
+} // namespace QTlsPrivate
+
+QT_END_NAMESPACE
+
+#endif // QTLSKEY_SCHANNEL_P_H
+
diff --git a/src/plugins/tls/schannel/qx509_schannel.cpp b/src/plugins/tls/schannel/qx509_schannel.cpp
new file mode 100644
index 0000000000..d9d82dce29
--- /dev/null
+++ b/src/plugins/tls/schannel/qx509_schannel.cpp
@@ -0,0 +1,214 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qtlsbackend_schannel_p.h"
+#include "qtlskey_schannel_p.h"
+#include "qx509_schannel_p.h"
+
+#include <QtCore/private/qsystemerror_p.h>
+#include <QtNetwork/private/qsslcertificate_p.h>
+
+#include <memory>
+
+QT_BEGIN_NAMESPACE
+
+namespace QTlsPrivate {
+
+X509CertificateSchannel::X509CertificateSchannel() = default;
+
+X509CertificateSchannel::~X509CertificateSchannel()
+{
+ if (certificateContext)
+ CertFreeCertificateContext(certificateContext);
+}
+
+TlsKey *X509CertificateSchannel::publicKey() const
+{
+ auto key = std::make_unique<TlsKeySchannel>(QSsl::PublicKey);
+ if (publicKeyAlgorithm != QSsl::Opaque)
+ key->decodeDer(QSsl::PublicKey, publicKeyAlgorithm, publicKeyDerData, {}, false);
+
+ return key.release();
+}
+
+Qt::HANDLE X509CertificateSchannel::handle() const
+{
+ return Qt::HANDLE(certificateContext);
+}
+
+QSslCertificate X509CertificateSchannel::QSslCertificate_from_CERT_CONTEXT(const CERT_CONTEXT *certificateContext)
+{
+ QByteArray derData = QByteArray((const char *)certificateContext->pbCertEncoded,
+ certificateContext->cbCertEncoded);
+ QSslCertificate certificate(derData, QSsl::Der);
+ if (!certificate.isNull()) {
+ auto *certBackend = QTlsBackend::backend<X509CertificateSchannel>(certificate);
+ Q_ASSERT(certBackend);
+ certBackend->certificateContext = CertDuplicateCertificateContext(certificateContext);
+ }
+ return certificate;
+}
+
+bool X509CertificateSchannel::importPkcs12(QIODevice *device, QSslKey *key, QSslCertificate *cert,
+ QList<QSslCertificate> *caCertificates,
+ const QByteArray &passPhrase)
+{
+ // These are required
+ Q_ASSERT(device);
+ Q_ASSERT(key);
+ Q_ASSERT(cert);
+
+ QByteArray pkcs12data = device->readAll();
+ if (pkcs12data.size() == 0)
+ return false;
+
+ CRYPT_DATA_BLOB dataBlob;
+ dataBlob.cbData = pkcs12data.size();
+ dataBlob.pbData = reinterpret_cast<BYTE*>(pkcs12data.data());
+
+ const auto password = QString::fromUtf8(passPhrase);
+
+ const DWORD flags = (CRYPT_EXPORTABLE | PKCS12_NO_PERSIST_KEY | PKCS12_PREFER_CNG_KSP);
+
+ auto certStore = QHCertStorePointer(PFXImportCertStore(&dataBlob,
+ reinterpret_cast<LPCWSTR>(password.utf16()),
+ flags));
+
+ if (!certStore) {
+ qCWarning(lcTlsBackendSchannel, "Failed to import PFX data: %s",
+ qPrintable(QSystemError::windowsString()));
+ return false;
+ }
+
+ // first extract the certificate with the private key
+ const auto certContext = QPCCertContextPointer(CertFindCertificateInStore(certStore.get(),
+ X509_ASN_ENCODING |
+ PKCS_7_ASN_ENCODING,
+ 0,
+ CERT_FIND_HAS_PRIVATE_KEY,
+ nullptr, nullptr));
+
+ if (!certContext) {
+ qCWarning(lcTlsBackendSchannel, "Failed to find certificate in PFX store: %s",
+ qPrintable(QSystemError::windowsString()));
+ return false;
+ }
+
+ *cert = QSslCertificate_from_CERT_CONTEXT(certContext.get());
+
+ // retrieve the private key for the certificate
+ NCRYPT_KEY_HANDLE keyHandle = {};
+ DWORD keyHandleSize = sizeof(keyHandle);
+ if (!CertGetCertificateContextProperty(certContext.get(), CERT_NCRYPT_KEY_HANDLE_PROP_ID,
+ &keyHandle, &keyHandleSize)) {
+ qCWarning(lcTlsBackendSchannel, "Failed to find private key handle in certificate context: %s",
+ qPrintable(QSystemError::windowsString()));
+ return false;
+ }
+
+ SECURITY_STATUS securityStatus = ERROR_SUCCESS;
+
+ // we need the 'NCRYPT_ALLOW_PLAINTEXT_EXPORT_FLAG' to make NCryptExportKey succeed
+ DWORD policy = (NCRYPT_ALLOW_EXPORT_FLAG | NCRYPT_ALLOW_PLAINTEXT_EXPORT_FLAG);
+ DWORD policySize = sizeof(policy);
+
+ securityStatus = NCryptSetProperty(keyHandle, NCRYPT_EXPORT_POLICY_PROPERTY,
+ reinterpret_cast<BYTE*>(&policy), policySize, 0);
+ if (securityStatus != ERROR_SUCCESS) {
+ qCWarning(lcTlsBackendSchannel, "Failed to update export policy of private key: 0x%x",
+ static_cast<unsigned int>(securityStatus));
+ return false;
+ }
+
+ DWORD blobSize = {};
+ securityStatus = NCryptExportKey(keyHandle, {}, BCRYPT_RSAFULLPRIVATE_BLOB,
+ nullptr, nullptr, 0, &blobSize, 0);
+ if (securityStatus != ERROR_SUCCESS) {
+ qCWarning(lcTlsBackendSchannel, "Failed to retrieve private key size: 0x%x",
+ static_cast<unsigned int>(securityStatus));
+ return false;
+ }
+
+ std::vector<BYTE> blob(blobSize);
+ securityStatus = NCryptExportKey(keyHandle, {}, BCRYPT_RSAFULLPRIVATE_BLOB,
+ nullptr, blob.data(), blobSize, &blobSize, 0);
+ if (securityStatus != ERROR_SUCCESS) {
+ qCWarning(lcTlsBackendSchannel, "Failed to retrieve private key from certificate: 0x%x",
+ static_cast<unsigned int>(securityStatus));
+ return false;
+ }
+
+ DWORD privateKeySize = {};
+
+ if (!CryptEncodeObject(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, CNG_RSA_PRIVATE_KEY_BLOB,
+ blob.data(), nullptr, &privateKeySize)) {
+ qCWarning(lcTlsBackendSchannel, "Failed to encode private key to key info: %s",
+ qPrintable(QSystemError::windowsString()));
+ return false;
+ }
+
+ std::vector<BYTE> privateKeyData(privateKeySize);
+
+ CRYPT_PRIVATE_KEY_INFO privateKeyInfo = {};
+ privateKeyInfo.Algorithm.pszObjId = const_cast<PSTR>(szOID_RSA_RSA);
+ privateKeyInfo.PrivateKey.cbData = privateKeySize;
+ privateKeyInfo.PrivateKey.pbData = privateKeyData.data();
+
+ if (!CryptEncodeObject(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
+ CNG_RSA_PRIVATE_KEY_BLOB, blob.data(),
+ privateKeyInfo.PrivateKey.pbData, &privateKeyInfo.PrivateKey.cbData)) {
+ qCWarning(lcTlsBackendSchannel, "Failed to encode private key to key info: %s",
+ qPrintable(QSystemError::windowsString()));
+ return false;
+ }
+
+
+ DWORD derSize = {};
+
+ if (!CryptEncodeObject(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, PKCS_PRIVATE_KEY_INFO,
+ &privateKeyInfo, nullptr, &derSize)) {
+ qCWarning(lcTlsBackendSchannel, "Failed to encode key info to DER format: %s",
+ qPrintable(QSystemError::windowsString()));
+
+ return false;
+ }
+
+ QByteArray derData(derSize, Qt::Uninitialized);
+
+ if (!CryptEncodeObject(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, PKCS_PRIVATE_KEY_INFO,
+ &privateKeyInfo, reinterpret_cast<BYTE*>(derData.data()), &derSize)) {
+ qCWarning(lcTlsBackendSchannel, "Failed to encode key info to DER format: %s",
+ qPrintable(QSystemError::windowsString()));
+
+ return false;
+ }
+
+ *key = QSslKey(derData, QSsl::Rsa, QSsl::Der, QSsl::PrivateKey);
+ if (key->isNull()) {
+ qCWarning(lcTlsBackendSchannel, "Failed to parse private key from DER format");
+ return false;
+ }
+
+ // fetch all the remaining certificates as CA certificates
+ if (caCertificates) {
+ PCCERT_CONTEXT caCertContext = nullptr;
+ while ((caCertContext = CertFindCertificateInStore(certStore.get(),
+ X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
+ 0, CERT_FIND_ANY, nullptr, caCertContext))) {
+ if (CertCompareCertificate(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
+ certContext->pCertInfo, caCertContext->pCertInfo))
+ continue; // ignore the certificate with private key
+
+ auto caCertificate = QSslCertificate_from_CERT_CONTEXT(caCertContext);
+
+ caCertificates->append(caCertificate);
+ }
+ }
+
+ return true;
+}
+
+} // namespace QTlsPrivate
+
+QT_END_NAMESPACE
+
diff --git a/src/plugins/tls/schannel/qx509_schannel_p.h b/src/plugins/tls/schannel/qx509_schannel_p.h
new file mode 100644
index 0000000000..4625c9584c
--- /dev/null
+++ b/src/plugins/tls/schannel/qx509_schannel_p.h
@@ -0,0 +1,53 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QX509_SCHANNEL_P_H
+#define QX509_SCHANNEL_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 <QtNetwork/private/qtnetworkglobal_p.h>
+
+#include "../shared/qx509_generic_p.h"
+#include "../shared/qwincrypt_p.h"
+
+#include <QtCore/qglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QTlsPrivate {
+
+class X509CertificateSchannel final : public X509CertificateGeneric
+{
+public:
+ X509CertificateSchannel();
+ ~X509CertificateSchannel();
+
+ TlsKey *publicKey() const override;
+ Qt::HANDLE handle() const override;
+
+ static QSslCertificate QSslCertificate_from_CERT_CONTEXT(const CERT_CONTEXT *certificateContext);
+
+ static bool importPkcs12(QIODevice *device, QSslKey *key, QSslCertificate *cert,
+ QList<QSslCertificate> *caCertificates,
+ const QByteArray &passPhrase);
+private:
+ const CERT_CONTEXT *certificateContext = nullptr;
+
+ Q_DISABLE_COPY_MOVE(X509CertificateSchannel);
+};
+
+} // namespace QTlsPrivate
+
+QT_END_NAMESPACE
+
+#endif // QX509_SCHANNEL_P_H
diff --git a/src/plugins/tls/securetransport/CMakeLists.txt b/src/plugins/tls/securetransport/CMakeLists.txt
new file mode 100644
index 0000000000..bb560229e8
--- /dev/null
+++ b/src/plugins/tls/securetransport/CMakeLists.txt
@@ -0,0 +1,35 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+qt_internal_add_plugin(QSecureTransportBackendPlugin
+ OUTPUT_NAME qsecuretransportbackend
+ CLASS_NAME QSecureTransportBackend
+ PLUGIN_TYPE tls
+ DEFAULT_IF APPLE
+ SOURCES
+ ../shared/qsslsocket_mac_shared.cpp
+ ../shared/qtlskey_generic_p.h
+ ../shared/qtlskey_generic.cpp
+ ../shared/qx509_base_p.h
+ ../shared/qx509_base.cpp
+ ../shared/qx509_generic_p.h
+ ../shared/qx509_generic.cpp
+ ../shared/qtlskey_base_p.h
+ ../shared/qtlskey_base.cpp
+ ../shared/qsslsocket_qt.cpp
+ ../shared/qasn1element_p.h
+ ../shared/qasn1element.cpp
+ qtlsbackend_st.cpp
+ qtlsbackend_st_p.h
+ qx509_st.cpp
+ qtlskey_st.cpp
+ qtlskey_st_p.h
+ qx509_st_p.h
+ qtls_st.cpp
+ qtls_st_p.h
+ LIBRARIES
+ Qt::NetworkPrivate
+ Qt::CorePrivate
+ ${FWCoreFoundation}
+ ${FWSecurity}
+)
diff --git a/src/plugins/tls/securetransport/qtls_st.cpp b/src/plugins/tls/securetransport/qtls_st.cpp
new file mode 100644
index 0000000000..48b7f3364f
--- /dev/null
+++ b/src/plugins/tls/securetransport/qtls_st.cpp
@@ -0,0 +1,1321 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// Copyright (C) 2014 Jeremy Lainé <jeremy.laine@m4x.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qtls_st_p.h"
+#include "qtlsbackend_st_p.h"
+#include "qtlskey_st_p.h"
+
+#include <QtNetwork/private/qssl_p.h>
+
+#include <QtNetwork/private/qsslcertificate_p.h>
+#include <QtNetwork/private/qsslcipher_p.h>
+#include <QtNetwork/private/qsslkey_p.h>
+
+#include <QtNetwork/qsslsocket.h>
+
+#include <QtCore/qmessageauthenticationcode.h>
+#include <QtCore/qoperatingsystemversion.h>
+#include <QtCore/qscopedvaluerollback.h>
+#include <QtCore/qcryptographichash.h>
+#include <QtCore/qsystemdetection.h>
+#include <QtCore/qdatastream.h>
+#include <QtCore/qsysinfo.h>
+#include <QtCore/qlist.h>
+#include <QtCore/qmutex.h>
+#include <QtCore/qdebug.h>
+#include <QtCore/quuid.h>
+#include <QtCore/qdir.h>
+
+#include <algorithm>
+#include <cstddef>
+#include <limits>
+#include <vector>
+
+#include <QtCore/private/qcore_mac_p.h>
+
+#ifdef Q_OS_MACOS
+#include <CoreServices/CoreServices.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+using namespace Qt::StringLiterals;
+
+// Defined in qsslsocket_qt.cpp.
+QByteArray _q_makePkcs12(const QList<QSslCertificate> &certs, const QSslKey &key,
+ const QString &passPhrase);
+
+namespace QTlsPrivate {
+
+// Defined in qtlsbackend_st.cpp
+QSslCipher QSslCipher_from_SSLCipherSuite(SSLCipherSuite cipher);
+
+namespace {
+
+#ifdef Q_OS_MACOS
+/*
+
+Our own temporarykeychain is needed only on macOS where SecPKCS12Import changes
+the default keychain and where we see annoying pop-ups asking about accessing a
+private key.
+
+*/
+
+struct EphemeralSecKeychain
+{
+ EphemeralSecKeychain();
+ ~EphemeralSecKeychain();
+
+ SecKeychainRef keychain = nullptr;
+ Q_DISABLE_COPY_MOVE(EphemeralSecKeychain)
+};
+
+EphemeralSecKeychain::EphemeralSecKeychain()
+{
+ const auto uuid = QUuid::createUuid();
+ if (uuid.isNull()) {
+ qCWarning(lcSecureTransport) << "Failed to create a unique keychain name";
+ return;
+ }
+
+ const QByteArray uuidAsByteArray = uuid.toByteArray();
+ Q_ASSERT(uuidAsByteArray.size() > 2);
+ Q_ASSERT(uuidAsByteArray.startsWith('{'));
+ Q_ASSERT(uuidAsByteArray.endsWith('}'));
+ const auto uuidAsString = QLatin1StringView(uuidAsByteArray.data(), uuidAsByteArray.size()).mid(1, uuidAsByteArray.size() - 2);
+
+ const QString keychainName
+ = QDir::tempPath() + QDir::separator() + uuidAsString + ".keychain"_L1;
+ // SecKeychainCreate, pathName parameter:
+ //
+ // "A constant character string representing the POSIX path indicating where
+ // to store the keychain."
+ //
+ // Internally they seem to use std::string, but this does not really help.
+ // Fortunately, CFString has a convenient API.
+ QCFType<CFStringRef> cfName = keychainName.toCFString();
+ std::vector<char> posixPath;
+ // "Extracts the contents of a string as a NULL-terminated 8-bit string
+ // appropriate for passing to POSIX APIs."
+ posixPath.resize(CFStringGetMaximumSizeOfFileSystemRepresentation(cfName));
+ const auto ok = CFStringGetFileSystemRepresentation(cfName, &posixPath[0],
+ CFIndex(posixPath.size()));
+ if (!ok) {
+ 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(lcSecureTransport) << "SecRandomCopyBytes: failed to create a key";
+ return;
+ }
+
+ const OSStatus status = SecKeychainCreate(&posixPath[0], passUtf8.size(),
+ &passUtf8[0], FALSE, nullptr,
+ &keychain);
+ if (status != errSecSuccess || !keychain) {
+ qCWarning(lcSecureTransport) << "SecKeychainCreate: failed to create a custom keychain";
+ if (keychain) {
+ SecKeychainDelete(keychain);
+ CFRelease(keychain);
+ keychain = nullptr;
+ }
+ }
+
+ if (keychain) {
+ SecKeychainSettings settings = {};
+ settings.version = SEC_KEYCHAIN_SETTINGS_VERS1;
+ // Strange, huh? But that's what their docs say to do! With lockOnSleep
+ // == false, set interval to INT_MAX to never lock ...
+ settings.lockInterval = INT_MAX;
+ if (SecKeychainSetSettings(keychain, &settings) != errSecSuccess)
+ qCWarning(lcSecureTransport) << "SecKeychainSettings: failed to disable lock on sleep";
+ }
+
+#ifdef QSSLSOCKET_DEBUG
+ if (keychain) {
+ qCDebug(lcSecureTransport) << "Custom keychain with name" << keychainName << "was created"
+ << "successfully";
+ }
+#endif
+}
+
+EphemeralSecKeychain::~EphemeralSecKeychain()
+{
+ if (keychain) {
+ // clear file off disk
+ SecKeychainDelete(keychain);
+ CFRelease(keychain);
+ }
+}
+
+#endif // Q_OS_MACOS
+
+void qt_releaseSecureTransportContext(SSLContextRef context)
+{
+ if (context)
+ CFRelease(context);
+}
+
+} // unnamed namespace
+
+// To be also used by qtlsbackend_st.cpp (thus not in unnamed namespace).
+SSLContextRef qt_createSecureTransportContext(QSslSocket::SslMode mode)
+{
+ const bool isServer = mode == QSslSocket::SslServerMode;
+ const SSLProtocolSide side = isServer ? kSSLServerSide : kSSLClientSide;
+ // We never use kSSLDatagramType, so it's kSSLStreamType unconditionally.
+ SSLContextRef context = SSLCreateContext(nullptr, side, kSSLStreamType);
+ if (!context)
+ qCWarning(lcSecureTransport) << "SSLCreateContext failed";
+ return context;
+}
+
+QSecureTransportContext::QSecureTransportContext(SSLContextRef c)
+ : context(c)
+{
+}
+
+QSecureTransportContext::~QSecureTransportContext()
+{
+ qt_releaseSecureTransportContext(context);
+}
+
+QSecureTransportContext::operator SSLContextRef()const
+{
+ return context;
+}
+
+void QSecureTransportContext::reset(SSLContextRef newContext)
+{
+ qt_releaseSecureTransportContext(context);
+ context = newContext;
+}
+
+#if !defined(QT_PLATFORM_UIKIT) // dhparam is only used on macOS. (see the SSLSetDiffieHellmanParams call below)
+static const uint8_t dhparam[] =
+ "\x30\x82\x01\x08\x02\x82\x01\x01\x00\x97\xea\xd0\x46\xf7\xae\xa7\x76\x80"
+ "\x9c\x74\x56\x98\xd8\x56\x97\x2b\x20\x6c\x77\xe2\x82\xbb\xc8\x84\xbe\xe7"
+ "\x63\xaf\xcc\x30\xd0\x67\x97\x7d\x1b\xab\x59\x30\xa9\x13\x67\x21\xd7\xd4"
+ "\x0e\x46\xcf\xe5\x80\xdf\xc9\xb9\xba\x54\x9b\x46\x2f\x3b\x45\xfc\x2f\xaf"
+ "\xad\xc0\x17\x56\xdd\x52\x42\x57\x45\x70\x14\xe5\xbe\x67\xaa\xde\x69\x75"
+ "\x30\x0d\xf9\xa2\xc4\x63\x4d\x7a\x39\xef\x14\x62\x18\x33\x44\xa1\xf9\xc1"
+ "\x52\xd1\xb6\x72\x21\x98\xf8\xab\x16\x1b\x7b\x37\x65\xe3\xc5\x11\x00\xf6"
+ "\x36\x1f\xd8\x5f\xd8\x9f\x43\xa8\xce\x9d\xbf\x5e\xd6\x2d\xfa\x0a\xc2\x01"
+ "\x54\xc2\xd9\x81\x54\x55\xb5\x26\xf8\x88\x37\xf5\xfe\xe0\xef\x4a\x34\x81"
+ "\xdc\x5a\xb3\x71\x46\x27\xe3\xcd\x24\xf6\x1b\xf1\xe2\x0f\xc2\xa1\x39\x53"
+ "\x5b\xc5\x38\x46\x8e\x67\x4c\xd9\xdd\xe4\x37\x06\x03\x16\xf1\x1d\x7a\xba"
+ "\x2d\xc1\xe4\x03\x1a\x58\xe5\x29\x5a\x29\x06\x69\x61\x7a\xd8\xa9\x05\x9f"
+ "\xc1\xa2\x45\x9c\x17\xad\x52\x69\x33\xdc\x18\x8d\x15\xa6\x5e\xcd\x94\xf4"
+ "\x45\xbb\x9f\xc2\x7b\x85\x00\x61\xb0\x1a\xdc\x3c\x86\xaa\x9f\x5c\x04\xb3"
+ "\x90\x0b\x35\x64\xff\xd9\xe3\xac\xf2\xf2\xeb\x3a\x63\x02\x01\x02";
+#endif
+
+OSStatus TlsCryptographSecureTransport::ReadCallback(TlsCryptographSecureTransport *socket,
+ char *data, size_t *dataLength)
+{
+ Q_ASSERT(socket);
+ Q_ASSERT(data);
+ Q_ASSERT(dataLength);
+
+ Q_ASSERT(socket->d);
+ QTcpSocket *plainSocket = socket->d->plainTcpSocket();
+ Q_ASSERT(plainSocket);
+
+ if (socket->isHandshakeComplete()) {
+ // Check if it's a renegotiation attempt, when the handshake is complete, the
+ // session state is 'kSSLConnected':
+ SSLSessionState currentState = kSSLConnected;
+ const OSStatus result = SSLGetSessionState(socket->context, &currentState);
+ if (result != noErr) {
+ *dataLength = 0;
+ return result;
+ }
+
+ if (currentState == kSSLHandshake) {
+ // Renegotiation detected, don't allow read more yet - 'transmit'
+ // will notice this and will call 'startHandshake':
+ *dataLength = 0;
+ socket->renegotiating = true;
+ return errSSLWouldBlock;
+ }
+ }
+
+ const qint64 bytes = plainSocket->read(data, *dataLength);
+#ifdef QSSLSOCKET_DEBUG
+ qCDebug(lcSecureTransport) << plainSocket << "read" << bytes;
+#endif
+ if (bytes < 0) {
+ *dataLength = 0;
+ return errSecIO;
+ }
+
+ const OSStatus err = (size_t(bytes) < *dataLength) ? OSStatus(errSSLWouldBlock) : OSStatus(errSecSuccess);
+ *dataLength = bytes;
+
+ return err;
+}
+
+OSStatus TlsCryptographSecureTransport::WriteCallback(TlsCryptographSecureTransport *socket,
+ const char *data, size_t *dataLength)
+{
+ Q_ASSERT(socket);
+ Q_ASSERT(data);
+ Q_ASSERT(dataLength);
+
+ Q_ASSERT(socket->d);
+ QTcpSocket *plainSocket = socket->d->plainTcpSocket();
+ Q_ASSERT(plainSocket);
+
+ const qint64 bytes = plainSocket->write(data, *dataLength);
+#ifdef QSSLSOCKET_DEBUG
+ qCDebug(lcSecureTransport) << plainSocket << "write" << bytes;
+#endif
+ if (bytes < 0) {
+ *dataLength = 0;
+ return errSecIO;
+ }
+
+ const OSStatus err = (size_t(bytes) < *dataLength) ? OSStatus(errSSLWouldBlock) : OSStatus(errSecSuccess);
+ *dataLength = bytes;
+
+ return err;
+}
+
+TlsCryptographSecureTransport::TlsCryptographSecureTransport()
+ : context(nullptr)
+{
+}
+
+TlsCryptographSecureTransport::~TlsCryptographSecureTransport()
+{
+ destroySslContext();
+}
+
+void TlsCryptographSecureTransport::init(QSslSocket *qObj, QSslSocketPrivate *dObj)
+{
+ Q_ASSERT(qObj);
+ Q_ASSERT(dObj);
+ q = qObj;
+ d = dObj;
+
+ renegotiating = false;
+ shutdown = false;
+}
+
+void TlsCryptographSecureTransport::continueHandshake()
+{
+ Q_ASSERT(q);
+ Q_ASSERT(d);
+ d->setEncrypted(true);
+#ifdef QSSLSOCKET_DEBUG
+ qCDebug(lcSecureTransport) << d->plainTcpSocket() << "connection encrypted";
+#endif
+
+ // Unlike OpenSSL, Secure Transport does not allow to negotiate protocols via
+ // a callback during handshake. We can only set our list of preferred protocols
+ // (and send it during handshake) and then receive what our peer has sent to us.
+ // And here we can finally try to find a match (if any).
+ const auto &configuration = q->sslConfiguration();
+ const auto &requestedProtocols = configuration.allowedNextProtocols();
+ if (const int requestedCount = requestedProtocols.size()) {
+ QTlsBackend::setAlpnStatus(d, QSslConfiguration::NextProtocolNegotiationNone);
+ QTlsBackend::setNegotiatedProtocol(d, {});
+
+ QCFType<CFArrayRef> cfArray;
+ const OSStatus result = SSLCopyALPNProtocols(context, &cfArray);
+ if (result == errSecSuccess && cfArray && CFArrayGetCount(cfArray)) {
+ const int size = CFArrayGetCount(cfArray);
+ QList<QString> peerProtocols(size);
+ for (int i = 0; i < size; ++i)
+ peerProtocols[i] = QString::fromCFString((CFStringRef)CFArrayGetValueAtIndex(cfArray, i));
+
+ for (int i = 0; i < requestedCount; ++i) {
+ const auto requestedName = QString::fromLatin1(requestedProtocols[i]);
+ for (int j = 0; j < size; ++j) {
+ if (requestedName == peerProtocols[j]) {
+ QTlsBackend::setNegotiatedProtocol(d, requestedName.toLatin1());
+ QTlsBackend::setAlpnStatus(d, QSslConfiguration::NextProtocolNegotiationNegotiated);
+ break;
+ }
+ }
+ if (configuration.nextProtocolNegotiationStatus() == QSslConfiguration::NextProtocolNegotiationNegotiated)
+ break;
+ }
+ }
+ }
+
+ if (!renegotiating)
+ emit q->encrypted();
+
+ if (d->isAutoStartingHandshake() && d->isPendingClose()) {
+ d->setPendingClose(false);
+ q->disconnectFromHost();
+ }
+}
+
+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.
+ // It will be destroyed when the socket is deleted.
+}
+
+void TlsCryptographSecureTransport::disconnectFromHost()
+{
+ Q_ASSERT(d && d->plainTcpSocket());
+ if (context) {
+ if (!shutdown) {
+ SSLClose(context);
+ context.reset(nullptr);
+ shutdown = true;
+ }
+ }
+ d->plainTcpSocket()->disconnectFromHost();
+}
+
+QSslCipher TlsCryptographSecureTransport::sessionCipher() const
+{
+ SSLCipherSuite cipher = 0;
+ if (context && SSLGetNegotiatedCipher(context, &cipher) == errSecSuccess)
+ return QSslCipher_from_SSLCipherSuite(cipher);
+
+ return QSslCipher();
+}
+
+QSsl::SslProtocol TlsCryptographSecureTransport::sessionProtocol() const
+{
+ if (!context)
+ return QSsl::UnknownProtocol;
+
+ SSLProtocol protocol = kSSLProtocolUnknown;
+ const OSStatus err = SSLGetNegotiatedProtocolVersion(context, &protocol);
+ if (err != errSecSuccess) {
+ 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:
+ return QSsl::TlsV1_3;
+ default:
+ return QSsl::UnknownProtocol;
+ }
+}
+
+void TlsCryptographSecureTransport::startClientEncryption()
+{
+ if (!initSslContext()) {
+ Q_ASSERT(d);
+ // Error description/code were set, 'error' emitted
+ // by initSslContext, but OpenSSL socket also sets error,
+ // emits a signal twice, so ...
+ setErrorAndEmit(d, QAbstractSocket::SslInternalError, QStringLiteral("Unable to init SSL Context"));
+ return;
+ }
+
+ startHandshake();
+}
+
+void TlsCryptographSecureTransport::startServerEncryption()
+{
+ if (!initSslContext()) {
+ // Error description/code were set, 'error' emitted
+ // by initSslContext, but OpenSSL socket also sets error
+ // emits a signal twice, so ...
+ setErrorAndEmit(d, QAbstractSocket::SslInternalError, QStringLiteral("Unable to init SSL Context"));
+ return;
+ }
+
+ startHandshake();
+}
+
+void TlsCryptographSecureTransport::transmit()
+{
+ Q_ASSERT(q);
+ Q_ASSERT(d);
+
+ // If we don't have any SSL context, don't bother transmitting.
+ // Edit: if SSL session closed, don't bother either.
+ if (!context || shutdown)
+ return;
+
+ if (!isHandshakeComplete())
+ startHandshake();
+
+ auto &writeBuffer = d->tlsWriteBuffer();
+ if (isHandshakeComplete() && !writeBuffer.isEmpty()) {
+ qint64 totalBytesWritten = 0;
+ while (writeBuffer.nextDataBlockSize() > 0 && context) {
+ const size_t nextDataBlockSize = writeBuffer.nextDataBlockSize();
+ size_t writtenBytes = 0;
+ const OSStatus err = SSLWrite(context, writeBuffer.readPointer(), nextDataBlockSize, &writtenBytes);
+#ifdef QSSLSOCKET_DEBUG
+ qCDebug(lcSecureTransport) << d->plainTcpSocket() << "SSLWrite returned" << err;
+#endif
+ if (err != errSecSuccess && err != errSSLWouldBlock) {
+ setErrorAndEmit(d, QAbstractSocket::SslInternalError,
+ QStringLiteral("SSLWrite failed: %1").arg(err));
+ break;
+ }
+
+ if (writtenBytes) {
+ writeBuffer.free(writtenBytes);
+ totalBytesWritten += writtenBytes;
+ }
+
+ if (writtenBytes < nextDataBlockSize)
+ break;
+ }
+
+ if (totalBytesWritten > 0) {
+ // Don't emit bytesWritten() recursively.
+ auto &emittedBytesWritten = d->tlsEmittedBytesWritten();
+ if (!emittedBytesWritten) {
+ emittedBytesWritten = true;
+ emit q->bytesWritten(totalBytesWritten);
+ emittedBytesWritten = false;
+ }
+ emit q->channelBytesWritten(0, totalBytesWritten);
+ }
+ }
+
+ auto &buffer = d->tlsBuffer();
+ const auto readBufferMaxSize = d->maxReadBufferSize();
+ if (isHandshakeComplete()) {
+ QVarLengthArray<char, 4096> data;
+ while (context && (!readBufferMaxSize || buffer.size() < readBufferMaxSize)) {
+ size_t readBytes = 0;
+ data.resize(4096);
+ const OSStatus err = SSLRead(context, data.data(), data.size(), &readBytes);
+#ifdef QSSLSOCKET_DEBUG
+ 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
+ setErrorAndEmit(d, QAbstractSocket::RemoteHostClosedError,
+ QSslSocket::tr("The TLS/SSL connection has been closed"));
+ break;
+ } else if (err != errSecSuccess && err != errSSLWouldBlock) {
+ setErrorAndEmit(d, QAbstractSocket::SslInternalError,
+ QStringLiteral("SSLRead failed: %1").arg(err));
+ break;
+ }
+
+ if (err == errSSLWouldBlock && renegotiating) {
+ startHandshake();
+ break;
+ }
+
+ if (readBytes) {
+ buffer.append(data.constData(), readBytes);
+ if (bool *readyReadEmittedPointer = d->readyReadPointer())
+ *readyReadEmittedPointer = true;
+ emit q->readyRead();
+ emit q->channelReadyRead(0);
+ }
+
+ if (err == errSSLWouldBlock)
+ break;
+ }
+ }
+}
+
+SSLCipherSuite TlsCryptographSecureTransport::SSLCipherSuite_from_QSslCipher(const QSslCipher &ciph)
+{
+ if (ciph.name() == "AES128-SHA"_L1)
+ return TLS_RSA_WITH_AES_128_CBC_SHA;
+ if (ciph.name() == "DHE-RSA-AES128-SHA"_L1)
+ return TLS_DHE_RSA_WITH_AES_128_CBC_SHA;
+ if (ciph.name() == "AES256-SHA"_L1)
+ return TLS_RSA_WITH_AES_256_CBC_SHA;
+ if (ciph.name() == "DHE-RSA-AES256-SHA"_L1)
+ return TLS_DHE_RSA_WITH_AES_256_CBC_SHA;
+ if (ciph.name() == "ECDH-ECDSA-NULL-SHA"_L1)
+ return TLS_ECDH_ECDSA_WITH_NULL_SHA;
+ if (ciph.name() == "ECDH-ECDSA-RC4-SHA"_L1)
+ return TLS_ECDH_ECDSA_WITH_RC4_128_SHA;
+ if (ciph.name() == "ECDH-ECDSA-DES-CBC3-SHA"_L1)
+ return TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA;
+ if (ciph.name() == "ECDH-ECDSA-AES128-SHA"_L1)
+ return TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA;
+ if (ciph.name() == "ECDH-ECDSA-AES256-SHA"_L1)
+ return TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA;
+ if (ciph.name() == "ECDH-ECDSA-RC4-SHA"_L1)
+ return TLS_ECDHE_ECDSA_WITH_RC4_128_SHA;
+ if (ciph.name() == "ECDH-ECDSA-DES-CBC3-SHA"_L1)
+ return TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA;
+ if (ciph.name() == "ECDH-ECDSA-AES128-SHA"_L1)
+ return TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA;
+ if (ciph.name() == "ECDH-ECDSA-AES256-SHA"_L1)
+ return TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA;
+ if (ciph.name() == "ECDH-RSA-NULL-SHA"_L1)
+ return TLS_ECDH_RSA_WITH_NULL_SHA;
+ if (ciph.name() == "ECDH-RSA-RC4-SHA"_L1)
+ return TLS_ECDH_RSA_WITH_RC4_128_SHA;
+ if (ciph.name() == "ECDH-RSA-DES-CBC3-SHA"_L1)
+ return TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA;
+ if (ciph.name() == "ECDH-RSA-AES128-SHA"_L1)
+ return TLS_ECDH_RSA_WITH_AES_128_CBC_SHA;
+ if (ciph.name() == "ECDH-RSA-AES256-SHA"_L1)
+ return TLS_ECDH_RSA_WITH_AES_256_CBC_SHA;
+ if (ciph.name() == "ECDH-RSA-RC4-SHA"_L1)
+ return TLS_ECDHE_RSA_WITH_RC4_128_SHA;
+ if (ciph.name() == "ECDH-RSA-DES-CBC3-SHA"_L1)
+ return TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA;
+ if (ciph.name() == "ECDH-RSA-AES128-SHA"_L1)
+ return TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA;
+ if (ciph.name() == "ECDH-RSA-AES256-SHA"_L1)
+ return TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA;
+ if (ciph.name() == "DES-CBC3-SHA"_L1)
+ return TLS_RSA_WITH_3DES_EDE_CBC_SHA;
+ if (ciph.name() == "AES128-SHA256"_L1)
+ return TLS_RSA_WITH_AES_128_CBC_SHA256;
+ if (ciph.name() == "AES256-SHA256"_L1)
+ return TLS_RSA_WITH_AES_256_CBC_SHA256;
+ if (ciph.name() == "DHE-RSA-DES-CBC3-SHA"_L1)
+ return TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA;
+ if (ciph.name() == "DHE-RSA-AES128-SHA256"_L1)
+ return TLS_DHE_RSA_WITH_AES_128_CBC_SHA256;
+ if (ciph.name() == "DHE-RSA-AES256-SHA256"_L1)
+ return TLS_DHE_RSA_WITH_AES_256_CBC_SHA256;
+ if (ciph.name() == "AES256-GCM-SHA384"_L1)
+ return TLS_RSA_WITH_AES_256_GCM_SHA384;
+ if (ciph.name() == "ECDHE-ECDSA-AES128-SHA256"_L1)
+ return TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256;
+ if (ciph.name() == "ECDHE-ECDSA-AES256-SHA384"_L1)
+ return TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384;
+ if (ciph.name() == "ECDH-ECDSA-AES128-SHA256"_L1)
+ return TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256;
+ if (ciph.name() == "ECDH-ECDSA-AES256-SHA384"_L1)
+ return TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384;
+ if (ciph.name() == "ECDHE-RSA-AES128-SHA256"_L1)
+ return TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256;
+ if (ciph.name() == "ECDHE-RSA-AES256-SHA384"_L1)
+ return TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384;
+ if (ciph.name() == "ECDHE-RSA-AES256-SHA384"_L1)
+ return TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256;
+ if (ciph.name() == "ECDHE-RSA-AES256-GCM-SHA384"_L1)
+ return TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384;
+ if (ciph.name() == "AES128-GCM-SHA256"_L1)
+ return TLS_AES_128_GCM_SHA256;
+ if (ciph.name() == "AES256-GCM-SHA384"_L1)
+ return TLS_AES_256_GCM_SHA384;
+ if (ciph.name() == "CHACHA20-POLY1305-SHA256"_L1)
+ return TLS_CHACHA20_POLY1305_SHA256;
+ if (ciph.name() == "AES128-CCM-SHA256"_L1)
+ return TLS_AES_128_CCM_SHA256;
+ if (ciph.name() == "AES128-CCM8-SHA256"_L1)
+ return TLS_AES_128_CCM_8_SHA256;
+ if (ciph.name() == "ECDHE-ECDSA-AES128-GCM-SHA256"_L1)
+ return TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256;
+ if (ciph.name() == "ECDHE-ECDSA-AES256-GCM-SHA384"_L1)
+ return TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384;
+ if (ciph.name() == "ECDH-ECDSA-AES128-GCM-SHA256"_L1)
+ return TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256;
+ if (ciph.name() == "ECDH-ECDSA-AES256-GCM-SHA384"_L1)
+ return TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384;
+ if (ciph.name() == "ECDHE-RSA-AES128-GCM-SHA256"_L1)
+ return TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256;
+ if (ciph.name() == "ECDH-RSA-AES128-GCM-SHA256"_L1)
+ return TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256;
+ if (ciph.name() == "ECDH-RSA-AES256-GCM-SHA384"_L1)
+ return TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384;
+ if (ciph.name() == "ECDHE-RSA-CHACHA20-POLY1305-SHA256"_L1)
+ return TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256;
+ if (ciph.name() == "ECDHE-ECDSA-CHACHA20-POLY1305-SHA256"_L1)
+ return TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256;
+
+ return 0;
+}
+
+bool TlsCryptographSecureTransport::initSslContext()
+{
+ Q_ASSERT(q);
+ Q_ASSERT(d);
+
+ Q_ASSERT_X(!context, Q_FUNC_INFO, "invalid socket state, context is not null");
+ auto *plainSocket = d->plainTcpSocket();
+ Q_ASSERT(plainSocket);
+
+ const auto mode = d->tlsMode();
+
+ context.reset(qt_createSecureTransportContext(mode));
+ if (!context) {
+ setErrorAndEmit(d, QAbstractSocket::SslInternalError, QStringLiteral("SSLCreateContext failed"));
+ return false;
+ }
+
+ const OSStatus err = SSLSetIOFuncs(context,
+ reinterpret_cast<SSLReadFunc>(&TlsCryptographSecureTransport::ReadCallback),
+ reinterpret_cast<SSLWriteFunc>(&TlsCryptographSecureTransport::WriteCallback));
+ if (err != errSecSuccess) {
+ destroySslContext();
+ setErrorAndEmit(d, QAbstractSocket::SslInternalError,
+ QStringLiteral("SSLSetIOFuncs failed: %1").arg(err));
+ return false;
+ }
+
+ SSLSetConnection(context, this);
+
+ const auto &configuration = q->sslConfiguration();
+ if (mode == QSslSocket::SslServerMode
+ && !configuration.localCertificateChain().isEmpty()) {
+ QString errorDescription;
+ QAbstractSocket::SocketError errorCode = QAbstractSocket::UnknownSocketError;
+ if (!setSessionCertificate(errorDescription, errorCode)) {
+ destroySslContext();
+ setErrorAndEmit(d, errorCode, errorDescription);
+ return false;
+ }
+ }
+
+ if (!setSessionProtocol()) {
+ destroySslContext();
+ setErrorAndEmit(d, QAbstractSocket::SslInternalError, QStringLiteral("Failed to set protocol version"));
+ return false;
+ }
+
+ const auto protocolNames = configuration.allowedNextProtocols();
+ QCFType<CFMutableArrayRef> cfNames(CFArrayCreateMutable(nullptr, 0, &kCFTypeArrayCallBacks));
+ if (cfNames) {
+ for (const QByteArray &name : protocolNames) {
+ if (name.size() > 255) {
+ qCWarning(lcSecureTransport) << "TLS ALPN extension" << name
+ << "is too long and will be ignored.";
+ continue;
+ } else if (name.isEmpty()) {
+ continue;
+ }
+ QCFString cfName(QString::fromLatin1(name).toCFString());
+ CFArrayAppendValue(cfNames, cfName);
+ }
+
+ if (CFArrayGetCount(cfNames)) {
+ // Up to the application layer to check that negotiation
+ // 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(lcSecureTransport) << "SSLSetALPNProtocols failed - too long protocol names?";
+ }
+ } else {
+ qCWarning(lcSecureTransport) << "failed to allocate ALPN names array";
+ }
+
+ if (mode == QSslSocket::SslClientMode) {
+ // enable Server Name Indication (SNI)
+ const auto verificationPeerName = d->verificationName();
+ QString tlsHostName(verificationPeerName.isEmpty() ? q->peerName() : verificationPeerName);
+ if (tlsHostName.isEmpty())
+ tlsHostName = d->tlsHostName();
+
+ const QByteArray ace(QUrl::toAce(tlsHostName));
+ SSLSetPeerDomainName(context, ace.data(), ace.size());
+ // tell SecureTransport we handle peer verification ourselves
+ OSStatus err = SSLSetSessionOption(context, kSSLSessionOptionBreakOnServerAuth, true);
+ if (err == errSecSuccess)
+ err = SSLSetSessionOption(context, kSSLSessionOptionBreakOnCertRequested, true);
+
+ if (err != errSecSuccess) {
+ destroySslContext();
+ setErrorAndEmit(d, QSslSocket::SslInternalError,
+ QStringLiteral("SSLSetSessionOption failed: %1").arg(err));
+ return false;
+ }
+ //
+ } else {
+ if (configuration.peerVerifyMode() != QSslSocket::VerifyNone) {
+ // kAlwaysAuthenticate - always fails even if we set break on client auth.
+ OSStatus err = SSLSetClientSideAuthenticate(context, kTryAuthenticate);
+ if (err == errSecSuccess) {
+ // We'd like to verify peer ourselves, otherwise handshake will
+ // most probably fail before we can do anything.
+ err = SSLSetSessionOption(context, kSSLSessionOptionBreakOnClientAuth, true);
+ }
+
+ if (err != errSecSuccess) {
+ destroySslContext();
+ setErrorAndEmit(d, QAbstractSocket::SslInternalError,
+ QStringLiteral("failed to set SSL context option in server mode: %1").arg(err));
+ return false;
+ }
+ }
+#if !defined(QT_PLATFORM_UIKIT)
+ // No SSLSetDiffieHellmanParams on iOS; calling it is optional according to docs.
+ SSLSetDiffieHellmanParams(context, dhparam, sizeof(dhparam));
+#endif
+ }
+ if (configuration.ciphers().size() > 0) {
+ QVector<SSLCipherSuite> cfCiphers;
+ for (const QSslCipher &cipher : configuration.ciphers()) {
+ if (auto sslCipher = TlsCryptographSecureTransport::SSLCipherSuite_from_QSslCipher(cipher))
+ cfCiphers << sslCipher;
+ }
+ if (cfCiphers.size() == 0) {
+ 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(lcSecureTransport) << "failed to set the ciphers from the configuration";
+ return false;
+ }
+ }
+ return true;
+}
+
+void TlsCryptographSecureTransport::destroySslContext()
+{
+ context.reset(nullptr);
+}
+
+bool TlsCryptographSecureTransport::setSessionCertificate(QString &errorDescription, QAbstractSocket::SocketError &errorCode)
+{
+ Q_ASSERT_X(context, Q_FUNC_INFO, "invalid SSL context (null)");
+
+ Q_ASSERT(d);
+ const auto &configuration = q->sslConfiguration();
+
+#ifdef QSSLSOCKET_DEBUG
+ auto *plainSocket = d->plainTcpSocket();
+#endif
+
+ QSslCertificate localCertificate;
+
+ if (!configuration.localCertificateChain().isEmpty())
+ localCertificate = configuration.localCertificateChain().at(0);
+
+ if (!localCertificate.isNull()) {
+ // Require a private key as well.
+ if (configuration.privateKey().isNull()) {
+ errorCode = QAbstractSocket::SslInvalidUserDataError;
+ errorDescription = QStringLiteral("Cannot provide a certificate with no key");
+ return false;
+ }
+
+ // import certificates and key
+ const QString passPhrase(QString::fromLatin1("foobar"));
+ QCFType<CFDataRef> pkcs12 = _q_makePkcs12(configuration.localCertificateChain(),
+ configuration.privateKey(), passPhrase).toCFData();
+ QCFType<CFStringRef> password = passPhrase.toCFString();
+ const void *keys[2] = { kSecImportExportPassphrase };
+ const void *values[2] = { password };
+ CFIndex nKeys = 1;
+#ifdef Q_OS_MACOS
+ bool envOk = false;
+ const int env = qEnvironmentVariableIntValue("QT_SSL_USE_TEMPORARY_KEYCHAIN", &envOk);
+ if (envOk && env) {
+ static const EphemeralSecKeychain temporaryKeychain;
+ if (temporaryKeychain.keychain) {
+ nKeys = 2;
+ keys[1] = kSecImportExportKeychain;
+ values[1] = temporaryKeychain.keychain;
+ }
+ }
+#endif
+ QCFType<CFDictionaryRef> options = CFDictionaryCreate(nullptr, keys, values, nKeys,
+ nullptr, nullptr);
+ QCFType<CFArrayRef> items;
+ OSStatus err = SecPKCS12Import(pkcs12, options, &items);
+ if (err != errSecSuccess) {
+#ifdef QSSLSOCKET_DEBUG
+ qCWarning(lcSecureTransport) << plainSocket
+ << QStringLiteral("SecPKCS12Import failed: %1").arg(err);
+#endif
+ errorCode = QAbstractSocket::SslInvalidUserDataError;
+ errorDescription = QStringLiteral("SecPKCS12Import failed: %1").arg(err);
+ return false;
+ }
+
+ if (!CFArrayGetCount(items)) {
+#ifdef QSSLSOCKET_DEBUG
+ qCWarning(lcSecureTransport) << plainSocket << "SecPKCS12Import returned no items";
+#endif
+ errorCode = QAbstractSocket::SslInvalidUserDataError;
+ errorDescription = QStringLiteral("SecPKCS12Import returned no items");
+ return false;
+ }
+
+ CFDictionaryRef import = (CFDictionaryRef)CFArrayGetValueAtIndex(items, 0);
+ SecIdentityRef identity = (SecIdentityRef)CFDictionaryGetValue(import, kSecImportItemIdentity);
+ if (!identity) {
+#ifdef QSSLSOCKET_DEBUG
+ qCWarning(lcSecureTransport) << plainSocket << "SecPKCS12Import returned no identity";
+#endif
+ errorCode = QAbstractSocket::SslInvalidUserDataError;
+ errorDescription = QStringLiteral("SecPKCS12Import returned no identity");
+ return false;
+ }
+
+ QCFType<CFMutableArrayRef> certs = CFArrayCreateMutable(nullptr, 0, &kCFTypeArrayCallBacks);
+ if (!certs) {
+ errorCode = QAbstractSocket::SslInternalError;
+ errorDescription = QStringLiteral("Failed to allocate certificates array");
+ return false;
+ }
+
+ CFArrayAppendValue(certs, identity);
+
+ CFArrayRef chain = (CFArrayRef)CFDictionaryGetValue(import, kSecImportItemCertChain);
+ if (chain) {
+ for (CFIndex i = 1, e = CFArrayGetCount(chain); i < e; ++i)
+ CFArrayAppendValue(certs, CFArrayGetValueAtIndex(chain, i));
+ }
+
+ err = SSLSetCertificate(context, certs);
+ if (err != errSecSuccess) {
+#ifdef QSSLSOCKET_DEBUG
+ 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);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool TlsCryptographSecureTransport::setSessionProtocol()
+{
+ Q_ASSERT_X(context, Q_FUNC_INFO, "invalid SSL context (null)");
+ Q_ASSERT(q);
+ Q_ASSERT(d);
+ // SecureTransport has kTLSProtocol13 constant and also, kTLSProtocolMaxSupported.
+ // Calling SSLSetProtocolVersionMax/Min with any of these two constants results
+ // in errInvalidParam and a failure to set the protocol version. This means
+ // no TLS 1.3 on macOS and iOS.
+ const auto &configuration = q->sslConfiguration();
+ auto *plainSocket = d->plainTcpSocket();
+ switch (configuration.protocol()) {
+ case QSsl::TlsV1_3:
+ case QSsl::TlsV1_3OrLater:
+ 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(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(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(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(lcSecureTransport) << plainSocket << "requesting : any";
+ #endif
+ err = SSLSetProtocolVersionMin(context, kTLSProtocol1);
+ } else if (configuration.protocol() == QSsl::SecureProtocols) {
+ #ifdef QSSLSOCKET_DEBUG
+ qCDebug(lcSecureTransport) << plainSocket << "requesting : TLSv1.2";
+ #endif
+ err = SSLSetProtocolVersionMin(context, kTLSProtocol12);
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
+ } else if (configuration.protocol() == QSsl::TlsV1_0OrLater) {
+ #ifdef QSSLSOCKET_DEBUG
+ qCDebug(lcSecureTransport) << plainSocket << "requesting : TLSv1 - TLSv1.2";
+ #endif
+ err = SSLSetProtocolVersionMin(context, kTLSProtocol1);
+ } else if (configuration.protocol() == QSsl::TlsV1_1OrLater) {
+ #ifdef QSSLSOCKET_DEBUG
+ 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(lcSecureTransport) << plainSocket << "requesting : TLSv1.2";
+ #endif
+ err = SSLSetProtocolVersionMin(context, kTLSProtocol12);
+ } else {
+ #ifdef QSSLSOCKET_DEBUG
+ qCDebug(lcSecureTransport) << plainSocket << "no protocol version found in the configuration";
+ #endif
+ return false;
+ }
+
+ return err == errSecSuccess;
+}
+
+bool TlsCryptographSecureTransport::canIgnoreTrustVerificationFailure() const
+{
+ Q_ASSERT(q);
+ Q_ASSERT(d);
+ const auto &configuration = q->sslConfiguration();
+ const QSslSocket::PeerVerifyMode verifyMode = configuration.peerVerifyMode();
+ return d->tlsMode() == QSslSocket::SslServerMode
+ && (verifyMode == QSslSocket::QueryPeer
+ || verifyMode == QSslSocket::AutoVerifyPeer
+ || verifyMode == QSslSocket::VerifyNone);
+}
+
+bool TlsCryptographSecureTransport::verifySessionProtocol() const
+{
+ Q_ASSERT(q);
+
+ const auto &configuration = q->sslConfiguration();
+ bool protocolOk = false;
+ if (configuration.protocol() == QSsl::AnyProtocol)
+ protocolOk = true;
+ else if (configuration.protocol() == QSsl::SecureProtocols)
+ 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)
+ protocolOk = (sessionProtocol() >= QSsl::TlsV1_3OrLater);
+ else
+ protocolOk = (sessionProtocol() == configuration.protocol());
+
+ return protocolOk;
+}
+
+bool TlsCryptographSecureTransport::verifyPeerTrust()
+{
+ Q_ASSERT(q);
+ Q_ASSERT(d);
+
+ const auto mode = d->tlsMode();
+ const QSslSocket::PeerVerifyMode verifyMode = q->peerVerifyMode();
+ const bool canIgnoreVerify = canIgnoreTrustVerificationFailure();
+
+ Q_ASSERT_X(context, Q_FUNC_INFO, "invalid SSL context (null)");
+
+ auto *plainSocket = d->plainTcpSocket();
+ Q_ASSERT(plainSocket);
+
+ QCFType<SecTrustRef> trust;
+ OSStatus err = SSLCopyPeerTrust(context, &trust);
+ // !trust - SSLCopyPeerTrust can return errSecSuccess but null trust.
+ if (err != errSecSuccess || !trust) {
+ if (!canIgnoreVerify) {
+ setErrorAndEmit(d, QAbstractSocket::SslHandshakeFailedError,
+ QStringLiteral("Failed to obtain peer trust: %1").arg(err));
+ plainSocket->disconnectFromHost();
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ QList<QSslError> errors;
+
+ // Store certificates.
+ // Apple's docs say SetTrustEvaluate must be called before
+ // SecTrustGetCertificateAtIndex, but this results
+ // in 'kSecTrustResultRecoverableTrustFailure', so
+ // here we just ignore 'res' (later we'll use SetAnchor etc.
+ // and evaluate again).
+ SecTrustResultType res = kSecTrustResultInvalid;
+ err = SecTrustEvaluate(trust, &res);
+ if (err != errSecSuccess) {
+ // We can not ignore this, it's not even about trust verification
+ // probably ...
+ setErrorAndEmit(d, QAbstractSocket::SslHandshakeFailedError,
+ QStringLiteral("SecTrustEvaluate failed: %1").arg(err));
+ plainSocket->disconnectFromHost();
+ return false;
+ }
+
+ QTlsBackend::clearPeerCertificates(d);
+
+ QList<QSslCertificate> peerCertificateChain;
+ const CFIndex certCount = SecTrustGetCertificateCount(trust);
+ for (CFIndex i = 0; i < certCount; ++i) {
+ SecCertificateRef cert = SecTrustGetCertificateAtIndex(trust, i);
+ QCFType<CFDataRef> derData = SecCertificateCopyData(cert);
+ peerCertificateChain << QSslCertificate(QByteArray::fromCFData(derData), QSsl::Der);
+ }
+ QTlsBackend::storePeerCertificateChain(d, peerCertificateChain);
+
+ if (peerCertificateChain.size())
+ QTlsBackend::storePeerCertificate(d, peerCertificateChain.at(0));
+
+ // Check the whole chain for blacklisting (including root, as we check for subjectInfo and issuer):
+ for (const QSslCertificate &cert : std::as_const(peerCertificateChain)) {
+ if (QSslCertificatePrivate::isBlacklisted(cert) && !canIgnoreVerify) {
+ const QSslError error(QSslError::CertificateBlacklisted, cert);
+ errors << error;
+ emit q->peerVerifyError(error);
+ if (q->state() != QAbstractSocket::ConnectedState)
+ return false;
+ }
+ }
+
+ const bool doVerifyPeer = verifyMode == QSslSocket::VerifyPeer
+ || (verifyMode == QSslSocket::AutoVerifyPeer
+ && d->tlsMode() == QSslSocket::SslClientMode);
+ // Check the peer certificate itself. First try the subject's common name
+ // (CN) as a wildcard, then try all alternate subject name DNS entries the
+ // same way.
+ const auto &peerCertificate = q->peerCertificate();
+ if (!peerCertificate.isNull()) {
+ // but only if we're a client connecting to a server
+ // if we're the server, don't check CN
+ const QString verificationPeerName = d->verificationName();
+ if (mode == QSslSocket::SslClientMode) {
+ const QString peerName(verificationPeerName.isEmpty () ? q->peerName() : verificationPeerName);
+ if (!isMatchingHostname(peerCertificate, peerName) && !canIgnoreVerify) {
+ // No matches in common names or alternate names.
+ const QSslError error(QSslError::HostNameMismatch, peerCertificate);
+ errors << error;
+ emit q->peerVerifyError(error);
+ if (q->state() != QAbstractSocket::ConnectedState)
+ return false;
+ }
+ }
+ } else {
+ // No peer certificate presented. Report as error if the socket
+ // expected one.
+ if (doVerifyPeer && !canIgnoreVerify) {
+ const QSslError error(QSslError::NoPeerCertificate);
+ errors << error;
+ emit q->peerVerifyError(error);
+ if (q->state() != QAbstractSocket::ConnectedState)
+ return false;
+ }
+ }
+
+ // verify certificate chain
+ QCFType<CFMutableArrayRef> certArray = CFArrayCreateMutable(nullptr, 0, &kCFTypeArrayCallBacks);
+ const auto &caCertificates = q->sslConfiguration().caCertificates();
+ for (const QSslCertificate &cert : caCertificates) {
+ QCFType<CFDataRef> certData = cert.toDer().toCFData();
+ if (QCFType<SecCertificateRef> secRef = SecCertificateCreateWithData(nullptr, certData))
+ CFArrayAppendValue(certArray, secRef);
+ }
+
+ SecTrustSetAnchorCertificates(trust, certArray);
+
+ // By default SecTrustEvaluate uses both CA certificates provided in
+ // QSslConfiguration and the ones from the system database. This behavior can
+ // be unexpected if a user's code tries to limit the trusted CAs to those
+ // explicitly set in QSslConfiguration.
+ // Since on macOS we initialize the default QSslConfiguration copying the
+ // system CA certificates (using SecTrustSettingsCopyCertificates) we can
+ // call SecTrustSetAnchorCertificatesOnly(trust, true) to force SecTrustEvaluate
+ // to use anchors only from our QSslConfiguration.
+ // Unfortunately, SecTrustSettingsCopyCertificates is not available on iOS
+ // and the default QSslConfiguration always has an empty list of system CA
+ // certificates. This leaves no way to provide client code with access to the
+ // actual system CA certificate list (which most use-cases need) other than
+ // by letting SecTrustEvaluate fall through to the system list; so, in this case
+ // (even though the client code may have provided its own certs), we retain
+ // the default behavior. Note, with macOS SDK below 10.12 using 'trust my
+ // anchors only' may result in some valid chains rejected, apparently the
+ // ones containing intermediated certificates; so we use this functionality
+ // on more recent versions only.
+
+ bool anchorsFromConfigurationOnly = false;
+
+#ifdef Q_OS_MACOS
+ if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::MacOSSierra)
+ anchorsFromConfigurationOnly = true;
+#endif // Q_OS_MACOS
+
+ SecTrustSetAnchorCertificatesOnly(trust, anchorsFromConfigurationOnly);
+
+ SecTrustResultType trustResult = kSecTrustResultInvalid;
+ SecTrustEvaluate(trust, &trustResult);
+ switch (trustResult) {
+ case kSecTrustResultUnspecified:
+ case kSecTrustResultProceed:
+ break;
+ default:
+ if (!canIgnoreVerify) {
+ const QSslError error(QSslError::CertificateUntrusted, peerCertificate);
+ errors << error;
+ emit q->peerVerifyError(error);
+ }
+ }
+
+ // report errors
+ if (!errors.isEmpty() && !canIgnoreVerify) {
+ sslErrors = errors;
+ // checkSslErrors unconditionally emits sslErrors:
+ // a user's slot can abort/close/disconnect on this
+ // signal, so we also test the socket's state:
+ if (!checkSslErrors() || q->state() != QAbstractSocket::ConnectedState)
+ return false;
+ } else {
+ sslErrors.clear();
+ }
+
+ return true;
+}
+
+/*
+ Copied verbatim from qsslsocket_openssl.cpp
+*/
+bool TlsCryptographSecureTransport::checkSslErrors()
+{
+ if (sslErrors.isEmpty())
+ return true;
+
+ Q_ASSERT(q);
+ Q_ASSERT(d);
+
+ emit q->sslErrors(sslErrors);
+ const auto mode = d->tlsMode();
+ const auto &configuration = q->sslConfiguration();
+ const bool doVerifyPeer = configuration.peerVerifyMode() == QSslSocket::VerifyPeer
+ || (configuration.peerVerifyMode() == QSslSocket::AutoVerifyPeer
+ && mode == QSslSocket::SslClientMode);
+ const bool doEmitSslError = !d->verifyErrorsHaveBeenIgnored();
+ // check whether we need to emit an SSL handshake error
+ if (doVerifyPeer && doEmitSslError) {
+ if (q->pauseMode() & QAbstractSocket::PauseOnSslErrors) {
+ QSslSocketPrivate::pauseSocketNotifiers(q);
+ d->setPaused(true);
+ } else {
+ setErrorAndEmit(d, QAbstractSocket::SslHandshakeFailedError,
+ sslErrors.constFirst().errorString());
+ Q_ASSERT(d->plainTcpSocket());
+ d->plainTcpSocket()->disconnectFromHost();
+ }
+ return false;
+ }
+
+ return true;
+}
+
+bool TlsCryptographSecureTransport::startHandshake()
+{
+ Q_ASSERT(context);
+ Q_ASSERT(q);
+ Q_ASSERT(d);
+
+ auto *plainSocket = d->plainTcpSocket();
+ Q_ASSERT(plainSocket);
+ const auto mode = d->tlsMode();
+
+ OSStatus err = SSLHandshake(context);
+#ifdef QSSLSOCKET_DEBUG
+ qCDebug(lcSecureTransport) << plainSocket << "SSLHandhake returned" << err;
+#endif
+
+ if (err == errSSLWouldBlock) {
+ // startHandshake has to be called again ... later.
+ return false;
+ } else if (err == errSSLServerAuthCompleted) {
+ // errSSLServerAuthCompleted is a define for errSSLPeerAuthCompleted,
+ // it works for both server/client modes.
+ // In future we'll evaluate peer's trust at this point,
+ // for now we just continue.
+ // if (!verifyPeerTrust())
+ // ...
+ return startHandshake();
+ } else if (err == errSSLClientCertRequested) {
+ Q_ASSERT(mode == QSslSocket::SslClientMode);
+ QString errorDescription;
+ QAbstractSocket::SocketError errorCode = QAbstractSocket::UnknownSocketError;
+ // setSessionCertificate does not fail if we have no certificate.
+ // Failure means a real error (invalid certificate, no private key, etc).
+ if (!setSessionCertificate(errorDescription, errorCode)) {
+ setErrorAndEmit(d, errorCode, errorDescription);
+ renegotiating = false;
+ return false;
+ } else {
+ // We try to resume a handshake, even if have no
+ // local certificates ... (up to server to deal with our failure).
+ return startHandshake();
+ }
+ } else if (err != errSecSuccess) {
+ if (err == errSSLBadCert && canIgnoreTrustVerificationFailure()) {
+ // We're on the server side and client did not provide any
+ // certificate. This is the new 'nice' error returned by
+ // Security Framework after it was recently updated.
+ return startHandshake();
+ }
+
+ renegotiating = false;
+ setErrorAndEmit(d, QAbstractSocket::SslHandshakeFailedError,
+ QStringLiteral("SSLHandshake failed: %1").arg(err));
+ plainSocket->disconnectFromHost();
+ return false;
+ }
+
+ // Connection aborted during handshake phase.
+ if (q->state() != QAbstractSocket::ConnectedState) {
+ qCDebug(lcSecureTransport) << "connection aborted";
+ renegotiating = false;
+ return false;
+ }
+
+ // check protocol version ourselves, as Secure Transport does not enforce
+ // the requested min / max versions.
+ if (!verifySessionProtocol()) {
+ setErrorAndEmit(d, QAbstractSocket::SslHandshakeFailedError, QStringLiteral("Protocol version mismatch"));
+ plainSocket->disconnectFromHost();
+ renegotiating = false;
+ return false;
+ }
+
+ if (verifyPeerTrust()) {
+ continueHandshake();
+ renegotiating = false;
+ return true;
+ } else {
+ renegotiating = false;
+ return false;
+ }
+}
+
+bool TlsCryptographSecureTransport::isHandshakeComplete() const
+{
+ Q_ASSERT(q);
+ return q->isEncrypted() && !renegotiating;
+}
+
+QList<QSslError> TlsCryptographSecureTransport::tlsErrors() const
+{
+ return sslErrors;
+}
+
+} // namespace QTlsPrivate
+
+QT_END_NAMESPACE
diff --git a/src/plugins/tls/securetransport/qtls_st_p.h b/src/plugins/tls/securetransport/qtls_st_p.h
new file mode 100644
index 0000000000..2903ef4815
--- /dev/null
+++ b/src/plugins/tls/securetransport/qtls_st_p.h
@@ -0,0 +1,110 @@
+// Copyright (C) 2014 Jeremy Lainé <jeremy.laine@m4x.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QTLS_ST_P_H
+#define QTLS_ST_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of the QtNetwork library. This header file may change from
+// version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtNetwork/private/qtnetworkglobal_p.h>
+
+#include "qtlsbackend_st_p.h"
+
+#include <QtCore/qobject.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qglobal.h>
+#include <QtCore/qlist.h>
+
+#include <QtNetwork/qabstractsocket.h>
+#include <QtNetwork/private/qsslsocket_p.h>
+
+#warning SecureTransport was deprecated in macOS 10.15 and iOS 13, \
+and is no longer supported. We should be using Network.framework instead. \
+See QTBUG-85231 for more information.
+QT_WARNING_DISABLE_DEPRECATED
+
+#include <Security/Security.h>
+#include <Security/SecureTransport.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QTlsPrivate {
+
+class QSecureTransportContext
+{
+public:
+ explicit QSecureTransportContext(SSLContextRef context);
+ ~QSecureTransportContext();
+
+ operator SSLContextRef () const;
+ void reset(SSLContextRef newContext);
+private:
+ SSLContextRef context;
+
+ Q_DISABLE_COPY_MOVE(QSecureTransportContext)
+};
+
+class TlsCryptographSecureTransport : public TlsCryptograph
+{
+public:
+ TlsCryptographSecureTransport();
+ ~TlsCryptographSecureTransport() override;
+
+ void init(QSslSocket *qObj, QSslSocketPrivate *dObj) override;
+ void continueHandshake() override;
+ void disconnected() override;
+ void disconnectFromHost() override;
+ QSslCipher sessionCipher() const override;
+ QSsl::SslProtocol sessionProtocol() const override;
+ void startClientEncryption() override;
+ void startServerEncryption() override;
+ void transmit() override;
+ QList<QSslError> tlsErrors() const override;
+
+ SSLCipherSuite SSLCipherSuite_from_QSslCipher(const QSslCipher &ciph);
+
+private:
+ // SSL context management/properties:
+ bool initSslContext();
+ void destroySslContext();
+ bool setSessionCertificate(QString &errorDescription,
+ QAbstractSocket::SocketError &errorCode);
+ bool setSessionProtocol();
+ // Aux. functions to do a verification during handshake phase:
+ bool canIgnoreTrustVerificationFailure() const;
+ bool verifySessionProtocol() const;
+ bool verifyPeerTrust();
+
+ bool checkSslErrors();
+ bool startHandshake();
+
+ bool isHandshakeComplete() const;
+
+ // IO callbacks:
+ static OSStatus ReadCallback(TlsCryptographSecureTransport *socket, char *data, size_t *dataLength);
+ static OSStatus WriteCallback(TlsCryptographSecureTransport *plainSocket, const char *data, size_t *dataLength);
+
+ QSecureTransportContext context;
+ bool renegotiating = false;
+ QSslSocket *q = nullptr;
+ QSslSocketPrivate *d = nullptr;
+ bool shutdown = false;
+ QList<QSslError> sslErrors;
+
+ Q_DISABLE_COPY_MOVE(TlsCryptographSecureTransport)
+};
+
+} // namespace QTlsPrivate
+
+QT_END_NAMESPACE
+
+#endif // QTLS_ST_P_H
diff --git a/src/plugins/tls/securetransport/qtlsbackend_st.cpp b/src/plugins/tls/securetransport/qtlsbackend_st.cpp
new file mode 100644
index 0000000000..54e45d1720
--- /dev/null
+++ b/src/plugins/tls/securetransport/qtlsbackend_st.cpp
@@ -0,0 +1,361 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qtlsbackend_st_p.h"
+#include "qtlskey_st_p.h"
+#include "qx509_st_p.h"
+#include "qtls_st_p.h"
+
+#include <QtCore/qsysinfo.h>
+#include <QtCore/qmutex.h>
+
+QT_BEGIN_NAMESPACE
+
+using namespace Qt::StringLiterals;
+
+Q_GLOBAL_STATIC(QRecursiveMutex, qt_securetransport_mutex)
+
+Q_LOGGING_CATEGORY(lcSecureTransport, "qt.tlsbackend.securetransport");
+
+namespace QTlsPrivate {
+
+QList<QSslCertificate> systemCaCertificates(); // defined in qsslsocket_mac_shared.cpp
+
+SSLContextRef qt_createSecureTransportContext(QSslSocket::SslMode mode);
+
+QSslCipher QSslCipher_from_SSLCipherSuite(SSLCipherSuite cipher)
+{
+ QString name;
+ switch (cipher) {
+ // Sorted as in CipherSuite.h (and groupped by their RFC)
+ // TLS addenda using AES, per RFC 3268
+ case TLS_RSA_WITH_AES_128_CBC_SHA:
+ name = "AES128-SHA"_L1;
+ break;
+ case TLS_DHE_RSA_WITH_AES_128_CBC_SHA:
+ name = "DHE-RSA-AES128-SHA"_L1;
+ break;
+ case TLS_RSA_WITH_AES_256_CBC_SHA:
+ name = "AES256-SHA"_L1;
+ break;
+ case TLS_DHE_RSA_WITH_AES_256_CBC_SHA:
+ name = "DHE-RSA-AES256-SHA"_L1;
+ break;
+
+ // ECDSA addenda, RFC 4492
+ case TLS_ECDH_ECDSA_WITH_NULL_SHA:
+ name = "ECDH-ECDSA-NULL-SHA"_L1;
+ break;
+ case TLS_ECDH_ECDSA_WITH_RC4_128_SHA:
+ name = "ECDH-ECDSA-RC4-SHA"_L1;
+ break;
+ case TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA:
+ name = "ECDH-ECDSA-DES-CBC3-SHA"_L1;
+ break;
+ case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA:
+ name = "ECDH-ECDSA-AES128-SHA"_L1;
+ break;
+ case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA:
+ name = "ECDH-ECDSA-AES256-SHA"_L1;
+ break;
+ case TLS_ECDHE_ECDSA_WITH_NULL_SHA:
+ name = "ECDHE-ECDSA-NULL-SHA"_L1;
+ break;
+ case TLS_ECDHE_ECDSA_WITH_RC4_128_SHA:
+ name = "ECDHE-ECDSA-RC4-SHA"_L1;
+ break;
+ case TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA:
+ name = "ECDHE-ECDSA-DES-CBC3-SHA"_L1;
+ break;
+ case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA:
+ name = "ECDHE-ECDSA-AES128-SHA"_L1;
+ break;
+ case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:
+ name = "ECDHE-ECDSA-AES256-SHA"_L1;
+ break;
+ case TLS_ECDH_RSA_WITH_NULL_SHA:
+ name = "ECDH-RSA-NULL-SHA"_L1;
+ break;
+ case TLS_ECDH_RSA_WITH_RC4_128_SHA:
+ name = "ECDH-RSA-RC4-SHA"_L1;
+ break;
+ case TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA:
+ name = "ECDH-RSA-DES-CBC3-SHA"_L1;
+ break;
+ case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA:
+ name = "ECDH-RSA-AES128-SHA"_L1;
+ break;
+ case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA:
+ name = "ECDH-RSA-AES256-SHA"_L1;
+ break;
+ case TLS_ECDHE_RSA_WITH_NULL_SHA:
+ name = "ECDHE-RSA-NULL-SHA"_L1;
+ break;
+ case TLS_ECDHE_RSA_WITH_RC4_128_SHA:
+ name = "ECDHE-RSA-RC4-SHA"_L1;
+ break;
+ case TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA:
+ name = "ECDHE-RSA-DES-CBC3-SHA"_L1;
+ break;
+ case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:
+ name = "ECDHE-RSA-AES128-SHA"_L1;
+ break;
+ case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:
+ name = "ECDHE-RSA-AES256-SHA"_L1;
+ break;
+
+ // TLS 1.2 addenda, RFC 5246
+ case TLS_RSA_WITH_3DES_EDE_CBC_SHA:
+ name = "DES-CBC3-SHA"_L1;
+ break;
+ case TLS_RSA_WITH_AES_128_CBC_SHA256:
+ name = "AES128-SHA256"_L1;
+ break;
+ case TLS_RSA_WITH_AES_256_CBC_SHA256:
+ name = "AES256-SHA256"_L1;
+ break;
+ case TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA:
+ name = "DHE-RSA-DES-CBC3-SHA"_L1;
+ break;
+ case TLS_DHE_RSA_WITH_AES_128_CBC_SHA256:
+ name = "DHE-RSA-AES128-SHA256"_L1;
+ break;
+ case TLS_DHE_RSA_WITH_AES_256_CBC_SHA256:
+ name = "DHE-RSA-AES256-SHA256"_L1;
+ break;
+
+ // Addendum from RFC 4279, TLS PSK
+ // all missing atm.
+
+ // RFC 4785 - Pre-Shared Key (PSK) Ciphersuites with NULL Encryption
+ // all missing atm.
+
+ // Addenda from rfc 5288 AES Galois Counter Mode (CGM) Cipher Suites for TLS
+ case TLS_RSA_WITH_AES_256_GCM_SHA384:
+ name = "AES256-GCM-SHA384"_L1;
+ break;
+
+ // RFC 5487 - PSK with SHA-256/384 and AES GCM
+ // all missing atm.
+
+ // Addenda from rfc 5289 Elliptic Curve Cipher Suites with HMAC SHA-256/384
+ case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256:
+ name = "ECDHE-ECDSA-AES128-SHA256"_L1;
+ break;
+ case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384:
+ name = "ECDHE-ECDSA-AES256-SHA384"_L1;
+ break;
+ case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256:
+ name = "ECDH-ECDSA-AES128-SHA256"_L1;
+ break;
+ case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384:
+ name = "ECDH-ECDSA-AES256-SHA384"_L1;
+ break;
+ case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:
+ name = "ECDHE-RSA-AES128-SHA256"_L1;
+ break;
+ case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384:
+ name = "ECDHE-RSA-AES256-SHA384"_L1;
+ break;
+ case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256:
+ name = "ECDH-RSA-AES128-SHA256"_L1;
+ break;
+ case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384:
+ name = "ECDH-RSA-AES256-SHA384"_L1;
+ break;
+
+ // Addenda from rfc 5289 Elliptic Curve Cipher Suites
+ // with SHA-256/384 and AES Galois Counter Mode (GCM)
+ case TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:
+ name = "ECDHE-RSA-AES256-GCM-SHA384"_L1;
+ break;
+
+ // TLS 1.3 standard cipher suites for ChaCha20+Poly1305.
+ // Note: TLS 1.3 ciphersuites do not specify the key exchange
+ // algorithm -- they only specify the symmetric ciphers.
+ case TLS_AES_128_GCM_SHA256:
+ name = "AES128-GCM-SHA256"_L1;
+ break;
+ case TLS_AES_256_GCM_SHA384:
+ name = "AES256-GCM-SHA384"_L1;
+ break;
+ case TLS_CHACHA20_POLY1305_SHA256:
+ name = "CHACHA20-POLY1305-SHA256"_L1;
+ break;
+ case TLS_AES_128_CCM_SHA256:
+ name = "AES128-CCM-SHA256"_L1;
+ break;
+ case TLS_AES_128_CCM_8_SHA256:
+ name = "AES128-CCM8-SHA256"_L1;
+ break;
+ // Addenda from rfc 5289 Elliptic Curve Cipher Suites with
+ // SHA-256/384 and AES Galois Counter Mode (GCM).
+ case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
+ name = "ECDHE-ECDSA-AES128-GCM-SHA256"_L1;
+ break;
+ case TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:
+ name = "ECDHE-ECDSA-AES256-GCM-SHA384"_L1;
+ break;
+ case TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256:
+ name = "ECDH-ECDSA-AES128-GCM-SHA256"_L1;
+ break;
+ case TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384:
+ name = "ECDH-ECDSA-AES256-GCM-SHA384"_L1;
+ break;
+ case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:
+ name = "ECDHE-RSA-AES128-GCM-SHA256"_L1;
+ break;
+ case TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256:
+ name = "ECDH-RSA-AES128-GCM-SHA256"_L1;
+ break;
+ case TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384:
+ name = "ECDH-RSA-AES256-GCM-SHA384"_L1;
+ break;
+ // Addenda from rfc 7905 ChaCha20-Poly1305 Cipher Suites for
+ // Transport Layer Security (TLS).
+ case TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
+ name = "ECDHE-RSA-CHACHA20-POLY1305-SHA256"_L1;
+ break;
+ case TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:
+ name = "ECDHE-ECDSA-CHACHA20-POLY1305-SHA256"_L1;
+ break;
+ default:
+ return {};
+ }
+
+ return QTlsBackend::createCiphersuite(name, QSsl::TlsV1_2, "TLSv1.2"_L1);
+}
+
+} // namespace QTlsPrivate
+
+bool QSecureTransportBackend::s_loadedCiphersAndCerts = false;
+
+QString QSecureTransportBackend::tlsLibraryVersionString() const
+{
+ return "Secure Transport, "_L1 + QSysInfo::prettyProductName();
+}
+
+QString QSecureTransportBackend::tlsLibraryBuildVersionString() const
+{
+ return tlsLibraryVersionString();
+}
+
+void QSecureTransportBackend::ensureInitialized() const
+{
+ const QMutexLocker locker(qt_securetransport_mutex());
+ if (s_loadedCiphersAndCerts)
+ return;
+
+ // We have to set it before setDefaultSupportedCiphers,
+ // since this function can trigger static (global)'s initialization
+ // and as a result - recursive ensureInitialized call
+ // from QSslCertificatePrivate's ctor.
+ s_loadedCiphersAndCerts = true;
+
+ const QTlsPrivate::QSecureTransportContext context(QTlsPrivate::qt_createSecureTransportContext(QSslSocket::SslClientMode));
+ if (context) {
+ QList<QSslCipher> ciphers;
+ QList<QSslCipher> defaultCiphers;
+
+ size_t numCiphers = 0;
+ // Fails only if any of parameters is null.
+ SSLGetNumberSupportedCiphers(context, &numCiphers);
+ QList<SSLCipherSuite> cfCiphers(numCiphers);
+ // Fails only if any of parameter is null or number of ciphers is wrong.
+ SSLGetSupportedCiphers(context, cfCiphers.data(), &numCiphers);
+
+ for (size_t i = 0; i < size_t(cfCiphers.size()); ++i) {
+ const QSslCipher ciph(QTlsPrivate::QSslCipher_from_SSLCipherSuite(cfCiphers.at(i)));
+ if (!ciph.isNull()) {
+ ciphers << ciph;
+ if (ciph.usedBits() >= 128)
+ defaultCiphers << ciph;
+ }
+ }
+
+ setDefaultSupportedCiphers(ciphers);
+ setDefaultCiphers(defaultCiphers);
+
+ if (!QSslSocketPrivate::rootCertOnDemandLoadingSupported())
+ setDefaultCaCertificates(systemCaCertificates());
+ } else {
+ s_loadedCiphersAndCerts = false;
+ }
+}
+
+QString QSecureTransportBackend::backendName() const
+{
+ return builtinBackendNames[nameIndexSecureTransport];
+}
+
+QTlsPrivate::TlsKey *QSecureTransportBackend::createKey() const
+{
+ return new QTlsPrivate::TlsKeySecureTransport;
+}
+
+QTlsPrivate::X509Certificate *QSecureTransportBackend::createCertificate() const
+{
+ return new QTlsPrivate::X509CertificateSecureTransport;
+}
+
+QList<QSslCertificate> QSecureTransportBackend::systemCaCertificates() const
+{
+ return QTlsPrivate::systemCaCertificates();
+}
+
+QList<QSsl::SslProtocol> QSecureTransportBackend::supportedProtocols() const
+{
+ QList<QSsl::SslProtocol> protocols;
+
+ 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;
+
+ return protocols;
+}
+
+QList<QSsl::SupportedFeature> QSecureTransportBackend::supportedFeatures() const
+{
+ QList<QSsl::SupportedFeature> features;
+ features << QSsl::SupportedFeature::ClientSideAlpn;
+
+ return features;
+}
+
+QList<QSsl::ImplementedClass> QSecureTransportBackend::implementedClasses() const
+{
+ QList<QSsl::ImplementedClass> classes;
+ classes << QSsl::ImplementedClass::Socket;
+ classes << QSsl::ImplementedClass::Certificate;
+ classes << QSsl::ImplementedClass::Key;
+
+ return classes;
+}
+
+QTlsPrivate::X509PemReaderPtr QSecureTransportBackend::X509PemReader() const
+{
+ return QTlsPrivate::X509CertificateGeneric::certificatesFromPem;
+}
+
+QTlsPrivate::X509DerReaderPtr QSecureTransportBackend::X509DerReader() const
+{
+ return QTlsPrivate::X509CertificateGeneric::certificatesFromDer;
+}
+
+QTlsPrivate::TlsCryptograph *QSecureTransportBackend::createTlsCryptograph() const
+{
+ return new QTlsPrivate::TlsCryptographSecureTransport;
+}
+
+QT_END_NAMESPACE
+
+
+#include "moc_qtlsbackend_st_p.cpp"
diff --git a/src/plugins/tls/securetransport/qtlsbackend_st_p.h b/src/plugins/tls/securetransport/qtlsbackend_st_p.h
new file mode 100644
index 0000000000..968a080cd4
--- /dev/null
+++ b/src/plugins/tls/securetransport/qtlsbackend_st_p.h
@@ -0,0 +1,64 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QTLSBACKEND_ST_P_H
+#define QTLSBACKEND_ST_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 <QtNetwork/private/qtnetworkglobal_p.h>
+
+#include <QtNetwork/private/qtlsbackend_p.h>
+
+#include <QtCore/qglobal.h>
+
+
+QT_BEGIN_NAMESPACE
+
+class QSecureTransportBackend : public QTlsBackend
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID QTlsBackend_iid)
+ Q_INTERFACES(QTlsBackend)
+
+private:
+
+ QString tlsLibraryVersionString() const override;
+ virtual QString tlsLibraryBuildVersionString() const override;
+ virtual void ensureInitialized() const override;
+
+ QString backendName() const override;
+
+ QList<QSsl::SslProtocol> supportedProtocols() const override;
+ QList<QSsl::SupportedFeature> supportedFeatures() const override;
+ QList<QSsl::ImplementedClass> implementedClasses() const override;
+
+ QTlsPrivate::TlsKey *createKey() const override;
+ QTlsPrivate::X509Certificate *createCertificate() const override;
+
+ QList<QSslCertificate> systemCaCertificates() const override;
+
+ QTlsPrivate::X509PemReaderPtr X509PemReader() const override;
+ QTlsPrivate::X509DerReaderPtr X509DerReader() const override;
+
+ QTlsPrivate::TlsCryptograph *createTlsCryptograph() const override;
+
+ static bool s_loadedCiphersAndCerts;
+};
+
+Q_DECLARE_LOGGING_CATEGORY(lcSecureTransport)
+
+QT_END_NAMESPACE
+
+#endif // QTLSBACKEND_ST_P_H
+
+
diff --git a/src/plugins/tls/securetransport/qtlskey_st.cpp b/src/plugins/tls/securetransport/qtlskey_st.cpp
new file mode 100644
index 0000000000..db4187ee03
--- /dev/null
+++ b/src/plugins/tls/securetransport/qtlskey_st.cpp
@@ -0,0 +1,75 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// Copyright (C) 2014 Jeremy Lainé <jeremy.laine@m4x.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qtlskey_st_p.h"
+
+#include <QtNetwork/private/qsslkey_p.h>
+
+#include <QtCore/qbytearray.h>
+
+#include <CommonCrypto/CommonCrypto.h>
+
+#include <cstddef>
+
+QT_BEGIN_NAMESPACE
+
+namespace QTlsPrivate {
+namespace {
+
+// Before this code was located in qsslkey_mac.cpp.
+QByteArray wrapCCCrypt(CCOperation ccOp, QSslKeyPrivate::Cipher cipher,
+ const QByteArray &data, const QByteArray &key,
+ const QByteArray &iv)
+{
+ int blockSize = {};
+ CCAlgorithm ccAlgorithm = {};
+ switch (cipher) {
+ case Cipher::DesCbc:
+ blockSize = kCCBlockSizeDES;
+ ccAlgorithm = kCCAlgorithmDES;
+ break;
+ case Cipher::DesEde3Cbc:
+ blockSize = kCCBlockSize3DES;
+ ccAlgorithm = kCCAlgorithm3DES;
+ break;
+ case Cipher::Rc2Cbc:
+ blockSize = kCCBlockSizeRC2;
+ ccAlgorithm = kCCAlgorithmRC2;
+ break;
+ case Cipher::Aes128Cbc:
+ case Cipher::Aes192Cbc:
+ case Cipher::Aes256Cbc:
+ blockSize = kCCBlockSizeAES128;
+ ccAlgorithm = kCCAlgorithmAES;
+ break;
+ }
+ std::size_t plainLength = 0;
+ QByteArray plain(data.size() + blockSize, 0);
+ CCCryptorStatus status = CCCrypt(ccOp, ccAlgorithm, kCCOptionPKCS7Padding,
+ key.constData(), std::size_t(key.size()),
+ iv.constData(), data.constData(), std::size_t(data.size()),
+ plain.data(), std::size_t(plain.size()), &plainLength);
+ if (status == kCCSuccess)
+ return plain.left(int(plainLength));
+
+ return {};
+}
+
+} // Unnamed namespace.
+
+QByteArray TlsKeySecureTransport::decrypt(Cipher cipher, const QByteArray &data,
+ const QByteArray &key, const QByteArray &iv) const
+{
+ return wrapCCCrypt(kCCDecrypt, cipher, data, key, iv);
+}
+
+QByteArray TlsKeySecureTransport::encrypt(Cipher cipher, const QByteArray &data,
+ const QByteArray &key, const QByteArray &iv) const
+{
+ return wrapCCCrypt(kCCEncrypt, cipher, data, key, iv);
+}
+
+} // namespace QTlsPrivate
+
+QT_END_NAMESPACE
diff --git a/src/plugins/tls/securetransport/qtlskey_st_p.h b/src/plugins/tls/securetransport/qtlskey_st_p.h
new file mode 100644
index 0000000000..62e1173941
--- /dev/null
+++ b/src/plugins/tls/securetransport/qtlskey_st_p.h
@@ -0,0 +1,47 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QTLSKEY_ST_P_H
+#define QTLSKEY_ST_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 <QtNetwork/private/qtnetworkglobal_p.h>
+
+#include "../shared/qtlskey_generic_p.h"
+
+#include <QtCore/qglobal.h>
+
+QT_REQUIRE_CONFIG(ssl);
+
+QT_BEGIN_NAMESPACE
+
+namespace QTlsPrivate {
+
+class TlsKeySecureTransport final : public TlsKeyGeneric
+{
+public:
+ using TlsKeyGeneric::TlsKeyGeneric;
+
+ QByteArray decrypt(Cipher cipher, const QByteArray &data,
+ const QByteArray &key, const QByteArray &iv) const override;
+ QByteArray encrypt(Cipher cipher, const QByteArray &data,
+ const QByteArray &key, const QByteArray &iv) const override;
+
+ Q_DISABLE_COPY_MOVE(TlsKeySecureTransport)
+};
+
+} // namespace QTlsPrivate
+
+QT_END_NAMESPACE
+
+#endif // QTLSKEY_ST_P_H
diff --git a/src/plugins/tls/securetransport/qx509_st.cpp b/src/plugins/tls/securetransport/qx509_st.cpp
new file mode 100644
index 0000000000..3f797a6891
--- /dev/null
+++ b/src/plugins/tls/securetransport/qx509_st.cpp
@@ -0,0 +1,25 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qtlskey_st_p.h"
+#include "qx509_st_p.h"
+
+#include <memory>
+
+QT_BEGIN_NAMESPACE
+
+namespace QTlsPrivate {
+
+TlsKey *X509CertificateSecureTransport::publicKey() const
+{
+ auto key = std::make_unique<TlsKeySecureTransport>(QSsl::PublicKey);
+ if (publicKeyAlgorithm != QSsl::Opaque)
+ key->decodeDer(QSsl::PublicKey, publicKeyAlgorithm, publicKeyDerData, {}, false);
+
+ return key.release();
+}
+
+} // namespace QTlsPrivate
+
+QT_END_NAMESPACE
+
diff --git a/src/plugins/tls/securetransport/qx509_st_p.h b/src/plugins/tls/securetransport/qx509_st_p.h
new file mode 100644
index 0000000000..bda89231ed
--- /dev/null
+++ b/src/plugins/tls/securetransport/qx509_st_p.h
@@ -0,0 +1,38 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QX509_ST_P_H
+#define QX509_ST_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 <QtNetwork/private/qtnetworkglobal_p.h>
+
+#include "../shared/qx509_generic_p.h"
+
+#include <QtCore/qglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QTlsPrivate {
+
+class X509CertificateSecureTransport final : public X509CertificateGeneric
+{
+public:
+ TlsKey *publicKey() const override;
+};
+
+} // namespace QTlsPrivate
+
+QT_END_NAMESPACE
+
+#endif // QX509_ST_P_H
diff --git a/src/plugins/tls/shared/qasn1element.cpp b/src/plugins/tls/shared/qasn1element.cpp
new file mode 100644
index 0000000000..97be46866d
--- /dev/null
+++ b/src/plugins/tls/shared/qasn1element.cpp
@@ -0,0 +1,353 @@
+// Copyright (C) 2014 Jeremy Lainé <jeremy.laine@m4x.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+
+#include "qasn1element_p.h"
+
+#include <QtCore/qdatastream.h>
+#include <QtCore/qdatetime.h>
+#include <QtCore/qtimezone.h>
+#include <QtCore/qlist.h>
+#include <QDebug>
+#include <private/qtools_p.h>
+
+#include <limits>
+
+QT_BEGIN_NAMESPACE
+
+using namespace QtMiscUtils;
+
+typedef QMap<QByteArray, QByteArray> OidNameMap;
+static OidNameMap createOidMap()
+{
+ OidNameMap oids;
+ // used by unit tests
+ oids.insert(oids.cend(), QByteArrayLiteral("0.9.2342.19200300.100.1.5"), QByteArrayLiteral("favouriteDrink"));
+ oids.insert(oids.cend(), QByteArrayLiteral("1.2.840.113549.1.9.1"), QByteArrayLiteral("emailAddress"));
+ oids.insert(oids.cend(), QByteArrayLiteral("1.3.6.1.5.5.7.1.1"), QByteArrayLiteral("authorityInfoAccess"));
+ oids.insert(oids.cend(), QByteArrayLiteral("1.3.6.1.5.5.7.48.1"), QByteArrayLiteral("OCSP"));
+ oids.insert(oids.cend(), QByteArrayLiteral("1.3.6.1.5.5.7.48.2"), QByteArrayLiteral("caIssuers"));
+ oids.insert(oids.cend(), QByteArrayLiteral("2.5.29.14"), QByteArrayLiteral("subjectKeyIdentifier"));
+ oids.insert(oids.cend(), QByteArrayLiteral("2.5.29.15"), QByteArrayLiteral("keyUsage"));
+ oids.insert(oids.cend(), QByteArrayLiteral("2.5.29.17"), QByteArrayLiteral("subjectAltName"));
+ oids.insert(oids.cend(), QByteArrayLiteral("2.5.29.19"), QByteArrayLiteral("basicConstraints"));
+ oids.insert(oids.cend(), QByteArrayLiteral("2.5.29.35"), QByteArrayLiteral("authorityKeyIdentifier"));
+ oids.insert(oids.cend(), QByteArrayLiteral("2.5.4.10"), QByteArrayLiteral("O"));
+ oids.insert(oids.cend(), QByteArrayLiteral("2.5.4.11"), QByteArrayLiteral("OU"));
+ oids.insert(oids.cend(), QByteArrayLiteral("2.5.4.12"), QByteArrayLiteral("title"));
+ oids.insert(oids.cend(), QByteArrayLiteral("2.5.4.13"), QByteArrayLiteral("description"));
+ oids.insert(oids.cend(), QByteArrayLiteral("2.5.4.17"), QByteArrayLiteral("postalCode"));
+ oids.insert(oids.cend(), QByteArrayLiteral("2.5.4.3"), QByteArrayLiteral("CN"));
+ oids.insert(oids.cend(), QByteArrayLiteral("2.5.4.4"), QByteArrayLiteral("SN"));
+ oids.insert(oids.cend(), QByteArrayLiteral("2.5.4.41"), QByteArrayLiteral("name"));
+ oids.insert(oids.cend(), QByteArrayLiteral("2.5.4.42"), QByteArrayLiteral("GN"));
+ oids.insert(oids.cend(), QByteArrayLiteral("2.5.4.43"), QByteArrayLiteral("initials"));
+ oids.insert(oids.cend(), QByteArrayLiteral("2.5.4.46"), QByteArrayLiteral("dnQualifier"));
+ oids.insert(oids.cend(), QByteArrayLiteral("2.5.4.5"), QByteArrayLiteral("serialNumber"));
+ oids.insert(oids.cend(), QByteArrayLiteral("2.5.4.6"), QByteArrayLiteral("C"));
+ oids.insert(oids.cend(), QByteArrayLiteral("2.5.4.7"), QByteArrayLiteral("L"));
+ oids.insert(oids.cend(), QByteArrayLiteral("2.5.4.8"), QByteArrayLiteral("ST"));
+ oids.insert(oids.cend(), QByteArrayLiteral("2.5.4.9"), QByteArrayLiteral("street"));
+ return oids;
+}
+Q_GLOBAL_STATIC_WITH_ARGS(OidNameMap, oidNameMap, (createOidMap()))
+
+QAsn1Element::QAsn1Element(quint8 type, const QByteArray &value)
+ : mType(type)
+ , mValue(value)
+{
+}
+
+bool QAsn1Element::read(QDataStream &stream)
+{
+ // type
+ quint8 tmpType;
+ stream >> tmpType;
+ if (!tmpType)
+ return false;
+
+ // length
+ quint64 length = 0;
+ quint8 first;
+ stream >> first;
+ if (first & 0x80) {
+ // long form
+ const quint8 bytes = (first & 0x7f);
+ if (bytes > 7)
+ return false;
+
+ quint8 b;
+ for (int i = 0; i < bytes; i++) {
+ stream >> b;
+ length = (length << 8) | b;
+ }
+ } else {
+ // short form
+ length = (first & 0x7f);
+ }
+
+ if (length > quint64(std::numeric_limits<int>::max()))
+ return false;
+
+ // read value in blocks to avoid being fooled by incorrect length
+ const int BUFFERSIZE = 4 * 1024;
+ QByteArray tmpValue;
+ int remainingLength = length;
+ while (remainingLength) {
+ char readBuffer[BUFFERSIZE];
+ const int bytesToRead = qMin(remainingLength, BUFFERSIZE);
+ const int count = stream.readRawData(readBuffer, bytesToRead);
+ if (count != int(bytesToRead))
+ return false;
+ tmpValue.append(readBuffer, bytesToRead);
+ remainingLength -= bytesToRead;
+ }
+
+ mType = tmpType;
+ mValue.swap(tmpValue);
+ return true;
+}
+
+bool QAsn1Element::read(const QByteArray &data)
+{
+ QDataStream stream(data);
+ return read(stream);
+}
+
+void QAsn1Element::write(QDataStream &stream) const
+{
+ // type
+ stream << mType;
+
+ // length
+ qint64 length = mValue.size();
+ if (length >= 128) {
+ // long form
+ quint8 encodedLength = 0x80;
+ QByteArray ba;
+ while (length) {
+ ba.prepend(quint8((length & 0xff)));
+ length >>= 8;
+ encodedLength += 1;
+ }
+ stream << encodedLength;
+ stream.writeRawData(ba.data(), ba.size());
+ } else {
+ // short form
+ stream << quint8(length);
+ }
+
+ // value
+ stream.writeRawData(mValue.data(), mValue.size());
+}
+
+QAsn1Element QAsn1Element::fromBool(bool val)
+{
+ return QAsn1Element(QAsn1Element::BooleanType,
+ QByteArray(1, val ? 0xff : 0x00));
+}
+
+QAsn1Element QAsn1Element::fromInteger(unsigned int val)
+{
+ QAsn1Element elem(QAsn1Element::IntegerType);
+ while (val > 127) {
+ elem.mValue.prepend(val & 0xff);
+ val >>= 8;
+ }
+ elem.mValue.prepend(val & 0x7f);
+ return elem;
+}
+
+QAsn1Element QAsn1Element::fromVector(const QList<QAsn1Element> &items)
+{
+ QAsn1Element seq;
+ seq.mType = SequenceType;
+ QDataStream stream(&seq.mValue, QDataStream::WriteOnly);
+ for (auto it = items.cbegin(), end = items.cend(); it != end; ++it)
+ it->write(stream);
+ return seq;
+}
+
+QAsn1Element QAsn1Element::fromObjectId(const QByteArray &id)
+{
+ QAsn1Element elem;
+ elem.mType = ObjectIdentifierType;
+ const QList<QByteArray> bits = id.split('.');
+ Q_ASSERT(bits.size() > 2);
+ elem.mValue += quint8((bits[0].toUInt() * 40 + bits[1].toUInt()));
+ for (int i = 2; i < bits.size(); ++i) {
+ char buffer[std::numeric_limits<unsigned int>::digits / 7 + 2];
+ char *pBuffer = buffer + sizeof(buffer);
+ *--pBuffer = '\0';
+ unsigned int node = bits[i].toUInt();
+ *--pBuffer = quint8((node & 0x7f));
+ node >>= 7;
+ while (node) {
+ *--pBuffer = quint8(((node & 0x7f) | 0x80));
+ node >>= 7;
+ }
+ elem.mValue += pBuffer;
+ }
+ return elem;
+}
+
+bool QAsn1Element::toBool(bool *ok) const
+{
+ if (*this == fromBool(true)) {
+ if (ok)
+ *ok = true;
+ return true;
+ } else if (*this == fromBool(false)) {
+ if (ok)
+ *ok = true;
+ return false;
+ } else {
+ if (ok)
+ *ok = false;
+ return false;
+ }
+}
+
+QDateTime QAsn1Element::toDateTime() const
+{
+ QDateTime result;
+
+ if (mValue.size() != 13 && mValue.size() != 15)
+ return result;
+
+ // QDateTime::fromString is lenient and accepts +- signs in front
+ // of the year; but ASN.1 doesn't allow them.
+ if (!isAsciiDigit(mValue[0]))
+ return result;
+
+ // Timezone must be present, and UTC
+ if (mValue.back() != 'Z')
+ return result;
+
+ if (mType == UtcTimeType && mValue.size() == 13) {
+ // RFC 2459:
+ // Where YY is greater than or equal to 50, the year shall be
+ // interpreted as 19YY; and
+ //
+ // Where YY is less than 50, the year shall be interpreted as 20YY.
+ //
+ // so use 1950 as base year.
+ constexpr int rfc2459CenturyStart = 1950;
+ const QLatin1StringView inputView(mValue);
+ QDate date = QDate::fromString(inputView.first(6), u"yyMMdd", rfc2459CenturyStart);
+ if (!date.isValid())
+ return result;
+
+ Q_ASSERT(date.year() >= rfc2459CenturyStart);
+ Q_ASSERT(date.year() < 100 + rfc2459CenturyStart);
+
+ QTime time = QTime::fromString(inputView.sliced(6, 6), u"HHmmss");
+ if (!time.isValid())
+ return result;
+ result = QDateTime(date, time, QTimeZone::UTC);
+ } else if (mType == GeneralizedTimeType && mValue.size() == 15) {
+ result = QDateTime::fromString(QString::fromLatin1(mValue), u"yyyyMMddHHmmsst");
+ }
+
+ return result;
+}
+
+QMultiMap<QByteArray, QString> QAsn1Element::toInfo() const
+{
+ QMultiMap<QByteArray, QString> info;
+ QAsn1Element elem;
+ QDataStream issuerStream(mValue);
+ while (elem.read(issuerStream) && elem.mType == QAsn1Element::SetType) {
+ QAsn1Element issuerElem;
+ QDataStream setStream(elem.mValue);
+ if (issuerElem.read(setStream) && issuerElem.mType == QAsn1Element::SequenceType) {
+ const auto elems = issuerElem.toList();
+ if (elems.size() == 2) {
+ const QByteArray key = elems.front().toObjectName();
+ if (!key.isEmpty())
+ info.insert(key, elems.back().toString());
+ }
+ }
+ }
+ return info;
+}
+
+qint64 QAsn1Element::toInteger(bool *ok) const
+{
+ if (mType != QAsn1Element::IntegerType || mValue.isEmpty()) {
+ if (ok)
+ *ok = false;
+ return 0;
+ }
+
+ // NOTE: - negative numbers are not handled
+ // - greater sizes would overflow
+ if (mValue.at(0) & 0x80 || mValue.size() > 8) {
+ if (ok)
+ *ok = false;
+ return 0;
+ }
+
+ qint64 value = mValue.at(0) & 0x7f;
+ for (int i = 1; i < mValue.size(); ++i)
+ value = (value << 8) | quint8(mValue.at(i));
+
+ if (ok)
+ *ok = true;
+ return value;
+}
+
+QList<QAsn1Element> QAsn1Element::toList() const
+{
+ QList<QAsn1Element> items;
+ if (mType == SequenceType) {
+ QAsn1Element elem;
+ QDataStream stream(mValue);
+ while (elem.read(stream))
+ items << elem;
+ }
+ return items;
+}
+
+QByteArray QAsn1Element::toObjectId() const
+{
+ QByteArray key;
+ if (mType == ObjectIdentifierType && !mValue.isEmpty()) {
+ quint8 b = mValue.at(0);
+ key += QByteArray::number(b / 40) + '.' + QByteArray::number (b % 40);
+ unsigned int val = 0;
+ for (int i = 1; i < mValue.size(); ++i) {
+ b = mValue.at(i);
+ val = (val << 7) | (b & 0x7f);
+ if (!(b & 0x80)) {
+ key += '.' + QByteArray::number(val);
+ val = 0;
+ }
+ }
+ }
+ return key;
+}
+
+QByteArray QAsn1Element::toObjectName() const
+{
+ QByteArray key = toObjectId();
+ return oidNameMap->value(key, key);
+}
+
+QString QAsn1Element::toString() const
+{
+ // Detect embedded NULs and reject
+ if (qstrlen(mValue) < uint(mValue.size()))
+ return QString();
+
+ if (mType == PrintableStringType || mType == TeletexStringType
+ || mType == Rfc822NameType || mType == DnsNameType
+ || mType == UniformResourceIdentifierType)
+ return QString::fromLatin1(mValue, mValue.size());
+ if (mType == Utf8StringType)
+ return QString::fromUtf8(mValue, mValue.size());
+
+ return QString();
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/tls/shared/qasn1element_p.h b/src/plugins/tls/shared/qasn1element_p.h
new file mode 100644
index 0000000000..0de46be009
--- /dev/null
+++ b/src/plugins/tls/shared/qasn1element_p.h
@@ -0,0 +1,152 @@
+// Copyright (C) 2014 Jeremy Lainé <jeremy.laine@m4x.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+
+#ifndef QASN1ELEMENT_P_H
+#define QASN1ELEMENT_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 <QtNetwork/private/qtnetworkglobal_p.h>
+#include <QtCore/qdatetime.h>
+#include <QtCore/qmap.h>
+
+QT_BEGIN_NAMESPACE
+
+// General
+#define RSADSI_OID "1.2.840.113549."
+
+#define RSA_ENCRYPTION_OID QByteArrayLiteral(RSADSI_OID "1.1.1")
+#define DSA_ENCRYPTION_OID QByteArrayLiteral("1.2.840.10040.4.1")
+#define EC_ENCRYPTION_OID QByteArrayLiteral("1.2.840.10045.2.1")
+#define DH_ENCRYPTION_OID QByteArrayLiteral(RSADSI_OID "1.3.1")
+
+// These are mostly from the RFC for PKCS#5
+// PKCS#5: https://tools.ietf.org/html/rfc8018#appendix-B
+#define PKCS5_OID RSADSI_OID "1.5."
+// PKCS#12: https://tools.ietf.org/html/rfc7292#appendix-D)
+#define PKCS12_OID RSADSI_OID "1.12."
+
+// -PBES1
+#define PKCS5_MD2_DES_CBC_OID QByteArrayLiteral(PKCS5_OID "1") // Not (yet) implemented
+#define PKCS5_MD2_RC2_CBC_OID QByteArrayLiteral(PKCS5_OID "4") // Not (yet) implemented
+#define PKCS5_MD5_DES_CBC_OID QByteArrayLiteral(PKCS5_OID "3")
+#define PKCS5_MD5_RC2_CBC_OID QByteArrayLiteral(PKCS5_OID "6")
+#define PKCS5_SHA1_DES_CBC_OID QByteArrayLiteral(PKCS5_OID "10")
+#define PKCS5_SHA1_RC2_CBC_OID QByteArrayLiteral(PKCS5_OID "11")
+#define PKCS12_SHA1_RC4_128_OID QByteArrayLiteral(PKCS12_OID "1.1") // Not (yet) implemented
+#define PKCS12_SHA1_RC4_40_OID QByteArrayLiteral(PKCS12_OID "1.2") // Not (yet) implemented
+#define PKCS12_SHA1_3KEY_3DES_CBC_OID QByteArrayLiteral(PKCS12_OID "1.3")
+#define PKCS12_SHA1_2KEY_3DES_CBC_OID QByteArrayLiteral(PKCS12_OID "1.4")
+#define PKCS12_SHA1_RC2_128_CBC_OID QByteArrayLiteral(PKCS12_OID "1.5")
+#define PKCS12_SHA1_RC2_40_CBC_OID QByteArrayLiteral(PKCS12_OID "1.6")
+
+// -PBKDF2
+#define PKCS5_PBKDF2_ENCRYPTION_OID QByteArrayLiteral(PKCS5_OID "12")
+
+// -PBES2
+#define PKCS5_PBES2_ENCRYPTION_OID QByteArrayLiteral(PKCS5_OID "13")
+
+// Digest
+#define DIGEST_ALGORITHM_OID RSADSI_OID "2."
+// -HMAC-SHA-1
+#define HMAC_WITH_SHA1 QByteArrayLiteral(DIGEST_ALGORITHM_OID "7")
+// -HMAC-SHA-2
+#define HMAC_WITH_SHA224 QByteArrayLiteral(DIGEST_ALGORITHM_OID "8")
+#define HMAC_WITH_SHA256 QByteArrayLiteral(DIGEST_ALGORITHM_OID "9")
+#define HMAC_WITH_SHA384 QByteArrayLiteral(DIGEST_ALGORITHM_OID "10")
+#define HMAC_WITH_SHA512 QByteArrayLiteral(DIGEST_ALGORITHM_OID "11")
+#define HMAC_WITH_SHA512_224 QByteArrayLiteral(DIGEST_ALGORITHM_OID "12")
+#define HMAC_WITH_SHA512_256 QByteArrayLiteral(DIGEST_ALGORITHM_OID "13")
+
+// Encryption algorithms
+#define ENCRYPTION_ALGORITHM_OID RSADSI_OID "3."
+#define DES_CBC_ENCRYPTION_OID QByteArrayLiteral("1.3.14.3.2.7")
+#define DES_EDE3_CBC_ENCRYPTION_OID QByteArrayLiteral(ENCRYPTION_ALGORITHM_OID "7")
+#define RC2_CBC_ENCRYPTION_OID QByteArrayLiteral(ENCRYPTION_ALGORITHM_OID "2")
+#define RC5_CBC_ENCRYPTION_OID QByteArrayLiteral(ENCRYPTION_ALGORITHM_OID "9") // Not (yet) implemented
+#define AES_OID "2.16.840.1.101.3.4.1."
+#define AES128_CBC_ENCRYPTION_OID QByteArrayLiteral(AES_OID "2")
+#define AES192_CBC_ENCRYPTION_OID QByteArrayLiteral(AES_OID "22") // Not (yet) implemented
+#define AES256_CBC_ENCRYPTION_OID QByteArrayLiteral(AES_OID "42") // Not (yet) implemented
+
+class QAsn1Element
+{
+public:
+ enum ElementType {
+ // universal
+ BooleanType = 0x01,
+ IntegerType = 0x02,
+ BitStringType = 0x03,
+ OctetStringType = 0x04,
+ NullType = 0x05,
+ ObjectIdentifierType = 0x06,
+ Utf8StringType = 0x0c,
+ PrintableStringType = 0x13,
+ TeletexStringType = 0x14,
+ UtcTimeType = 0x17,
+ GeneralizedTimeType = 0x18,
+ SequenceType = 0x30,
+ SetType = 0x31,
+
+ // GeneralNameTypes
+ Rfc822NameType = 0x81,
+ DnsNameType = 0x82,
+ UniformResourceIdentifierType = 0x86,
+ IpAddressType = 0x87,
+
+ // context specific
+ Context0Type = 0xA0,
+ Context1Type = 0xA1,
+ Context3Type = 0xA3
+ };
+
+ explicit QAsn1Element(quint8 type = 0, const QByteArray &value = QByteArray());
+ bool read(QDataStream &data);
+ bool read(const QByteArray &data);
+ void write(QDataStream &data) const;
+
+ static QAsn1Element fromBool(bool val);
+ static QAsn1Element fromInteger(unsigned int val);
+ static QAsn1Element fromVector(const QList<QAsn1Element> &items);
+ static QAsn1Element fromObjectId(const QByteArray &id);
+
+ bool toBool(bool *ok = nullptr) const;
+ QDateTime toDateTime() const;
+ QMultiMap<QByteArray, QString> toInfo() const;
+ qint64 toInteger(bool *ok = nullptr) const;
+ QList<QAsn1Element> toList() const;
+ QByteArray toObjectId() const;
+ QByteArray toObjectName() const;
+ QString toString() const;
+
+ quint8 type() const { return mType; }
+ QByteArray value() const { return mValue; }
+
+ friend inline bool operator==(const QAsn1Element &, const QAsn1Element &);
+ friend inline bool operator!=(const QAsn1Element &, const QAsn1Element &);
+
+private:
+ quint8 mType;
+ QByteArray mValue;
+};
+Q_DECLARE_TYPEINFO(QAsn1Element, Q_RELOCATABLE_TYPE);
+
+inline bool operator==(const QAsn1Element &e1, const QAsn1Element &e2)
+{ return e1.mType == e2.mType && e1.mValue == e2.mValue; }
+
+inline bool operator!=(const QAsn1Element &e1, const QAsn1Element &e2)
+{ return e1.mType != e2.mType || e1.mValue != e2.mValue; }
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/plugins/tls/shared/qdtls_base.cpp b/src/plugins/tls/shared/qdtls_base.cpp
new file mode 100644
index 0000000000..19131e5497
--- /dev/null
+++ b/src/plugins/tls/shared/qdtls_base.cpp
@@ -0,0 +1,79 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qdtls_base_p.h"
+
+QT_BEGIN_NAMESPACE
+
+void QDtlsBasePrivate::setDtlsError(QDtlsError code, const QString &description)
+{
+ errorCode = code;
+ errorDescription = description;
+}
+
+QDtlsError QDtlsBasePrivate::error() const
+{
+ return errorCode;
+}
+
+QString QDtlsBasePrivate::errorString() const
+{
+ return errorDescription;
+}
+
+void QDtlsBasePrivate::clearDtlsError()
+{
+ errorCode = QDtlsError::NoError;
+ errorDescription.clear();
+}
+
+QSslConfiguration QDtlsBasePrivate::configuration() const
+{
+ return dtlsConfiguration;
+}
+
+void QDtlsBasePrivate::setConfiguration(const QSslConfiguration &configuration)
+{
+ dtlsConfiguration = configuration;
+ clearDtlsError();
+}
+
+bool QDtlsBasePrivate::setCookieGeneratorParameters(const GenParams &params)
+{
+ if (!params.secret.size()) {
+ setDtlsError(QDtlsError::InvalidInputParameters,
+ QDtls::tr("Invalid (empty) secret"));
+ return false;
+ }
+
+ clearDtlsError();
+
+ hashAlgorithm = params.hash;
+ secret = params.secret;
+
+ return true;
+}
+
+QDtlsClientVerifier::GeneratorParameters
+QDtlsBasePrivate::cookieGeneratorParameters() const
+{
+ return {hashAlgorithm, secret};
+}
+
+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;
+ default:
+ return false;
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/tls/shared/qdtls_base_p.h b/src/plugins/tls/shared/qdtls_base_p.h
new file mode 100644
index 0000000000..a8faad6a26
--- /dev/null
+++ b/src/plugins/tls/shared/qdtls_base_p.h
@@ -0,0 +1,80 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QDTLS_BASE_P_H
+#define QDTLS_BASE_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 <QtNetwork/private/qtnetworkglobal_p.h>
+
+QT_REQUIRE_CONFIG(dtls);
+
+#include <QtNetwork/private/qtlsbackend_p.h>
+
+#include <QtNetwork/qsslconfiguration.h>
+#include <QtNetwork/qsslcipher.h>
+#include <QtNetwork/qsslsocket.h>
+#include <QtNetwork/qssl.h>
+
+#include <QtNetwork/qhostaddress.h>
+
+#include <QtCore/qcryptographichash.h>
+#include <QtCore/qbytearray.h>
+#include <QtCore/qglobal.h>
+#include <QtCore/qstring.h>
+
+QT_BEGIN_NAMESPACE
+
+// This class exists to re-implement the shared error/cookie handling
+// for both QDtls and QDtlsClientVerifier classes. Use it if/when
+// you need it. Backend neutral.
+class QDtlsBasePrivate : virtual public QTlsPrivate::DtlsBase
+{
+public:
+ QDtlsBasePrivate(QSslSocket::SslMode m, const QByteArray &s) : mode(m), secret(s) {}
+ void setDtlsError(QDtlsError code, const QString &description) override;
+ QDtlsError error() const override;
+ QString errorString() const override;
+ void clearDtlsError() override;
+
+ void setConfiguration(const QSslConfiguration &configuration) override;
+ QSslConfiguration configuration() const override;
+
+ bool setCookieGeneratorParameters(const GenParams &) override;
+ GenParams cookieGeneratorParameters() const override;
+
+ static bool isDtlsProtocol(QSsl::SslProtocol protocol);
+
+ QHostAddress remoteAddress;
+ quint16 remotePort = 0;
+ quint16 mtuHint = 0;
+
+ QDtlsError errorCode = QDtlsError::NoError;
+ QString errorDescription;
+ QSslConfiguration dtlsConfiguration;
+ QSslSocket::SslMode mode = QSslSocket::SslClientMode;
+ QSslCipher sessionCipher;
+ QSsl::SslProtocol sessionProtocol = QSsl::UnknownProtocol;
+ QString peerVfyName;
+ QByteArray secret;
+
+#ifdef QT_CRYPTOGRAPHICHASH_ONLY_SHA1
+ QCryptographicHash::Algorithm hashAlgorithm = QCryptographicHash::Sha1;
+#else
+ QCryptographicHash::Algorithm hashAlgorithm = QCryptographicHash::Sha256;
+#endif
+};
+
+QT_END_NAMESPACE
+
+#endif // QDTLS_BASE_P_H
diff --git a/src/plugins/tls/shared/qsslsocket_mac_shared.cpp b/src/plugins/tls/shared/qsslsocket_mac_shared.cpp
new file mode 100644
index 0000000000..1257240ee2
--- /dev/null
+++ b/src/plugins/tls/shared/qsslsocket_mac_shared.cpp
@@ -0,0 +1,168 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2015 ownCloud Inc
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <QtNetwork/private/qtlsbackend_p.h>
+
+#include <QtNetwork/qsslcertificate.h>
+
+#include <QtCore/qloggingcategory.h>
+#include <QtCore/qglobal.h>
+#include <QtCore/qdebug.h>
+
+
+#ifdef Q_OS_MACOS
+
+#include <QtCore/private/qcore_mac_p.h>
+
+#include <CoreFoundation/CFArray.h>
+#include <Security/Security.h>
+
+#endif // Q_OS_MACOS
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(lcX509, "qt.mac.shared.x509");
+
+#ifdef Q_OS_MACOS
+namespace {
+
+bool hasTrustedSslServerPolicy(SecPolicyRef policy, CFDictionaryRef props) {
+ QCFType<CFDictionaryRef> policyProps = SecPolicyCopyProperties(policy);
+ // only accept certificates with policies for SSL server validation for now
+ if (CFEqual(CFDictionaryGetValue(policyProps, kSecPolicyOid), kSecPolicyAppleSSL)) {
+ CFBooleanRef policyClient;
+ if (CFDictionaryGetValueIfPresent(policyProps, kSecPolicyClient, reinterpret_cast<const void**>(&policyClient)) &&
+ CFEqual(policyClient, kCFBooleanTrue)) {
+ return false; // no client certs
+ }
+ if (!CFDictionaryContainsKey(props, kSecTrustSettingsResult)) {
+ // as per the docs, no trust settings result implies full trust
+ return true;
+ }
+ CFNumberRef number = static_cast<CFNumberRef>(CFDictionaryGetValue(props, kSecTrustSettingsResult));
+ SecTrustSettingsResult settingsResult;
+ CFNumberGetValue(number, kCFNumberSInt32Type, &settingsResult);
+ switch (settingsResult) {
+ case kSecTrustSettingsResultTrustRoot:
+ case kSecTrustSettingsResultTrustAsRoot:
+ return true;
+ default:
+ return false;
+ }
+ }
+ return false;
+}
+
+bool isCaCertificateTrusted(SecCertificateRef cfCert, int domain)
+{
+ QCFType<CFArrayRef> cfTrustSettings;
+ OSStatus status = SecTrustSettingsCopyTrustSettings(cfCert, SecTrustSettingsDomain(domain), &cfTrustSettings);
+ if (status == noErr) {
+ CFIndex size = CFArrayGetCount(cfTrustSettings);
+ // if empty, trust for everything (as per the Security Framework documentation)
+ if (size == 0) {
+ return true;
+ } else {
+ for (CFIndex i = 0; i < size; ++i) {
+ CFDictionaryRef props = static_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(cfTrustSettings, i));
+ if (CFDictionaryContainsKey(props, kSecTrustSettingsPolicy)) {
+ if (hasTrustedSslServerPolicy((SecPolicyRef)CFDictionaryGetValue(props, kSecTrustSettingsPolicy), props))
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+bool canDERBeParsed(CFDataRef derData, const QSslCertificate &qtCert)
+{
+ // We are observing certificates, that while accepted when we copy them
+ // from the keychain(s), later give us 'Failed to create SslCertificate
+ // from QSslCertificate'. It's interesting to know at what step the failure
+ // occurred. Let's check it and skip it below if it's not valid.
+
+ auto checkDer = [](CFDataRef derData, const char *source)
+ {
+ Q_ASSERT(source);
+ Q_ASSERT(derData);
+
+ const auto cfLength = CFDataGetLength(derData);
+ if (cfLength <= 0) {
+ qCWarning(lcX509) << source << "returned faulty DER data with invalid length.";
+ return false;
+ }
+
+ QCFType<SecCertificateRef> secRef = SecCertificateCreateWithData(nullptr, derData);
+ if (!secRef) {
+ qCWarning(lcX509) << source << "returned faulty DER data which cannot be parsed back.";
+ return false;
+ }
+ return true;
+ };
+
+ if (!checkDer(derData, "SecCertificateCopyData")) {
+ qCDebug(lcX509) << "Faulty QSslCertificate is:" << qtCert;// Just in case we managed to parse something.
+ return false;
+ }
+
+ // Generic parser failed?
+ if (qtCert.isNull()) {
+ qCWarning(lcX509, "QSslCertificate failed to parse DER");
+ return false;
+ }
+
+ const QCFType<CFDataRef> qtDerData = qtCert.toDer().toCFData();
+ if (!checkDer(qtDerData, "QSslCertificate")) {
+ qCWarning(lcX509) << "Faulty QSslCertificate is:" << qtCert;
+ return false;
+ }
+
+ return true;
+}
+
+} // unnamed namespace
+#endif // Q_OS_MACOS
+
+namespace QTlsPrivate {
+QList<QSslCertificate> systemCaCertificates()
+{
+ QList<QSslCertificate> systemCerts;
+ // SecTrustSettingsCopyCertificates is not defined on iOS.
+#ifdef Q_OS_MACOS
+ // iterate through all enum members, order:
+ // kSecTrustSettingsDomainUser, kSecTrustSettingsDomainAdmin, kSecTrustSettingsDomainSystem
+ for (int dom = kSecTrustSettingsDomainUser; dom <= int(kSecTrustSettingsDomainSystem); dom++) {
+ QCFType<CFArrayRef> cfCerts;
+ OSStatus status = SecTrustSettingsCopyCertificates(SecTrustSettingsDomain(dom), &cfCerts);
+ if (status == noErr) {
+ const CFIndex size = CFArrayGetCount(cfCerts);
+ for (CFIndex i = 0; i < size; ++i) {
+ SecCertificateRef cfCert = (SecCertificateRef)CFArrayGetValueAtIndex(cfCerts, i);
+ QCFType<CFDataRef> derData = SecCertificateCopyData(cfCert);
+ if (isCaCertificateTrusted(cfCert, dom)) {
+ if (derData) {
+ const auto newCert = QSslCertificate(QByteArray::fromCFData(derData), QSsl::Der);
+ if (!canDERBeParsed(derData, newCert)) {
+ // Last attempt to get some information about the certificate:
+ CFShow(cfCert);
+ continue;
+ }
+ systemCerts << newCert;
+ } else {
+ // "Returns NULL if the data passed in the certificate parameter
+ // is not a valid certificate object."
+ qCWarning(lcX509, "SecCertificateCopyData returned invalid DER data (nullptr).");
+ }
+ }
+ }
+ }
+ }
+#endif
+ return systemCerts;
+}
+} // namespace QTlsPrivate
+
+QT_END_NAMESPACE
diff --git a/src/plugins/tls/shared/qsslsocket_qt.cpp b/src/plugins/tls/shared/qsslsocket_qt.cpp
new file mode 100644
index 0000000000..f55b3e3ded
--- /dev/null
+++ b/src/plugins/tls/shared/qsslsocket_qt.cpp
@@ -0,0 +1,271 @@
+// Copyright (C) 2014 Jeremy Lainé <jeremy.laine@m4x.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qasn1element_p.h"
+
+#include <QtCore/qbytearray.h>
+#include <QtCore/qdatastream.h>
+#include <QtCore/qmessageauthenticationcode.h>
+#include <QtCore/qrandom.h>
+
+#include <QtNetwork/private/qsslsocket_p.h>
+#include <QtNetwork/private/qsslkey_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/*
+ PKCS12 helpers.
+*/
+
+static QAsn1Element wrap(quint8 type, const QAsn1Element &child)
+{
+ QByteArray value;
+ QDataStream stream(&value, QIODevice::WriteOnly);
+ child.write(stream);
+ return QAsn1Element(type, value);
+}
+
+static QAsn1Element _q_PKCS7_data(const QByteArray &data)
+{
+ QList<QAsn1Element> items;
+ items << QAsn1Element::fromObjectId("1.2.840.113549.1.7.1");
+ items << wrap(QAsn1Element::Context0Type,
+ QAsn1Element(QAsn1Element::OctetStringType, data));
+ return QAsn1Element::fromVector(items);
+}
+
+/*!
+ PKCS #12 key derivation.
+
+ Some test vectors:
+ http://www.drh-consultancy.demon.co.uk/test.txt
+ \internal
+*/
+static QByteArray _q_PKCS12_keygen(char id, const QByteArray &salt, const QString &passPhrase, int n, int r)
+{
+ const int u = 20;
+ const int v = 64;
+
+ // password formatting
+ QByteArray passUnicode(passPhrase.size() * 2 + 2, '\0');
+ char *p = passUnicode.data();
+ for (int i = 0; i < passPhrase.size(); ++i) {
+ quint16 ch = passPhrase[i].unicode();
+ *(p++) = (ch & 0xff00) >> 8;
+ *(p++) = (ch & 0xff);
+ }
+
+ // prepare I
+ QByteArray D(64, id);
+ QByteArray S, P;
+ const int sSize = v * ((salt.size() + v - 1) / v);
+ S.resize(sSize);
+ for (int i = 0; i < sSize; ++i)
+ S[i] = salt[i % salt.size()];
+ const int pSize = v * ((passUnicode.size() + v - 1) / v);
+ P.resize(pSize);
+ for (int i = 0; i < pSize; ++i)
+ P[i] = passUnicode[i % passUnicode.size()];
+ QByteArray I = S + P;
+
+ // apply hashing
+ const int c = (n + u - 1) / u;
+ QByteArray A;
+ QByteArray B;
+ B.resize(v);
+ for (int i = 0; i < c; ++i) {
+ // hash r iterations
+ QByteArray Ai = D + I;
+ 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];
+
+ // modify I as Ij = (Ij + B + 1) modulo 2^v
+ for (int p = 0; p < I.size(); p += v) {
+ quint8 carry = 1;
+ for (int j = v - 1; j >= 0; --j) {
+ quint16 v = quint8(I[p + j]) + quint8(B[j]) + carry;
+ I[p + j] = v & 0xff;
+ carry = (v & 0xff00) >> 8;
+ }
+ }
+ A += Ai;
+ }
+ return A.left(n);
+}
+
+static QByteArray _q_PKCS12_salt()
+{
+ QByteArray salt;
+ salt.resize(8);
+ for (int i = 0; i < salt.size(); ++i)
+ salt[i] = (QRandomGenerator::global()->generate() & 0xff);
+ return salt;
+}
+
+static QByteArray _q_PKCS12_certBag(const QSslCertificate &cert)
+{
+ QList<QAsn1Element> items;
+ items << QAsn1Element::fromObjectId("1.2.840.113549.1.12.10.1.3");
+
+ // certificate
+ QList<QAsn1Element> certItems;
+ certItems << QAsn1Element::fromObjectId("1.2.840.113549.1.9.22.1");
+ certItems << wrap(QAsn1Element::Context0Type,
+ QAsn1Element(QAsn1Element::OctetStringType, cert.toDer()));
+ items << wrap(QAsn1Element::Context0Type,
+ QAsn1Element::fromVector(certItems));
+
+ // local key id
+ const QByteArray localKeyId = cert.digest(QCryptographicHash::Sha1);
+ QList<QAsn1Element> idItems;
+ idItems << QAsn1Element::fromObjectId("1.2.840.113549.1.9.21");
+ idItems << wrap(QAsn1Element::SetType,
+ QAsn1Element(QAsn1Element::OctetStringType, localKeyId));
+ items << wrap(QAsn1Element::SetType, QAsn1Element::fromVector(idItems));
+
+ // dump
+ QAsn1Element root = wrap(QAsn1Element::SequenceType, QAsn1Element::fromVector(items));
+ QByteArray ba;
+ QDataStream stream(&ba, QIODevice::WriteOnly);
+ root.write(stream);
+ return ba;
+}
+
+static QAsn1Element _q_PKCS12_key(const QSslKey &key)
+{
+ Q_ASSERT(key.algorithm() == QSsl::Rsa || key.algorithm() == QSsl::Dsa);
+
+ QList<QAsn1Element> keyItems;
+ keyItems << QAsn1Element::fromInteger(0);
+ QList<QAsn1Element> algoItems;
+ if (key.algorithm() == QSsl::Rsa)
+ algoItems << QAsn1Element::fromObjectId(RSA_ENCRYPTION_OID);
+ else if (key.algorithm() == QSsl::Dsa)
+ algoItems << QAsn1Element::fromObjectId(DSA_ENCRYPTION_OID);
+ algoItems << QAsn1Element(QAsn1Element::NullType);
+ keyItems << QAsn1Element::fromVector(algoItems);
+ keyItems << QAsn1Element(QAsn1Element::OctetStringType, key.toDer());
+ return QAsn1Element::fromVector(keyItems);
+}
+
+static QByteArray _q_PKCS12_shroudedKeyBag(const QSslKey &key, const QString &passPhrase, const QByteArray &localKeyId)
+{
+ const int iterations = 2048;
+ QByteArray salt = _q_PKCS12_salt();
+ QByteArray cKey = _q_PKCS12_keygen(1, salt, passPhrase, 24, iterations);
+ QByteArray cIv = _q_PKCS12_keygen(2, salt, passPhrase, 8, iterations);
+
+ // prepare and encrypt data
+ QByteArray plain;
+ QDataStream plainStream(&plain, QIODevice::WriteOnly);
+ _q_PKCS12_key(key).write(plainStream);
+ QByteArray crypted = QSslKeyPrivate::encrypt(QTlsPrivate::Cipher::DesEde3Cbc,
+ plain, cKey, cIv);
+
+ QList<QAsn1Element> items;
+ items << QAsn1Element::fromObjectId("1.2.840.113549.1.12.10.1.2");
+
+ // key
+ QList<QAsn1Element> keyItems;
+ QList<QAsn1Element> algoItems;
+ algoItems << QAsn1Element::fromObjectId("1.2.840.113549.1.12.1.3");
+ QList<QAsn1Element> paramItems;
+ paramItems << QAsn1Element(QAsn1Element::OctetStringType, salt);
+ paramItems << QAsn1Element::fromInteger(iterations);
+ algoItems << QAsn1Element::fromVector(paramItems);
+ keyItems << QAsn1Element::fromVector(algoItems);
+ keyItems << QAsn1Element(QAsn1Element::OctetStringType, crypted);
+ items << wrap(QAsn1Element::Context0Type,
+ QAsn1Element::fromVector(keyItems));
+
+ // local key id
+ QList<QAsn1Element> idItems;
+ idItems << QAsn1Element::fromObjectId("1.2.840.113549.1.9.21");
+ idItems << wrap(QAsn1Element::SetType,
+ QAsn1Element(QAsn1Element::OctetStringType, localKeyId));
+ items << wrap(QAsn1Element::SetType,
+ QAsn1Element::fromVector(idItems));
+
+ // dump
+ QAsn1Element root = wrap(QAsn1Element::SequenceType, QAsn1Element::fromVector(items));
+ QByteArray ba;
+ QDataStream stream(&ba, QIODevice::WriteOnly);
+ root.write(stream);
+ return ba;
+}
+
+static QByteArray _q_PKCS12_bag(const QList<QSslCertificate> &certs, const QSslKey &key, const QString &passPhrase)
+{
+ QList<QAsn1Element> items;
+
+ // certs
+ for (int i = 0; i < certs.size(); ++i)
+ items << _q_PKCS7_data(_q_PKCS12_certBag(certs[i]));
+
+ // key
+ if (!key.isNull()) {
+ const QByteArray localKeyId = certs.first().digest(QCryptographicHash::Sha1);
+ items << _q_PKCS7_data(_q_PKCS12_shroudedKeyBag(key, passPhrase, localKeyId));
+ }
+
+ // dump
+ QAsn1Element root = QAsn1Element::fromVector(items);
+ QByteArray ba;
+ QDataStream stream(&ba, QIODevice::WriteOnly);
+ root.write(stream);
+ return ba;
+}
+
+static QAsn1Element _q_PKCS12_mac(const QByteArray &data, const QString &passPhrase)
+{
+ const int iterations = 2048;
+
+ // salt generation
+ QByteArray macSalt = _q_PKCS12_salt();
+ QByteArray key = _q_PKCS12_keygen(3, macSalt, passPhrase, 20, iterations);
+
+ // HMAC calculation
+ QMessageAuthenticationCode hmac(QCryptographicHash::Sha1, key);
+ hmac.addData(data);
+
+ QList<QAsn1Element> algoItems;
+ algoItems << QAsn1Element::fromObjectId("1.3.14.3.2.26");
+ algoItems << QAsn1Element(QAsn1Element::NullType);
+
+ QList<QAsn1Element> digestItems;
+ digestItems << QAsn1Element::fromVector(algoItems);
+ digestItems << QAsn1Element(QAsn1Element::OctetStringType, hmac.result());
+
+ QList<QAsn1Element> macItems;
+ macItems << QAsn1Element::fromVector(digestItems);
+ macItems << QAsn1Element(QAsn1Element::OctetStringType, macSalt);
+ macItems << QAsn1Element::fromInteger(iterations);
+ return QAsn1Element::fromVector(macItems);
+}
+
+QByteArray _q_makePkcs12(const QList<QSslCertificate> &certs, const QSslKey &key, const QString &passPhrase)
+{
+ QList<QAsn1Element> items;
+
+ // version
+ items << QAsn1Element::fromInteger(3);
+
+ // auth safe
+ const QByteArray data = _q_PKCS12_bag(certs, key, passPhrase);
+ items << _q_PKCS7_data(data);
+
+ // HMAC
+ items << _q_PKCS12_mac(data, passPhrase);
+
+ // dump
+ QAsn1Element root = QAsn1Element::fromVector(items);
+ QByteArray ba;
+ QDataStream stream(&ba, QIODevice::WriteOnly);
+ root.write(stream);
+ return ba;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/tls/shared/qtlskey_base.cpp b/src/plugins/tls/shared/qtlskey_base.cpp
new file mode 100644
index 0000000000..ff541165fe
--- /dev/null
+++ b/src/plugins/tls/shared/qtlskey_base.cpp
@@ -0,0 +1,97 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qtlskey_base_p.h"
+#include "qasn1element_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QTlsPrivate {
+
+QByteArray TlsKeyBase::pemFromDer(const QByteArray &der, const QMap<QByteArray, QByteArray> &headers) const
+{
+ QByteArray pem(der.toBase64());
+
+ const int lineWidth = 64; // RFC 1421
+ const int newLines = pem.size() / lineWidth;
+ const bool rem = pem.size() % lineWidth;
+
+ for (int i = 0; i < newLines; ++i)
+ pem.insert((i + 1) * lineWidth + i, '\n');
+ if (rem)
+ pem.append('\n');
+
+ QByteArray extra;
+ if (!headers.isEmpty()) {
+ QMap<QByteArray, QByteArray>::const_iterator it = headers.constEnd();
+ do {
+ --it;
+ extra += it.key() + ": " + it.value() + '\n';
+ } while (it != headers.constBegin());
+ extra += '\n';
+ }
+
+ if (isEncryptedPkcs8(der)) {
+ pem.prepend(pkcs8Header(true) + '\n' + extra);
+ pem.append(pkcs8Footer(true) + '\n');
+ } else if (isPkcs8()) {
+ pem.prepend(pkcs8Header(false) + '\n' + extra);
+ pem.append(pkcs8Footer(false) + '\n');
+ } else {
+ pem.prepend(pemHeader() + '\n' + extra);
+ pem.append(pemFooter() + '\n');
+ }
+
+ return pem;
+}
+
+QByteArray TlsKeyBase::pkcs8Header(bool encrypted)
+{
+ return encrypted
+ ? QByteArrayLiteral("-----BEGIN ENCRYPTED PRIVATE KEY-----")
+ : QByteArrayLiteral("-----BEGIN PRIVATE KEY-----");
+}
+
+QByteArray TlsKeyBase::pkcs8Footer(bool encrypted)
+{
+ return encrypted
+ ? QByteArrayLiteral("-----END ENCRYPTED PRIVATE KEY-----")
+ : QByteArrayLiteral("-----END PRIVATE KEY-----");
+}
+
+bool TlsKeyBase::isEncryptedPkcs8(const QByteArray &der)
+{
+ static const QList<QByteArray> pbes1OIds {
+ // PKCS5
+ { PKCS5_MD2_DES_CBC_OID }, { PKCS5_MD2_RC2_CBC_OID }, { PKCS5_MD5_DES_CBC_OID },
+ { PKCS5_MD5_RC2_CBC_OID }, { PKCS5_SHA1_DES_CBC_OID }, { PKCS5_SHA1_RC2_CBC_OID },
+ };
+ QAsn1Element elem;
+ if (!elem.read(der) || elem.type() != QAsn1Element::SequenceType)
+ return false;
+
+ const auto items = elem.toList();
+ if (items.size() != 2
+ || items[0].type() != QAsn1Element::SequenceType
+ || items[1].type() != QAsn1Element::OctetStringType) {
+ return false;
+ }
+
+ const auto encryptionSchemeContainer = items[0].toList();
+ if (encryptionSchemeContainer.size() != 2
+ || encryptionSchemeContainer[0].type() != QAsn1Element::ObjectIdentifierType
+ || encryptionSchemeContainer[1].type() != QAsn1Element::SequenceType) {
+ return false;
+ }
+
+ const QByteArray encryptionScheme = encryptionSchemeContainer[0].toObjectId();
+ return encryptionScheme == PKCS5_PBES2_ENCRYPTION_OID
+ || pbes1OIds.contains(encryptionScheme)
+ || encryptionScheme.startsWith(PKCS12_OID);
+}
+
+} // namespace QTlsPrivate
+
+QT_END_NAMESPACE
+
+
diff --git a/src/plugins/tls/shared/qtlskey_base_p.h b/src/plugins/tls/shared/qtlskey_base_p.h
new file mode 100644
index 0000000000..ebfa15a2f9
--- /dev/null
+++ b/src/plugins/tls/shared/qtlskey_base_p.h
@@ -0,0 +1,72 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QTLSKEY_BASE_P_H
+#define QTLSKEY_BASE_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 <QtNetwork/private/qtnetworkglobal_p.h>
+
+#include <QtNetwork/private/qtlsbackend_p.h>
+
+#include <QtNetwork/qssl.h>
+
+#include <QtCore/qglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QTlsPrivate {
+
+class TlsKeyBase : public TlsKey
+{
+public:
+ TlsKeyBase(KeyType type = QSsl::PublicKey, KeyAlgorithm algorithm = QSsl::Opaque)
+ : keyType(type),
+ keyAlgorithm(algorithm)
+ {
+ }
+
+ bool isNull() const override
+ {
+ return keyIsNull;
+ }
+ KeyType type() const override
+ {
+ return keyType;
+ }
+ KeyAlgorithm algorithm() const override
+ {
+ return keyAlgorithm;
+ }
+ bool isPkcs8 () const override
+ {
+ return false;
+ }
+
+ QByteArray pemFromDer(const QByteArray &der, const QMap<QByteArray, QByteArray> &headers) const override;
+
+protected:
+ static QByteArray pkcs8Header(bool encrypted);
+ static QByteArray pkcs8Footer(bool encrypted);
+ static bool isEncryptedPkcs8(const QByteArray &der);
+
+ bool keyIsNull = true;
+ KeyType keyType = QSsl::PublicKey;
+ KeyAlgorithm keyAlgorithm = QSsl::Opaque;
+};
+
+} // namespace QTlsPrivate
+
+QT_END_NAMESPACE
+
+#endif // QTLSKEY_BASE_P_H
diff --git a/src/plugins/tls/shared/qtlskey_generic.cpp b/src/plugins/tls/shared/qtlskey_generic.cpp
new file mode 100644
index 0000000000..4645ef4703
--- /dev/null
+++ b/src/plugins/tls/shared/qtlskey_generic.cpp
@@ -0,0 +1,849 @@
+// Copyright (C) 2014 Jeremy Lainé <jeremy.laine@m4x.org>
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qtlskey_generic_p.h"
+#include "qasn1element_p.h"
+
+#include <QtNetwork/private/qsslkey_p.h>
+
+#include <QtNetwork/qpassworddigestor.h>
+
+#include <QtCore/QMessageAuthenticationCode>
+#include <QtCore/qcryptographichash.h>
+#include <QtCore/qrandom.h>
+
+#include <QtCore/qdatastream.h>
+#include <QtCore/qbytearray.h>
+#include <QtCore/qdebug.h>
+#include <QtCore/qmap.h>
+
+#include <cstring>
+
+QT_BEGIN_NAMESPACE
+
+// The code here is essentially what we had in qsslkey_qt.cpp before, with
+// minimal changes/restructure.
+
+namespace QTlsPrivate {
+
+// OIDs of named curves allowed in TLS as per RFCs 4492 and 7027,
+// see also https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-8
+namespace {
+
+const quint8 bits_table[256] = {
+ 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,
+ 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+ 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+ 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+ 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+ 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+ 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+ 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+ 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+ 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+ 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+};
+
+using OidLengthMap = QMap<QByteArray, int>;
+
+OidLengthMap createOidMap()
+{
+ OidLengthMap oids;
+ oids.insert(oids.cend(), QByteArrayLiteral("1.2.840.10045.3.1.1"), 192); // secp192r1 a.k.a prime192v1
+ oids.insert(oids.cend(), QByteArrayLiteral("1.2.840.10045.3.1.7"), 256); // secp256r1 a.k.a prime256v1
+ oids.insert(oids.cend(), QByteArrayLiteral("1.3.132.0.1"), 193); // sect193r2
+ oids.insert(oids.cend(), QByteArrayLiteral("1.3.132.0.10"), 256); // secp256k1
+ oids.insert(oids.cend(), QByteArrayLiteral("1.3.132.0.16"), 283); // sect283k1
+ oids.insert(oids.cend(), QByteArrayLiteral("1.3.132.0.17"), 283); // sect283r1
+ oids.insert(oids.cend(), QByteArrayLiteral("1.3.132.0.26"), 233); // sect233k1
+ oids.insert(oids.cend(), QByteArrayLiteral("1.3.132.0.27"), 233); // sect233r1
+ oids.insert(oids.cend(), QByteArrayLiteral("1.3.132.0.3"), 239); // sect239k1
+ oids.insert(oids.cend(), QByteArrayLiteral("1.3.132.0.30"), 160); // secp160r2
+ oids.insert(oids.cend(), QByteArrayLiteral("1.3.132.0.31"), 192); // secp192k1
+ oids.insert(oids.cend(), QByteArrayLiteral("1.3.132.0.32"), 224); // secp224k1
+ oids.insert(oids.cend(), QByteArrayLiteral("1.3.132.0.33"), 224); // secp224r1
+ oids.insert(oids.cend(), QByteArrayLiteral("1.3.132.0.34"), 384); // secp384r1
+ oids.insert(oids.cend(), QByteArrayLiteral("1.3.132.0.35"), 521); // secp521r1
+ oids.insert(oids.cend(), QByteArrayLiteral("1.3.132.0.36"), 409); // sect409k1
+ oids.insert(oids.cend(), QByteArrayLiteral("1.3.132.0.37"), 409); // sect409r1
+ oids.insert(oids.cend(), QByteArrayLiteral("1.3.132.0.38"), 571); // sect571k1
+ oids.insert(oids.cend(), QByteArrayLiteral("1.3.132.0.39"), 571); // sect571r1
+ oids.insert(oids.cend(), QByteArrayLiteral("1.3.132.0.8"), 160); // secp160r1
+ oids.insert(oids.cend(), QByteArrayLiteral("1.3.132.0.9"), 160); // secp160k1
+ oids.insert(oids.cend(), QByteArrayLiteral("1.3.36.3.3.2.8.1.1.11"), 384); // brainpoolP384r1
+ oids.insert(oids.cend(), QByteArrayLiteral("1.3.36.3.3.2.8.1.1.13"), 512); // brainpoolP512r1
+ oids.insert(oids.cend(), QByteArrayLiteral("1.3.36.3.3.2.8.1.1.7"), 256); // brainpoolP256r1
+ return oids;
+}
+
+} // Unnamed namespace.
+
+Q_GLOBAL_STATIC_WITH_ARGS(OidLengthMap, oidLengthMap, (createOidMap()))
+
+namespace {
+
+// Maps OIDs to the encryption cipher they specify
+const QMap<QByteArray, QSslKeyPrivate::Cipher> oidCipherMap {
+ {DES_CBC_ENCRYPTION_OID, QSslKeyPrivate::Cipher::DesCbc},
+ {DES_EDE3_CBC_ENCRYPTION_OID, QSslKeyPrivate::Cipher::DesEde3Cbc},
+ // {PKCS5_MD2_DES_CBC_OID, QSslKeyPrivate::Cipher::DesCbc}, // No MD2
+ {PKCS5_MD5_DES_CBC_OID, QSslKeyPrivate::Cipher::DesCbc},
+ {PKCS5_SHA1_DES_CBC_OID, QSslKeyPrivate::Cipher::DesCbc},
+ // {PKCS5_MD2_RC2_CBC_OID, QSslKeyPrivate::Cipher::Rc2Cbc}, // No MD2
+ {PKCS5_MD5_RC2_CBC_OID, QSslKeyPrivate::Cipher::Rc2Cbc},
+ {PKCS5_SHA1_RC2_CBC_OID, QSslKeyPrivate::Cipher::Rc2Cbc},
+ {RC2_CBC_ENCRYPTION_OID, QSslKeyPrivate::Cipher::Rc2Cbc}
+ // {RC5_CBC_ENCRYPTION_OID, QSslKeyPrivate::Cipher::Rc5Cbc}, // No RC5
+ // {AES128_CBC_ENCRYPTION_OID, QSslKeyPrivate::Cipher::Aes128}, // no AES
+ // {AES192_CBC_ENCRYPTION_OID, QSslKeyPrivate::Cipher::Aes192},
+ // {AES256_CBC_ENCRYPTION_OID, QSslKeyPrivate::Cipher::Aes256}
+};
+
+struct EncryptionData
+{
+ EncryptionData() = default;
+
+ EncryptionData(QSslKeyPrivate::Cipher cipher, QByteArray key, QByteArray iv)
+ : initialized(true), cipher(cipher), key(key), iv(iv)
+ {
+ }
+ bool initialized = false;
+ QSslKeyPrivate::Cipher cipher;
+ QByteArray key;
+ QByteArray iv;
+};
+
+EncryptionData readPbes2(const QList<QAsn1Element> &element, const QByteArray &passPhrase)
+{
+ // RFC 8018: https://tools.ietf.org/html/rfc8018#section-6.2
+ /*** Scheme: ***
+ * Sequence (scheme-specific info..)
+ * Sequence (key derivation info)
+ * Object Identifier (Key derivation algorithm (e.g. PBKDF2))
+ * Sequence (salt)
+ * CHOICE (this entry can be either of the types it contains)
+ * Octet string (actual salt)
+ * Object identifier (Anything using this is deferred to a later version of PKCS #5)
+ * Integer (iteration count)
+ * Sequence (encryption algorithm info)
+ * Object identifier (identifier for the algorithm)
+ * Algorithm dependent, is covered in the switch further down
+ */
+
+ static const QMap<QByteArray, QCryptographicHash::Algorithm> pbes2OidHashFunctionMap {
+ // PBES2/PBKDF2
+ {HMAC_WITH_SHA1, QCryptographicHash::Sha1},
+ {HMAC_WITH_SHA224, QCryptographicHash::Sha224},
+ {HMAC_WITH_SHA256, QCryptographicHash::Sha256},
+ {HMAC_WITH_SHA512, QCryptographicHash::Sha512},
+ {HMAC_WITH_SHA512_224, QCryptographicHash::Sha512},
+ {HMAC_WITH_SHA512_256, QCryptographicHash::Sha512},
+ {HMAC_WITH_SHA384, QCryptographicHash::Sha384}
+ };
+
+ // Values from their respective sections here: https://tools.ietf.org/html/rfc8018#appendix-B.2
+ static const QMap<QSslKeyPrivate::Cipher, int> cipherKeyLengthMap {
+ {QSslKeyPrivate::Cipher::DesCbc, 8},
+ {QSslKeyPrivate::Cipher::DesEde3Cbc, 24},
+ // @note: variable key-length (https://tools.ietf.org/html/rfc8018#appendix-B.2.3)
+ {QSslKeyPrivate::Cipher::Rc2Cbc, 4}
+ // @todo: AES(, rc5?)
+ };
+
+ const QList<QAsn1Element> keyDerivationContainer = element[0].toList();
+ if (keyDerivationContainer.size() != 2
+ || keyDerivationContainer[0].type() != QAsn1Element::ObjectIdentifierType
+ || keyDerivationContainer[1].type() != QAsn1Element::SequenceType) {
+ return {};
+ }
+
+ const QByteArray keyDerivationAlgorithm = keyDerivationContainer[0].toObjectId();
+ const auto keyDerivationParams = keyDerivationContainer[1].toList();
+
+ const auto encryptionAlgorithmContainer = element[1].toList();
+ if (encryptionAlgorithmContainer.size() != 2
+ || encryptionAlgorithmContainer[0].type() != QAsn1Element::ObjectIdentifierType) {
+ return {};
+ }
+
+ auto iterator = oidCipherMap.constFind(encryptionAlgorithmContainer[0].toObjectId());
+ if (iterator == oidCipherMap.cend()) {
+ qWarning()
+ << "QSslKey: Unsupported encryption cipher OID:" << encryptionAlgorithmContainer[0].toObjectId()
+ << "\nFile a bug report to Qt (include the line above).";
+ return {};
+ }
+
+ QSslKeyPrivate::Cipher cipher = *iterator;
+ QByteArray key;
+ QByteArray iv;
+ switch (cipher) {
+ case QSslKeyPrivate::Cipher::DesCbc:
+ case QSslKeyPrivate::Cipher::DesEde3Cbc:
+ // https://tools.ietf.org/html/rfc8018#appendix-B.2.1 (DES-CBC-PAD)
+ // https://tools.ietf.org/html/rfc8018#appendix-B.2.2 (DES-EDE3-CBC-PAD)
+ // @todo https://tools.ietf.org/html/rfc8018#appendix-B.2.5 (AES-CBC-PAD)
+ /*** Scheme: ***
+ * Octet string (IV)
+ */
+ if (encryptionAlgorithmContainer[1].type() != QAsn1Element::OctetStringType)
+ return {};
+
+ // @note: All AES identifiers should be able to use this branch!!
+ iv = encryptionAlgorithmContainer[1].value();
+
+ if (iv.size() != 8) // @note: AES needs 16 bytes
+ return {};
+ break;
+ case QSslKeyPrivate::Cipher::Rc2Cbc: {
+ // https://tools.ietf.org/html/rfc8018#appendix-B.2.3
+ /*** Scheme: ***
+ * Sequence (rc2 parameters)
+ * Integer (rc2 parameter version)
+ * Octet string (IV)
+ */
+ if (encryptionAlgorithmContainer[1].type() != QAsn1Element::SequenceType)
+ return {};
+ const auto rc2ParametersContainer = encryptionAlgorithmContainer[1].toList();
+ if ((rc2ParametersContainer.size() != 1 && rc2ParametersContainer.size() != 2)
+ || rc2ParametersContainer.back().type() != QAsn1Element::OctetStringType) {
+ return {};
+ }
+ iv = rc2ParametersContainer.back().value();
+ if (iv.size() != 8)
+ return {};
+ break;
+ } // @todo(?): case (RC5 , AES)
+ case QSslKeyPrivate::Cipher::Aes128Cbc:
+ case QSslKeyPrivate::Cipher::Aes192Cbc:
+ case QSslKeyPrivate::Cipher::Aes256Cbc:
+ Q_UNREACHABLE();
+ }
+
+ if (Q_LIKELY(keyDerivationAlgorithm == PKCS5_PBKDF2_ENCRYPTION_OID)) {
+ // Definition: https://tools.ietf.org/html/rfc8018#appendix-A.2
+ QByteArray salt;
+ if (keyDerivationParams[0].type() == QAsn1Element::OctetStringType) {
+ salt = keyDerivationParams[0].value();
+ } else if (keyDerivationParams[0].type() == QAsn1Element::ObjectIdentifierType) {
+ Q_UNIMPLEMENTED();
+ /* See paragraph from https://tools.ietf.org/html/rfc8018#appendix-A.2
+ which ends with: "such facilities are deferred to a future version of PKCS #5"
+ */
+ return {};
+ } else {
+ return {};
+ }
+
+ // Iterations needed to derive the key
+ int iterationCount = keyDerivationParams[1].toInteger();
+ // Optional integer
+ int keyLength = -1;
+ int vectorPos = 2;
+ if (keyDerivationParams.size() > vectorPos
+ && keyDerivationParams[vectorPos].type() == QAsn1Element::IntegerType) {
+ keyLength = keyDerivationParams[vectorPos].toInteger(nullptr);
+ ++vectorPos;
+ } else {
+ keyLength = cipherKeyLengthMap[cipher];
+ }
+
+ // Optional algorithm identifier (default: HMAC-SHA-1)
+ QCryptographicHash::Algorithm hashAlgorithm = QCryptographicHash::Sha1;
+ if (keyDerivationParams.size() > vectorPos
+ && keyDerivationParams[vectorPos].type() == QAsn1Element::SequenceType) {
+ const auto hashAlgorithmContainer = keyDerivationParams[vectorPos].toList();
+ hashAlgorithm = pbes2OidHashFunctionMap[hashAlgorithmContainer.front().toObjectId()];
+ Q_ASSERT(hashAlgorithmContainer[1].type() == QAsn1Element::NullType);
+ ++vectorPos;
+ }
+ Q_ASSERT(keyDerivationParams.size() == vectorPos);
+
+ key = QPasswordDigestor::deriveKeyPbkdf2(hashAlgorithm, passPhrase, salt, iterationCount, keyLength);
+ } else {
+ qWarning()
+ << "QSslKey: Unsupported key derivation algorithm OID:" << keyDerivationAlgorithm
+ << "\nFile a bugreport to Qt (include the line above).";
+ return {};
+ }
+ return {cipher, key, iv};
+}
+
+// Maps OIDs to the hash function it specifies
+const QMap<QByteArray, QCryptographicHash::Algorithm> pbes1OidHashFunctionMap {
+#ifndef QT_CRYPTOGRAPHICHASH_ONLY_SHA1
+ // PKCS5
+ //{PKCS5_MD2_DES_CBC_OID, QCryptographicHash::Md2}, No MD2
+ //{PKCS5_MD2_RC2_CBC_OID, QCryptographicHash::Md2},
+ {PKCS5_MD5_DES_CBC_OID, QCryptographicHash::Md5},
+ {PKCS5_MD5_RC2_CBC_OID, QCryptographicHash::Md5},
+#endif
+ {PKCS5_SHA1_DES_CBC_OID, QCryptographicHash::Sha1},
+ {PKCS5_SHA1_RC2_CBC_OID, QCryptographicHash::Sha1},
+ // PKCS12 (unimplemented)
+ // {PKCS12_SHA1_RC4_128_OID, QCryptographicHash::Sha1}, // No RC4
+ // {PKCS12_SHA1_RC4_40_OID, QCryptographicHash::Sha1},
+ // @todo: lacking support. @note: there might be code to do this inside qsslsocket_mac...
+ // further note that more work may be required for the 3DES variations listed to be available.
+ // {PKCS12_SHA1_3KEY_3DES_CBC_OID, QCryptographicHash::Sha1},
+ // {PKCS12_SHA1_2KEY_3DES_CBC_OID, QCryptographicHash::Sha1},
+ // {PKCS12_SHA1_RC2_128_CBC_OID, QCryptographicHash::Sha1},
+ // {PKCS12_SHA1_RC2_40_CBC_OID, QCryptographicHash::Sha1}
+};
+
+EncryptionData readPbes1(const QList<QAsn1Element> &element, const QByteArray &encryptionScheme,
+ const QByteArray &passPhrase)
+{
+ // RFC 8018: https://tools.ietf.org/html/rfc8018#section-6.1
+ // Steps refer to this section: https://tools.ietf.org/html/rfc8018#section-6.1.2
+ /*** Scheme: ***
+ * Sequence (PBE Parameter)
+ * Octet string (salt)
+ * Integer (iteration counter)
+ */
+ // Step 1
+ if (element.size() != 2
+ || element[0].type() != QAsn1Element::ElementType::OctetStringType
+ || element[1].type() != QAsn1Element::ElementType::IntegerType) {
+ return {};
+ }
+ QByteArray salt = element[0].value();
+ if (salt.size() != 8)
+ return {};
+
+ int iterationCount = element[1].toInteger();
+ if (iterationCount < 0)
+ return {};
+
+ // Step 2
+ auto iterator = pbes1OidHashFunctionMap.constFind(encryptionScheme);
+ if (iterator == pbes1OidHashFunctionMap.cend()) {
+ // Qt was compiled with ONLY_SHA1 (or it's MD2)
+ return {};
+ }
+ QCryptographicHash::Algorithm hashAlgorithm = *iterator;
+ QByteArray key = QPasswordDigestor::deriveKeyPbkdf1(hashAlgorithm, passPhrase, salt, iterationCount, 16);
+ if (key.size() != 16)
+ return {};
+
+ // Step 3
+ QByteArray iv = key.right(8); // last 8 bytes are used as IV
+ key.truncate(8); // first 8 bytes are used for the key
+
+ QSslKeyPrivate::Cipher cipher = oidCipherMap[encryptionScheme];
+ // Steps 4-6 are done after returning
+ return {cipher, key, iv};
+}
+
+int curveBits(const QByteArray &oid)
+{
+ const int length = oidLengthMap->value(oid);
+ return length ? length : -1;
+}
+
+int numberOfBits(const QByteArray &modulus)
+{
+ int bits = modulus.size() * 8;
+ for (int i = 0; i < modulus.size(); ++i) {
+ quint8 b = modulus[i];
+ bits -= 8;
+ if (b != 0) {
+ bits += bits_table[b];
+ break;
+ }
+ }
+ return bits;
+}
+
+QByteArray deriveAesKey(QSslKeyPrivate::Cipher cipher, const QByteArray &passPhrase,
+ const QByteArray &iv)
+{
+ // This is somewhat simplified and shortened version of what OpenSSL does.
+ // See, for example, EVP_BytesToKey for the "algorithm" itself and elsewhere
+ // in their code for what they pass as arguments to EVP_BytesToKey when
+ // deriving encryption keys (when reading/writing pems files with encrypted
+ // keys).
+
+ Q_ASSERT(iv.size() >= 8);
+
+ QCryptographicHash hash(QCryptographicHash::Md5);
+
+ QByteArray data(passPhrase);
+ data.append(iv.data(), 8); // AKA PKCS5_SALT_LEN in OpenSSL.
+
+ hash.addData(data);
+
+ if (cipher == Cipher::Aes128Cbc)
+ return hash.result();
+
+ QByteArray key(hash.result());
+ hash.reset();
+ hash.addData(key);
+ hash.addData(data);
+
+ if (cipher == Cipher::Aes192Cbc)
+ return key.append(hash.resultView().first(8));
+
+ return key.append(hash.resultView());
+}
+
+QByteArray deriveKey(QSslKeyPrivate::Cipher cipher, const QByteArray &passPhrase,
+ const QByteArray &iv)
+{
+ QByteArray key;
+ QCryptographicHash hash(QCryptographicHash::Md5);
+ hash.addData(passPhrase);
+ hash.addData(iv);
+ switch (cipher) {
+ case Cipher::DesCbc:
+ key = hash.result().left(8);
+ break;
+ case Cipher::DesEde3Cbc:
+ key = hash.result();
+ hash.reset();
+ hash.addData(key);
+ hash.addData(passPhrase);
+ hash.addData(iv);
+ key += hash.result().left(8);
+ break;
+ case Cipher::Rc2Cbc:
+ key = hash.result();
+ break;
+ case Cipher::Aes128Cbc:
+ case Cipher::Aes192Cbc:
+ case Cipher::Aes256Cbc:
+ return deriveAesKey(cipher, passPhrase, iv);
+ }
+ return key;
+}
+
+int extractPkcs8KeyLength(const QList<QAsn1Element> &items, TlsKey *that)
+{
+ Q_ASSERT(items.size() == 3);
+ Q_ASSERT(that);
+
+ int keyLength = -1;
+
+ auto getName = [](QSsl::KeyAlgorithm algorithm) {
+ switch (algorithm){
+ case QSsl::Rsa: return "RSA";
+ case QSsl::Dsa: return "DSA";
+ case QSsl::Dh: return "DH";
+ case QSsl::Ec: return "EC";
+ case QSsl::Opaque: return "Opaque";
+ }
+ Q_UNREACHABLE();
+ };
+
+ const auto pkcs8Info = items[1].toList();
+ if (pkcs8Info.size() != 2 || pkcs8Info[0].type() != QAsn1Element::ObjectIdentifierType)
+ return -1;
+ const QByteArray value = pkcs8Info[0].toObjectId();
+ if (value == RSA_ENCRYPTION_OID) {
+ if (Q_UNLIKELY(that->algorithm() != QSsl::Rsa)) {
+ // We could change the 'algorithm' of QSslKey here and continue loading, but
+ // this is not supported in the openssl back-end, so we'll fail here and give
+ // the user some feedback.
+ qWarning() << "QSslKey: Found RSA key when asked to use" << getName(that->algorithm())
+ << "\nLoading will fail.";
+ return -1;
+ }
+ // Luckily it contains the 'normal' RSA-key format inside, so we can just recurse
+ // and read the key's info.
+ that->decodeDer(that->type(), that->algorithm(), items[2].value(), {}, true);
+ // The real info has been filled out in the call above, so return as if it was invalid
+ // to avoid overwriting the data.
+ return -1;
+ } else if (value == EC_ENCRYPTION_OID) {
+ if (Q_UNLIKELY(that->algorithm() != QSsl::Ec)) {
+ // As above for RSA.
+ qWarning() << "QSslKey: Found EC key when asked to use" << getName(that->algorithm())
+ << "\nLoading will fail.";
+ return -1;
+ }
+ // I don't know where this is documented, but the elliptic-curve identifier has been
+ // moved into the "pkcs#8 wrapper", which is what we're interested in.
+ if (pkcs8Info[1].type() != QAsn1Element::ObjectIdentifierType)
+ return -1;
+ keyLength = curveBits(pkcs8Info[1].toObjectId());
+ } else if (value == DSA_ENCRYPTION_OID) {
+ if (Q_UNLIKELY(that->algorithm() != QSsl::Dsa)) {
+ // As above for RSA.
+ qWarning() << "QSslKey: Found DSA when asked to use" << getName(that->algorithm())
+ << "\nLoading will fail.";
+ return -1;
+ }
+ // DSA's structure is documented here:
+ // https://www.cryptsoft.com/pkcs11doc/STANDARD/v201-95.pdf in section 11.9.
+ if (pkcs8Info[1].type() != QAsn1Element::SequenceType)
+ return -1;
+ const auto dsaInfo = pkcs8Info[1].toList();
+ if (dsaInfo.size() != 3 || dsaInfo[0].type() != QAsn1Element::IntegerType)
+ return -1;
+ keyLength = numberOfBits(dsaInfo[0].value());
+ } else if (value == DH_ENCRYPTION_OID) {
+ if (Q_UNLIKELY(that->algorithm() != QSsl::Dh)) {
+ // As above for RSA.
+ qWarning() << "QSslKey: Found DH when asked to use" << getName(that->algorithm())
+ << "\nLoading will fail.";
+ return -1;
+ }
+ // DH's structure is documented here:
+ // https://www.cryptsoft.com/pkcs11doc/STANDARD/v201-95.pdf in section 11.9.
+ if (pkcs8Info[1].type() != QAsn1Element::SequenceType)
+ return -1;
+ const auto dhInfo = pkcs8Info[1].toList();
+ if (dhInfo.size() < 2 || dhInfo.size() > 3 || dhInfo[0].type() != QAsn1Element::IntegerType)
+ return -1;
+ keyLength = numberOfBits(dhInfo[0].value());
+ } else {
+ // in case of unexpected formats:
+ qWarning() << "QSslKey: Unsupported PKCS#8 key algorithm:" << value
+ << "\nFile a bugreport to Qt (include the line above).";
+ return -1;
+ }
+
+ return keyLength;
+}
+
+} // Unnamed namespace
+
+void TlsKeyGeneric::decodeDer(QSsl::KeyType type, QSsl::KeyAlgorithm algorithm, const QByteArray &der,
+ const QByteArray &passPhrase, bool deepClear)
+{
+ keyType = type;
+ keyAlgorithm = algorithm;
+
+ clear(deepClear);
+
+ if (der.isEmpty())
+ return;
+ // decryptPkcs8 decrypts if necessary or returns 'der' unaltered
+ QByteArray decryptedDer = decryptPkcs8(der, passPhrase);
+
+ QAsn1Element elem;
+ if (!elem.read(decryptedDer) || elem.type() != QAsn1Element::SequenceType)
+ return;
+
+ if (type == QSsl::PublicKey) {
+ // key info
+ QDataStream keyStream(elem.value());
+ if (!elem.read(keyStream) || elem.type() != QAsn1Element::SequenceType)
+ return;
+ const auto infoItems = elem.toList();
+ if (infoItems.size() < 2 || infoItems[0].type() != QAsn1Element::ObjectIdentifierType)
+ return;
+ if (algorithm == QSsl::Rsa) {
+ if (infoItems[0].toObjectId() != RSA_ENCRYPTION_OID)
+ return;
+ // key data
+ if (!elem.read(keyStream) || elem.type() != QAsn1Element::BitStringType || elem.value().isEmpty())
+ return;
+ if (!elem.read(elem.value().mid(1)) || elem.type() != QAsn1Element::SequenceType)
+ return;
+ if (!elem.read(elem.value()) || elem.type() != QAsn1Element::IntegerType)
+ return;
+ keyLength = numberOfBits(elem.value());
+ } else if (algorithm == QSsl::Dsa) {
+ if (infoItems[0].toObjectId() != DSA_ENCRYPTION_OID)
+ return;
+ if (infoItems[1].type() != QAsn1Element::SequenceType)
+ return;
+ // key params
+ const auto params = infoItems[1].toList();
+ if (params.isEmpty() || params[0].type() != QAsn1Element::IntegerType)
+ return;
+ keyLength = numberOfBits(params[0].value());
+ } else if (algorithm == QSsl::Dh) {
+ if (infoItems[0].toObjectId() != DH_ENCRYPTION_OID)
+ return;
+ if (infoItems[1].type() != QAsn1Element::SequenceType)
+ return;
+ // key params
+ const auto params = infoItems[1].toList();
+ if (params.isEmpty() || params[0].type() != QAsn1Element::IntegerType)
+ return;
+ keyLength = numberOfBits(params[0].value());
+ } else if (algorithm == QSsl::Ec) {
+ if (infoItems[0].toObjectId() != EC_ENCRYPTION_OID)
+ return;
+ if (infoItems[1].type() != QAsn1Element::ObjectIdentifierType)
+ return;
+ keyLength = curveBits(infoItems[1].toObjectId());
+ }
+
+ } else {
+ const auto items = elem.toList();
+ if (items.isEmpty())
+ return;
+
+ // version
+ if (items[0].type() != QAsn1Element::IntegerType)
+ return;
+ const QByteArray versionHex = items[0].value().toHex();
+
+ if (items.size() == 3 && items[1].type() == QAsn1Element::SequenceType
+ && items[2].type() == QAsn1Element::OctetStringType) {
+ if (versionHex != "00" && versionHex != "01")
+ return;
+ int pkcs8KeyLength = extractPkcs8KeyLength(items, this);
+ if (pkcs8KeyLength == -1)
+ return;
+ pkcs8 = true;
+ keyLength = pkcs8KeyLength;
+ } else if (algorithm == QSsl::Rsa) {
+ if (versionHex != "00")
+ return;
+ if (items.size() != 9 || items[1].type() != QAsn1Element::IntegerType)
+ return;
+ keyLength = numberOfBits(items[1].value());
+ } else if (algorithm == QSsl::Dsa) {
+ if (versionHex != "00")
+ return;
+ if (items.size() != 6 || items[1].type() != QAsn1Element::IntegerType)
+ return;
+ keyLength = numberOfBits(items[1].value());
+ } else if (algorithm == QSsl::Dh) {
+ if (versionHex != "00")
+ return;
+ if (items.size() < 5 || items.size() > 6 || items[1].type() != QAsn1Element::IntegerType)
+ return;
+ keyLength = numberOfBits(items[1].value());
+ } else if (algorithm == QSsl::Ec) {
+ if (versionHex != "01")
+ return;
+ if (items.size() != 4
+ || items[1].type() != QAsn1Element::OctetStringType
+ || items[2].type() != QAsn1Element::Context0Type
+ || items[3].type() != QAsn1Element::Context1Type)
+ return;
+ QAsn1Element oidElem;
+ if (!oidElem.read(items[2].value())
+ || oidElem.type() != QAsn1Element::ObjectIdentifierType)
+ return;
+ keyLength = curveBits(oidElem.toObjectId());
+ }
+ }
+
+ derData = decryptedDer;
+ keyIsNull = false;
+}
+
+void TlsKeyGeneric::decodePem(QSsl::KeyType type, QSsl::KeyAlgorithm algorithm, const QByteArray &pem,
+ const QByteArray &passPhrase, bool deepClear)
+{
+ keyType = type;
+ keyAlgorithm = algorithm;
+
+ QMap<QByteArray, QByteArray> headers;
+ QByteArray data = derFromPem(pem, &headers);
+
+ if (headers.value("Proc-Type") == "4,ENCRYPTED") {
+ const QList<QByteArray> dekInfo = headers.value("DEK-Info").split(',');
+ if (dekInfo.size() != 2) {
+ clear(deepClear);
+ return;
+ }
+
+ QSslKeyPrivate::Cipher cipher;
+ if (dekInfo.first() == "DES-CBC") {
+ cipher = Cipher::DesCbc;
+ } else if (dekInfo.first() == "DES-EDE3-CBC") {
+ cipher = Cipher::DesEde3Cbc;
+ } else if (dekInfo.first() == "RC2-CBC") {
+ cipher = Cipher::Rc2Cbc;
+ } else if (dekInfo.first() == "AES-128-CBC") {
+ cipher = Cipher::Aes128Cbc;
+ } else if (dekInfo.first() == "AES-192-CBC") {
+ cipher = Cipher::Aes192Cbc;
+ } else if (dekInfo.first() == "AES-256-CBC") {
+ cipher = Cipher::Aes256Cbc;
+ } else {
+ clear(deepClear);
+ return;
+ }
+
+ const QByteArray iv = QByteArray::fromHex(dekInfo.last());
+ const QByteArray key = deriveKey(cipher, passPhrase, iv);
+ data = decrypt(cipher, data, key, iv);
+ }
+
+ decodeDer(keyType, keyAlgorithm, data, passPhrase, deepClear);
+}
+
+QByteArray TlsKeyGeneric::toPem(const QByteArray &passPhrase) const
+{
+ QByteArray data;
+ QMap<QByteArray, QByteArray> headers;
+
+ if (type() == QSsl::PrivateKey && !passPhrase.isEmpty()) {
+ // ### use a cryptographically secure random number generator
+ quint64 random = QRandomGenerator::system()->generate64();
+ QByteArray iv = QByteArray::fromRawData(reinterpret_cast<const char *>(&random), sizeof(random));
+
+ auto cipher = Cipher::DesEde3Cbc;
+ const QByteArray key = deriveKey(cipher, passPhrase, iv);
+ data = encrypt(cipher, derData, key, iv);
+
+ headers.insert("Proc-Type", "4,ENCRYPTED");
+ headers.insert("DEK-Info", "DES-EDE3-CBC," + iv.toHex());
+ } else {
+ data = derData;
+ }
+
+ return pemFromDer(data, headers);
+}
+
+QByteArray TlsKeyGeneric::derFromPem(const QByteArray &pem, QMap<QByteArray, QByteArray> *headers) const
+{
+ if (derData.size())
+ return derData;
+
+ QByteArray header = pemHeader();
+ QByteArray footer = pemFooter();
+
+ QByteArray der(pem);
+
+ int headerIndex = der.indexOf(header);
+ int footerIndex = der.indexOf(footer, headerIndex + header.length());
+ if (type() != QSsl::PublicKey) {
+ if (headerIndex == -1 || footerIndex == -1) {
+ header = pkcs8Header(true);
+ footer = pkcs8Footer(true);
+ headerIndex = der.indexOf(header);
+ footerIndex = der.indexOf(footer, headerIndex + header.length());
+ }
+ if (headerIndex == -1 || footerIndex == -1) {
+ header = pkcs8Header(false);
+ footer = pkcs8Footer(false);
+ headerIndex = der.indexOf(header);
+ footerIndex = der.indexOf(footer, headerIndex + header.length());
+ }
+ }
+ if (headerIndex == -1 || footerIndex == -1)
+ return QByteArray();
+
+ der = der.mid(headerIndex + header.size(), footerIndex - (headerIndex + header.size()));
+
+ if (der.contains("Proc-Type:")) {
+ // taken from QHttpNetworkReplyPrivate::parseHeader
+ int i = 0;
+ while (i < der.length()) {
+ int j = der.indexOf(':', i); // field-name
+ if (j == -1)
+ break;
+ const QByteArray field = der.mid(i, j - i).trimmed();
+ j++;
+ // any number of LWS is allowed before and after the value
+ QByteArray value;
+ do {
+ i = der.indexOf('\n', j);
+ if (i == -1)
+ break;
+ if (!value.isEmpty())
+ value += ' ';
+ // check if we have CRLF or only LF
+ bool hasCR = (i && der[i-1] == '\r');
+ int length = i -(hasCR ? 1: 0) - j;
+ value += der.mid(j, length).trimmed();
+ j = ++i;
+ } while (i < der.length() && (der.at(i) == ' ' || der.at(i) == '\t'));
+ if (i == -1)
+ break; // something is wrong
+
+ headers->insert(field, value);
+ }
+ der = der.mid(i);
+ }
+
+ return QByteArray::fromBase64(der); // ignores newlines
+}
+
+void TlsKeyGeneric::fromHandle(Qt::HANDLE handle, KeyType expectedType)
+{
+ opaque = handle;
+ keyType = expectedType;
+}
+
+void TlsKeyGeneric::clear(bool deep)
+{
+ keyIsNull = true;
+ if (deep)
+ std::memset(derData.data(), 0, derData.size());
+ derData.clear();
+ keyLength = -1;
+}
+
+QByteArray TlsKeyGeneric::decryptPkcs8(const QByteArray &encrypted, const QByteArray &passPhrase)
+{
+ // RFC 5958: https://tools.ietf.org/html/rfc5958
+ /*** Scheme: ***
+ * Sequence
+ * Sequence
+ * Object Identifier (encryption scheme (currently PBES2, PBES1, @todo PKCS12))
+ * Sequence (scheme parameters)
+ * Octet String (the encrypted data)
+ */
+ QAsn1Element elem;
+ if (!elem.read(encrypted) || elem.type() != QAsn1Element::SequenceType)
+ return encrypted;
+
+ const auto items = elem.toList();
+ if (items.size() != 2
+ || items[0].type() != QAsn1Element::SequenceType
+ || items[1].type() != QAsn1Element::OctetStringType) {
+ return encrypted;
+ }
+
+ const auto encryptionSchemeContainer = items[0].toList();
+
+ if (encryptionSchemeContainer.size() != 2
+ || encryptionSchemeContainer[0].type() != QAsn1Element::ObjectIdentifierType
+ || encryptionSchemeContainer[1].type() != QAsn1Element::SequenceType) {
+ return encrypted;
+ }
+
+ const QByteArray encryptionScheme = encryptionSchemeContainer[0].toObjectId();
+ const auto schemeParameterContainer = encryptionSchemeContainer[1].toList();
+
+ if (schemeParameterContainer.size() != 2
+ && schemeParameterContainer[0].type() != QAsn1Element::SequenceType
+ && schemeParameterContainer[1].type() != QAsn1Element::SequenceType) {
+ return encrypted;
+ }
+
+ EncryptionData data;
+ if (encryptionScheme == PKCS5_PBES2_ENCRYPTION_OID) {
+ data = readPbes2(schemeParameterContainer, passPhrase);
+ } else if (pbes1OidHashFunctionMap.contains(encryptionScheme)) {
+ data = readPbes1(schemeParameterContainer, encryptionScheme, passPhrase);
+ } else if (encryptionScheme.startsWith(PKCS12_OID)) {
+ Q_UNIMPLEMENTED(); // this isn't some 'unknown', I know these aren't implemented
+ return encrypted;
+ } else {
+ qWarning()
+ << "QSslKey: Unsupported encryption scheme OID:" << encryptionScheme
+ << "\nFile a bugreport to Qt (include the line above).";
+ return encrypted;
+ }
+
+ if (!data.initialized) {
+ // something went wrong, return
+ return encrypted;
+ }
+
+ QByteArray decryptedKey = decrypt(data.cipher, items[1].value(), data.key, data.iv);
+ // The data is still wrapped in a octet string, so let's unwrap it
+ QAsn1Element decryptedKeyElement(QAsn1Element::ElementType::OctetStringType, decryptedKey);
+ return decryptedKeyElement.value();
+}
+
+} // namespace QTlsPrivate
+
+QT_END_NAMESPACE
diff --git a/src/plugins/tls/shared/qtlskey_generic_p.h b/src/plugins/tls/shared/qtlskey_generic_p.h
new file mode 100644
index 0000000000..6344633cc7
--- /dev/null
+++ b/src/plugins/tls/shared/qtlskey_generic_p.h
@@ -0,0 +1,83 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QTLSKEY_GENERIC_P_H
+#define QTLSKEY_GENERIC_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 <QtNetwork/private/qtnetworkglobal_p.h>
+
+#include <QtNetwork/private/qtlsbackend_p.h>
+
+#include "qtlskey_base_p.h"
+
+
+#include <QtCore/qnamespace.h>
+#include <QtCore/qglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QTlsPrivate {
+
+// This class is what previously was known as qsslkey_qt:
+// it implements most of functionality needed by QSslKey
+// not relying on any TLS implementation. It's used by
+// our SecureTransport and Schannel backends.
+class TlsKeyGeneric : public TlsKeyBase
+{
+public:
+ using TlsKeyBase::TlsKeyBase;
+
+ void decodeDer(KeyType type, KeyAlgorithm algorithm, const QByteArray &der,
+ const QByteArray &passPhrase, bool deepClear) override;
+ void decodePem(KeyType type, KeyAlgorithm algorithm, const QByteArray &pem,
+ const QByteArray &passPhrase, bool deepClear) override;
+
+ QByteArray toPem(const QByteArray &passPhrase) const override;
+
+ QByteArray derFromPem(const QByteArray &pem, QMap<QByteArray,
+ QByteArray> *headers) const override;
+
+ void fromHandle(Qt::HANDLE opaque, KeyType expectedType) override;
+
+ void clear(bool deep) override;
+
+ Qt::HANDLE handle() const override
+ {
+ return Qt::HANDLE(opaque);
+ }
+
+ int length() const override
+ {
+ return keyLength;
+ }
+
+ bool isPkcs8() const override
+ {
+ return pkcs8;
+ }
+
+private:
+ QByteArray decryptPkcs8(const QByteArray &encrypted, const QByteArray &passPhrase);
+
+ bool pkcs8 = false;
+ Qt::HANDLE opaque = nullptr;
+ QByteArray derData;
+ int keyLength = -1;
+};
+
+} // namespace QTlsPrivate
+
+QT_END_NAMESPACE
+
+#endif // QTLSKEY_GENERIC_P_H
diff --git a/src/plugins/tls/shared/qwincrypt_p.h b/src/plugins/tls/shared/qwincrypt_p.h
new file mode 100644
index 0000000000..48ca4247fa
--- /dev/null
+++ b/src/plugins/tls/shared/qwincrypt_p.h
@@ -0,0 +1,55 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QWINCRYPT_P_H
+#define QWINCRYPT_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 <QtNetwork/private/qtnetworkglobal_p.h>
+
+#include <QtCore/qt_windows.h>
+
+#include <QtCore/qglobal.h>
+
+#include <wincrypt.h>
+#ifndef HCRYPTPROV_LEGACY
+#define HCRYPTPROV_LEGACY HCRYPTPROV
+#endif // !HCRYPTPROV_LEGACY
+
+#include <memory>
+
+QT_BEGIN_NAMESPACE
+
+struct QHCertStoreDeleter {
+ void operator()(HCERTSTORE store)
+ {
+ CertCloseStore(store, 0);
+ }
+};
+
+// A simple RAII type used by Schannel code and Window CA fetcher class:
+using QHCertStorePointer = std::unique_ptr<void, QHCertStoreDeleter>;
+
+struct QPCCertContextDeleter {
+ void operator()(PCCERT_CONTEXT context) const
+ {
+ CertFreeCertificateContext(context);
+ }
+};
+
+// A simple RAII type used by Schannel code
+using QPCCertContextPointer = std::unique_ptr<const CERT_CONTEXT, QPCCertContextDeleter>;
+
+QT_END_NAMESPACE
+
+#endif // QWINCRYPT_P_H
diff --git a/src/plugins/tls/shared/qx509_base.cpp b/src/plugins/tls/shared/qx509_base.cpp
new file mode 100644
index 0000000000..dfa6569fa6
--- /dev/null
+++ b/src/plugins/tls/shared/qx509_base.cpp
@@ -0,0 +1,142 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qx509_base_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QTlsPrivate {
+
+QByteArray X509CertificateBase::subjectInfoToString(QSslCertificate::SubjectInfo info)
+{
+ QByteArray str;
+ switch (info) {
+ case QSslCertificate::Organization: str = QByteArray("O"); break;
+ case QSslCertificate::CommonName: str = QByteArray("CN"); break;
+ case QSslCertificate::LocalityName: str = QByteArray("L"); break;
+ case QSslCertificate::OrganizationalUnitName: str = QByteArray("OU"); break;
+ case QSslCertificate::CountryName: str = QByteArray("C"); break;
+ case QSslCertificate::StateOrProvinceName: str = QByteArray("ST"); break;
+ case QSslCertificate::DistinguishedNameQualifier: str = QByteArray("dnQualifier"); break;
+ case QSslCertificate::SerialNumber: str = QByteArray("serialNumber"); break;
+ case QSslCertificate::EmailAddress: str = QByteArray("emailAddress"); break;
+ }
+
+ return str;
+}
+
+bool X509CertificateBase::matchLineFeed(const QByteArray &pem, int *offset)
+{
+ Q_ASSERT(offset);
+
+ char ch = 0;
+ // ignore extra whitespace at the end of the line
+ while (*offset < pem.size() && (ch = pem.at(*offset)) == ' ')
+ ++*offset;
+
+ if (ch == '\n') {
+ *offset += 1;
+ return true;
+ }
+
+ if (ch == '\r' && pem.size() > (*offset + 1) && pem.at(*offset + 1) == '\n') {
+ *offset += 2;
+ return true;
+ }
+
+ return false;
+}
+
+bool X509CertificateBase::isNull() const
+{
+ return null;
+}
+
+QByteArray X509CertificateBase::version() const
+{
+ return versionString;
+}
+
+QByteArray X509CertificateBase::serialNumber() const
+{
+ return serialNumberString;
+}
+
+QStringList X509CertificateBase::issuerInfo(QSslCertificate::SubjectInfo info) const
+{
+ return issuerInfo(subjectInfoToString(info));
+}
+
+QStringList X509CertificateBase::issuerInfo(const QByteArray &attribute) const
+{
+ return issuerInfoEntries.values(attribute);
+}
+
+QStringList X509CertificateBase::subjectInfo(QSslCertificate::SubjectInfo info) const
+{
+ return subjectInfo(subjectInfoToString(info));
+}
+
+QStringList X509CertificateBase::subjectInfo(const QByteArray &attribute) const
+{
+ return subjectInfoEntries.values(attribute);
+}
+
+QList<QByteArray> X509CertificateBase::subjectInfoAttributes() const
+{
+ return subjectInfoEntries.uniqueKeys();
+}
+
+QList<QByteArray> X509CertificateBase::issuerInfoAttributes() const
+{
+ return issuerInfoEntries.uniqueKeys();
+}
+
+QDateTime X509CertificateBase::effectiveDate() const
+{
+ return notValidBefore;
+}
+
+QDateTime X509CertificateBase::expiryDate() const
+{
+ return notValidAfter;
+}
+
+qsizetype X509CertificateBase::numberOfExtensions() const
+{
+ return extensions.size();
+}
+
+QString X509CertificateBase::oidForExtension(qsizetype index) const
+{
+ Q_ASSERT(validIndex(index));
+ return extensions[index].oid;
+}
+
+QString X509CertificateBase::nameForExtension(qsizetype index) const
+{
+ Q_ASSERT(validIndex(index));
+ return extensions[index].name;
+}
+
+QVariant X509CertificateBase::valueForExtension(qsizetype index) const
+{
+ Q_ASSERT(validIndex(index));
+ return extensions[index].value;
+}
+
+bool X509CertificateBase::isExtensionCritical(qsizetype index) const
+{
+ Q_ASSERT(validIndex(index));
+ return extensions[index].critical;
+}
+
+bool X509CertificateBase::isExtensionSupported(qsizetype index) const
+{
+ Q_ASSERT(validIndex(index));
+ return extensions[index].supported;
+}
+
+} // namespace QTlsPrivate
+
+QT_END_NAMESPACE
diff --git a/src/plugins/tls/shared/qx509_base_p.h b/src/plugins/tls/shared/qx509_base_p.h
new file mode 100644
index 0000000000..0f268880af
--- /dev/null
+++ b/src/plugins/tls/shared/qx509_base_p.h
@@ -0,0 +1,89 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QX509CERTIFICATE_BASE_P_H
+#define QX509CERTIFICATE_BASE_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 <QtNetwork/private/qtnetworkglobal_p.h>
+
+#include <QtNetwork/private/qtlsbackend_p.h>
+
+#include <QtNetwork/qssl.h>
+
+#include <QtCore/qbytearray.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qglobal.h>
+#include <QtCore/qlist.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QTlsPrivate {
+
+class X509CertificateBase : public X509Certificate
+{
+public:
+ bool isNull() const override;
+ QByteArray version() const override;
+ QByteArray serialNumber() const override;
+ QStringList issuerInfo(QSslCertificate::SubjectInfo info) const override;
+ QStringList issuerInfo(const QByteArray &attribute) const override;
+ QStringList subjectInfo(QSslCertificate::SubjectInfo info) const override;
+ QStringList subjectInfo(const QByteArray &attribute) const override;
+ QList<QByteArray> subjectInfoAttributes() const override;
+ QList<QByteArray> issuerInfoAttributes() const override;
+ QDateTime effectiveDate() const override;
+ QDateTime expiryDate() const override;
+
+ qsizetype numberOfExtensions() const override;
+ QString oidForExtension(qsizetype index) const override;
+ QString nameForExtension(qsizetype index) const override;
+ QVariant valueForExtension(qsizetype index) const override;
+ bool isExtensionCritical(qsizetype index) const override;
+ bool isExtensionSupported(qsizetype index) const override;
+
+ static QByteArray subjectInfoToString(QSslCertificate::SubjectInfo info);
+ static bool matchLineFeed(const QByteArray &pem, int *offset);
+
+protected:
+ bool validIndex(qsizetype index) const
+ {
+ return index >= 0 && index < extensions.size();
+ }
+
+ bool null = true;
+ QByteArray versionString;
+ QByteArray serialNumberString;
+
+ QMultiMap<QByteArray, QString> issuerInfoEntries;
+ QMultiMap<QByteArray, QString> subjectInfoEntries;
+ QDateTime notValidAfter;
+ QDateTime notValidBefore;
+
+ struct X509CertificateExtension
+ {
+ QString oid;
+ QString name;
+ QVariant value;
+ bool critical = false;
+ bool supported = false;
+ };
+
+ QList<X509CertificateExtension> extensions;
+};
+
+} // namespace QTlsPrivate
+
+QT_END_NAMESPACE
+
+#endif // QX509CERTIFICATE_BASE_P_H
diff --git a/src/plugins/tls/shared/qx509_generic.cpp b/src/plugins/tls/shared/qx509_generic.cpp
new file mode 100644
index 0000000000..5006db1a72
--- /dev/null
+++ b/src/plugins/tls/shared/qx509_generic.cpp
@@ -0,0 +1,432 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <QtNetwork/private/qsslcertificate_p.h>
+#include <QtNetwork/private/qssl_p.h>
+
+#include "qasn1element_p.h"
+#include "qx509_generic_p.h"
+
+#include <QtNetwork/qhostaddress.h>
+
+#include <QtCore/qendian.h>
+#include <QtCore/qhash.h>
+
+#include <memory>
+
+QT_BEGIN_NAMESPACE
+
+using namespace Qt::StringLiterals;
+
+namespace QTlsPrivate {
+
+namespace {
+
+QByteArray colonSeparatedHex(const QByteArray &value)
+{
+ const int size = value.size();
+ int i = 0;
+ while (i < size && !value.at(i)) // skip leading zeros
+ ++i;
+
+ return value.mid(i).toHex(':');
+}
+
+} // Unnamed namespace.
+
+bool X509CertificateGeneric::isEqual(const X509Certificate &rhs) const
+{
+ const auto &other = static_cast<const X509CertificateGeneric &>(rhs);
+ return derData == other.derData;
+}
+
+bool X509CertificateGeneric::isSelfSigned() const
+{
+ if (null)
+ return false;
+
+ return subjectMatchesIssuer;
+}
+
+QMultiMap<QSsl::AlternativeNameEntryType, QString> X509CertificateGeneric::subjectAlternativeNames() const
+{
+ return saNames;
+}
+
+#define BEGINCERTSTRING "-----BEGIN CERTIFICATE-----"
+#define ENDCERTSTRING "-----END CERTIFICATE-----"
+
+QByteArray X509CertificateGeneric::toPem() const
+{
+ QByteArray array = toDer();
+ // Convert to Base64 - wrap at 64 characters.
+ array = array.toBase64();
+ QByteArray tmp;
+ for (int i = 0; i <= array.size() - 64; i += 64) {
+ tmp += QByteArray::fromRawData(array.data() + i, 64);
+ tmp += '\n';
+ }
+ if (int remainder = array.size() % 64) {
+ tmp += QByteArray::fromRawData(array.data() + array.size() - remainder, remainder);
+ tmp += '\n';
+ }
+
+ return BEGINCERTSTRING "\n" + tmp + ENDCERTSTRING "\n";
+}
+
+QByteArray X509CertificateGeneric::toDer() const
+{
+ return derData;
+}
+
+QString X509CertificateGeneric::toText() const
+{
+ Q_UNIMPLEMENTED();
+ return {};
+}
+
+Qt::HANDLE X509CertificateGeneric::handle() const
+{
+ Q_UNIMPLEMENTED();
+ return nullptr;
+}
+
+size_t X509CertificateGeneric::hash(size_t seed) const noexcept
+{
+ return qHash(toDer(), seed);
+}
+
+QList<QSslCertificate> X509CertificateGeneric::certificatesFromPem(const QByteArray &pem, int count)
+{
+ QList<QSslCertificate> certificates;
+ int offset = 0;
+ while (count == -1 || certificates.size() < count) {
+ int startPos = pem.indexOf(BEGINCERTSTRING, offset);
+ if (startPos == -1)
+ break;
+ startPos += sizeof(BEGINCERTSTRING) - 1;
+ if (!matchLineFeed(pem, &startPos))
+ break;
+
+ int endPos = pem.indexOf(ENDCERTSTRING, startPos);
+ if (endPos == -1)
+ break;
+
+ offset = endPos + sizeof(ENDCERTSTRING) - 1;
+ if (offset < pem.size() && !matchLineFeed(pem, &offset))
+ break;
+
+ QByteArray decoded = QByteArray::fromBase64(
+ QByteArray::fromRawData(pem.data() + startPos, endPos - startPos));
+ certificates << certificatesFromDer(decoded, 1);
+ }
+
+ return certificates;
+}
+
+QList<QSslCertificate> X509CertificateGeneric::certificatesFromDer(const QByteArray &der, int count)
+{
+ QList<QSslCertificate> certificates;
+
+ QByteArray data = der;
+ while (count == -1 || certificates.size() < count) {
+ QSslCertificate cert;
+ auto *certBackend = QTlsBackend::backend<X509CertificateGeneric>(cert);
+ if (!certBackend->parse(data))
+ break;
+
+ certificates << cert;
+ data.remove(0, certBackend->derData.size());
+ }
+
+ return certificates;
+}
+
+bool X509CertificateGeneric::parse(const QByteArray &data)
+{
+ QAsn1Element root;
+
+ QDataStream dataStream(data);
+ if (!root.read(dataStream) || root.type() != QAsn1Element::SequenceType)
+ return false;
+
+ QDataStream rootStream(root.value());
+ QAsn1Element cert;
+ if (!cert.read(rootStream) || cert.type() != QAsn1Element::SequenceType)
+ return false;
+
+ // version or serial number
+ QAsn1Element elem;
+ QDataStream certStream(cert.value());
+ if (!elem.read(certStream))
+ return false;
+
+ if (elem.type() == QAsn1Element::Context0Type) {
+ QDataStream versionStream(elem.value());
+ if (!elem.read(versionStream)
+ || elem.type() != QAsn1Element::IntegerType
+ || elem.value().isEmpty())
+ return false;
+
+ versionString = QByteArray::number(elem.value().at(0) + 1);
+ if (!elem.read(certStream))
+ return false;
+ } else {
+ versionString = QByteArray::number(1);
+ }
+
+ // serial number
+ if (elem.type() != QAsn1Element::IntegerType)
+ return false;
+ serialNumberString = colonSeparatedHex(elem.value());
+
+ // algorithm ID
+ if (!elem.read(certStream) || elem.type() != QAsn1Element::SequenceType)
+ return false;
+
+ // issuer info
+ if (!elem.read(certStream) || elem.type() != QAsn1Element::SequenceType)
+ return false;
+
+ QByteArray issuerDer = data.mid(dataStream.device()->pos() - elem.value().size(), elem.value().size());
+ issuerInfoEntries = elem.toInfo();
+
+ // validity period
+ if (!elem.read(certStream) || elem.type() != QAsn1Element::SequenceType)
+ return false;
+
+ QDataStream validityStream(elem.value());
+ if (!elem.read(validityStream) || (elem.type() != QAsn1Element::UtcTimeType && elem.type() != QAsn1Element::GeneralizedTimeType))
+ return false;
+
+ notValidBefore = elem.toDateTime();
+ if (!notValidBefore.isValid())
+ return false;
+
+ if (!elem.read(validityStream) || (elem.type() != QAsn1Element::UtcTimeType && elem.type() != QAsn1Element::GeneralizedTimeType))
+ return false;
+
+ notValidAfter = elem.toDateTime();
+ if (!notValidAfter.isValid())
+ return false;
+
+
+ // subject name
+ if (!elem.read(certStream) || elem.type() != QAsn1Element::SequenceType)
+ return false;
+
+ QByteArray subjectDer = data.mid(dataStream.device()->pos() - elem.value().size(), elem.value().size());
+ subjectInfoEntries = elem.toInfo();
+ subjectMatchesIssuer = issuerDer == subjectDer;
+
+ // public key
+ qint64 keyStart = certStream.device()->pos();
+ if (!elem.read(certStream) || elem.type() != QAsn1Element::SequenceType)
+ return false;
+
+ publicKeyDerData.resize(certStream.device()->pos() - keyStart);
+ QDataStream keyStream(elem.value());
+ if (!elem.read(keyStream) || elem.type() != QAsn1Element::SequenceType)
+ return false;
+
+
+ // key algorithm
+ if (!elem.read(elem.value()) || elem.type() != QAsn1Element::ObjectIdentifierType)
+ return false;
+
+ const QByteArray oid = elem.toObjectId();
+ if (oid == RSA_ENCRYPTION_OID)
+ publicKeyAlgorithm = QSsl::Rsa;
+ else if (oid == DSA_ENCRYPTION_OID)
+ publicKeyAlgorithm = QSsl::Dsa;
+ else if (oid == EC_ENCRYPTION_OID)
+ publicKeyAlgorithm = QSsl::Ec;
+ else
+ publicKeyAlgorithm = QSsl::Opaque;
+
+ certStream.device()->seek(keyStart);
+ certStream.readRawData(publicKeyDerData.data(), publicKeyDerData.size());
+
+ // extensions
+ while (elem.read(certStream)) {
+ if (elem.type() == QAsn1Element::Context3Type) {
+ if (elem.read(elem.value()) && elem.type() == QAsn1Element::SequenceType) {
+ QDataStream extStream(elem.value());
+ while (elem.read(extStream) && elem.type() == QAsn1Element::SequenceType) {
+ X509CertificateExtension extension;
+ if (!parseExtension(elem.value(), extension))
+ return false;
+
+ if (extension.oid == "2.5.29.17"_L1) {
+ // subjectAltName
+
+ // Note, parseExtension() returns true for this extensions,
+ // but considers it to be unsupported and assigns a useless
+ // value. OpenSSL also treats this extension as unsupported,
+ // but properly creates a map with 'name' and 'value' taken
+ // from the extension. We only support 'email', 'IP' and 'DNS',
+ // but this is what our subjectAlternativeNames map can contain
+ // anyway.
+ QVariantMap extValue;
+ QAsn1Element sanElem;
+ if (sanElem.read(extension.value.toByteArray()) && sanElem.type() == QAsn1Element::SequenceType) {
+ QDataStream nameStream(sanElem.value());
+ QAsn1Element nameElem;
+ while (nameElem.read(nameStream)) {
+ switch (nameElem.type()) {
+ case QAsn1Element::Rfc822NameType:
+ saNames.insert(QSsl::EmailEntry, nameElem.toString());
+ extValue[QStringLiteral("email")] = nameElem.toString();
+ break;
+ case QAsn1Element::DnsNameType:
+ saNames.insert(QSsl::DnsEntry, nameElem.toString());
+ extValue[QStringLiteral("DNS")] = nameElem.toString();
+ break;
+ case QAsn1Element::IpAddressType: {
+ QHostAddress ipAddress;
+ QByteArray ipAddrValue = nameElem.value();
+ switch (ipAddrValue.size()) {
+ case 4: // IPv4
+ ipAddress = QHostAddress(qFromBigEndian(*reinterpret_cast<quint32 *>(ipAddrValue.data())));
+ break;
+ case 16: // IPv6
+ ipAddress = QHostAddress(reinterpret_cast<quint8 *>(ipAddrValue.data()));
+ break;
+ default: // Unknown IP address format
+ break;
+ }
+ if (!ipAddress.isNull()) {
+ saNames.insert(QSsl::IpAddressEntry, ipAddress.toString());
+ extValue[QStringLiteral("IP")] = ipAddress.toString();
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ extension.value = extValue;
+ extension.supported = true;
+ }
+ }
+
+ extensions << extension;
+ }
+ }
+ }
+ }
+
+ derData = data.left(dataStream.device()->pos());
+ null = false;
+ return true;
+}
+
+bool X509CertificateGeneric::parseExtension(const QByteArray &data, X509CertificateExtension &extension)
+{
+ bool ok = false;
+ bool critical = false;
+ QAsn1Element oidElem, valElem;
+
+ QDataStream seqStream(data);
+
+ // oid
+ if (!oidElem.read(seqStream) || oidElem.type() != QAsn1Element::ObjectIdentifierType)
+ return false;
+
+ const QByteArray oid = oidElem.toObjectId();
+ // critical and value
+ if (!valElem.read(seqStream))
+ return false;
+
+ if (valElem.type() == QAsn1Element::BooleanType) {
+ critical = valElem.toBool(&ok);
+
+ if (!ok || !valElem.read(seqStream))
+ return false;
+ }
+
+ if (valElem.type() != QAsn1Element::OctetStringType)
+ return false;
+
+ // interpret value
+ QAsn1Element val;
+ bool supported = true;
+ QVariant value;
+ if (oid == "1.3.6.1.5.5.7.1.1") {
+ // authorityInfoAccess
+ if (!val.read(valElem.value()) || val.type() != QAsn1Element::SequenceType)
+ return false;
+ QVariantMap result;
+ const auto elems = val.toList();
+ for (const QAsn1Element &el : elems) {
+ const auto items = el.toList();
+ if (items.size() != 2)
+ return false;
+ const QString key = QString::fromLatin1(items.at(0).toObjectName());
+ switch (items.at(1).type()) {
+ case QAsn1Element::Rfc822NameType:
+ case QAsn1Element::DnsNameType:
+ case QAsn1Element::UniformResourceIdentifierType:
+ result[key] = items.at(1).toString();
+ break;
+ }
+ }
+ value = result;
+ } else if (oid == "2.5.29.14") {
+ // subjectKeyIdentifier
+ if (!val.read(valElem.value()) || val.type() != QAsn1Element::OctetStringType)
+ return false;
+ value = colonSeparatedHex(val.value()).toUpper();
+ } else if (oid == "2.5.29.19") {
+ // basicConstraints
+ if (!val.read(valElem.value()) || val.type() != QAsn1Element::SequenceType)
+ return false;
+
+ QVariantMap result;
+ const auto items = val.toList();
+ if (items.size() > 0) {
+ result[QStringLiteral("ca")] = items.at(0).toBool(&ok);
+ if (!ok)
+ return false;
+ } else {
+ result[QStringLiteral("ca")] = false;
+ }
+ if (items.size() > 1) {
+ result[QStringLiteral("pathLenConstraint")] = items.at(1).toInteger(&ok);
+ if (!ok)
+ return false;
+ }
+ value = result;
+ } else if (oid == "2.5.29.35") {
+ // authorityKeyIdentifier
+ if (!val.read(valElem.value()) || val.type() != QAsn1Element::SequenceType)
+ return false;
+ QVariantMap result;
+ const auto elems = val.toList();
+ for (const QAsn1Element &el : elems) {
+ if (el.type() == 0x80) {
+ const QString key = QStringLiteral("keyid");
+ result[key] = el.value().toHex();
+ } else if (el.type() == 0x82) {
+ const QString serial = QStringLiteral("serial");
+ result[serial] = colonSeparatedHex(el.value());
+ }
+ }
+ value = result;
+ } else {
+ supported = false;
+ value = valElem.value();
+ }
+
+ extension.critical = critical;
+ extension.supported = supported;
+ extension.oid = QString::fromLatin1(oid);
+ extension.name = QString::fromLatin1(oidElem.toObjectName());
+ extension.value = value;
+
+ return true;
+}
+
+} // namespace QTlsPrivate
+
+QT_END_NAMESPACE
diff --git a/src/plugins/tls/shared/qx509_generic_p.h b/src/plugins/tls/shared/qx509_generic_p.h
new file mode 100644
index 0000000000..94a4bae7cf
--- /dev/null
+++ b/src/plugins/tls/shared/qx509_generic_p.h
@@ -0,0 +1,65 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+#ifndef QX509_GENERIC_P_H
+#define QX509_GENERIC_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 <QtNetwork/private/qtnetworkglobal_p.h>
+
+#include <QtNetwork/private/qtlsbackend_p.h>
+
+#include "qx509_base_p.h"
+
+#include <QtCore/qbytearray.h>
+#include <QtCore/qglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QTlsPrivate {
+
+// A part of SecureTransport and Schannel plugin.
+class X509CertificateGeneric : public X509CertificateBase
+{
+public:
+ bool isEqual(const X509Certificate &rhs) const override;
+ bool isSelfSigned() const override;
+
+ QMultiMap<QSsl::AlternativeNameEntryType, QString> subjectAlternativeNames() const override;
+ QByteArray toPem() const override;
+ QByteArray toDer() const override;
+ QString toText() const override;
+ Qt::HANDLE handle() const override;
+
+ size_t hash(size_t seed) const noexcept override;
+
+ static QList<QSslCertificate> certificatesFromPem(const QByteArray &pem, int count);
+ static QList<QSslCertificate> certificatesFromDer(const QByteArray &der, int count);
+
+protected:
+
+ bool subjectMatchesIssuer = false;
+ QSsl::KeyAlgorithm publicKeyAlgorithm = QSsl::Rsa;
+ QByteArray publicKeyDerData;
+
+ QMultiMap<QSsl::AlternativeNameEntryType, QString> saNames;
+ QByteArray derData;
+
+ bool parse(const QByteArray &data);
+ bool parseExtension(const QByteArray &data, X509CertificateExtension &extension);
+};
+
+} // namespace QTlsPrivate
+
+QT_END_NAMESPACE
+
+#endif // QX509_GENERIC_P_H
diff --git a/src/plugins/tracing/CMakeLists.txt b/src/plugins/tracing/CMakeLists.txt
new file mode 100644
index 0000000000..823e11c174
--- /dev/null
+++ b/src/plugins/tracing/CMakeLists.txt
@@ -0,0 +1,32 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+function(make_includable input_file output_file)
+ get_filename_component(infile "${CMAKE_CURRENT_SOURCE_DIR}/${input_file}" ABSOLUTE)
+ set(outfile ${CMAKE_CURRENT_BINARY_DIR}/${output_file})
+ file(READ ${infile} content)
+ set(content "R\"(${content})\"")
+ file(WRITE ${outfile} "${content}")
+endfunction(make_includable)
+
+make_includable(metadata_template.txt metadata_template.h)
+
+qt_internal_add_plugin(QCtfTracePlugin
+ CLASS_NAME QCtfTracePlugin
+ PLUGIN_TYPE tracing
+ SOURCES
+ qctflib_p.h qctflib.cpp metadata_template.txt qctfplugin.cpp qctfplugin_p.h
+ qctfserver_p.h qctfserver.cpp
+ LIBRARIES
+ Qt::Core Qt::CorePrivate Qt::Network
+)
+
+qt_internal_extend_target(QCtfTracePlugin CONDITION QT_FEATURE_zstd
+ LIBRARIES
+ WrapZSTD::WrapZSTD
+)
+
+qt_internal_extend_target(QCtfTracePlugin CONDITION (QT_FEATURE_cxx17_filesystem) AND (GCC AND (QMAKE_GCC_MAJOR_VERSION LESS 9))
+ LINK_OPTIONS
+ "-lstdc++fs"
+)
diff --git a/src/plugins/tracing/metadata_template.txt b/src/plugins/tracing/metadata_template.txt
new file mode 100644
index 0000000000..5f27e79da5
--- /dev/null
+++ b/src/plugins/tracing/metadata_template.txt
@@ -0,0 +1,77 @@
+/* CTF 1.8 */
+
+typealias integer { size = 8; align = 8; signed = false; } := uint8_t;
+typealias integer { size = 16; align = 8; signed = false; } := uint16_t;
+typealias integer { size = 32; align = 8; signed = false; } := uint32_t;
+typealias integer { size = 64; align = 8; signed = false; } := uint64_t;
+typealias integer { size = 8; align = 8; signed = true; } := int8_t;
+typealias integer { size = 16; align = 8; signed = true; } := int16_t;
+typealias integer { size = 32; align = 8; signed = true; } := int32_t;
+typealias integer { size = 64; align = 8; signed = true; } := int64_t;
+typealias integer { size = 32; align = 8; signed = true; base = 16; } := intptr32_t;
+typealias integer { size = 64; align = 8; signed = true; base = 16; } := intptr64_t;
+typealias floating_point { exp_dig = 8; mant_dig = 24; align = 8; byte_order = native; } := float;
+typealias floating_point { exp_dig = 11; mant_dig = 53; align = 8; byte_order = native; } := double;
+
+typealias enum : integer { size = 8; } {
+ false,
+ true
+} := Boolean;
+
+trace {
+ major = 1;
+ minor = 8;
+ uuid = "$TRACE_UUID";
+ byte_order = $ENDIANNESS;
+ packet.header := struct {
+ uint32_t magic;
+ uint8_t uuid[16];
+ uint32_t stream_id;
+ } align(8);
+};
+
+env {
+ domain = "ust";
+ tracer_name = "qtctf";
+ tracer_major = 1;
+ tracer_minor = 0;
+ architecture_bit_width = $ARC_BIT_WIDTH;
+ trace_name = "$SESSION_NAME";
+ trace_creation_datetime = "$CREATION_TIME";
+ hostname = "$HOST_NAME";
+};
+
+clock {
+ name = "$CLOCK_NAME";
+ uuid = "53836526-5a62-4de0-93c8-3a1970afab23";
+ description = "$CLOCK_TYPE";
+ freq = $CLOCK_FREQUENCY;
+ offset = $CLOCK_OFFSET;
+};
+
+typealias integer {
+ size = 64; align = 8; signed = false;
+ map = clock.monotonic.value;
+} := uint64_clock_monotonic_t;
+
+struct packet_context {
+ uint64_clock_monotonic_t timestamp_begin;
+ uint64_clock_monotonic_t timestamp_end;
+ uint64_t content_size;
+ uint64_t packet_size;
+ uint64_t packet_seq_num;
+ uint64_t events_discarded;
+ uint32_t thread_id;
+ string thread_name;
+} align(8);
+
+struct event_header {
+ uint32_t id;
+ uint64_clock_monotonic_t timestamp;
+} align(8);
+
+stream {
+ id = 0;
+ event.header := struct event_header;
+ packet.context := struct packet_context;
+};
diff --git a/src/plugins/tracing/qctflib.cpp b/src/plugins/tracing/qctflib.cpp
new file mode 100644
index 0000000000..fe3946d27c
--- /dev/null
+++ b/src/plugins/tracing/qctflib.cpp
@@ -0,0 +1,447 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+#define BUILD_LIBRARY
+#include <qstring.h>
+#include <qthread.h>
+#include <stdio.h>
+#include <qjsondocument.h>
+#include <qjsonarray.h>
+#include <qjsonobject.h>
+#include <qfileinfo.h>
+#include <qrect.h>
+#include <qsize.h>
+#include <qmetaobject.h>
+#include <qendian.h>
+#include <qplatformdefs.h>
+#include "qctflib_p.h"
+
+#if QT_CONFIG(cxx17_filesystem)
+#include <filesystem>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+using namespace Qt::StringLiterals;
+
+Q_LOGGING_CATEGORY(lcDebugTrace, "qt.core.ctf", QtWarningMsg)
+
+static const size_t packetHeaderSize = 24 + 6 * 8 + 4;
+static const size_t packetSize = 4096;
+
+static const char traceMetadataTemplate[] =
+#include "metadata_template.h"
+;
+static const size_t traceMetadataSize = sizeof(traceMetadataTemplate);
+
+static inline QString allLiteral() { return QStringLiteral("all"); }
+static inline QString defaultLiteral() { return QStringLiteral("default"); }
+
+
+template <typename T>
+static QByteArray &operator<<(QByteArray &arr, T val)
+{
+ static_assert(std::is_arithmetic_v<T>);
+ arr.append(reinterpret_cast<char *>(&val), sizeof(val));
+ return arr;
+}
+
+static FILE *openFile(const QString &filename, const QString &mode)
+{
+#ifdef Q_OS_WINDOWS
+ return _wfopen(qUtf16Printable(filename), qUtf16Printable(mode));
+#else
+ return fopen(qPrintable(filename), qPrintable(mode));
+#endif
+}
+
+QCtfLibImpl *QCtfLibImpl::s_instance = nullptr;
+
+QCtfLib *QCtfLibImpl::instance()
+{
+ if (!s_instance)
+ s_instance = new QCtfLibImpl();
+ return s_instance;
+}
+
+void QCtfLibImpl::cleanup()
+{
+ delete s_instance;
+ s_instance = nullptr;
+}
+
+void QCtfLibImpl::handleSessionChange()
+{
+ m_sessionChanged = true;
+}
+
+void QCtfLibImpl::handleStatusChange(QCtfServer::ServerStatus status)
+{
+ switch (status) {
+ case QCtfServer::Error: {
+ m_serverClosed = true;
+ } break;
+ default:
+ break;
+ }
+}
+
+void QCtfLibImpl::buildMetadata()
+{
+ const QString mhn = QSysInfo::machineHostName();
+ QString metadata = QString::fromUtf8(traceMetadataTemplate, traceMetadataSize);
+ metadata.replace(QStringLiteral("$TRACE_UUID"), s_TraceUuid.toString(QUuid::WithoutBraces));
+ metadata.replace(QStringLiteral("$ARC_BIT_WIDTH"), QString::number(Q_PROCESSOR_WORDSIZE * 8));
+ metadata.replace(QStringLiteral("$SESSION_NAME"), m_session.name);
+ metadata.replace(QStringLiteral("$CREATION_TIME"), m_datetime.toString(Qt::ISODate));
+ metadata.replace(QStringLiteral("$HOST_NAME"), mhn);
+ metadata.replace(QStringLiteral("$CLOCK_FREQUENCY"), QStringLiteral("1000000000"));
+ metadata.replace(QStringLiteral("$CLOCK_NAME"), QStringLiteral("monotonic"));
+ metadata.replace(QStringLiteral("$CLOCK_TYPE"), QStringLiteral("Monotonic clock"));
+ metadata.replace(QStringLiteral("$CLOCK_OFFSET"), QString::number(m_datetime.toMSecsSinceEpoch() * 1000000));
+ metadata.replace(QStringLiteral("$ENDIANNESS"), QSysInfo::ByteOrder == QSysInfo::BigEndian ? u"be"_s : u"le"_s);
+ writeMetadata(metadata, true);
+}
+
+QCtfLibImpl::QCtfLibImpl()
+{
+ QString location = qEnvironmentVariable("QTRACE_LOCATION");
+ if (location.isEmpty()) {
+ qCInfo(lcDebugTrace) << "QTRACE_LOCATION not set";
+ return;
+ }
+
+ if (location.startsWith(u"tcp")) {
+ QUrl url(location);
+ m_server.reset(new QCtfServer());
+ m_server->setCallback(this);
+ m_server->setHost(url.host());
+ m_server->setPort(url.port());
+ m_server->startServer();
+ m_streaming = true;
+ m_session.tracepoints.append(allLiteral());
+ m_session.name = defaultLiteral();
+ } else {
+#if !QT_CONFIG(cxx17_filesystem)
+ qCWarning(lcDebugTrace) << "Unable to use filesystem";
+ return;
+#endif
+ // Check if the location is writable
+ if (QT_ACCESS(qPrintable(location), W_OK) != 0) {
+ qCWarning(lcDebugTrace) << "Unable to write to location";
+ return;
+ }
+ const QString filename = location + u"/session.json";
+ FILE *file = openFile(qPrintable(filename), "rb"_L1);
+ if (!file) {
+ qCWarning(lcDebugTrace) << "unable to open session file: "
+ << filename << ", " << qt_error_string();
+ m_location = location;
+ m_session.tracepoints.append(allLiteral());
+ m_session.name = defaultLiteral();
+ } else {
+ QT_STATBUF stat;
+ if (QT_FSTAT(QT_FILENO(file), &stat) != 0) {
+ qCWarning(lcDebugTrace) << "Unable to stat session file, " << qt_error_string();
+ return;
+ }
+ qsizetype filesize = qMin(stat.st_size, std::numeric_limits<qsizetype>::max());
+ QByteArray data(filesize, Qt::Uninitialized);
+ qsizetype size = static_cast<qsizetype>(fread(data.data(), 1, filesize, file));
+ fclose(file);
+ if (size != filesize)
+ return;
+ QJsonDocument json(QJsonDocument::fromJson(data));
+ QJsonObject obj = json.object();
+ bool valid = false;
+ if (!obj.isEmpty()) {
+ const auto it = obj.begin();
+ if (it.value().isArray()) {
+ m_session.name = it.key();
+ for (auto var : it.value().toArray())
+ m_session.tracepoints.append(var.toString());
+ valid = true;
+ }
+ }
+ if (!valid) {
+ qCWarning(lcDebugTrace) << "Session file is not valid";
+ m_session.tracepoints.append(allLiteral());
+ m_session.name = defaultLiteral();
+ }
+ m_location = location + u"/ust";
+#if QT_CONFIG(cxx17_filesystem)
+ std::filesystem::create_directory(qPrintable(m_location), qPrintable(location));
+#endif
+ }
+ clearLocation();
+ }
+
+ m_session.all = m_session.tracepoints.contains(allLiteral());
+ // Get datetime to when the timer was started to store the offset to epoch time for the traces
+ m_datetime = QDateTime::currentDateTime().toUTC();
+ m_timer.start();
+ if (!m_streaming)
+ buildMetadata();
+}
+
+void QCtfLibImpl::clearLocation()
+{
+#if QT_CONFIG(cxx17_filesystem)
+ const std::filesystem::path location{qUtf16Printable(m_location)};
+ for (auto const& dirEntry : std::filesystem::directory_iterator{location})
+ {
+ const auto path = dirEntry.path();
+#if __cplusplus > 201703L
+ if (dirEntry.is_regular_file()
+ && path.filename().wstring().starts_with(std::wstring_view(L"channel_"))
+ && !path.has_extension()) {
+#else
+ const auto strview = std::wstring_view(L"channel_");
+ const auto sub = path.filename().wstring().substr(0, strview.length());
+ if (dirEntry.is_regular_file() && sub.compare(strview) == 0
+ && !path.has_extension()) {
+#endif
+ if (!std::filesystem::remove(path)) {
+ qCInfo(lcDebugTrace) << "Unable to clear output location.";
+ break;
+ }
+ }
+ }
+#endif
+}
+
+void QCtfLibImpl::writeMetadata(const QString &metadata, bool overwrite)
+{
+ if (m_streaming) {
+ auto mt = metadata.toUtf8();
+ mt.resize(mt.size() - 1);
+ m_server->bufferData(QStringLiteral("metadata"), mt, overwrite);
+ } else {
+ FILE *file = nullptr;
+ file = openFile(qPrintable(m_location + "/metadata"_L1), overwrite ? "w+b"_L1: "ab"_L1);
+ if (!file)
+ return;
+
+ if (!overwrite)
+ fputs("\n", file);
+
+ // data contains zero at the end, hence size - 1.
+ const QByteArray data = metadata.toUtf8();
+ fwrite(data.data(), data.size() - 1, 1, file);
+ fclose(file);
+ }
+}
+
+void QCtfLibImpl::writeCtfPacket(QCtfLibImpl::Channel &ch)
+{
+ FILE *file = nullptr;
+ if (!m_streaming)
+ file = openFile(ch.channelName, "ab"_L1);
+ if (file || m_streaming) {
+ /* Each packet contains header and context, which are defined in the metadata.txt */
+ QByteArray packet;
+ packet << s_CtfHeaderMagic;
+ packet.append(QByteArrayView(s_TraceUuid.toBytes()));
+
+ packet << quint32(0);
+ packet << ch.minTimestamp;
+ packet << ch.maxTimestamp;
+ packet << quint64(ch.data.size() + packetHeaderSize + ch.threadNameLength) * 8u;
+ packet << quint64(packetSize) * 8u;
+ packet << ch.seqnumber++;
+ packet << quint64(0);
+ packet << ch.threadIndex;
+ if (ch.threadName.size())
+ packet.append(ch.threadName);
+ packet << (char)0;
+
+ Q_ASSERT(ch.data.size() + packetHeaderSize + ch.threadNameLength <= packetSize);
+ Q_ASSERT(packet.size() == qsizetype(packetHeaderSize + ch.threadNameLength));
+ if (m_streaming) {
+ ch.data.resize(packetSize - packet.size(), 0);
+ packet += ch.data;
+ m_server->bufferData(QString::fromLatin1(ch.channelName), packet, false);
+ } else {
+ fwrite(packet.data(), packet.size(), 1, file);
+ ch.data.resize(packetSize - packet.size(), 0);
+ fwrite(ch.data.data(), ch.data.size(), 1, file);
+ fclose(file);
+ }
+ }
+}
+
+QCtfLibImpl::Channel::~Channel()
+{
+ impl->writeCtfPacket(*this);
+ impl->removeChannel(this);
+}
+
+QCtfLibImpl::~QCtfLibImpl()
+{
+ if (!m_server.isNull())
+ m_server->stopServer();
+ qDeleteAll(m_eventPrivs);
+}
+
+void QCtfLibImpl::removeChannel(Channel *ch)
+{
+ const QMutexLocker lock(&m_mutex);
+ m_channels.removeOne(ch);
+}
+
+bool QCtfLibImpl::tracepointEnabled(const QCtfTracePointEvent &point)
+{
+ if (m_sessionChanged) {
+ const QMutexLocker lock(&m_mutex);
+ buildMetadata();
+ m_session.name = m_server->sessionName();
+ m_session.tracepoints = m_server->sessionTracepoints().split(';');
+ m_session.all = m_session.tracepoints.contains(allLiteral());
+ m_sessionChanged = false;
+ for (const auto &meta : m_additionalMetadata)
+ writeMetadata(meta->metadata);
+ for (auto *priv : m_eventPrivs)
+ writeMetadata(priv->metadata);
+ quint64 timestamp = m_timer.nsecsElapsed();
+ for (auto *ch : m_channels) {
+ writeCtfPacket(*ch);
+ ch->data.clear();
+ ch->minTimestamp = ch->maxTimestamp = timestamp;
+ }
+ }
+ if (m_streaming && (m_serverClosed || (!m_server->bufferOnIdle() && m_server->status() == QCtfServer::Idle)))
+ return false;
+ return m_session.all || m_session.tracepoints.contains(point.provider.provider);
+}
+
+static QString toMetadata(const QString &provider, const QString &name, const QString &metadata, quint32 eventId)
+{
+/*
+ generates event structure:
+event {
+ name = provider:tracepoint_name;
+ id = eventId;
+ stream_id = 0;
+ loglevel = 13;
+ fields := struct {
+ metadata
+ };
+};
+*/
+ return QStringView(u"event {\n name = \"") + provider + QLatin1Char(':') + name + u"\";\n"
+ + u" id = " + QString::number(eventId) + u";\n"
+ + u" stream_id = 0;\n loglevel = 13;\n fields := struct {\n "
+ + metadata + u"\n };\n};\n";
+}
+
+QCtfTracePointPrivate *QCtfLibImpl::initializeTracepoint(const QCtfTracePointEvent &point)
+{
+ QMutexLocker lock(&m_mutex);
+ QCtfTracePointPrivate *priv = point.d;
+ if (!point.d) {
+ if (const auto &it = m_eventPrivs.find(point.eventName); it != m_eventPrivs.end()) {
+ priv = *it;
+ } else {
+ priv = new QCtfTracePointPrivate();
+ m_eventPrivs.insert(point.eventName, priv);
+ priv->id = eventId();
+ priv->metadata = toMetadata(point.provider.provider, point.eventName, point.metadata, priv->id);
+ }
+ }
+ return priv;
+}
+
+void QCtfLibImpl::doTracepoint(const QCtfTracePointEvent &point, const QByteArray &arr)
+{
+ QCtfTracePointPrivate *priv = point.d;
+ quint64 timestamp = 0;
+ QThread *thread = nullptr;
+ if (m_streaming && m_serverClosed)
+ return;
+ {
+ QMutexLocker lock(&m_mutex);
+ if (!priv->metadataWritten) {
+ priv->metadataWritten = true;
+ auto providerMetadata = point.provider.metadata;
+ while (providerMetadata) {
+ registerMetadata(*providerMetadata);
+ providerMetadata = providerMetadata->next;
+ }
+ if (m_newAdditionalMetadata.size()) {
+ for (const QString &name : m_newAdditionalMetadata)
+ writeMetadata(m_additionalMetadata[name]->metadata);
+ m_newAdditionalMetadata.clear();
+ }
+ writeMetadata(priv->metadata);
+ }
+ timestamp = m_timer.nsecsElapsed();
+ }
+ if (arr.size() != point.size) {
+ if (arr.size() < point.size)
+ return;
+ if (arr.size() > point.size && !point.variableSize && !point.metadata.isEmpty())
+ return;
+ }
+
+ thread = QThread::currentThread();
+ if (thread == nullptr)
+ return;
+
+ Channel &ch = m_threadData.localData();
+
+ if (ch.channelName[0] == 0) {
+ ch.impl = this;
+ m_channels.append(&ch);
+ m_threadIndices.insert(thread, m_threadIndices.size());
+ sprintf(ch.channelName, "%s/channel_%d", qPrintable(m_location), m_threadIndices[thread]);
+ ch.minTimestamp = ch.maxTimestamp = timestamp;
+ ch.thread = thread;
+ ch.threadIndex = m_threadIndices[thread];
+ ch.threadName = thread->objectName().toUtf8();
+ if (ch.threadName.isEmpty()) {
+ const QMetaObject *obj = thread->metaObject();
+ ch.threadName = QByteArray(obj->className());
+ }
+ ch.threadNameLength = ch.threadName.size() + 1;
+ }
+ if (ch.locked)
+ return;
+ Q_ASSERT(ch.thread == thread);
+ ch.locked = true;
+
+ QByteArray event;
+ event << priv->id << timestamp;
+ if (!point.metadata.isEmpty())
+ event.append(arr);
+
+ if (ch.threadNameLength + ch.data.size() + event.size() + packetHeaderSize >= packetSize) {
+ writeCtfPacket(ch);
+ ch.data = event;
+ ch.minTimestamp = ch.maxTimestamp = timestamp;
+ } else {
+ ch.data.append(event);
+ }
+
+ ch.locked = false;
+ ch.maxTimestamp = timestamp;
+}
+
+bool QCtfLibImpl::sessionEnabled()
+{
+ return !m_session.name.isEmpty();
+}
+
+int QCtfLibImpl::eventId()
+{
+ return m_eventId++;
+}
+
+void QCtfLibImpl::registerMetadata(const QCtfTraceMetadata &metadata)
+{
+ if (m_additionalMetadata.contains(metadata.name))
+ return;
+
+ m_additionalMetadata.insert(metadata.name, &metadata);
+ m_newAdditionalMetadata.insert(metadata.name);
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/tracing/qctflib_p.h b/src/plugins/tracing/qctflib_p.h
new file mode 100644
index 0000000000..297d38ee50
--- /dev/null
+++ b/src/plugins/tracing/qctflib_p.h
@@ -0,0 +1,125 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QT_CTFLIB_H
+#define QT_CTFLIB_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 <private/qctf_p.h>
+#include "qctfplugin_p.h"
+#include <qstring.h>
+#include <qmutex.h>
+#include <qelapsedtimer.h>
+#include <qhash.h>
+#include <qset.h>
+#include <qthreadstorage.h>
+#include <qthread.h>
+#include <qloggingcategory.h>
+#include "qctfserver_p.h"
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_LOGGING_CATEGORY(lcDebugTrace)
+
+struct QCtfTracePointPrivate
+{
+ QString metadata;
+ quint32 id = 0;
+ quint32 payloadSize = 0;
+ bool metadataWritten = false;
+};
+
+class QCtfLibImpl : public QCtfLib, public QCtfServer::ServerCallback
+{
+ struct Session
+ {
+ QString name;
+ QStringList tracepoints;
+ bool all = false;
+ };
+ struct Channel
+ {
+ char channelName[512];
+ QByteArray data;
+ quint64 minTimestamp = 0;
+ quint64 maxTimestamp = 0;
+ quint64 seqnumber = 0;
+ QThread *thread = nullptr;
+ quint32 threadIndex = 0;
+ QByteArray threadName;
+ quint32 threadNameLength = 0;
+ bool locked = false;
+ QCtfLibImpl *impl = nullptr;
+ Channel()
+ {
+ memset(channelName, 0, sizeof(channelName));
+ }
+
+ ~Channel();
+ };
+
+public:
+ QCtfLibImpl();
+ ~QCtfLibImpl();
+
+ bool tracepointEnabled(const QCtfTracePointEvent &point) override;
+ void doTracepoint(const QCtfTracePointEvent &point, const QByteArray &arr) override;
+ bool sessionEnabled() override;
+ QCtfTracePointPrivate *initializeTracepoint(const QCtfTracePointEvent &point) override;
+ void registerMetadata(const QCtfTraceMetadata &metadata);
+ int eventId();
+ void shutdown(bool *) override
+ {
+
+ }
+
+ static QCtfLib *instance();
+ static void cleanup();
+private:
+ static QCtfLibImpl *s_instance;
+ QHash<QString, QCtfTracePointPrivate *> m_eventPrivs;
+ void removeChannel(Channel *ch);
+ void updateMetadata(const QCtfTracePointEvent &point);
+ void writeMetadata(const QString &metadata, bool overwrite = false);
+ void clearLocation();
+ void handleSessionChange() override;
+ void handleStatusChange(QCtfServer::ServerStatus status) override;
+ void writeCtfPacket(Channel &ch);
+ void buildMetadata();
+
+ static constexpr QUuid s_TraceUuid = QUuid(0x3e589c95, 0xed11, 0xc159, 0x42, 0x02, 0x6a, 0x9b, 0x02, 0x00, 0x12, 0xac);
+ static constexpr quint32 s_CtfHeaderMagic = 0xC1FC1FC1;
+
+ QMutex m_mutex;
+ QElapsedTimer m_timer;
+ QString m_metadata;
+ QString m_location;
+ Session m_session;
+ QHash<QThread*, quint32> m_threadIndices;
+ QThreadStorage<Channel> m_threadData;
+ QList<Channel *> m_channels;
+ QHash<QString, const QCtfTraceMetadata *> m_additionalMetadata;
+ QSet<QString> m_newAdditionalMetadata;
+ QDateTime m_datetime;
+ int m_eventId = 0;
+ bool m_streaming = false;
+ std::atomic_bool m_sessionChanged = false;
+ std::atomic_bool m_serverClosed = false;
+ QScopedPointer<QCtfServer> m_server;
+ friend struct Channel;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/plugins/tracing/qctfplugin.cpp b/src/plugins/tracing/qctfplugin.cpp
new file mode 100644
index 0000000000..93e508e199
--- /dev/null
+++ b/src/plugins/tracing/qctfplugin.cpp
@@ -0,0 +1,63 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#define BUILD_LIBRARY
+#include <qstring.h>
+#include "qctfplugin_p.h"
+#include "qctflib_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QCtfTracePlugin : public QCtfLib
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QCtfLib" FILE "trace.json")
+ Q_INTERFACES(QCtfLib)
+
+public:
+ QCtfTracePlugin()
+ {
+
+ }
+ ~QCtfTracePlugin()
+ {
+ m_cleanup = true;
+ *m_shutdown = true;
+ QCtfLibImpl::cleanup();
+ }
+ void shutdown(bool *shutdown) override
+ {
+ m_shutdown = shutdown;
+ }
+ bool tracepointEnabled(const QCtfTracePointEvent &point) override
+ {
+ if (m_cleanup)
+ return false;
+ return QCtfLibImpl::instance()->tracepointEnabled(point);
+ }
+ void doTracepoint(const QCtfTracePointEvent &point, const QByteArray &arr) override
+ {
+ if (m_cleanup)
+ return;
+ QCtfLibImpl::instance()->doTracepoint(point, arr);
+ }
+ bool sessionEnabled() override
+ {
+ if (m_cleanup)
+ return false;
+ return QCtfLibImpl::instance()->sessionEnabled();
+ }
+ QCtfTracePointPrivate *initializeTracepoint(const QCtfTracePointEvent &point) override
+ {
+ if (m_cleanup)
+ return nullptr;
+ return QCtfLibImpl::instance()->initializeTracepoint(point);
+ }
+private:
+ bool m_cleanup = false;
+ bool *m_shutdown = nullptr;
+};
+
+QT_END_NAMESPACE
+
+#include "qctfplugin.moc"
diff --git a/src/plugins/tracing/qctfplugin_p.h b/src/plugins/tracing/qctfplugin_p.h
new file mode 100644
index 0000000000..987c4d925f
--- /dev/null
+++ b/src/plugins/tracing/qctfplugin_p.h
@@ -0,0 +1,28 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef Q_CTFPLUGIN_P_H
+#define Q_CTFPLUGIN_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 <private/qctf_p.h>
+#include <qplugin.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_INTERFACE(QCtfLib, "org.qt-project.Qt.QCtfLib")
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/plugins/tracing/qctfserver.cpp b/src/plugins/tracing/qctfserver.cpp
new file mode 100644
index 0000000000..d97c345e11
--- /dev/null
+++ b/src/plugins/tracing/qctfserver.cpp
@@ -0,0 +1,404 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <qloggingcategory.h>
+#include "qctfserver_p.h"
+
+#if QT_CONFIG(zstd)
+#include <zstd.h>
+#endif
+
+using namespace Qt::Literals::StringLiterals;
+
+Q_LOGGING_CATEGORY(lcCtfInfoTrace, "qt.core.ctfserver", QtWarningMsg)
+
+#if QT_CONFIG(zstd)
+static QByteArray zstdCompress(ZSTD_CCtx *&context, const QByteArray &data, int compression)
+{
+ if (context == nullptr)
+ context = ZSTD_createCCtx();
+ qsizetype size = data.size();
+ size = ZSTD_COMPRESSBOUND(size);
+ QByteArray compressed(size, Qt::Uninitialized);
+ char *dst = compressed.data();
+ size_t n = ZSTD_compressCCtx(context, dst, size,
+ data.constData(), data.size(),
+ compression);
+ if (ZSTD_isError(n)) {
+ qCWarning(lcCtfInfoTrace) << "Compression with zstd failed: " << QString::fromUtf8(ZSTD_getErrorName(n));
+ return {};
+ }
+ compressed.truncate(n);
+ return compressed;
+}
+#endif
+
+QCtfServer::QCtfServer(QObject *parent)
+ : QThread(parent)
+{
+ m_keySet << "cliendId"_L1
+ << "clientVersion"_L1
+ << "sessionName"_L1
+ << "sessionTracepoints"_L1
+ << "flags"_L1
+ << "bufferSize"_L1
+ << "compressionScheme"_L1;
+}
+
+QCtfServer::~QCtfServer()
+{
+#if QT_CONFIG(zstd)
+ ZSTD_freeCCtx(m_zstdCCtx);
+#endif
+}
+
+void QCtfServer::setHost(const QString &address)
+{
+ m_address = address;
+}
+
+void QCtfServer::setPort(int port)
+{
+ m_port = port;
+}
+
+void QCtfServer::setCallback(ServerCallback *cb)
+{
+ m_cb = cb;
+}
+
+QString QCtfServer::sessionName() const
+{
+ return m_req.sessionName;
+}
+
+QString QCtfServer::sessionTracepoints() const
+{
+ return m_req.sessionTracepoints;
+}
+
+bool QCtfServer::bufferOnIdle() const
+{
+ return m_bufferOnIdle;
+}
+
+QCtfServer::ServerStatus QCtfServer::status() const
+{
+ return m_status;
+}
+
+void QCtfServer::setStatusAndNotify(ServerStatus status)
+{
+ m_status = status;
+ m_cb->handleStatusChange(status);
+}
+
+void QCtfServer::bytesWritten(qint64 size)
+{
+ m_writtenSize += size;
+ if (m_writtenSize >= m_waitWriteSize && m_eventLoop)
+ m_eventLoop->exit();
+}
+
+void QCtfServer::initWrite()
+{
+ m_waitWriteSize = 0;
+ m_writtenSize = 0;
+}
+
+bool QCtfServer::waitSocket()
+{
+ if (m_eventLoop)
+ m_eventLoop->exec();
+ return m_socket->state() == QTcpSocket::ConnectedState;
+}
+
+void QCtfServer::handleString(QCborStreamReader &cbor)
+{
+ const auto readString = [](QCborStreamReader &cbor) -> QString {
+ QString result;
+ auto r = cbor.readString();
+ while (r.status == QCborStreamReader::Ok) {
+ result += r.data;
+ r = cbor.readString();
+ }
+
+ if (r.status == QCborStreamReader::Error) {
+ // handle error condition
+ result.clear();
+ }
+ return result;
+ };
+ do {
+ if (m_currentKey.isEmpty()) {
+ m_currentKey = readString(cbor);
+ } else {
+ switch (m_keySet.indexOf(m_currentKey)) {
+ case RequestSessionName:
+ m_req.sessionName = readString(cbor);
+ break;
+ case RequestSessionTracepoints:
+ m_req.sessionTracepoints = readString(cbor);
+ break;
+ case RequestCompressionScheme:
+ m_requestedCompressionScheme = readString(cbor);
+ break;
+ default:
+ // handle error
+ break;
+ }
+ m_currentKey.clear();
+ }
+ if (cbor.lastError() == QCborError::EndOfFile) {
+ if (!waitSocket())
+ return;
+ cbor.reparse();
+ }
+ } while (cbor.lastError() == QCborError::EndOfFile);
+}
+
+void QCtfServer::handleFixedWidth(QCborStreamReader &cbor)
+{
+ switch (m_keySet.indexOf(m_currentKey)) {
+ case RequestClientId:
+ if (!cbor.isUnsignedInteger())
+ return;
+ m_req.clientId = cbor.toUnsignedInteger();
+ break;
+ case RequestClientVersion:
+ if (!cbor.isUnsignedInteger())
+ return;
+ m_req.clientVersion = cbor.toUnsignedInteger();
+ break;
+ case RequestFlags:
+ if (!cbor.isUnsignedInteger())
+ return;
+ m_req.flags = cbor.toUnsignedInteger();
+ break;
+ case RequestBufferSize:
+ if (!cbor.isUnsignedInteger())
+ return;
+ m_req.bufferSize = cbor.toUnsignedInteger();
+ break;
+ default:
+ // handle error
+ break;
+ }
+ m_currentKey.clear();
+}
+
+void QCtfServer::readCbor(QCborStreamReader &cbor)
+{
+ switch (cbor.type()) {
+ case QCborStreamReader::UnsignedInteger:
+ case QCborStreamReader::NegativeInteger:
+ case QCborStreamReader::SimpleType:
+ case QCborStreamReader::Float16:
+ case QCborStreamReader::Float:
+ case QCborStreamReader::Double:
+ handleFixedWidth(cbor);
+ cbor.next();
+ break;
+ case QCborStreamReader::ByteArray:
+ case QCborStreamReader::String:
+ handleString(cbor);
+ break;
+ case QCborStreamReader::Array:
+ case QCborStreamReader::Map:
+ cbor.enterContainer();
+ while (cbor.lastError() == QCborError::NoError && cbor.hasNext())
+ readCbor(cbor);
+ if (cbor.lastError() == QCborError::NoError)
+ cbor.leaveContainer();
+ default:
+ break;
+ }
+}
+
+void QCtfServer::writePacket(TracePacket &packet, QCborStreamWriter &cbor)
+{
+ cbor.startMap(4);
+ cbor.append("magic"_L1);
+ cbor.append(packet.PacketMagicNumber);
+ cbor.append("name"_L1);
+ cbor.append(QString::fromUtf8(packet.stream_name));
+ cbor.append("flags"_L1);
+ cbor.append(packet.flags);
+
+ cbor.append("data"_L1);
+ if (m_compression > 0) {
+ QByteArray compressed;
+#if QT_CONFIG(zstd)
+ if (m_requestedCompressionScheme == QStringLiteral("zstd"))
+ compressed = zstdCompress(m_zstdCCtx, packet.stream_data, m_compression);
+ else
+#endif
+ compressed = qCompress(packet.stream_data, m_compression);
+
+ cbor.append(compressed);
+ } else {
+ cbor.append(packet.stream_data);
+ }
+
+ cbor.endMap();
+}
+
+bool QCtfServer::recognizedCompressionScheme() const
+{
+ if (m_requestedCompressionScheme.isEmpty())
+ return true;
+#if QT_CONFIG(zstd)
+ if (m_requestedCompressionScheme == QStringLiteral("zstd"))
+ return true;
+#endif
+ if (m_requestedCompressionScheme == QStringLiteral("zlib"))
+ return true;
+ return false;
+}
+
+void QCtfServer::run()
+{
+ m_server = new QTcpServer();
+ QHostAddress addr;
+ if (m_address.isEmpty())
+ addr = QHostAddress(QHostAddress::Any);
+ else
+ addr = QHostAddress(m_address);
+
+ qCInfo(lcCtfInfoTrace) << "Starting CTF server: " << m_address << ", port: " << m_port;
+
+ while (m_stopping == 0) {
+ if (!m_server->isListening()) {
+ if (!m_server->listen(addr, m_port)) {
+ qCInfo(lcCtfInfoTrace) << "Unable to start server";
+ m_stopping = 1;
+ setStatusAndNotify(Error);
+ }
+ }
+ setStatusAndNotify(Idle);
+ if (m_server->waitForNewConnection(-1)) {
+ qCInfo(lcCtfInfoTrace) << "client connection";
+ m_eventLoop = new QEventLoop();
+ m_socket = m_server->nextPendingConnection();
+
+ QObject::connect(m_socket, &QTcpSocket::readyRead, [&](){
+ if (m_eventLoop) m_eventLoop->exit();
+ });
+ QObject::connect(m_socket, &QTcpSocket::bytesWritten, this, &QCtfServer::bytesWritten);
+ QObject::connect(m_socket, &QTcpSocket::disconnected, [&](){
+ if (m_eventLoop) m_eventLoop->exit();
+ });
+
+ m_server->close(); // Do not wait for more connections
+ setStatusAndNotify(Connected);
+
+ if (waitSocket())
+ {
+ QCborStreamReader cbor(m_socket);
+
+ m_req = {};
+ while (cbor.hasNext() && cbor.lastError() == QCborError::NoError)
+ readCbor(cbor);
+
+ if (!m_req.isValid()) {
+ qCInfo(lcCtfInfoTrace) << "Invalid trace request.";
+ m_socket->close();
+ } else {
+ m_compression = m_req.flags & CompressionMask;
+#if QT_CONFIG(zstd)
+ m_compression = qMin(m_compression, ZSTD_maxCLevel());
+#else
+ m_compression = qMin(m_compression, 9);
+#endif
+ m_bufferOnIdle = !(m_req.flags & DontBufferOnIdle);
+
+ m_maxPackets = qMax(m_req.bufferSize / TracePacket::PacketSize, 16u);
+
+ if (!recognizedCompressionScheme()) {
+ qCWarning(lcCtfInfoTrace) << "Client requested unrecognized compression scheme: " << m_requestedCompressionScheme;
+ m_requestedCompressionScheme.clear();
+ m_compression = 0;
+ }
+
+ qCInfo(lcCtfInfoTrace) << "request received: " << m_req.sessionName << ", " << m_req.sessionTracepoints;
+
+ m_cb->handleSessionChange();
+ {
+ TraceResponse resp;
+ resp.serverId = ServerId;
+ resp.serverVersion = 1;
+ resp.serverName = QStringLiteral("Ctf Server");
+
+ QCborStreamWriter cbor(m_socket);
+ cbor.startMap(m_compression ? 4 : 3);
+ cbor.append("serverId"_L1);
+ cbor.append(resp.serverId);
+ cbor.append("serverVersion"_L1);
+ cbor.append(resp.serverVersion);
+ cbor.append("serverName"_L1);
+ cbor.append(resp.serverName);
+ if (m_compression) {
+ cbor.append("compressionScheme"_L1);
+ cbor.append(m_requestedCompressionScheme);
+ }
+ cbor.endMap();
+ }
+
+ qCInfo(lcCtfInfoTrace) << "response sent, sending data";
+ if (waitSocket()) {
+ while (m_socket->state() == QTcpSocket::ConnectedState) {
+ QList<TracePacket> packets;
+ {
+ QMutexLocker lock(&m_mutex);
+ while (m_packets.size() == 0)
+ m_bufferHasData.wait(&m_mutex);
+ packets = std::exchange(m_packets, {});
+ }
+
+ {
+ QCborStreamWriter cbor(m_socket);
+ for (TracePacket &packet : packets) {
+ writePacket(packet, cbor);
+ if (!waitSocket())
+ break;
+ }
+ }
+ qCInfo(lcCtfInfoTrace) << packets.size() << " packets written";
+ }
+ }
+
+ qCInfo(lcCtfInfoTrace) << "client connection closed";
+ }
+ }
+ delete m_eventLoop;
+ m_eventLoop = nullptr;
+ } else {
+ qCInfo(lcCtfInfoTrace) << "error: " << m_server->errorString();
+ m_stopping = 1;
+ setStatusAndNotify(Error);
+ }
+ }
+}
+
+void QCtfServer::startServer()
+{
+ start();
+}
+void QCtfServer::stopServer()
+{
+ this->m_stopping = 1;
+ wait();
+}
+
+void QCtfServer::bufferData(const QString &stream, const QByteArray &data, quint32 flags)
+{
+ QMutexLocker lock(&m_mutex);
+ TracePacket packet;
+ packet.stream_name = stream.toUtf8();
+ packet.stream_data = data;
+ packet.flags = flags;
+ m_packets.append(packet);
+ if (m_packets.size() > m_maxPackets)
+ m_packets.pop_front();
+ m_bufferHasData.wakeOne();
+}
diff --git a/src/plugins/tracing/qctfserver_p.h b/src/plugins/tracing/qctfserver_p.h
new file mode 100644
index 0000000000..3660df7f09
--- /dev/null
+++ b/src/plugins/tracing/qctfserver_p.h
@@ -0,0 +1,194 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QT_CTFSERVER_H
+#define QT_CTFSERVER_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 <qbytearray.h>
+#include <qdatastream.h>
+#include <qthread.h>
+#include <qmutex.h>
+#include <qwaitcondition.h>
+#include <qeventloop.h>
+#include <QtNetwork/qtcpserver.h>
+#include <QtNetwork/qtcpsocket.h>
+#include <qcborstreamreader.h>
+#include <qcborstreamwriter.h>
+#include <qlist.h>
+
+typedef struct ZSTD_CCtx_s ZSTD_CCtx;
+
+QT_BEGIN_NAMESPACE
+
+class QCtfServer;
+struct TracePacket
+{
+ static constexpr quint32 PacketMagicNumber = 0x100924da;
+ static constexpr quint32 PacketSize = 4096 + 9;
+ QByteArray stream_name;
+ QByteArray stream_data;
+ quint32 flags = 0;
+
+ TracePacket() = default;
+
+ TracePacket(const TracePacket &t)
+ {
+ stream_name = t.stream_name;
+ stream_data = t.stream_data;
+ flags = t.flags;
+ }
+ TracePacket &operator = (const TracePacket &t)
+ {
+ stream_name = t.stream_name;
+ stream_data = t.stream_data;
+ flags = t.flags;
+ return *this;
+ }
+ TracePacket(TracePacket &&t)
+ {
+ stream_name = std::move(t.stream_name);
+ stream_data = std::move(t.stream_data);
+ flags = t.flags;
+ }
+ TracePacket &operator = (TracePacket &&t)
+ {
+ stream_name = std::move(t.stream_name);
+ stream_data = std::move(t.stream_data);
+ flags = t.flags;
+ return *this;
+ }
+};
+
+auto constexpr operator""_MB(quint64 s) -> quint64
+{
+ return s * 1024ul * 1024ul;
+}
+
+struct TraceRequest
+{
+ quint32 clientId;
+ quint32 clientVersion;
+ quint32 flags;
+ quint32 bufferSize;
+ QString sessionName;
+ QString sessionTracepoints;
+
+ static constexpr quint32 MaxBufferSize = 1024_MB;
+
+ bool isValid() const
+ {
+ if (clientId != 0 && clientVersion != 0 && !sessionName.isEmpty()
+ && !sessionTracepoints.isEmpty() && bufferSize < MaxBufferSize)
+ return true;
+ return false;
+ }
+};
+
+struct TraceResponse
+{
+ quint32 serverId;
+ quint32 serverVersion;
+ QString serverName;
+};
+
+class QCtfServer : public QThread
+{
+ Q_OBJECT
+public:
+ enum ServerStatus
+ {
+ Uninitialized,
+ Idle,
+ Connected,
+ Error,
+ };
+ enum ServerFlags
+ {
+ CompressionMask = 255,
+ DontBufferOnIdle = 256, // not set -> the server is buffering even without client connection
+ // set -> the server is buffering only when client is connected
+ };
+ enum RequestIds
+ {
+ RequestClientId = 0,
+ RequestClientVersion,
+ RequestSessionName,
+ RequestSessionTracepoints,
+ RequestFlags,
+ RequestBufferSize,
+ RequestCompressionScheme,
+ };
+
+ struct ServerCallback
+ {
+ virtual void handleSessionChange() = 0;
+ virtual void handleStatusChange(ServerStatus status) = 0;
+ };
+ QCtfServer(QObject *parent = nullptr);
+ ~QCtfServer();
+ void setCallback(ServerCallback *cb);
+ void setHost(const QString &address);
+ void setPort(int port);
+ void run() override;
+ void startServer();
+ void stopServer();
+ void bufferData(const QString &stream, const QByteArray &data, quint32 flags);
+ QString sessionName() const;
+ QString sessionTracepoints() const;
+ bool bufferOnIdle() const;
+ ServerStatus status() const;
+private:
+
+ void initWrite();
+ void bytesWritten(qint64 size);
+ bool waitSocket();
+ void readCbor(QCborStreamReader &cbor);
+ void handleString(QCborStreamReader &cbor);
+ void handleFixedWidth(QCborStreamReader &cbor);
+ bool recognizedCompressionScheme() const;
+ void setStatusAndNotify(ServerStatus status);
+ void writePacket(TracePacket &packet, QCborStreamWriter &cbor);
+
+ QMutex m_mutex;
+ QWaitCondition m_bufferHasData;
+ QList<TracePacket> m_packets;
+ QString m_address;
+ QTcpServer *m_server = nullptr;
+ QTcpSocket *m_socket = nullptr;
+ QEventLoop *m_eventLoop = nullptr;
+ QList<QString> m_keySet;
+ TraceRequest m_req;
+ ServerCallback *m_cb = nullptr;
+ ServerStatus m_status = Uninitialized;
+ qint64 m_waitWriteSize = 0;
+ qint64 m_writtenSize = 0;
+ int m_port;
+ int m_compression = 0;
+ int m_maxPackets = DefaultMaxPackets;
+ QAtomicInt m_stopping;
+ bool m_bufferOnIdle = true;
+ QString m_currentKey;
+ QString m_requestedCompressionScheme;
+#if QT_CONFIG(zstd)
+ ZSTD_CCtx *m_zstdCCtx = nullptr;
+#endif
+
+ static constexpr quint32 ServerId = 1;
+ static constexpr quint32 DefaultMaxPackets = 256; // 1 MB
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/plugins/tracing/trace.json b/src/plugins/tracing/trace.json
new file mode 100644
index 0000000000..1b991122d4
--- /dev/null
+++ b/src/plugins/tracing/trace.json
@@ -0,0 +1,3 @@
+{
+ "Keys": [ "CTF" ]
+}